From 26939857c963b34f8a39c8084a60f842d6f4c7fe Mon Sep 17 00:00:00 2001 From: Tsuki Date: Mon, 15 Apr 2024 22:29:35 +0800 Subject: [PATCH] sync --- src/components/app.rs | 78 +++++++++++++-- src/coords/cms.rs | 2 +- src/data_utils.rs | 4 +- src/pipeline/element.rs | 34 +++---- src/pipeline/element_imp.rs | 91 ++++++++++++++---- src/pipeline/element_impl.rs | 2 +- src/pipeline/mod.rs | 1 + src/pipeline/new_pipeline.rs | 12 --- src/pipeline/offscreen_renderer.rs | 1 - src/pipeline/runner.rs | 146 +++++++++++++++++++++++++++++ src/predefined/color_mapper.rs | 17 ++++ 11 files changed, 326 insertions(+), 62 deletions(-) create mode 100644 src/pipeline/runner.rs diff --git a/src/components/app.rs b/src/components/app.rs index 68bcfea..fc25501 100644 --- a/src/components/app.rs +++ b/src/components/app.rs @@ -9,8 +9,12 @@ use super::{ use crate::components::sidebar::{SideBarInputMsg, SideBarModel}; use crate::data_utils::tools; use crate::pipeline::element::DataTarget; +use crate::pipeline::element_imp::{Context, ElementInput, GridImpConfig}; +use crate::pipeline::runner::Runner; use crate::pipeline::OffscreenRenderer; +use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete}; use crate::predefined::widgets::ColorBar; +use crate::utils::meshgrid; use crate::widgets::{AssoElement, DynamicCol}; use crate::{ actions::register_layer_actions, @@ -35,8 +39,9 @@ use chrono::{prelude::*, Duration}; use futures::future::BoxFuture; use gtk::glib::clone; use gtk::prelude::*; +use ndarray::{ArrayView1, ArrayViewD}; use once_cell::sync::Lazy; -use radarg_plugin_interface::PluginResult; +use radarg_plugin_interface::{PluginResult, VecResult}; use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup}; use relm4::*; use relm4::{gtk, Component, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent}; @@ -182,12 +187,12 @@ impl Component for AppModel { #[wrap(Some)] #[name="paned"] set_child_paned = >k::Paned{ - #[local_ref] - #[wrap(Some)] - set_start_child=render->gtk::Frame{}, - #[local_ref] - #[wrap(Some)] - set_end_child=sidebar->gtk::Box{}, + #[local_ref] + #[wrap(Some)] + set_start_child=render->gtk::Frame{}, + #[local_ref] + #[wrap(Some)] + set_end_child=sidebar->gtk::Box{}, } } }, @@ -278,6 +283,63 @@ impl Component for AppModel { let mut renderer = OffscreenRenderer::new(3000, 3000).unwrap(); let mut canvas = renderer.create_canvas(); let mut dialog_cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0)); + let mut context = Context::new(dialog_cms, canvas); + + use femtovg::Color; + + let mut runner = Runner::new( + imp, + Arc::new(GridImpConfig { + color_map: ColorMapperComb::BoundaryNormDiscrete(ColorMapper::new( + Discrete::new(vec![ + Color::rgb(0, 172, 164), + Color::rgb(192, 192, 254), + Color::rgb(122, 114, 238), + Color::rgb(30, 38, 208), + Color::rgb(166, 252, 168), + Color::rgb(0, 234, 0), + Color::rgb(16, 146, 26), + Color::rgb(252, 244, 100), + Color::rgb(200, 200, 2), + Color::rgb(140, 140, 0), + Color::rgb(254, 172, 172), + Color::rgb(254, 100, 92), + Color::rgb(238, 2, 48), + Color::rgb(212, 142, 254), + Color::rgb(170, 36, 250), + ]), + BoundaryNorm::new( + vec![ + 0i8, 5i8, 10i8, 15i8, 20i8, 25i8, 30i8, 35i8, 40i8, + 45i8, 50i8, 55i8, 60i8, 65i8, 70i8, 75i8, + ], + false, + Some(-125), + ), + )), + }), + context, + ); + + let target = runner.run(&data); + let data_target = DataTarget::new(Some(data), target); + + let element = Element::create_instant( + InstantElementDrawerType::Prepared(data_target), + dialog_dispatcher.clone(), + "ET".to_string(), + ) + .get_instance(); + let layer = Layer::new( + true, + "New Layer".to_string(), + AssoElement::Instant(element), + ); + dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map())); + dialog_render_sender.emit(MonitorInputMsg::SetRenderRange( + lon_start, lon_end, lat_start, lat_end, + )); + // let data_target = element_impl.render(&data, &mut canvas, &mut dialog_cms); // let data_target = DataTarget::new(Some(data), data_target); // let element = Element::create_instant( @@ -295,7 +357,7 @@ impl Component for AppModel { // dialog_render_sender.emit(MonitorInputMsg::SetRenderRange( // lon_start, lon_end, lat_start, lat_end, // )); - let layer = Layer::new(true, "New Layer".to_string(), AssoElement::Test); + // let layer = Layer::new(true, "New Layer".to_string(), AssoElement::Test); AppMsg::LayerManager(LayerMsg::Add(layer)) } diff --git a/src/coords/cms.rs b/src/coords/cms.rs index a88bfa0..be1a2fa 100644 --- a/src/coords/cms.rs +++ b/src/coords/cms.rs @@ -55,7 +55,7 @@ impl CMS { let (x, y) = ( self.bounds.0 + x * (self.bounds.1 - self.bounds.0), - self.bounds.1 + y * (self.bounds.3 - self.bounds.2), + self.bounds.2 + y * (self.bounds.3 - self.bounds.2), ); self.mapper.inverse_map((x, y)).ok() diff --git a/src/data_utils.rs b/src/data_utils.rs index 7037a95..97bdfa5 100644 --- a/src/data_utils.rs +++ b/src/data_utils.rs @@ -18,9 +18,7 @@ pub fn tools(data: &PluginResult) -> ElementImpl { let block = data.blocks.first().unwrap(); match block.coord_type { - CoordType::Polar => { - todo!(); - } + CoordType::Polar => PolarElementImp().into(), CoordType::Cartesian => match block.shape { DataShape::Cube => MultiLayerGridImp().into(), DataShape::Matrix => GridImp().into(), diff --git a/src/pipeline/element.rs b/src/pipeline/element.rs index 0e06ba1..f6d33c5 100644 --- a/src/pipeline/element.rs +++ b/src/pipeline/element.rs @@ -101,7 +101,7 @@ pub struct TimeSeriesElement { #[derive(Clone)] pub enum InstantElementDrawerType { Draw(DrawFunc), - Prepared((DataTarget, Arc)), + Prepared(DataTarget), } impl Debug for InstantElementDrawerType { @@ -141,7 +141,7 @@ impl InstantElement { InstantElementDrawerType::Draw(ref func) => { func(render); } - InstantElementDrawerType::Prepared((ref mut target, _)) => { + InstantElementDrawerType::Prepared(ref mut target) => { render.draw_img(target); } } @@ -157,21 +157,21 @@ impl InstantElement { cms: CMS, ) -> (TimeSeriesElement, DateTime) { // let imp = Arc::new(InstantElementImpl::new(self)); - if let InstantElementDrawerType::Prepared((mut target, imp)) = self.draw_type { - let mut time_series = TimeSeriesElement::new(imp, dispatcher, cms, self.key); - let data = target.take_data().unwrap(); - let time_stamp = data.blocks.first().unwrap().datetime; - let meta_info: MetaInfo = data.meta.clone().into(); - use chrono::prelude::*; - let time = Utc.timestamp_opt(time_stamp, 0).unwrap(); - (*time_series.buffer) - .lock() - .unwrap() - .insert(time, Some(RenderResult::new(target, meta_info))); - (time_series, time) - } else { - panic!("InstantElementDrawerType is not prepared"); - } + // if let InstantElementDrawerType::Prepared(mut target) = self.draw_type { + // let mut time_series = TimeSeriesElement::new(imp, dispatcher, cms, self.key); + // let data = target.take_data().unwrap(); + // let time_stamp = data.blocks.first().unwrap().datetime; + // let meta_info: MetaInfo = data.meta.clone().into(); + // use chrono::prelude::*; + // let time = Utc.timestamp_opt(time_stamp, 0).unwrap(); + // (*time_series.buffer) + // .lock() + // .unwrap() + // .insert(time, Some(RenderResult::new(target, meta_info))); + // (time_series, time) + // } else { + panic!("InstantElementDrawerType is not prepared"); + // } } } diff --git a/src/pipeline/element_imp.rs b/src/pipeline/element_imp.rs index 1a5c176..beb003c 100644 --- a/src/pipeline/element_imp.rs +++ b/src/pipeline/element_imp.rs @@ -5,7 +5,7 @@ use crate::pipeline::offscreen_renderer::CanvasWrapper; use crate::predefined::color_mapper::{CMap, ColorMapper, ColorMapperComb, VMap}; use abi_stable::std_types::RVec; use femtovg::{Paint, Path}; -use ndarray::{ArrayBase, ArrayView1, ArrayView2, ArrayViewD, Axis, Ix2, Ix3}; +use ndarray::{ArrayBase, ArrayView1, ArrayView2, ArrayView3, ArrayViewD, Axis, Ix2, Ix3}; use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps}; use radarg_plugin_interface::{DataShape, PluginResult, VecResult}; use std::any::Any; @@ -16,9 +16,9 @@ const EARTH_RADIUS: f64 = 6371.0; macro_rules! impl_element_imp_dispatch { ($({$Abc: ident, $t:ty},)+) => { impl ElementImpl { - pub fn process(&self, + pub fn process<'a, T>(&'a self, dims: (ArrayView2, ArrayView2), - input: ArrayViewD<'_, T>, + input: ElementInput<'a, T>, config: &dyn Any, context: &mut Context ) @@ -29,11 +29,16 @@ macro_rules! impl_element_imp_dispatch { $( Self::$Abc(imp) => { let config = config.downcast_ref::<<$t as ElementImp>::Config>().unwrap(); - imp.process(dims, input, config, context); + if let ElementInput::$Abc(data) = input { + imp.process(dims, data, config, context); + } else { + panic!("Invalid input type"); + } } )+ } } + } }; } @@ -66,6 +71,18 @@ macro_rules! impl_element_into_dispatch { }; } +macro_rules! impl_element_input_into_dispatch { + ($({$Abc: ident, $t: ty},)+) => { + $( + impl<'a, T> From<$t> for ElementInput<'a, T> { + fn from(value: $t) -> Self { + Self::$Abc(value) + } + } + )+ + }; +} + macro_rules! for_all_variants { ($macro: tt) => { $macro! { @@ -76,17 +93,43 @@ macro_rules! for_all_variants { }; } +macro_rules! result_to_array { + ($v: ident, $shape: expr) => { + match $v { + VecResult::I16(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::U8(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::I8(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::Bool(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::F32(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::F64(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::I32(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::I64(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::U32(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + VecResult::U64(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(), + } + }; +} + pub struct Context { - cms: CMS, - canvas: CanvasWrapper, + pub cms: CMS, + pub canvas: CanvasWrapper, +} + +impl Context { + pub fn new(cms: CMS, canvas: CanvasWrapper) -> Self { + Self { cms, canvas } + } } pub trait ElementImp: Debug + TryFrom + Into { type Config; - fn process( - &self, + type Input<'a, T: 'a> + where + Self: 'a; + fn process<'a, T>( + &'a self, dims: (ArrayView2, ArrayView2), - input: ArrayViewD<'_, T>, + input: Self::Input<'a, T>, config: &Self::Config, context: &mut Context, ) where @@ -100,7 +143,7 @@ pub struct GridImpConfig where T: PartialOrd + PartialEq + Send + Sync + Debug, { - color_map: ColorMapperComb, + pub color_map: ColorMapperComb, } impl GridImp { @@ -153,10 +196,11 @@ impl GridImp { impl ElementImp for GridImp { type Config = GridImpConfig; - fn process( - &self, + type Input<'a, T: 'a> = ArrayViewD<'a, T>; + fn process<'a, T>( + &'a self, dims: (ArrayView2, ArrayView2), - input: ArrayViewD<'_, T>, + input: Self::Input<'a, T>, config: &Self::Config, context: &mut Context, ) where @@ -186,11 +230,12 @@ where impl ElementImp for MultiLayerGridImp { type Config = MultiLayerGridImpConfig; + type Input<'a, T: 'a> = ArrayViewD<'a, T>; - fn process( - &self, + fn process<'a, T>( + &'a self, dims: (ArrayView2, ArrayView2), - input: ArrayViewD<'_, T>, + input: Self::Input<'a, T>, config: &Self::Config, context: &mut Context, ) where @@ -320,10 +365,11 @@ impl PolarElementImp { impl ElementImp for PolarElementImp { type Config = PolarElementConfig; - fn process( - &self, + type Input<'a, T: 'a> = ArrayViewD<'a, T>; + fn process<'a, T>( + &'a self, dims: (ArrayView2, ArrayView2), - input: ArrayViewD<'_, T>, + input: Self::Input<'a, T>, config: &Self::Config, context: &mut Context, ) where @@ -346,6 +392,13 @@ pub enum ElementImpl { Polar(PolarElementImp), } +#[derive(Debug)] +pub enum ElementInput<'a, T> { + Grid(ArrayViewD<'a, T>), + MultiLayerGrid(ArrayViewD<'a, T>), + Polar(ArrayViewD<'a, T>), +} + for_all_variants!(impl_element_into_dispatch); for_all_variants!(impl_element_try_from_dispatch); for_all_variants!(impl_element_imp_dispatch); diff --git a/src/pipeline/element_impl.rs b/src/pipeline/element_impl.rs index ea280b8..6a9e00e 100644 --- a/src/pipeline/element_impl.rs +++ b/src/pipeline/element_impl.rs @@ -58,7 +58,7 @@ where panic!("Vector data is not supported") } DataShape::Matrix => { - let data:Radar2d = first_block.clone().into(); + let data: Radar2d = first_block.clone().into(); let data = data.as_ref(); let result = self.renderer.render(canvas, cms, &data, (3000.0, 3000.0)); result diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs index 3a3ccee..6aac0a5 100644 --- a/src/pipeline/mod.rs +++ b/src/pipeline/mod.rs @@ -8,6 +8,7 @@ pub mod offscreen_renderer; // mod predefined; pub mod element_imp; mod renders; +pub mod runner; // pub mod utils; pub use dispatcher::Dispatcher; diff --git a/src/pipeline/new_pipeline.rs b/src/pipeline/new_pipeline.rs index d1c527c..943ba09 100644 --- a/src/pipeline/new_pipeline.rs +++ b/src/pipeline/new_pipeline.rs @@ -29,18 +29,6 @@ use tokio::{ task, }; -// #[derive(Clone, Debug)] -// pub struct RenderResult { -// target: Target, -// meta_info: MetaInfo, -// } - -// impl RenderResult { -// pub fn new(target: Target, meta_info: MetaInfo) -> Self { -// Self { target, meta_info } -// } -// } - type RenderR = Result; pub struct Pipeline { pool: Vec>, diff --git a/src/pipeline/offscreen_renderer.rs b/src/pipeline/offscreen_renderer.rs index 248b6af..4fabef7 100644 --- a/src/pipeline/offscreen_renderer.rs +++ b/src/pipeline/offscreen_renderer.rs @@ -1,4 +1,3 @@ -// use super::utils::*; use crate::pipeline::element::Target; use euclid::Size2D; use femtovg::{renderer::OpenGl, Canvas}; diff --git a/src/pipeline/runner.rs b/src/pipeline/runner.rs new file mode 100644 index 0000000..f635c4b --- /dev/null +++ b/src/pipeline/runner.rs @@ -0,0 +1,146 @@ +use std::{any::Any, sync::Arc}; + +use femtovg::RenderTarget; +use gl::types::GLvoid; +use image::Rgba; +use ndarray::{ArrayView1, ArrayViewD}; +use radarg_plugin_interface::{PluginResult, VecResult}; + +use crate::{ + pipeline::{ + element_imp::{ElementInput, GridImpConfig}, + TargetType, + }, + utils::meshgrid, +}; + +use super::{ + element_imp::{Context, ElementImp, ElementImpl}, + Target, +}; + +macro_rules! impl_for_runner { + ($imp:ident, $data:ident, $dims:expr, $size:ident, $config:ident, $context:ident, $({$t:tt},)+) => { + match $data { + $( + $t(ref v) => { + let input = ArrayViewD::from_shape($size, v.as_ref()).unwrap(); + let data = ElementInput::Grid(input); + $imp.process($dims, data, $config, $context ); + } + + )+ + } + }; +} + +pub struct Runner { + imp: ElementImpl, + config: Arc, + context: Context, +} + +impl Runner { + pub fn new(imp: ElementImpl, config: Arc, context: Context) -> Self { + Self { + imp, + config, + context, + } + } + + pub fn run(&mut self, data: &PluginResult) -> Target { + let block = data.blocks.first().unwrap(); + let data = &block.data; + let dims = &block.dimension_values; + + let dims = if dims.len() == 3 { + let (a, b) = ( + ArrayView1::from(dims[2].as_ref()), + ArrayView1::from(dims[1].as_ref()), + ); + meshgrid(a, b) + } else { + let (a, b) = ( + ArrayView1::from(dims[1].as_ref()), + ArrayView1::from(dims[0].as_ref()), + ); + meshgrid(a, b) + }; + + let size = block.size.to_owned().to_vec(); + let config = &*self.config; + let imp: &ElementImpl = &self.imp; + let context: &mut Context = &mut self.context; + let cms = &mut context.cms; + let canvas = &mut context.canvas; + let (w, h) = (canvas.width(), canvas.height()); + use femtovg::{ImageFlags, PixelFormat::Rgba8}; + + let new_img = canvas + .create_image_empty(w as usize, h as usize, Rgba8, ImageFlags::empty()) + .expect("Can't Create Image"); + canvas.image_size(new_img).unwrap(); + canvas.set_render_target(RenderTarget::Image(new_img)); + + let lat_start = dims.1.view().first().unwrap().clone(); + let lat_end = dims.1.view().last().unwrap().clone(); + + let lon_start = dims.0.view().first().unwrap().clone(); + let lon_end = dims.0.view().last().unwrap().clone(); + + cms.set_lat_range(lat_start..lat_end); + cms.set_lon_range(lon_start..lon_end); + + use VecResult::*; + + impl_for_runner!( + imp, + data, + (dims.0.view(), dims.1.view()), + size, + config, + context, + { I32 }, + { F64 }, + { I64 }, + { Bool }, + { F32 }, + { I8 }, + { U8 }, + { I16 }, + { U64 }, + { U32 }, + ); + + context.canvas.flush(); + + let mut pixels: Vec = vec![0; w as usize * h as usize * 4]; + unsafe { + gl::ReadPixels( + 0, + 0, + w as i32, + h as i32, + gl::RGBA, + gl::UNSIGNED_BYTE, + pixels.as_mut_ptr() as *mut GLvoid, + ); + debug_assert_eq!(gl::GetError(), gl::NO_ERROR); + } + let d1_start = (dims.0.view()).first().unwrap().clone(); + let d1_end = (dims.0.view()).last().unwrap().clone(); + + let d2_start = dims.1.view().first().unwrap().clone(); + let d2_end = dims.1.view().last().unwrap().clone(); + context.canvas.set_render_target(RenderTarget::Screen); + + Target::new( + TargetType::NativeBuffer(pixels), + w as f32, + h as f32, + ((d1_start, d1_end).into(), (d2_start, d2_end).into()), + None, + ) + } +} diff --git a/src/predefined/color_mapper.rs b/src/predefined/color_mapper.rs index ae28e3c..83ba8c6 100644 --- a/src/predefined/color_mapper.rs +++ b/src/predefined/color_mapper.rs @@ -68,6 +68,17 @@ pub struct BoundaryNorm { extrand: bool, invalid_value: Option, } + +impl BoundaryNorm { + pub fn new(boundaries: Vec, extrand: bool, invalid_value: Option) -> Self { + Self { + boundaries, + extrand, + invalid_value, + } + } +} + impl VMap for BoundaryNorm where T: PartialOrd + PartialEq + Debug, @@ -100,6 +111,12 @@ pub struct Discrete { colors: Vec, } +impl Discrete { + pub fn new(colors: Vec) -> Self { + Self { colors } + } +} + impl CMap for Discrete { fn map(&self, v: f32) -> Color { let size = (self.colors.len() as f32 * v) as usize;