Merge branch 'parameterize-renderer'
This commit is contained in:
@@ -8,6 +8,7 @@ use crate::sim::{GenericSim, SimState};
|
|||||||
use crate::stim::AbstractStimulus;
|
use crate::stim::AbstractStimulus;
|
||||||
|
|
||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
|
use serde::Serialize;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
|
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};
|
||||||
@@ -16,7 +17,7 @@ use threadpool::ThreadPool;
|
|||||||
|
|
||||||
pub struct Driver<M=GenericMaterial> {
|
pub struct Driver<M=GenericMaterial> {
|
||||||
pub state: SimState<M>,
|
pub state: SimState<M>,
|
||||||
renderer: Arc<MultiRenderer>,
|
renderer: Arc<MultiRenderer<SimState<M>>>,
|
||||||
// TODO: use Rayon's thread pool?
|
// TODO: use Rayon's thread pool?
|
||||||
render_pool: ThreadPool,
|
render_pool: ThreadPool,
|
||||||
render_channel: (SyncSender<()>, Receiver<()>),
|
render_channel: (SyncSender<()>, Receiver<()>),
|
||||||
@@ -51,12 +52,6 @@ impl<M: Default> Driver<M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material + Clone + Send + Sync + 'static> Driver<M> {
|
|
||||||
pub fn dyn_state(&mut self) -> &mut dyn GenericSim {
|
|
||||||
&mut self.state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M: Material> Driver<M> {
|
impl<M: Material> Driver<M> {
|
||||||
pub fn add_stimulus<S: AbstractStimulus + 'static>(&mut self, s: S) {
|
pub fn add_stimulus<S: AbstractStimulus + 'static>(&mut self, s: S) {
|
||||||
self.stimuli.push(Box::new(s))
|
self.stimuli.push(Box::new(s))
|
||||||
@@ -69,8 +64,30 @@ impl<M: Material> Driver<M> {
|
|||||||
pub fn set_steps_per_frame(&mut self, steps_per_frame: u64) {
|
pub fn set_steps_per_frame(&mut self, steps_per_frame: u64) {
|
||||||
self.steps_per_frame = steps_per_frame;
|
self.steps_per_frame = steps_per_frame;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn add_renderer<R: Renderer + 'static>(&mut self, renderer: R, name: &str) {
|
impl<M: Material + Clone> Driver<M> {
|
||||||
|
pub fn fill_region<R: Region>(&mut self, region: &R, mat: M) {
|
||||||
|
for z in 0..self.state.depth() {
|
||||||
|
for y in 0..self.state.height() {
|
||||||
|
for x in 0..self.state.width() {
|
||||||
|
let loc = Index((x, y, z).into());
|
||||||
|
let meters = loc.to_meters(self.state.feature_size());
|
||||||
|
if region.contains(meters) {
|
||||||
|
*self.state.get_mut(loc).mat_mut() = mat.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: Material + Clone + Send + Sync + 'static> Driver<M> {
|
||||||
|
pub fn dyn_state(&mut self) -> &mut dyn GenericSim {
|
||||||
|
&mut self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_renderer<R: Renderer<SimState<M>> + 'static>(&mut self, renderer: R, name: &str) {
|
||||||
info!("render to {}", name);
|
info!("render to {}", name);
|
||||||
self.renderer.push(renderer);
|
self.renderer.push(renderer);
|
||||||
}
|
}
|
||||||
@@ -88,25 +105,11 @@ impl<M: Material> Driver<M> {
|
|||||||
pub fn add_term_renderer(&mut self) {
|
pub fn add_term_renderer(&mut self) {
|
||||||
self.add_renderer(render::ColorTermRenderer, "terminal");
|
self.add_renderer(render::ColorTermRenderer, "terminal");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_serializer_renderer(&mut self, out_base: &str) {
|
|
||||||
self.add_renderer(render::SerializerRenderer::new(out_base), out_base);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material + Clone> Driver<M> {
|
impl<M: Material + Serialize + Clone + Send + Sync + 'static> Driver<M> {
|
||||||
pub fn fill_region<R: Region>(&mut self, region: &R, mat: M) {
|
pub fn add_serializer_renderer(&mut self, out_base: &str) {
|
||||||
for z in 0..self.state.depth() {
|
self.add_renderer(render::SerializerRenderer::new(out_base), out_base);
|
||||||
for y in 0..self.state.height() {
|
|
||||||
for x in 0..self.state.width() {
|
|
||||||
let loc = Index((x, y, z).into());
|
|
||||||
let meters = loc.to_meters(self.state.feature_size());
|
|
||||||
if region.contains(meters) {
|
|
||||||
*self.state.get_mut(loc).mat_mut() = mat.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,25 +185,6 @@ impl<M: Material + Clone + Default + Send + Sync + 'static> Driver<M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<M: Material + From<mat::Conductor>> Driver<M> {
|
impl<M: Material + From<mat::Conductor>> Driver<M> {
|
||||||
// pub fn add_boundary(&mut self, thickness: u32, base_conductivity: Flt) {
|
|
||||||
// for inset in 0..thickness {
|
|
||||||
// let depth = thickness - inset;
|
|
||||||
// let conductivity = base_conductivity * (depth*depth) as Flt;
|
|
||||||
// for x in inset..self.state.width() - inset {
|
|
||||||
// // left
|
|
||||||
// *self.state.get_mut((x, inset).into()).mat_mut() = mat::Static::conductor(conductivity).into();
|
|
||||||
// // right
|
|
||||||
// *self.state.get_mut((x, self.state.height() - 1 - inset).into()).mat_mut() = mat::Static::conductor(conductivity).into();
|
|
||||||
// }
|
|
||||||
// for y in inset..self.state.height() - inset {
|
|
||||||
// // top
|
|
||||||
// *self.state.get_mut((inset, y).into()).mat_mut() = mat::Static::conductor(conductivity).into();
|
|
||||||
// // bottom
|
|
||||||
// *self.state.get_mut((self.state.width() - 1 - inset, y).into()).mat_mut() = mat::Static::conductor(conductivity).into();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn add_upml_boundary<C: Coord>(&mut self, thickness: C) {
|
pub fn add_upml_boundary<C: Coord>(&mut self, thickness: C) {
|
||||||
// Based on explanation here (slide 63): https://empossible.net/wp-content/uploads/2020/01/Lecture-The-Perfectly-Matched-Layer.pdf
|
// Based on explanation here (slide 63): https://empossible.net/wp-content/uploads/2020/01/Lecture-The-Perfectly-Matched-Layer.pdf
|
||||||
let thickness = thickness.to_index(self.state.feature_size());
|
let thickness = thickness.to_index(self.state.feature_size());
|
||||||
|
@@ -239,7 +239,7 @@ impl PiecewiseLinearFerromagnet for Ferroxcube3R1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[enum_dispatch(Material)]
|
#[enum_dispatch(Material)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub enum GenericMaterial {
|
pub enum GenericMaterial {
|
||||||
Conductor(Conductor),
|
Conductor(Conductor),
|
||||||
Ferroxcube3R1(Ferroxcube3R1),
|
Ferroxcube3R1(Ferroxcube3R1),
|
||||||
|
17
src/post.rs
17
src/post.rs
@@ -1,13 +1,14 @@
|
|||||||
//! Post-processing tools
|
//! Post-processing tools
|
||||||
use crate::StaticSim;
|
use crate::mat::GenericMaterial;
|
||||||
use crate::render::{ColorTermRenderer, Renderer as _, SerializedFrame};
|
use crate::render::{ColorTermRenderer, Renderer as _, SerializedFrame};
|
||||||
|
use crate::sim::{GenericSim, SimState, StaticSim};
|
||||||
|
|
||||||
use itertools::Itertools as _;
|
use itertools::Itertools as _;
|
||||||
use lru::LruCache;
|
use lru::LruCache;
|
||||||
use rayon::{ThreadPool, ThreadPoolBuilder};
|
use rayon::{ThreadPool, ThreadPoolBuilder};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::fs::{DirEntry, File, read_dir};
|
use std::fs::{DirEntry, File, read_dir};
|
||||||
use std::io::BufReader;
|
use std::io::{BufReader, Seek as _, SeekFrom};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -77,8 +78,16 @@ impl Loader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self, path: &Path) -> Frame {
|
fn load(&self, path: &Path) -> Frame {
|
||||||
let reader = BufReader::new(File::open(path).unwrap());
|
let mut reader = BufReader::new(File::open(path).unwrap());
|
||||||
let data = bincode::deserialize_from(reader).unwrap();
|
// Try to deserialize a couple different types of likely sims.
|
||||||
|
// TODO: would be good to drop a marker in the file to make sure we don't
|
||||||
|
// decode to a valid but incorrect state...
|
||||||
|
let data = bincode::deserialize_from(&mut reader).unwrap_or_else(|_| {
|
||||||
|
reader.seek(SeekFrom::Start(0)).unwrap();
|
||||||
|
let data: SerializedFrame<SimState<GenericMaterial>> =
|
||||||
|
bincode::deserialize_from(reader).unwrap();
|
||||||
|
data.to_static()
|
||||||
|
});
|
||||||
Frame {
|
Frame {
|
||||||
path: path.into(),
|
path: path.into(),
|
||||||
data
|
data
|
||||||
|
119
src/render.rs
119
src/render.rs
@@ -59,7 +59,7 @@ fn scale_vector(x: Vec2, typical_mag: Flt) -> Vec2 {
|
|||||||
x.with_mag(new_mag)
|
x.with_mag(new_mag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn im_size(state: &dyn GenericSim, max_w: u32, max_h: u32) -> (u32, u32) {
|
fn im_size<S: GenericSim>(state: &S, max_w: u32, max_h: u32) -> (u32, u32) {
|
||||||
let mut width = max_w;
|
let mut width = max_w;
|
||||||
let mut height = width * state.height() / state.width();
|
let mut height = width * state.height() / state.width();
|
||||||
if height > max_h {
|
if height > max_h {
|
||||||
@@ -70,21 +70,21 @@ fn im_size(state: &dyn GenericSim, max_w: u32, max_h: u32) -> (u32, u32) {
|
|||||||
(width, height)
|
(width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RenderSteps<'a> {
|
struct RenderSteps<'a, S> {
|
||||||
im: RgbImage,
|
im: RgbImage,
|
||||||
sim: &'a dyn GenericSim,
|
sim: &'a S,
|
||||||
meas: &'a [Box<dyn AbstractMeasurement>],
|
meas: &'a [Box<dyn AbstractMeasurement>],
|
||||||
/// Simulation z coordinate to sample
|
/// Simulation z coordinate to sample
|
||||||
z: u32,
|
z: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RenderSteps<'a> {
|
impl<'a, S: GenericSim> RenderSteps<'a, S> {
|
||||||
/// Render using default configuration constants
|
/// Render using default configuration constants
|
||||||
fn render(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
fn render(state: &'a S, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32) -> RgbImage {
|
||||||
Self::render_configured(state, measurements, z, (640, 480))
|
Self::render_configured(state, measurements, z, (640, 480))
|
||||||
}
|
}
|
||||||
/// Render, controlling things like the size.
|
/// Render, controlling things like the size.
|
||||||
fn render_configured(state: &'a dyn GenericSim, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32, max_size: (u32, u32)) -> RgbImage {
|
fn render_configured(state: &'a S, measurements: &'a [Box<dyn AbstractMeasurement>], z: u32, max_size: (u32, u32)) -> RgbImage {
|
||||||
let (width, height) = im_size(state, max_size.0, max_size.1);
|
let (width, height) = im_size(state, max_size.0, max_size.1);
|
||||||
trace!("rendering at {}x{} with z={}", width, height, z);
|
trace!("rendering at {}x{} with z={}", width, height, z);
|
||||||
let mut me = Self::new(state, measurements, width, height, z);
|
let mut me = Self::new(state, measurements, width, height, z);
|
||||||
@@ -109,7 +109,7 @@ impl<'a> RenderSteps<'a> {
|
|||||||
me.render_measurements();
|
me.render_measurements();
|
||||||
me.im
|
me.im
|
||||||
}
|
}
|
||||||
fn new(sim: &'a dyn GenericSim, meas: &'a [Box<dyn AbstractMeasurement>], width: u32, height: u32, z: u32) -> Self {
|
fn new(sim: &'a S, meas: &'a [Box<dyn AbstractMeasurement>], width: u32, height: u32, z: u32) -> Self {
|
||||||
RenderSteps {
|
RenderSteps {
|
||||||
im: RgbImage::new(width, height),
|
im: RgbImage::new(width, height),
|
||||||
sim,
|
sim,
|
||||||
@@ -259,20 +259,30 @@ impl ImageRenderExt for RgbImage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Renderer: Send + Sync {
|
pub trait Renderer<S>: Send + Sync {
|
||||||
fn render_z_slice(&self, state: &dyn GenericSim, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]);
|
||||||
self.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements);
|
// {
|
||||||
}
|
// self.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements);
|
||||||
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
// }
|
||||||
self.render_z_slice(state, state.depth() / 2, measurements);
|
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]);
|
||||||
}
|
|
||||||
/// Not intended to be called directly by users; implement this if you want the image to be
|
/// 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.
|
/// computed using default settings and you just manage where to display/save it.
|
||||||
fn render_with_image(&self, state: &dyn GenericSim, _im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render_with_image(&self, state: &S, _im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
self.render(state, measurements);
|
self.render(state, measurements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_render_z_slice<S: GenericSim, R: Renderer<S>>(
|
||||||
|
me: &R, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]
|
||||||
|
) {
|
||||||
|
me.render_with_image(state, &RenderSteps::render(state, measurements, z), measurements);
|
||||||
|
}
|
||||||
|
fn default_render<S: GenericSim, R: Renderer<S>>(
|
||||||
|
me: &R, state: &S, measurements: &[Box<dyn AbstractMeasurement>]
|
||||||
|
) {
|
||||||
|
me.render_z_slice(state, state.depth() / 2, measurements);
|
||||||
|
}
|
||||||
|
|
||||||
// pub struct NumericTermRenderer;
|
// pub struct NumericTermRenderer;
|
||||||
//
|
//
|
||||||
// impl Renderer for NumericTermRenderer {
|
// impl Renderer for NumericTermRenderer {
|
||||||
@@ -296,8 +306,11 @@ pub trait Renderer: Send + Sync {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ColorTermRenderer;
|
pub struct ColorTermRenderer;
|
||||||
|
|
||||||
impl Renderer for ColorTermRenderer {
|
impl<S: GenericSim> Renderer<S> for ColorTermRenderer {
|
||||||
fn render_z_slice(&self, state: &dyn GenericSim, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
|
default_render(self, state, measurements)
|
||||||
|
}
|
||||||
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
let (max_w, mut max_h) = crossterm::terminal::size().unwrap();
|
let (max_w, mut max_h) = crossterm::terminal::size().unwrap();
|
||||||
max_h = max_h.saturating_sub(1 + measurements.len() as u16);
|
max_h = max_h.saturating_sub(1 + measurements.len() as u16);
|
||||||
let im = RenderSteps::render_configured(state, &[], z, (max_w as _, max_h as _));
|
let im = RenderSteps::render_configured(state, &[], z, (max_w as _, max_h as _));
|
||||||
@@ -338,7 +351,7 @@ pub struct Y4MRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Y4MRenderer {
|
impl Y4MRenderer {
|
||||||
pub fn new<S: Into<PathBuf>>(output: S) -> Self {
|
pub fn new<P: Into<PathBuf>>(output: P) -> Self {
|
||||||
Self {
|
Self {
|
||||||
out_path: output.into(),
|
out_path: output.into(),
|
||||||
encoder: Mutex::new(None),
|
encoder: Mutex::new(None),
|
||||||
@@ -346,8 +359,14 @@ impl Y4MRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for Y4MRenderer {
|
impl<S: GenericSim> Renderer<S> for Y4MRenderer {
|
||||||
fn render_with_image(&self, _state: &dyn GenericSim, im: &RgbImage, _meas: &[Box<dyn AbstractMeasurement>]) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
|
default_render_z_slice(self, state, z, measurements)
|
||||||
|
}
|
||||||
|
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
|
default_render(self, state, measurements)
|
||||||
|
}
|
||||||
|
fn render_with_image(&self, _state: &S, im: &RgbImage, _meas: &[Box<dyn AbstractMeasurement>]) {
|
||||||
{
|
{
|
||||||
let mut enc = self.encoder.lock().unwrap();
|
let mut enc = self.encoder.lock().unwrap();
|
||||||
if enc.is_none() {
|
if enc.is_none() {
|
||||||
@@ -413,8 +432,11 @@ impl PlotlyRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for PlotlyRenderer {
|
impl<S: GenericSim> Renderer<S> for PlotlyRenderer {
|
||||||
fn render(&self, state: &dyn GenericSim, _meas: &[Box<dyn AbstractMeasurement>]) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
|
default_render_z_slice(self, state, z, measurements)
|
||||||
|
}
|
||||||
|
fn render(&self, state: &S, _meas: &[Box<dyn AbstractMeasurement>]) {
|
||||||
use plotly::{ImageFormat, Plot, Rgba};
|
use plotly::{ImageFormat, Plot, Rgba};
|
||||||
// use plotly::common::Marker;
|
// use plotly::common::Marker;
|
||||||
use plotly::layout::{AspectMode, Axis, Layout, LayoutScene};
|
use plotly::layout::{AspectMode, Axis, Layout, LayoutScene};
|
||||||
@@ -442,7 +464,7 @@ impl Renderer for PlotlyRenderer {
|
|||||||
// if x%5 == 0 || y%5 == 0 || z%5 == 0 {
|
// if x%5 == 0 || y%5 == 0 || z%5 == 0 {
|
||||||
// continue;
|
// continue;
|
||||||
// }
|
// }
|
||||||
let cell = state.get(Index(Vec3u::new(x, y, z)));
|
let cell = (state as &dyn GenericSim).get(Index(Vec3u::new(x, y, z)));
|
||||||
xv.push(x);
|
xv.push(x);
|
||||||
yv.push(y);
|
yv.push(y);
|
||||||
zv.push(z);
|
zv.push(z);
|
||||||
@@ -480,32 +502,42 @@ impl Renderer for PlotlyRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
pub struct MultiRenderer<S> {
|
||||||
pub struct MultiRenderer {
|
renderers: RwLock<Vec<Box<dyn Renderer<S>>>>,
|
||||||
renderers: RwLock<Vec<Box<dyn Renderer>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultiRenderer {
|
impl<S> Default for MultiRenderer<S> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
renderers: RwLock::new(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S> MultiRenderer<S> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
pub fn push<R: Renderer + 'static>(&self, r: R) {
|
pub fn push<R: Renderer<S> + 'static>(&self, r: R) {
|
||||||
self.renderers.write().unwrap().push(Box::new(r));
|
self.renderers.write().unwrap().push(Box::new(r));
|
||||||
}
|
}
|
||||||
pub fn with<R: Renderer + 'static>(self, r: R) -> Self {
|
pub fn with<R: Renderer<S> + 'static>(self, r: R) -> Self {
|
||||||
self.push(r);
|
self.push(r);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for MultiRenderer {
|
impl<S: GenericSim> Renderer<S> for MultiRenderer<S> {
|
||||||
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
|
default_render_z_slice(self, state, z, measurements)
|
||||||
|
}
|
||||||
|
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
if self.renderers.read().unwrap().len() != 0 {
|
if self.renderers.read().unwrap().len() != 0 {
|
||||||
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2), measurements);
|
self.render_with_image(state, &RenderSteps::render(state, measurements, state.depth() / 2), measurements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_with_image(&self, state: &dyn GenericSim, im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render_with_image(&self, state: &S, im: &RgbImage, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
for r in &*self.renderers.read().unwrap() {
|
for r in &*self.renderers.read().unwrap() {
|
||||||
r.render_with_image(state, im, measurements);
|
r.render_with_image(state, im, measurements);
|
||||||
}
|
}
|
||||||
@@ -513,11 +545,20 @@ impl Renderer for MultiRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct SerializedFrame {
|
pub struct SerializedFrame<S=StaticSim> {
|
||||||
pub state: StaticSim,
|
pub state: S,
|
||||||
pub measurements: Vec<Box<dyn AbstractMeasurement>>,
|
pub measurements: Vec<Box<dyn AbstractMeasurement>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<S: GenericSim> SerializedFrame<S> {
|
||||||
|
pub fn to_static(self) -> SerializedFrame<StaticSim> {
|
||||||
|
SerializedFrame {
|
||||||
|
state: self.state.to_static(),
|
||||||
|
measurements: self.measurements,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct SerializerRenderer {
|
pub struct SerializerRenderer {
|
||||||
out_base: String
|
out_base: String
|
||||||
}
|
}
|
||||||
@@ -530,11 +571,13 @@ impl SerializerRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for SerializerRenderer {
|
impl<S: GenericSim + Clone + Serialize> Renderer<S> for SerializerRenderer {
|
||||||
fn render(&self, state: &dyn GenericSim, measurements: &[Box<dyn AbstractMeasurement>]) {
|
fn render_z_slice(&self, state: &S, z: u32, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
let snap = state.to_static();
|
default_render_z_slice(self, state, z, measurements)
|
||||||
|
}
|
||||||
|
fn render(&self, state: &S, measurements: &[Box<dyn AbstractMeasurement>]) {
|
||||||
let frame = SerializedFrame {
|
let frame = SerializedFrame {
|
||||||
state: snap,
|
state: state.clone(),
|
||||||
measurements: measurements.iter().cloned().collect(),
|
measurements: measurements.iter().cloned().collect(),
|
||||||
};
|
};
|
||||||
let name = format!("{}{}.bc", self.out_base, frame.state.step_no());
|
let name = format!("{}{}.bc", self.out_base, frame.state.step_no());
|
||||||
|
Reference in New Issue
Block a user