AKA I made these changes a month ago but forgot to commit them and don't
really want to figure out what they did.
This commit is contained in:
2020-11-27 21:22:42 -08:00
parent 1a9093315a
commit 9d15e126a7
6 changed files with 228 additions and 86 deletions

View File

@@ -6,12 +6,12 @@ use crate::sim::{Cell, GenericSim};
use crate::meas::AbstractMeasurement;
use font8x8::{BASIC_FONTS, GREEK_FONTS, UnicodeFonts as _};
use log::{trace, info};
use plotly::{Plot, ImageFormat};
use plotly::heat_map::HeatMap;
use plotly;
use image::{RgbImage, Rgb};
use imageproc::{pixelops, drawing};
use std::fs::File;
use std::path::PathBuf;
use std::sync::{Mutex, RwLock};
use y4m;
/// Accept a value from (-\inf, \inf) and return a value in (-1, 1).
@@ -54,6 +54,17 @@ fn scale_vector(x: Vec2, typical_mag: Flt) -> Vec2 {
x.with_mag(new_mag)
}
fn im_size(state: &dyn GenericSim, max_w: u32, max_h: u32) -> (u32, u32) {
let mut width = max_w;
let mut height = width * state.height() / state.width();
if height > max_h {
let stretch = max_h as f32 / height as f32;
width = (width as f32 * stretch) as _;
height = max_h;
}
(width, height)
}
struct RenderSteps<'a> {
im: RgbImage,
sim: &'a dyn GenericSim,
@@ -64,14 +75,7 @@ struct RenderSteps<'a> {
impl<'a> RenderSteps<'a> {
fn render(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
let mut width = 640;
let max_height = 480;
let mut height = width * state.height() / state.width();
if height > max_height {
let stretch = max_height as f32 / height as f32;
width = (width as f32 * stretch) as _;
height = max_height;
}
let (width, height) = im_size(state, 640, 480);
trace!("rendering at {}x{} with z={}", width, height, z);
let mut me = Self::new(state, measurements, width, height, z);
me.render_scalar_field(10.0, false, 2, |cell| {
@@ -230,11 +234,13 @@ impl ImageRenderExt for RgbImage {
}
}
pub trait Renderer {
fn render(&mut self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
pub trait Renderer: Send + Sync {
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2));
}
fn render_with_image(&mut self, state: &dyn GenericSim, _im: &RgbImage) {
/// Not intended to be called directly by users; implement this if you want the image to be
/// computed using default settings and you just manage where to display/save it.
fn render_with_image(&self, state: &dyn GenericSim, _im: &RgbImage) {
self.render(state, &[]);
}
}
@@ -262,7 +268,7 @@ pub trait Renderer {
pub struct ColorTermRenderer;
impl Renderer for ColorTermRenderer {
fn render_with_image(&mut self, _state: &dyn GenericSim, im: &RgbImage) {
fn render_with_image(&self, _state: &dyn GenericSim, im: &RgbImage) {
let square = "";
let buf: String = im
.enumerate_rows()
@@ -279,27 +285,30 @@ impl Renderer for ColorTermRenderer {
pub struct Y4MRenderer {
out_path: PathBuf,
encoder: Option<y4m::Encoder<File>>,
encoder: Mutex<Option<y4m::Encoder<File>>>,
}
impl Y4MRenderer {
pub fn new<S: Into<PathBuf>>(output: S) -> Self {
Self {
out_path: output.into(),
encoder: None,
encoder: Mutex::new(None),
}
}
}
impl Renderer for Y4MRenderer {
fn render_with_image(&mut self, _state: &dyn GenericSim, im: &RgbImage) {
if self.encoder.is_none() {
let writer = File::create(&self.out_path).unwrap();
self.encoder = Some(y4m::encode(im.width() as usize, im.height() as usize, y4m::Ratio::new(30, 1))
.with_colorspace(y4m::Colorspace::C444)
.write_header(writer)
.unwrap()
);
fn render_with_image(&self, _state: &dyn GenericSim, im: &RgbImage) {
{
let mut enc = self.encoder.lock().unwrap();
if enc.is_none() {
let writer = File::create(&self.out_path).unwrap();
*enc = Some(y4m::encode(im.width() as usize, im.height() as usize, y4m::Ratio::new(30, 1))
.with_colorspace(y4m::Colorspace::C444)
.write_header(writer)
.unwrap()
);
}
}
let mut pix_y = Vec::new();
@@ -318,7 +327,8 @@ impl Renderer for Y4MRenderer {
}
let frame = y4m::Frame::new([&*pix_y, &*pix_u, &*pix_v], None);
let enc = self.encoder.as_mut().unwrap();
let mut lock = self.encoder.lock().unwrap();
let enc = lock.as_mut().unwrap();
trace!("write_frame begin");
let ret = enc.write_frame(&frame).unwrap();
trace!("write_frame end");
@@ -326,44 +336,112 @@ impl Renderer for Y4MRenderer {
}
}
pub struct PlotlyRenderer;
pub struct PlotlyRenderer {
out_base: String,
}
fn add_scatter(plot: &mut plotly::Plot, xv: &mut Vec<u32>, yv: &mut Vec<u32>, zv: &mut Vec<u32>, colors: &mut Vec<plotly::Rgba>) {
let xv = std::mem::replace(xv, Vec::new());
let yv = std::mem::replace(yv, Vec::new());
let zv = std::mem::replace(zv, Vec::new());
let colors = std::mem::replace(colors, Vec::new());
let scatter = plotly::Scatter::new3(xv, yv, zv)
.mode(plotly::common::Mode::Markers)
.marker(plotly::common::Marker::new()
.opacity(0.01)
//.size_array(sizes)
//.opacity_array(opacities)
.color_array(colors)
);
plot.add_trace(scatter);
}
impl PlotlyRenderer {
pub fn new(out_base: &str) -> Self {
Self {
out_base: out_base.into(),
}
}
}
impl Renderer for PlotlyRenderer {
fn render(&mut self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
use plotly::{ImageFormat, Plot, Rgba, Scatter};
use plotly::common::Marker;
use plotly::layout::{AspectMode, Axis, Layout, LayoutScene};
let mut plot = Plot::new();
let scene = LayoutScene::new()
.x_axis(Axis::new().range(vec![0, state.width() as i32]))
.y_axis(Axis::new().range(vec![0, state.height() as i32]))
.z_axis(Axis::new().range(vec![0, state.depth() as i32]))
.aspect_mode(AspectMode::Cube);
let layout = Layout::new()
.scene(scene);
plot.set_layout(layout);
let mut xv = Vec::new();
let mut yv = Vec::new();
let mut zv = Vec::new();
// let mut opacities = Vec::new();
let mut colors = Vec::new();
for z in 0..state.depth() {
if xv.len() >= 120000 {
add_scatter(&mut plot, &mut xv, &mut yv, &mut zv, &mut colors);
}
for y in 0..state.height() {
for x in 0..state.width() {
// if x%5 == 0 || y%5 == 0 || z%5 == 0 {
// continue;
// }
let cell = state.get(Index(Vec3u::new(x, y, z)));
if cell.e().mag() > 10.0 {
xv.push(x);
yv.push(y);
zv.push(z);
}
xv.push(x);
yv.push(y);
zv.push(z);
// opacities.push((cell.e().mag() * 0.1).min(1.0) as f64)
let mat = cell.mat().conductivity().mag() + if cell.mat().is_vacuum() {
0.0
} else {
5.0
};
//let g = scale_unsigned_to_u8(mat, 10.0);
//let r = scale_unsigned_to_u8(cell.mat().m().mag(), 100.0);
//let b = scale_unsigned_to_u8(cell.e().mag(), 1e2);
let r = scale_unsigned_to_u8(cell.mat().m().mag(), 100.0);
let g = scale_unsigned_to_u8(cell.e().mag(), 1e2);
let b = scale_unsigned_to_u8(mat, 10.0);
let alpha = 1.0;
colors.push(Rgba::new(r, g, b, alpha));
}
}
// let scatter = plotly::Scatter::new3(xv, yv, zv)
// .mode(plotly::common::Mode::Markers)
// .marker(plotly::common::Marker::new()
// //.opacity(0.2)
// //.size_array(sizes)
// //.opacity_array(opacities)
// .color_array(colors)
// );
// plot.add_trace(scatter);
}
let heat_map = HeatMap::new(xv, yv, zv);
plot.add_trace(heat_map);
let name = format!("frame{}", state.step_no());
plot.save(&*name, ImageFormat::PNG, state.width() as _, state.height() as _, 1.0);
add_scatter(&mut plot, &mut xv, &mut yv, &mut zv, &mut colors);
let name = format!("{}{}", self.out_base, state.step_no());
let (im_w, im_h) = im_size(state, 2048, 2048);
plot.save(&*name, ImageFormat::PNG, im_w as _, im_h as _, 1.0);
}
}
#[derive(Default)]
pub struct MultiRenderer {
renderers: Vec<Box<dyn Renderer>>,
renderers: RwLock<Vec<Box<dyn Renderer>>>,
}
impl MultiRenderer {
pub fn new() -> Self {
Default::default()
}
pub fn push<R: Renderer + 'static>(&mut self, r: R) {
self.renderers.push(Box::new(r));
pub fn push<R: Renderer + 'static>(&self, r: R) {
self.renderers.write().unwrap().push(Box::new(r));
}
pub fn with<R: Renderer + 'static>(mut self, r: R) -> Self {
self.push(r);
@@ -372,14 +450,14 @@ impl MultiRenderer {
}
impl Renderer for MultiRenderer {
fn render(&mut self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
if self.renderers.len() != 0 {
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
if self.renderers.read().unwrap().len() != 0 {
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2));
}
}
fn render_with_image(&mut self, state: &dyn GenericSim, im: &RgbImage) {
for r in &mut self.renderers {
fn render_with_image(&self, state: &dyn GenericSim, im: &RgbImage) {
for r in &*self.renderers.read().unwrap() {
r.render_with_image(state, im);
}
}