diff --git a/Cargo.lock b/Cargo.lock index 8582407..5e45ef3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -529,6 +529,7 @@ dependencies = [ "core_extensions", "crossbeam", "dirs", + "enum_dispatch", "epoxy", "euclid", "femtovg", @@ -986,7 +987,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.3", ] [[package]] @@ -1032,6 +1033,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum_dispatch" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e" +dependencies = [ + "once_cell", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", +] + [[package]] name = "env_logger" version = "0.9.3" diff --git a/Cargo.toml b/Cargo.toml index e75442b..8109431 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -72,6 +72,7 @@ reqwest = "0.11.25" url = "2.5.0" quick_cache = "0.4.1" fns = "0.0.7" +enum_dispatch = "0.3.12" [build-dependencies] diff --git a/src/components/app.rs b/src/components/app.rs index 1746618..68bcfea 100644 --- a/src/components/app.rs +++ b/src/components/app.rs @@ -7,7 +7,9 @@ use super::{ ControlPanelOutputMsg, TimelineMsg, }; use crate::components::sidebar::{SideBarInputMsg, SideBarModel}; -use crate::pipeline::{GridElementImpl, OffscreenRenderer}; +use crate::data_utils::tools; +use crate::pipeline::element::DataTarget; +use crate::pipeline::OffscreenRenderer; use crate::predefined::widgets::ColorBar; use crate::widgets::{AssoElement, DynamicCol}; use crate::{ @@ -22,12 +24,11 @@ use crate::{ }, data::MetaInfo, errors::RenderError, - pipeline::{utils::data_to_element, Dispatcher, Pipeline, RenderResult}, + pipeline::{Dispatcher, Pipeline, RenderResult}, plugin_system::init_plugin, widgets::render::Layer, CONFIG, PLUGIN_MANAGER, }; -use crate::{data_utils::plugin_result_impl, pipeline::element::DataTarget}; use abi_stable::std_types::RStr; use adw::prelude::*; use chrono::{prelude::*, Duration}; @@ -272,27 +273,29 @@ impl Component for AppModel { let meta: MetaInfo = (&data.meta).clone().into(); let (lat_start, lat_end) = meta.lat_range.unwrap(); let (lon_start, lon_end) = meta.lon_range.unwrap(); - let element_impl = plugin_result_impl(&data); + let imp = tools(&data); + // let element_impl = plugin_result_impl(&data); 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 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( - InstantElementDrawerType::Prepared((data_target, element_impl)), - 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( + // InstantElementDrawerType::Prepared((data_target, element_impl)), + // 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 layer = Layer::new(true, "New Layer".to_string(), AssoElement::Test); AppMsg::LayerManager(LayerMsg::Add(layer)) } @@ -425,8 +428,9 @@ impl AppModel { .load(RStr::from_str(path.as_ref().to_str().unwrap())) .unwrap(); let block = result.blocks.first().unwrap(); - data_to_element(block, dispatcher, cms) - .map(|v| (Some(Box::new(result) as Box), v)) + // data_to_element(block, dispatcher, cms) + // .map(|v| (Some(Box::new(result) as Box), v)) + None } fn open_file_only(path: impl AsRef) -> PluginResult { diff --git a/src/coords/cms.rs b/src/coords/cms.rs index 9b15764..a88bfa0 100644 --- a/src/coords/cms.rs +++ b/src/coords/cms.rs @@ -1,4 +1,5 @@ use crate::coords::Mapper; +use epoxy::XOR; use geo_types::LineString; use std::ops::Range; @@ -48,6 +49,18 @@ impl CMS { }) } + pub fn fore_map(&self, loc: (f32, f32)) -> Option<(f64, f64)> { + let (x, y) = loc; + let (x, y) = (x as f64, y as f64); + + let (x, y) = ( + self.bounds.0 + x * (self.bounds.1 - self.bounds.0), + self.bounds.1 + y * (self.bounds.3 - self.bounds.2), + ); + + self.mapper.inverse_map((x, y)).ok() + } + pub fn ring_map(&self, line: &LineString) -> Option> { Some( line.points() diff --git a/src/data/mod.rs b/src/data/mod.rs index 3ffaae6..c88d402 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -18,6 +18,20 @@ pub type Radar2dRef<'a, T> = RadarData2d, ViewRepr<&'a f64>, pub type Radar3dRef<'a, T> = RadarData3d, ViewRepr<&'a f64>, ViewRepr<&'a f64>, ViewRepr<&'a f64>>; +#[derive(Debug, Clone, Copy)] +pub enum DataType { + F64, + I64, + U64, + F32, + I32, + U32, + I16, + U16, + I8, + U8, +} + #[derive(Clone, Copy, Debug)] pub enum CoordType { Polar, diff --git a/src/data_utils.rs b/src/data_utils.rs index 17a5b2f..7037a95 100644 --- a/src/data_utils.rs +++ b/src/data_utils.rs @@ -1,44 +1,33 @@ -use crate::pipeline::element::ElementImpl; -use crate::pipeline::GridElementImpl; +use crate::pipeline::element_imp::*; use crate::utils::*; use radarg_plugin_interface::{CoordType, DataShape, PluginResult, PluginResultType}; +use std::any::Any; use std::sync::Arc; -macro_rules! data_to_grid { - ($_type:ident,$(($branch:path ,$boundary_norm: expr)),+) => { - match $_type { - $( - $branch => { - let element_impl = GridElementImpl::new($boundary_norm); - Arc::new(element_impl) - } - ),+ - _ => panic!("Invalid type") - } - }; -} -pub fn plugin_result_impl(a: &PluginResult) -> Arc { - let block = a.blocks.first().unwrap(); +pub fn tools(data: &PluginResult) -> ElementImpl { + let blocks_num = data.blocks.len(); + + if blocks_num == 0 { + panic!("No blocks found"); + } + + if blocks_num > 1 { + panic!("Too many blocks found"); + } + + let block = data.blocks.first().unwrap(); + match block.coord_type { - CoordType::Cartesian => { - let _type = block.data_type; - data_to_grid!( - _type, - (PluginResultType::R, create_dbz_boundarynorm()), - (PluginResultType::V, create_vel_boundarynorm()), - (PluginResultType::CC, create_cc_boundarynorm()), - (PluginResultType::ZDR, create_zdr_boundarynorm()), - (PluginResultType::PHIDP, create_phidp_boundarynorm()), - (PluginResultType::KDP, create_kdp_boundarynorm()), - (PluginResultType::DBZ, create_dbz_boundarynorm()), - (PluginResultType::VIL, create_vil_boundarynorm()), - (PluginResultType::OHP, create_vil_boundarynorm()), - (PluginResultType::THP, create_vil_boundarynorm()), - (PluginResultType::ET, create_et_boundarynorm()) - ) + CoordType::Polar => { + todo!(); } - CoordType::Other | CoordType::Polar => { - panic!("Invalid type"); + CoordType::Cartesian => match block.shape { + DataShape::Cube => MultiLayerGridImp().into(), + DataShape::Matrix => GridImp().into(), + _ => panic!("Invalid shape"), + }, + _ => { + panic!("Invalid type") } } } diff --git a/src/main.rs b/src/main.rs index e49c2d1..f090608 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ mod map_tile; mod map_tile_utils; mod predefined; mod widgets; +// mod element_imp; #[cfg(target_env = "msvc")] declare_surfman!(); diff --git a/src/pipeline/element_imp.rs b/src/pipeline/element_imp.rs new file mode 100644 index 0000000..1a5c176 --- /dev/null +++ b/src/pipeline/element_imp.rs @@ -0,0 +1,351 @@ +use super::Target; +use crate::coords::cms::CMS; +use crate::data::Radar2dRef; +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 num_traits::{AsPrimitive, FromPrimitive, Num, NumOps}; +use radarg_plugin_interface::{DataShape, PluginResult, VecResult}; +use std::any::Any; +use std::fmt::Debug; + +const EARTH_RADIUS: f64 = 6371.0; + +macro_rules! impl_element_imp_dispatch { + ($({$Abc: ident, $t:ty},)+) => { + impl ElementImpl { + pub fn process(&self, + dims: (ArrayView2, ArrayView2), + input: ArrayViewD<'_, T>, + config: &dyn Any, + context: &mut Context + ) + where + T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone + 'static, + { + match self { + $( + Self::$Abc(imp) => { + let config = config.downcast_ref::<<$t as ElementImp>::Config>().unwrap(); + imp.process(dims, input, config, context); + } + )+ + } + } + } + }; +} + +macro_rules! impl_element_try_from_dispatch { + ($({ $Abc: ident, $t:ty},)+) => { + $( + impl TryFrom for $t { + type Error = &'static str; + fn try_from(value: ElementImpl) -> Result { + match value { + ElementImpl::$Abc(imp) => Ok(imp), + _ => Err("Invalid type"), + } + } + } + )+ + }; +} + +macro_rules! impl_element_into_dispatch { + ($({ $Abc: ident, $t:ty},)+) => { + $( + impl From<$t> for ElementImpl { + fn from(value: $t) -> Self { + Self::$Abc(value) + } + } + )+ + }; +} + +macro_rules! for_all_variants { + ($macro: tt) => { + $macro! { + {Grid, GridImp}, + {MultiLayerGrid, MultiLayerGridImp}, + {Polar, PolarElementImp}, + } + }; +} + +pub struct Context { + cms: CMS, + canvas: CanvasWrapper, +} + +pub trait ElementImp: Debug + TryFrom + Into { + type Config; + fn process( + &self, + dims: (ArrayView2, ArrayView2), + input: ArrayViewD<'_, T>, + config: &Self::Config, + context: &mut Context, + ) where + T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone; +} + +#[derive(Debug)] +pub struct GridImp(); + +pub struct GridImpConfig +where + T: PartialOrd + PartialEq + Send + Sync + Debug, +{ + color_map: ColorMapperComb, +} + +impl GridImp { + fn draw_2d( + &self, + config: &GridImpConfig, + data: ArrayView2, + dims: (ArrayView2, ArrayView2), + context: &mut Context, + ) where + T: PartialEq + PartialOrd + Copy + Clone + Send + Sync + Debug, + { + let cms = &context.cms; + let canvas = &mut context.canvas; + let shape = data.shape(); + let mapper = &config.color_map; + let (rows, cols) = (shape[0], shape[1]); + let (dim1, dim2) = dims; + + let d1_s = dim1[[0, 0]]; + let d1_e = dim1[[0, cols - 1]]; + + let d2_s = dim2[[0, 0]]; + let d2_e = dim2[[rows - 1, 0]]; + + for r in 0..rows - 1 { + for c in 0..cols - 1 { + let lb_lat = dim2[[r, c]]; + let lb_lon = dim1[[r, c]]; + + let rt_lat = dim2[[r + 1, c + 1]]; + let rt_lon = dim1[[r + 1, c + 1]]; + let v = &data[[r, c]]; + let mapped_color = mapper.color(*v); + + if mapped_color.is_none() { + continue; + } + + let (ox, oy) = cms.map((lb_lon, lb_lat)).unwrap(); + let (rx, ry) = cms.map((rt_lon, rt_lat)).unwrap(); + + let mut path = Path::new(); + path.rect(ox, oy, (rx - ox) * 1.5, (ry - oy) * 1.5); + canvas.fill_path(&path, &Paint::color(mapped_color.unwrap())); + } + } + } +} + +impl ElementImp for GridImp { + type Config = GridImpConfig; + fn process( + &self, + dims: (ArrayView2, ArrayView2), + input: ArrayViewD<'_, T>, + config: &Self::Config, + context: &mut Context, + ) where + T: Send + Sync + Debug + PartialOrd + PartialEq + Copy + Clone, + { + let shape = input.shape(); + if shape.len() == 2 { + let data = input.into_dimensionality::().unwrap(); + let target = self.draw_2d(config, data, dims, context); + } else if shape.len() == 3 { + let data = input.into_dimensionality::().unwrap(); + } + } +} + +#[derive(Debug)] +pub struct MultiLayerGridImp(); + +pub struct MultiLayerGridImpConfig +where + T: PartialOrd + PartialEq + Send + Sync + Debug, +{ + twod: GridImp, + two_d_config: GridImpConfig, + layer: usize, +} + +impl ElementImp for MultiLayerGridImp { + type Config = MultiLayerGridImpConfig; + + fn process( + &self, + dims: (ArrayView2, ArrayView2), + input: ArrayViewD<'_, T>, + config: &Self::Config, + context: &mut Context, + ) where + T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone, + { + let data = input.into_dimensionality::().unwrap(); + let layer = config.layer; + let layer_data = data.index_axis(Axis(0), layer); + + config + .twod + .process(dims, layer_data.into_dyn(), &config.two_d_config, context); + } +} + +#[derive(Debug)] +pub struct PolarElementImp(); + +pub struct PolarElementConfig +where + T: PartialOrd + PartialEq + Send + Sync + Debug, +{ + color_map: ColorMapperComb, + center: (f64, f64), +} + +impl PolarElementImp { + fn closest_value(&self, x: f64, dpi: f64) -> f64 { + let n_floor = (x / dpi).floor() as i64; + let value_at_n_floor = n_floor as f64 * dpi; + let value_at_n_floor_plus_one = (n_floor + 1) as f64 * dpi; + if (x - value_at_n_floor).abs() < (value_at_n_floor_plus_one - x).abs() { + value_at_n_floor + } else { + value_at_n_floor_plus_one + } + } + + fn map_to_polar( + &self, + center: (f64, f64), + dpi: (f64, f64), + max_r: f64, + point: (f64, f64), + ) -> Option<(f64, f64)> { + let (center_lon, center_lat) = center; + let (lon, lat) = point; + + let center_lon_rad = center_lon.to_radians(); + let center_lat_rad = center_lat.to_radians(); + let lon_rad = lon.to_radians(); + let lat_rad = lat.to_radians(); + + let delta_lat = lat_rad - center_lat_rad; + let delta_lon = lon_rad - center_lon_rad; + + let a = (delta_lat / 2.0).sin().powi(2) + + center_lat_rad.cos() * lat_rad.cos() * (delta_lon / 2.0).sin().powi(2); + + let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt()); + + let distance = EARTH_RADIUS * c * 1000.0; + + if distance > max_r + dpi.1 { + return None; + } + + let x = delta_lon.cos() * lat_rad.sin(); + let y = center_lat_rad.cos() * lat_rad.sin() + - center_lat_rad.sin() * lat_rad.cos() * delta_lon.cos(); + let ori_degree = y.atan2(x).to_degrees(); + let degree = (ori_degree + 360.0) % 360.0; + + let distance_dpi = dpi.1; + let degree_dpi = dpi.0; + let final_degree = self.closest_value(degree, degree_dpi); + let final_distance = self.closest_value(distance, distance_dpi); + Some((final_degree, final_distance)) + } + + fn draw( + &self, + dims: (ArrayView2, ArrayView2), + center: (f64, f64), + data: ArrayView2, + config: &PolarElementConfig, + context: &mut Context, + ) where + T: PartialOrd + PartialEq + Send + Sync + Debug + Copy, + { + let canvas = &mut context.canvas; + let mapper = &context.cms; + let start_point = mapper.fore_map((0.0, 0.0)); + + let dpi = ( + dims.0[[0, 1]] - dims.0[[0, 0]], + dims.1[[1, 1]] - dims.1[[1, 0]], + ); + + let (azs, rs) = dims; + + let (w, h) = (canvas.width(), canvas.height()); + + for x in 0..w { + for y in 0..h { + let map_point = mapper.fore_map((x as f32 / w as f32, y as f32 / h as f32)); + if map_point.is_none() { + continue; + } + if let Some((_x, _y)) = self.map_to_polar(center, dpi, 0.0, map_point.unwrap()) { + let (_x, _y) = (_x as usize, _y as usize); + let value = data[[_x, _y]]; + let color = config.color_map.color(value); + + if color.is_none() { + continue; + } + + let mut path = Path::new(); + path.rect(x as f32, y as f32, 1.0, 1.0); + canvas.fill_path(&path, &Paint::color(color.unwrap())); + } + } + } + } +} + +impl ElementImp for PolarElementImp { + type Config = PolarElementConfig; + fn process( + &self, + dims: (ArrayView2, ArrayView2), + input: ArrayViewD<'_, T>, + config: &Self::Config, + context: &mut Context, + ) where + T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone, + { + let shape = input.shape(); + if shape.len() == 2 { + let data = input.into_dimensionality::().unwrap(); + self.draw(dims, config.center, data, config, context); + } else if shape.len() == 3 { + let data = input.into_dimensionality::().unwrap(); + } + } +} + +#[derive(Debug)] +pub enum ElementImpl { + Grid(GridImp), + MultiLayerGrid(MultiLayerGridImp), + Polar(PolarElementImp), +} + +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/mod.rs b/src/pipeline/mod.rs index adf81b4..3a3ccee 100644 --- a/src/pipeline/mod.rs +++ b/src/pipeline/mod.rs @@ -1,14 +1,17 @@ pub mod dispatcher; pub mod element; -mod element_impl; +// mod element_impl; +// mod new_element; +// mod new_element_impl; mod new_pipeline; pub mod offscreen_renderer; -mod predefined; +// mod predefined; +pub mod element_imp; mod renders; -pub mod utils; +// pub mod utils; pub use dispatcher::Dispatcher; pub use element::*; -pub use element_impl::*; +// pub use element_impl::*; pub use new_pipeline::Pipeline; pub use offscreen_renderer::OffscreenRenderer; diff --git a/src/pipeline/new_element.rs b/src/pipeline/new_element.rs new file mode 100644 index 0000000..13e0b32 --- /dev/null +++ b/src/pipeline/new_element.rs @@ -0,0 +1,196 @@ +use super::dispatcher; +use super::new_element_impl::ElementConfig; +use super::new_element_impl::ElementImp; +use super::offscreen_renderer::CanvasWrapper; +use super::Dispatcher; +use super::RenderResult; +use super::Target; +use crate::coords::cms::CMS; +use crate::pipeline::OffscreenRenderer; +use crate::PLUGIN_MANAGER; +use chrono::prelude::*; +use num_traits::AsPrimitive; +use num_traits::FromPrimitive; +use num_traits::Num; +use num_traits::NumOps; +use quick_cache::sync::Cache; +use radarg_plugin_interface::PluginResult; +use std::any::Any; +use std::collections::HashMap; +use std::fmt::Debug; +use std::hash::Hash; +use std::rc::Rc; +use std::sync::atomic::AtomicI32; +use std::sync::Arc; +use std::sync::RwLock; +use std::time::Duration; +use tokio::sync::oneshot; +use tokio::sync::{mpsc, Mutex}; + +static ELEMENT_ID: AtomicI32 = AtomicI32::new(0); +pub type ElementID = i32; +pub type Buffer = Cache>>; + +pub struct Element +where + V: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, +{ + pub id: i32, + pub name: String, + pub description: String, + imp: Arc>, + buffer: Arc>>, + config: Arc>>, + subscribers: Arc>>>>>>>, + cancellers: Arc>>>, + + dispatcher: Rc, + cms: Arc>, +} + +impl Element +where + V: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, +{ + pub fn new( + name: String, + description: String, + imp: ElementImp, + config: Box, + cms: CMS, + dispatcher: Rc, + ) -> Self { + let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + Element { + id, + name, + description, + imp: Arc::new(imp), + buffer: Arc::new(Mutex::new(Buffer::new(100))), + subscribers: Arc::new(Mutex::new(HashMap::new())), + config: Arc::new(RwLock::new(config)), + cancellers: Arc::new(Mutex::new(HashMap::new())), + cms: Arc::new(Mutex::new(cms)), + dispatcher, + } + } + + pub fn new_with_buffer( + name: String, + description: String, + imp: ElementImp, + buffer: Buffer, + config: Box, + cms: CMS, + dispatcher: Rc, + ) -> Self { + let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed); + Element { + id, + name, + description, + imp: Arc::new(imp), + buffer: Arc::new(Mutex::new(buffer)), + subscribers: Arc::new(Mutex::new(HashMap::new())), + config: Arc::new(RwLock::new(config)), + cancellers: Arc::new(Mutex::new(HashMap::new())), + cms: Arc::new(Mutex::new(cms)), + dispatcher, + } + } + + pub async fn get(&self, key: T) -> Arc> { + { + let cache = self.buffer.lock().await; + if cache.peek(&key).is_some() { + return cache.get(&key).unwrap(); + } + } + + { + let mut subscribers = self.subscribers.lock().await; + let (tx, rx) = oneshot::channel(); + if subscribers.contains_key(&key) { + subscribers.get_mut(&key).unwrap().push(tx); + drop(subscribers); + } else { + let (canceller_tx, canceller_rx) = oneshot::channel(); + subscribers.insert(key, vec![tx]); + drop(subscribers); + + { + let mut cancellers = self.cancellers.lock().await; + cancellers.insert(key, canceller_tx); + } + + let buffer = self.buffer.clone(); + let config = self.config.clone(); + let imp = self.imp.clone(); + let cancellers = self.cancellers.clone(); + let subscribers = self.subscribers.clone(); + + use tokio::task; + tokio::spawn(async move { + tokio::select! { + _ = async move { + + tokio::time::sleep(Duration::new(5, 0)).await; + let handle = task::spawn_blocking(move || { + let config = config.read().unwrap(); + let config: &ElementConfig = &*(*config); + + let loader = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap(); + let mut loaded_data = loader.load(path.as_ref().into()).unwrap(); + let meta = loaded_data.meta.clone().into(); + let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap(); + + // imp.render() + }); + let result = handle.await.unwrap(); + + { + let bf = Arc::new(Mutex::new(result)); + buffer.lock().await.insert(key, bf.clone()); + let mut subscribers = subscribers.lock().await; + for tx in subscribers.remove(&key).unwrap() { + let _ = tx.send(bf.clone()); + } + } + + } => {} + _ = canceller_rx => {} + } + let mut cancellers = cancellers.lock().await; + cancellers.remove(&key); + }); + } + + rx.await.unwrap() + } + } + + pub async fn cancel_task_for_timestamp(&self, key: T) { + let mut cancellers = self.cancellers.lock().await; + if let Some(canceller) = cancellers.remove(&key) { + let _ = canceller.send(()); // 发送取消信号 + } + } + + pub async fn cancel_all_tasks(&self) { + let mut cancellers = self.cancellers.lock().await; + for (_timestamp, canceller) in cancellers.drain() { + let _ = canceller.send(()); // 发送取消信号 + } + } +} + +pub trait ElementImpl: Debug + Send + Sync + 'static { + type Config; + fn render( + &self, + data: &PluginResult, + canvas: &mut CanvasWrapper, + cms: &mut CMS, + config: &Self::Config, + ) -> Target; +} diff --git a/src/pipeline/new_element_impl.rs b/src/pipeline/new_element_impl.rs new file mode 100644 index 0000000..76d8983 --- /dev/null +++ b/src/pipeline/new_element_impl.rs @@ -0,0 +1,104 @@ +use super::{ + new_element::ElementImpl, offscreen_renderer::CanvasWrapper, predefined::GridFieldRenderer, + renders::DataRenderer, Target, +}; +use crate::{ + data::{Radar2d, Radar3d}, + predefined::color_mapper::{BoundaryNorm, ColorMapper}, +}; +use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps}; +use radarg_plugin_interface::{DataShape, PluginResult}; +use std::{any::Any, fmt::Debug, marker::PhantomData}; + +macro_rules! create_element_imp { + ($imp: expr) => {{ + let c: ElementImp = $imp.into(); + c + }}; +} + +macro_rules! element { + ($generic:ident,$(($branch:tt,$imp:ty)),+) => { + pub(super) type ElementConfig = dyn Any + Send + Sync + 'static; + + pub enum ElementImp<$generic> + where + $generic: NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, + { + $( + $branch($imp), + )+ + } + + impl<$generic> ElementImp<$generic> + where + $generic: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, + { + pub fn render( + &self, + data: &PluginResult, + canvas: &mut CanvasWrapper, + cms: &mut crate::coords::cms::CMS, + config: &ElementConfig) -> Target + { + match self { + $( + ElementImp::$branch(imp) => imp.render(data,canvas,cms,config.downcast_ref::<<$imp as ElementImpl>::Config>().unwrap()), + )+ + } + } + } + + $( + impl<$generic> From<$imp> for ElementImp<$generic> + where + $generic: NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, + { + fn from(imp: $imp) -> Self { + ElementImp::$branch(imp) + } + } + )+ + }; +} + +// element!(T, (Grid, GridElementImpl)); + +#[derive(Debug)] +pub struct GridElementImpl {} + +impl GridElementImpl { + pub fn new() -> Self { + Self {} + } +} + +impl ElementImpl for GridElementImpl { + type Config = GridFieldRenderer, T>; + fn render( + &self, + data: &PluginResult, + canvas: &mut CanvasWrapper, + cms: &mut crate::coords::cms::CMS, + config: &Self::Config, + ) -> super::Target { + let first_block = data.blocks.first().unwrap(); + match first_block.shape { + DataShape::Vector => { + panic!("Vector data is not supported") + } + DataShape::Matrix => { + let data: Radar2d = first_block.clone().into(); + let data = data.as_ref(); + let result = config.render(canvas, cms, &data, (3000.0, 3000.0)); + result + } + DataShape::Cube => { + let data: Radar3d = first_block.clone().into(); + let data = data.index_axis(ndarray::Axis(0), 0); + let result = config.render(canvas, cms, &data, (3000.0, 3000.0)); + result + } + } + } +} diff --git a/src/pipeline/new_pipeline.rs b/src/pipeline/new_pipeline.rs index 4f24658..d1c527c 100644 --- a/src/pipeline/new_pipeline.rs +++ b/src/pipeline/new_pipeline.rs @@ -2,7 +2,7 @@ use super::{ dispatcher::Dispatcher, element::{DataTarget, RenderResult}, offscreen_renderer::{CanvasWrapper, OffscreenRenderer}, - utils::data_to_element, + // utils::data_to_element, }; use crate::coords::cms::CMS; use crate::pipeline::element::Target; diff --git a/src/pipeline/offscreen_renderer.rs b/src/pipeline/offscreen_renderer.rs index 39d4867..248b6af 100644 --- a/src/pipeline/offscreen_renderer.rs +++ b/src/pipeline/offscreen_renderer.rs @@ -1,4 +1,4 @@ -use super::utils::*; +// use super::utils::*; use crate::pipeline::element::Target; use euclid::Size2D; use femtovg::{renderer::OpenGl, Canvas}; diff --git a/src/predefined/color_mapper.rs b/src/predefined/color_mapper.rs index 9085d8d..ae28e3c 100644 --- a/src/predefined/color_mapper.rs +++ b/src/predefined/color_mapper.rs @@ -1,117 +1,236 @@ use std::fmt::Debug; use femtovg::Color; +use image::imageops::ColorMap; use num_traits::{AsPrimitive, FromPrimitive, NumOps}; -pub trait ColorMapper>: - Debug + Send + Sync -{ - fn map_value_to_color(&self, value: T, invalid: T) -> Option; - fn map_min_to_max(&self) -> Vec; +type BoundaryNormDiscrete = ColorMapper>; +macro_rules! color_mapper_comb { + ($comb: ident, $($key: tt,)+) => { - fn labels(&self) -> Vec; + impl $comb { - fn min_max(&self) -> (T, T); - fn invalid(&self) -> T; + pub fn color(&self, value: T) -> Option { + match self { + $( + Self::$key(mapper) => mapper.color(value), + )+ + } + + } + } + + }; } -#[derive(Debug, Clone)] -pub struct BoundaryNorm { +pub enum ColorMapperComb { + BoundaryNormDiscrete(BoundaryNormDiscrete), +} + +color_mapper_comb!(ColorMapperComb, BoundaryNormDiscrete,); + +pub trait VMap { + type Ty; + fn map(&self, v: Self::Ty) -> Option; +} + +pub trait CMap { + fn map(&self, v: f32) -> femtovg::Color; +} + +pub struct ColorMapper +where + CMAP: CMap, + VMAP: VMap, +{ + cmap: CMAP, + vmap: VMAP, +} + +impl ColorMapper +where + T: PartialEq + PartialOrd, + CMAP: CMap, + VMAP: VMap, +{ + pub fn new(cmap: CMAP, vmap: VMAP) -> Self { + Self { cmap, vmap } + } + + pub fn color(&self, value: T) -> Option { + self.vmap.map(value).map(|v| self.cmap.map(v)) + } +} + +#[derive(Debug)] +pub struct BoundaryNorm { boundaries: Vec, extrand: bool, - colors: Vec, - invalid_value: T, + invalid_value: Option, } - -impl Default for BoundaryNorm { - fn default() -> Self { - Self { - boundaries: vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65], - extrand: true, - colors: 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), - ], - invalid_value: -125, - } - } -} - -impl BoundaryNorm { - pub fn new( - boundaries: Vec, - colors: Vec, - extrand: bool, - invalid_value: T, - ) -> Self { - // assert_eq!(boundaries.len(), colors.len() + 1); - BoundaryNorm { - boundaries, - extrand, - colors, - invalid_value, - } - } - - pub fn map_value_to_color(&self, value: T, invalid_value: T) -> Option { +impl VMap for BoundaryNorm +where + T: PartialOrd + PartialEq + Debug, +{ + type Ty = T; + fn map(&self, v: Self::Ty) -> Option { let mut index = 0; - if value == invalid_value { - return None; + if let Some(invalid_value) = &self.invalid_value { + if v == *invalid_value { + return None; + } } + for (i, boundary) in self.boundaries.iter().enumerate() { - if value < *boundary { + if v < *boundary { break; } index = i; } - index = index.saturating_sub(1).min(self.colors.len() - 1); - Some(self.colors[index]) + + Some(index as f32 / self.boundaries.len() as f32) } } -impl ColorMapper for BoundaryNorm -where - T: NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, -{ - fn map_value_to_color(&self, value: T, invalid_value: T) -> Option { - self.map_value_to_color(value, invalid_value) - } +#[derive(Debug)] +pub struct Gradient {} - fn min_max(&self) -> (T, T) { - ( - self.boundaries.first().unwrap().clone(), - self.boundaries.last().unwrap().clone(), - ) - } +#[derive(Debug)] +pub struct Discrete { + colors: Vec, +} - fn invalid(&self) -> T { - self.invalid_value.clone() - } - - fn map_min_to_max(&self) -> Vec { - self.boundaries - .iter() - .map(|x| self.map_value_to_color(*x, self.invalid_value).unwrap()) - .collect() - } - - fn labels(&self) -> Vec { - self.boundaries - .iter() - .map(|x| format!("{:.2}", x.as_())) - .collect() +impl CMap for Discrete { + fn map(&self, v: f32) -> Color { + let size = (self.colors.len() as f32 * v) as usize; + self.colors.get(size).unwrap().clone() } } + +// #[derive(Debug, Clone)] +// pub struct BoundaryNorm { +// boundaries: Vec, +// extrand: bool, +// colors: Vec, +// invalid_value: T, +// } +// +// impl Default for BoundaryNorm { +// fn default() -> Self { +// Self { +// boundaries: vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65], +// extrand: true, +// colors: 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), +// ], +// invalid_value: -125, +// } +// } +// } +// +// impl BoundaryNorm { +// pub fn new( +// boundaries: Vec, +// colors: Vec, +// extrand: bool, +// invalid_value: T, +// ) -> Self { +// // assert_eq!(boundaries.len(), colors.len() + 1); +// BoundaryNorm { +// boundaries, +// extrand, +// colors, +// invalid_value, +// } +// } +// +// pub fn map_value_to_color(&self, value: f64, invalid_value: f64) -> Option { +// let mut index = 0; +// if value == invalid_value { +// return None; +// } +// for (i, boundary) in self.boundaries.iter().enumerate() { +// if value < *boundary { +// break; +// } +// index = i; +// } +// index = index.saturating_sub(1).min(self.colors.len() - 1); +// Some(self.colors[index]) +// } +// } +// +// impl ColorMapper for BoundaryNorm +// where +// T: NumOps + PartialOrd + FromPrimitive + AsPrimitive + Send + Sync + Debug, +// { +// +// type Ty = T; +// fn map_value_to_color(&self, value: Self::Ty, invalid_value: Self::Ty) -> Option { +// self.map_value_to_color(value, invalid_value) +// } +// +// fn min_max(&self) -> (f64, f64) { +// ( +// self.boundaries.first().unwrap().clone().as_(), +// self.boundaries.last().unwrap().clone().as_(), +// ) +// } +// +// fn invalid(&self) -> f64 { +// self.invalid_value.clone().as_() +// } +// +// fn map_min_to_max(&self) -> Vec { +// self.boundaries +// .iter() +// .map(|x| self.map_value_to_color(*x, self.invalid_value).unwrap()) +// .collect() +// } +// } + +// pub struct BoundaryNorm(); +// +// impl ColorMapper for BoundaryNorm { +// type Ty = T; +// fn map_value_to_color(&self, value: Self::Ty, invalid: T) -> Option { +// let mut index = 0; +// if value == invalid_value { +// return None; +// } +// for (i, boundary) in self.boundaries.iter().enumerate() { +// if value < *boundary { +// break; +// } +// index = i; +// } +// index = index.saturating_sub(1).min(self.colors.len() - 1); +// Some(self.colors[index]) +// } +// +// fn map_min_to_max(&self) -> Vec { +// vec![] +// } +// +// fn min_max(&self) -> (f64, f64) { +// (0.0, 0.0) +// } +// +// fn invalid(&self) -> f64 { +// 0.0 +// } +// } diff --git a/src/utils.rs b/src/utils.rs index 614dc21..91e9ac0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -31,272 +31,272 @@ where (xx, yy) } -pub fn create_dbz_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, - ], - vec![ - Color::rgb(23, 174, 165), - Color::rgb(198, 195, 253), - Color::rgb(124, 114, 236), - Color::rgb(1, 160, 246), - Color::rgb(0, 236, 236), - Color::rgb(0, 216, 0), - Color::rgb(1, 144, 0), - Color::rgb(255, 255, 0), - Color::rgb(231, 192, 0), - Color::rgb(255, 144, 0), - Color::rgb(255, 0, 0), - Color::rgb(214, 0, 0), - Color::rgb(192, 0, 0), - Color::rgb(255, 0, 240), - Color::rgb(150, 0, 180), - Color::rgb(139, 0, 255), - ], - true, - -125, - ) -} +// pub fn create_dbz_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// -5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, +// ], +// vec![ +// Color::rgb(23, 174, 165), +// Color::rgb(198, 195, 253), +// Color::rgb(124, 114, 236), +// Color::rgb(1, 160, 246), +// Color::rgb(0, 236, 236), +// Color::rgb(0, 216, 0), +// Color::rgb(1, 144, 0), +// Color::rgb(255, 255, 0), +// Color::rgb(231, 192, 0), +// Color::rgb(255, 144, 0), +// Color::rgb(255, 0, 0), +// Color::rgb(214, 0, 0), +// Color::rgb(192, 0, 0), +// Color::rgb(255, 0, 240), +// Color::rgb(150, 0, 180), +// Color::rgb(139, 0, 255), +// ], +// true, +// -125, +// ) +// } -pub fn create_vel_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - -35.0, -27.0, -20.0, -15.0, -10.0, -5.0, -1.0, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 27.0, - 35.0, - ], - vec![ - Color::rgb(0, 224, 255), - Color::rgb(0, 128, 255), - Color::rgb(50, 0, 150), - Color::rgb(0, 251, 144), - Color::rgb(0, 187, 144), - Color::rgb(0, 143, 0), - Color::rgb(205, 192, 159), - Color::rgb(255, 255, 255), - Color::rgb(248, 135, 0), - Color::rgb(255, 207, 0), - Color::rgb(255, 255, 0), - Color::rgb(174, 0, 0), - Color::rgb(208, 112, 0), - Color::rgb(255, 0, 0), - ], - true, - -125.0, - ) -} +// pub fn create_vel_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// -35.0, -27.0, -20.0, -15.0, -10.0, -5.0, -1.0, 0.0, 1.0, 5.0, 10.0, 15.0, 20.0, 27.0, +// 35.0, +// ], +// vec![ +// Color::rgb(0, 224, 255), +// Color::rgb(0, 128, 255), +// Color::rgb(50, 0, 150), +// Color::rgb(0, 251, 144), +// Color::rgb(0, 187, 144), +// Color::rgb(0, 143, 0), +// Color::rgb(205, 192, 159), +// Color::rgb(255, 255, 255), +// Color::rgb(248, 135, 0), +// Color::rgb(255, 207, 0), +// Color::rgb(255, 255, 0), +// Color::rgb(174, 0, 0), +// Color::rgb(208, 112, 0), +// Color::rgb(255, 0, 0), +// ], +// true, +// -125.0, +// ) +// } -pub fn create_phidp_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - 0.0, 22.0, 46.0, 68.0, 90.0, 112.0, 136.0, 158.0, 180.0, 202.0, 224.0, 248.0, 270.0, - 292.0, 314.0, 359.0, - ], - vec![ - Color::rgb(0, 60, 255), - Color::rgb(0, 239, 239), - Color::rgb(0, 186, 191), - Color::rgb(0, 131, 125), - Color::rgb(0, 137, 56), - Color::rgb(0, 183, 41), - Color::rgb(0, 218, 13), - Color::rgb(0, 255, 0), - Color::rgb(255, 255, 59), - Color::rgb(255, 240, 0), - Color::rgb(255, 198, 0), - Color::rgb(255, 165, 0), - Color::rgb(255, 114, 0), - Color::rgb(255, 31, 0), - Color::rgb(193, 0, 0), - ], - true, - -125.0, - ) -} +// pub fn create_phidp_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// 0.0, 22.0, 46.0, 68.0, 90.0, 112.0, 136.0, 158.0, 180.0, 202.0, 224.0, 248.0, 270.0, +// 292.0, 314.0, 359.0, +// ], +// vec![ +// Color::rgb(0, 60, 255), +// Color::rgb(0, 239, 239), +// Color::rgb(0, 186, 191), +// Color::rgb(0, 131, 125), +// Color::rgb(0, 137, 56), +// Color::rgb(0, 183, 41), +// Color::rgb(0, 218, 13), +// Color::rgb(0, 255, 0), +// Color::rgb(255, 255, 59), +// Color::rgb(255, 240, 0), +// Color::rgb(255, 198, 0), +// Color::rgb(255, 165, 0), +// Color::rgb(255, 114, 0), +// Color::rgb(255, 31, 0), +// Color::rgb(193, 0, 0), +// ], +// true, +// -125.0, +// ) +// } -pub fn create_zdr_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - -5.0, -4.5, -4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, - ], - vec![ - Color::rgb(70, 70, 70), - Color::rgb(80, 80, 80), - Color::rgb(90, 90, 90), - Color::rgb(100, 100, 100), - Color::rgb(110, 110, 110), - Color::rgb(120, 120, 120), - Color::rgb(130, 130, 130), - Color::rgb(140, 140, 140), - Color::rgb(150, 150, 150), - Color::rgb(175, 175, 175), - Color::rgb(200, 200, 200), - Color::rgb(220, 240, 220), - Color::rgb(0, 192, 39), - ], - true, - -125.0, - ) -} +// pub fn create_zdr_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// -5.0, -4.5, -4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, +// ], +// vec![ +// Color::rgb(70, 70, 70), +// Color::rgb(80, 80, 80), +// Color::rgb(90, 90, 90), +// Color::rgb(100, 100, 100), +// Color::rgb(110, 110, 110), +// Color::rgb(120, 120, 120), +// Color::rgb(130, 130, 130), +// Color::rgb(140, 140, 140), +// Color::rgb(150, 150, 150), +// Color::rgb(175, 175, 175), +// Color::rgb(200, 200, 200), +// Color::rgb(220, 240, 220), +// Color::rgb(0, 192, 39), +// ], +// true, +// -125.0, +// ) +// } -pub fn create_cc_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - 0.0, 0.1, 0.3, 0.5, 0.6, 0.7, 0.8, 0.85, 0.9, 0.92, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, - ], - vec![ - Color::rgb(0, 60, 255), - Color::rgb(0, 239, 239), - Color::rgb(0, 186, 191), - Color::rgb(0, 131, 125), - Color::rgb(0, 137, 56), - Color::rgb(0, 183, 41), - Color::rgb(0, 218, 13), - Color::rgb(0, 255, 0), - Color::rgb(255, 255, 59), - Color::rgb(255, 240, 0), - Color::rgb(255, 198, 0), - Color::rgb(255, 165, 0), - Color::rgb(255, 114, 0), - Color::rgb(255, 31, 0), - Color::rgb(193, 0, 0), - ], - true, - -125.0, - ) -} +// pub fn create_cc_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// 0.0, 0.1, 0.3, 0.5, 0.6, 0.7, 0.8, 0.85, 0.9, 0.92, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, +// ], +// vec![ +// Color::rgb(0, 60, 255), +// Color::rgb(0, 239, 239), +// Color::rgb(0, 186, 191), +// Color::rgb(0, 131, 125), +// Color::rgb(0, 137, 56), +// Color::rgb(0, 183, 41), +// Color::rgb(0, 218, 13), +// Color::rgb(0, 255, 0), +// Color::rgb(255, 255, 59), +// Color::rgb(255, 240, 0), +// Color::rgb(255, 198, 0), +// Color::rgb(255, 165, 0), +// Color::rgb(255, 114, 0), +// Color::rgb(255, 31, 0), +// Color::rgb(193, 0, 0), +// ], +// true, +// -125.0, +// ) +// } -pub fn create_vil_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35., 40., 45., 50., 55., 60., 65., 70., - ], - vec![ - Color::rgb(156, 156, 156), - Color::rgb(118, 118, 118), - Color::rgb(250, 170, 170), - Color::rgb(238, 140, 140), - Color::rgb(201, 112, 112), - Color::rgb(0, 251, 144), - Color::rgb(0, 187, 0), - Color::rgb(255, 255, 112), - Color::rgb(208, 208, 96), - Color::rgb(255, 96, 96), - Color::rgb(218, 0, 0), - Color::rgb(174, 0, 0), - Color::rgb(0, 0, 255), - Color::rgb(255, 255, 255), - ], - true, - -125.0, - ) -} +// pub fn create_vil_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// 1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35., 40., 45., 50., 55., 60., 65., 70., +// ], +// vec![ +// Color::rgb(156, 156, 156), +// Color::rgb(118, 118, 118), +// Color::rgb(250, 170, 170), +// Color::rgb(238, 140, 140), +// Color::rgb(201, 112, 112), +// Color::rgb(0, 251, 144), +// Color::rgb(0, 187, 0), +// Color::rgb(255, 255, 112), +// Color::rgb(208, 208, 96), +// Color::rgb(255, 96, 96), +// Color::rgb(218, 0, 0), +// Color::rgb(174, 0, 0), +// Color::rgb(0, 0, 255), +// Color::rgb(255, 255, 255), +// ], +// true, +// -125.0, +// ) +// } -pub fn create_hgt_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - 0.0, 2.0, 3.0, 5.0, 6.0, 8.0, 9.0, 11., 12., 14., 15., 17., 18., 20., 21., - ], - vec![ - Color::rgb(0, 0, 0), - Color::rgb(118, 118, 118), - Color::rgb(0, 224, 255), - Color::rgb(0, 176, 255), - Color::rgb(0, 144, 204), - Color::rgb(50, 0, 150), - Color::rgb(0, 251, 144), - Color::rgb(0, 187, 0), - Color::rgb(0, 239, 0), - Color::rgb(254, 191, 0), - Color::rgb(255, 255, 0), - Color::rgb(174, 0, 0), - Color::rgb(255, 0, 0), - Color::rgb(255, 255, 255), - ], - true, - -125.0, - ) -} +// pub fn create_hgt_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// 0.0, 2.0, 3.0, 5.0, 6.0, 8.0, 9.0, 11., 12., 14., 15., 17., 18., 20., 21., +// ], +// vec![ +// Color::rgb(0, 0, 0), +// Color::rgb(118, 118, 118), +// Color::rgb(0, 224, 255), +// Color::rgb(0, 176, 255), +// Color::rgb(0, 144, 204), +// Color::rgb(50, 0, 150), +// Color::rgb(0, 251, 144), +// Color::rgb(0, 187, 0), +// Color::rgb(0, 239, 0), +// Color::rgb(254, 191, 0), +// Color::rgb(255, 255, 0), +// Color::rgb(174, 0, 0), +// Color::rgb(255, 0, 0), +// Color::rgb(255, 255, 255), +// ], +// true, +// -125.0, +// ) +// } -pub fn create_et_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - 0.1, 0.2, 0.5, 1.0, 1.5, 2.0, 3.0, 5.0, 6.0, 8.0, 9.0, 11.0, 12.0, 14.0, 15.0, 17.0, - 18.0, 20.0, 21.0, - ], - vec![ - Color::rgb(204, 253, 255), - Color::rgb(153, 248, 255), - Color::rgb(101, 239, 255), - Color::rgb(50, 227, 255), - Color::rgb(134, 255, 134), - Color::rgb(80, 255, 80), - Color::rgb(0, 241, 1), - Color::rgb(0, 187, 0), - Color::rgb(255, 255, 84), - Color::rgb(255, 240, 0), - Color::rgb(255, 191, 0), - Color::rgb(255, 168, 0), - Color::rgb(255, 89, 89), - Color::rgb(255, 64, 64), - Color::rgb(255, 13, 13), - Color::rgb(237, 0, 0), - Color::rgb(205, 0, 0), - Color::rgb(139, 0, 0), - ], - true, - -125.0, - ) -} +// pub fn create_et_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// 0.1, 0.2, 0.5, 1.0, 1.5, 2.0, 3.0, 5.0, 6.0, 8.0, 9.0, 11.0, 12.0, 14.0, 15.0, 17.0, +// 18.0, 20.0, 21.0, +// ], +// vec![ +// Color::rgb(204, 253, 255), +// Color::rgb(153, 248, 255), +// Color::rgb(101, 239, 255), +// Color::rgb(50, 227, 255), +// Color::rgb(134, 255, 134), +// Color::rgb(80, 255, 80), +// Color::rgb(0, 241, 1), +// Color::rgb(0, 187, 0), +// Color::rgb(255, 255, 84), +// Color::rgb(255, 240, 0), +// Color::rgb(255, 191, 0), +// Color::rgb(255, 168, 0), +// Color::rgb(255, 89, 89), +// Color::rgb(255, 64, 64), +// Color::rgb(255, 13, 13), +// Color::rgb(237, 0, 0), +// Color::rgb(205, 0, 0), +// Color::rgb(139, 0, 0), +// ], +// true, +// -125.0, +// ) +// } -pub fn create_cpc_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], - vec![ - Color::rgb(201, 196, 191), - Color::rgb(112, 188, 73), - Color::rgb(245, 163, 110), - Color::rgb(208, 119, 52), - Color::rgb(234, 37, 47), - Color::rgb(199, 53, 47), - Color::rgb(145, 71, 152), - Color::rgb(178, 177, 65), - Color::rgb(103, 199, 208), - Color::rgb(55, 90, 165), - Color::rgb(187, 165, 204), - ], - true, - -125, - ) -} +// pub fn create_cpc_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], +// vec![ +// Color::rgb(201, 196, 191), +// Color::rgb(112, 188, 73), +// Color::rgb(245, 163, 110), +// Color::rgb(208, 119, 52), +// Color::rgb(234, 37, 47), +// Color::rgb(199, 53, 47), +// Color::rgb(145, 71, 152), +// Color::rgb(178, 177, 65), +// Color::rgb(103, 199, 208), +// Color::rgb(55, 90, 165), +// Color::rgb(187, 165, 204), +// ], +// true, +// -125, +// ) +// } -pub fn create_kdp_boundarynorm() -> BoundaryNorm { - BoundaryNorm::new( - vec![ - -0.8, -0.4, -0.2, -0.1, 0.1, 0.15, 0.22, 0.33, 0.5, 0.75, 1.1, 1.7, 2.4, 3.1, 7.0, 20.0, - ], - vec![ - Color::rgb(0, 255, 255), - Color::rgb(0, 239, 239), - Color::rgb(0, 168, 172), - Color::rgb(180, 180, 180), - Color::rgb(180, 180, 180), - Color::rgb(0, 192, 39), - Color::rgb(0, 232, 10), - Color::rgb(36, 255, 36), - Color::rgb(255, 255, 30), - Color::rgb(255, 230, 0), - Color::rgb(255, 188, 0), - Color::rgb(255, 152, 0), - Color::rgb(255, 94, 0), - Color::rgb(242, 15, 0), - Color::rgb(187, 0, 58), - Color::rgb(253, 6, 253), - ], - true, - -125.0, - ) -} +// pub fn create_kdp_boundarynorm() -> BoundaryNorm { +// BoundaryNorm::new( +// vec![ +// -0.8, -0.4, -0.2, -0.1, 0.1, 0.15, 0.22, 0.33, 0.5, 0.75, 1.1, 1.7, 2.4, 3.1, 7.0, 20.0, +// ], +// vec![ +// Color::rgb(0, 255, 255), +// Color::rgb(0, 239, 239), +// Color::rgb(0, 168, 172), +// Color::rgb(180, 180, 180), +// Color::rgb(180, 180, 180), +// Color::rgb(0, 192, 39), +// Color::rgb(0, 232, 10), +// Color::rgb(36, 255, 36), +// Color::rgb(255, 255, 30), +// Color::rgb(255, 230, 0), +// Color::rgb(255, 188, 0), +// Color::rgb(255, 152, 0), +// Color::rgb(255, 94, 0), +// Color::rgb(242, 15, 0), +// Color::rgb(187, 0, 58), +// Color::rgb(253, 6, 253), +// ], +// true, +// -125.0, +// ) +// } pub fn estimate_zoom_level( lat_min: f64,