Cleanup
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:
164
src/render.rs
164
src/render.rs
@@ -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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user