diff --git a/radar-g/src/components/app.rs b/radar-g/src/components/app.rs index c358ee8..2dd959f 100644 --- a/radar-g/src/components/app.rs +++ b/radar-g/src/components/app.rs @@ -8,11 +8,6 @@ use super::{ }; use crate::components::sidebar::{SideBarInputMsg, SideBarModel}; use crate::data_utils::tools; -use crate::pipeline::element::Buffer; -use crate::pipeline::element::Element; -use crate::pipeline::element_imp::{Context, ElementInput, GridImpConfig}; -use crate::pipeline::runner::Runner; -use crate::pipeline::{DataTarget, Key}; use crate::pipeline::{KVBuffer, OffscreenRenderer}; use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete}; use crate::predefined::widgets::ColorBar; @@ -82,10 +77,10 @@ pub enum AppMsg { CloseRequest, Close, OpenDialog, - LayerManager(LayerMsg), - Layer, - NewElement(Rc>), - DeleteElement(ElementKey), + // LayerManager(LayerMsg), + // Layer, + // NewElement(Rc>), + // DeleteElement(ElementKey), } type RcDispatcher = Rc; type ArcDispatcher = Arc; @@ -96,6 +91,8 @@ pub struct AppModel { #[do_not_track] cms: CMS, waiting_for: Option>, + + // Components #[do_not_track] open_dialog: Controller, #[do_not_track] @@ -104,15 +101,19 @@ pub struct AppModel { render: Controller, #[do_not_track] sidebar: Controller, + + // Data selected_layer: Vec, #[do_not_track] layers: Rc>>, - #[do_not_track] - buffer: Arc>, + // #[do_not_track] + // buffer: Arc>, + + // File Pool #[do_not_track] file_pool: Arc>>, - #[do_not_track] - elements: Vec>>, + // #[do_not_track] + // elements: Vec>>, #[do_not_track] setting: Controller, } @@ -239,87 +240,91 @@ impl Component for AppModel { }, ); - let buffer = Arc::new(Buffer::new(100)); + // let buffer = Arc::new(Buffer::new(100)); let file_pool = Arc::new(KVBuffer::new(20)); - let sidebar = - SideBarModel::builder() - .launch(layers.clone()) - .forward(sender.input_sender(), |msg| { - AppMsg::LayerManager(match msg { - SideBarOutputMsg::SelectLayer(idx) => LayerMsg::Select(idx), - SideBarOutputMsg::NewLayer(layer) => LayerMsg::Add(layer), - SideBarOutputMsg::SwitchToTimeSeries(idx) => LayerMsg::SwitchToTime(idx), - }) - }); - let render = - MonitorModel::builder() - .launch(layers.clone()) - .forward(sender.input_sender(), |a| match a { - MonitorOutputMsg::LayerRenderFinished => AppMsg::Close, - _ => AppMsg::Close, - }); + // SideBar Component + // let sidebar = + // SideBarModel::builder() + // .launch(layers.clone()) + // .forward(sender.input_sender(), |msg| { + // AppMsg::LayerManager(match msg { + // SideBarOutputMsg::SelectLayer(idx) => LayerMsg::Select(idx), + // SideBarOutputMsg::NewLayer(layer) => LayerMsg::Add(layer), + // SideBarOutputMsg::SwitchToTimeSeries(idx) => LayerMsg::SwitchToTime(idx), + // }) + // }); - let setting = SettingModel::builder() - .launch(()) - .forward(sender.input_sender(), |a| AppMsg::Close); + // // Monitor Component + // let render = + // MonitorModel::builder() + // .launch(layers.clone()) + // .forward(sender.input_sender(), |a| match a { + // MonitorOutputMsg::LayerRenderFinished => AppMsg::Close, + // _ => AppMsg::Close, + // }); - let mut dispatcher = Arc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1))); - let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0)); - let dialog_buffer = buffer.clone(); - let dialog_cms = cms.clone(); + // let setting = SettingModel::builder() + // .launch(()) + // .forward(sender.input_sender(), |a| AppMsg::Close); - let dialog = { - let dialog_dispatcher = dispatcher.clone(); - let dialog_sidebar_sender = sidebar.sender().clone(); - let dialog_render_sender = render.sender().clone(); - let dialog_file_pool = file_pool.clone(); - OpenDialog::builder() - .transient_for_native(&root) - .launch(OpenDialogSettings::default()) - .forward(sender.input_sender(), move |response| match response { - OpenDialogResponse::Accept(path) => { - *FILE_PATH_ROOT.lock().unwrap() = path.clone(); - let data = Self::open_file_only(path.clone()); - 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 (imp, cfg) = tools(&data); - dialog_file_pool.insert(path.clone(), Arc::new(data)); + // // Background Dispatcher + // let mut dispatcher = Arc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1))); + // let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0)); + // let dialog_buffer = buffer.clone(); + // let dialog_cms = cms.clone(); - let element = Rc::new(RefCell::new(Element::new( - "CR", - dialog_cms.clone(), - dialog_dispatcher.clone(), - true, - cfg, - path.clone(), - dialog_buffer.clone(), - dialog_file_pool.clone(), - imp, - ))); + // // File Dialog + // let dialog = { + // let dialog_dispatcher = dispatcher.clone(); + // let dialog_sidebar_sender = sidebar.sender().clone(); + // let dialog_render_sender = render.sender().clone(); + // let dialog_file_pool = file_pool.clone(); + // OpenDialog::builder() + // .transient_for_native(&root) + // .launch(OpenDialogSettings::default()) + // .forward(sender.input_sender(), move |response| match response { + // OpenDialogResponse::Accept(path) => { + // let data = Self::open_file_only(path.clone()); + // 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 (imp, cfg) = tools(&data); + // dialog_file_pool.insert(path.clone(), Arc::new(data)); - dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map())); - dialog_render_sender.emit(MonitorInputMsg::SetRenderRange( - lon_start, lon_end, lat_start, lat_end, - )); + // let element = Rc::new(RefCell::new(Element::new( + // "CR", + // dialog_cms.clone(), + // dialog_dispatcher.clone(), + // true, + // cfg, + // path.clone(), + // dialog_buffer.clone(), + // dialog_file_pool.clone(), + // imp, + // ))); - AppMsg::NewElement(element) - } - _ => AppMsg::Close, - }) - }; + // dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map())); + // dialog_render_sender.emit(MonitorInputMsg::SetRenderRange( + // lon_start, lon_end, lat_start, lat_end, + // )); + + // AppMsg::NewElement(element) + // } + // _ => AppMsg::Close, + // }) + // }; let model = AppModel { - cms, - dispatcher, + // cms, + // dispatcher, waiting_for: None, - buffer, + // buffer, file_pool, - open_dialog: dialog, + // open_dialog: dialog, selected_layer: vec![], - sidebar, - elements: vec![], + // sidebar, + // elements: vec![], control, render, layers, diff --git a/radar-g/src/coords/cms.rs b/radar-g/src/coords/cms.rs deleted file mode 100644 index be1a2fa..0000000 --- a/radar-g/src/coords/cms.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::coords::Mapper; -use epoxy::XOR; -use geo_types::LineString; -use std::ops::Range; - -#[derive(Debug, Clone)] -pub struct CMS { - mapper: Mapper, - window_size: (f32, f32), - bounds: (f64, f64, f64, f64), -} - -unsafe impl Send for CMS {} -unsafe impl Sync for CMS {} - -impl CMS { - pub fn new(mapper: Mapper, window_size: (f32, f32)) -> Self { - let bounds = mapper.get_bounds(); - Self { - mapper, - window_size, - bounds, - } - } - - pub fn set_lat_range(&mut self, lat_range: Range) { - self.mapper.set_lat_range(lat_range); - self.bounds = self.mapper.get_bounds() - } - - pub fn set_lon_range(&mut self, lon_range: Range) { - self.mapper.set_lon_range(lon_range); - self.bounds = self.mapper.get_bounds(); - } - - pub fn map(&self, loc: (f64, f64)) -> Option<(f32, f32)> { - self.mapper.map(loc).ok().map(|(x, y)| { - // println!("x: {}, y: {}", x, y); - let (w, h) = self.window_size; - let (w, h) = (w as f64, h as f64); - let (x, y) = (x - self.bounds.0, y - self.bounds.2); - // TODO: check if the following line is correct : 1.0 - y / (self.bounds.3 - self.bounds.2) - let (x, y) = ( - x / (self.bounds.1 - self.bounds.0), - y / (self.bounds.3 - self.bounds.2), - ); - let (x, y) = (x * w, y * h); - (x as f32, y as f32) - }) - } - - 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.2 + 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() - .into_iter() - .map(|p| self.map((p.x(), p.y())).unwrap()) - .collect::>() - .into(), - ) - } -} diff --git a/radar-g/src/coords/mapper.rs b/radar-g/src/coords/mapper.rs deleted file mode 100644 index d6f31e9..0000000 --- a/radar-g/src/coords/mapper.rs +++ /dev/null @@ -1,252 +0,0 @@ -use crate::widgets::render::WindowCoord; -use std::borrow::ToOwned; - -use super::{proj::ProjectionS, Range}; -use geo_types::{coord, Coord as GCoord, LineString}; -use proj::{Proj, ProjError}; - -pub struct Mapper { - proj: Proj, - pub range: (Range, Range), - bounds: (f64, f64, f64, f64), -} - -unsafe impl Send for Mapper {} -unsafe impl Sync for Mapper {} - -impl std::fmt::Debug for Mapper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Mapper") - .field("proj", &self.proj) - .field("range", &self.range) - .field("bounds", &self.bounds) - .finish() - } -} - -impl Clone for Mapper { - fn clone(&self) -> Self { - let c = self.proj.proj_info(); - let new_proj = Proj::new(c.definition.unwrap().as_str()).unwrap(); - Self { - proj: new_proj, - range: self.range, - bounds: self.bounds, - } - } -} - -impl From for Mapper { - fn from(proj: Proj) -> Self { - let default_range: (Range, Range) = ((-180.0..180.0).into(), (-81.0..81.0).into()); - let bounds = Self::bound(&proj, default_range.clone()).unwrap(); - Self { - proj, - range: (default_range.0.into(), default_range.1.into()), - bounds, - } - } -} - -impl From for Mapper { - fn from(proj: C) -> Self { - let p = Proj::new(proj.build().as_str()).unwrap(); - p.into() - } -} - -impl Mapper { - pub fn new( - proj: Proj, - lon_range: std::ops::Range, - lat_range: std::ops::Range, - ) -> Self { - let bounds = - Self::bound(&proj, (lon_range.clone().into(), lat_range.clone().into())).unwrap(); - let range = (lon_range.into(), lat_range.into()); - Self { - proj, - range, - bounds, - } - } - - pub fn inverse_map(&self, coord: (f64, f64)) -> Result<(f64, f64), ProjError> { - let (x, y) = coord; - // let c = (x as f64) * (self.bounds.1 - self.bounds.0) + self.bounds.0; - // let d = ((1.0 - y) as f64) * (self.bounds.3 - self.bounds.2) + self.bounds.2; - let (lon, lat) = self.proj.project((x, y), true)?; - Ok((lon.to_degrees(), lat.to_degrees())) - } - - pub fn point_in_bound(&self, point: (f64, f64)) -> bool { - let (x, y) = point; - let (lon_range, lat_range) = self.range; - return (x <= lon_range.1 && x >= lon_range.0) && (y <= lat_range.1 && y >= lat_range.0); - } - - pub fn get_bounds(&self) -> (f64, f64, f64, f64) { - self.bounds - } - - pub fn map(&self, point: (f64, f64)) -> Result<(f64, f64), ProjError> { - let mut point = point; - // if !self.point_in_bound(point) { - // point = ( - // point.0.clamp(self.range.0 .0, self.range.0 .1), - // point.1.clamp(self.range.1 .0, self.range.1 .1), - // ); - // } - let (p1, p2) = self - .proj - .convert((point.0.to_radians(), point.1.to_radians()))?; - - // let x = (p1 - self.bounds.0) / (self.bounds.1 - self.bounds.0); - // let y = (p2 - self.bounds.2) / (self.bounds.3 - self.bounds.2); - - // Ok((x, (1.0 - y))) - // - Ok((p1, p2)) - } - - pub fn set_lon_range(&mut self, range: std::ops::Range) -> &mut Self { - self.range.0 = range.into(); - self.bounds = Self::bound(&self.proj, self.range.clone()).unwrap(); - self - } - - pub fn set_lat_range(&mut self, range: std::ops::Range) -> &mut Self { - self.range.1 = range.into(); - self.bounds = Self::bound(&self.proj, self.range.clone()).unwrap(); - self - } - - fn bound(proj: &Proj, range: (Range, Range)) -> Result<(f64, f64, f64, f64), ProjError> { - let left_bottom = proj.convert((range.0 .0.to_radians(), range.1 .0.to_radians()))?; - let right_top = proj.convert((range.0 .1.to_radians(), range.1 .1.to_radians()))?; - Ok((left_bottom.0, right_top.0, left_bottom.1, right_top.1)) - } - - pub fn ring_map(&self, ring: &LineString) -> Result { - let mut result = Vec::new(); - let projed = self.map_line(ring)?; - for (l, p) in ring.lines().zip(projed.lines()) { - let start_projected: (f64, f64) = p.start.into(); - let end_projected: (f64, f64) = p.end.into(); - let cartesian_start = self.cartesian(l.start.x, l.start.y); - let cartesian_end = self.cartesian(l.end.x, l.end.y); - - let delta2 = 0.5; - let depth = 16; - let mut res: Vec = Vec::new(); - res.push(p.start); - self.resample_line_to( - start_projected, - end_projected, - l.start.x, - l.end.x, - cartesian_start, - cartesian_end, - &|x| self.map((x.x, x.y)), - delta2, - depth, - &mut res, - )?; - res.push(p.end); - result.extend(res); - } - - Ok(LineString::new(result)) - } - - pub fn map_line(&self, line: &LineString) -> Result { - let result: Result = - line.points().map(|p| self.map((p.x(), p.y()))).collect(); - - Ok(result?) - } - - #[inline] - fn cartesian(&self, lambda: f64, phi: f64) -> (f64, f64, f64) { - let cos_phi = phi.cosh(); - return (cos_phi * lambda.cosh(), cos_phi * lambda.sinh(), phi.sinh()); - } - - fn resample_line_to( - &self, - start_projected: (f64, f64), - end_projected: (f64, f64), - lambda0: f64, - lambda1: f64, - cartesian_start: (f64, f64, f64), - cartesian_end: (f64, f64, f64), - project: &F, - delta2: f64, - depth: u8, - result: &mut Vec, - ) -> Result<(), ProjError> - where - F: Fn(GCoord) -> Result<(f64, f64), ProjError>, - { - let cos_min_distance: f64 = 30f64.cosh(); - let (x0, y0) = start_projected; - let (x1, y1) = end_projected; - let (a0, b0, c0) = cartesian_start; - let (a1, b1, c1) = cartesian_end; - - let dx = x1 - x0; - let dy = y1 - y0; - let d2 = dx * dx + dy * dy; - - if d2 > 4.0 * delta2 && depth > 0 { - let a = a0 + a1; - let b = b0 + b1; - let c = c0 + c1; - let m = (a * a + b * b + c * c).sqrt(); - let depth = depth - 1; - - let phi2 = (c / m).asin(); - let lambda2 = - if (c / m).abs() - 1.0 < f64::EPSILON || (lambda0 - lambda1).abs() < f64::EPSILON { - (lambda0 + lambda1) / 2.0 - } else { - b.atan2(a) - }; - let (x2, y2) = project(coord! {x:lambda2,y:phi2})?; - let dx2 = x2 - x0; - let dy2 = y2 - y0; - let dz = dy * dx2 - dx * dy2; - if dz * dz / d2 > delta2 - || ((dx * dx2 + dy * dy2) / d2 - 0.5).abs() > 0.3 - || a0 * a1 + b0 * b1 + c0 * c1 < cos_min_distance - { - self.resample_line_to( - start_projected, - (x2, y2), - lambda0, - lambda2, - cartesian_start, - (a / m, b / m, c), - project, - delta2, - depth - 1, - result, - )?; - result.push(coord! {x:x2,y:y2}); - self.resample_line_to( - (x2, y2), - end_projected, - lambda2, - lambda1, - (a / m, b / m, c), - cartesian_end, - project, - delta2, - depth - 1, - result, - )?; - } - } - Ok(()) - } -} diff --git a/radar-g/src/coords/mod.rs b/radar-g/src/coords/mod.rs deleted file mode 100644 index 92d8216..0000000 --- a/radar-g/src/coords/mod.rs +++ /dev/null @@ -1,161 +0,0 @@ -use num_traits::AsPrimitive; -use num_traits::Num; -pub mod cms; -pub mod mapper; -pub mod proj; -pub mod wgs84; - -pub use mapper::Mapper; -// pub use wgs84::LatLonCoord; - -pub type ScreenCoord = (f64, f64); -type Lat = f64; -type Lon = f64; - -pub trait Coord { - fn map(&self, axis_1: T, axis_2: T) -> ScreenCoord; - fn dim1_range(&self) -> (T, T); - fn dim2_range(&self) -> (T, T); -} - -#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] -pub struct Range(pub f64, pub f64); - -impl Range { - pub fn key_points(&self, max_points: usize) -> Vec { - if max_points == 0 { - return vec![]; - } - - let range = (self.0.min(self.1) as f64, self.1.max(self.0) as f64); - assert!(!(range.0.is_nan() || range.1.is_nan())); - if (range.0 - range.1).abs() < std::f64::EPSILON { - return vec![range.0 as f64]; - } - - let mut scale = (10f64).powf((range.1 - range.0).log(10.0).floor()); - // The value granularity controls how we round the values. - // To avoid generating key points like 1.00000000001, we round to the nearest multiple of the - // value granularity. - // By default, we make the granularity as the 1/10 of the scale. - let mut value_granularity = scale / 10.0; - fn rem_euclid(a: f64, b: f64) -> f64 { - let ret = if b > 0.0 { - a - (a / b).floor() * b - } else { - a - (a / b).ceil() * b - }; - if (ret - b).abs() < std::f64::EPSILON { - 0.0 - } else { - ret - } - } - - // At this point we need to make sure that the loop invariant: - // The scale must yield number of points than requested - if 1 + ((range.1 - range.0) / scale).floor() as usize > max_points { - scale *= 10.0; - value_granularity *= 10.0; - } - - 'outer: loop { - let old_scale = scale; - for nxt in [2.0, 5.0, 10.0].iter() { - let mut new_left = range.0 - rem_euclid(range.0, old_scale / nxt); - if new_left < range.0 { - new_left += old_scale / nxt; - } - let new_right = range.1 - rem_euclid(range.1, old_scale / nxt); - - let npoints = 1.0 + ((new_right - new_left) / old_scale * nxt); - - if npoints.round() as usize > max_points { - break 'outer; - } - - scale = old_scale / nxt; - } - scale = old_scale / 10.0; - value_granularity /= 10.0; - } - - let mut ret = vec![]; - // In some extreme cases, left might be too big, so that (left + scale) - left == 0 due to - // floating point error. - // In this case, we may loop forever. To avoid this, we need to use two variables to store - // the current left value. So we need keep a left_base and a left_relative. - let left = { - let mut value = range.0 - rem_euclid(range.0, scale); - if value < range.0 { - value += scale; - } - value - }; - let left_base = (left / value_granularity).floor() * value_granularity; - let mut left_relative = left - left_base; - let right = range.1 - rem_euclid(range.1, scale); - while (right - left_relative - left_base) >= -std::f64::EPSILON { - let new_left_relative = (left_relative / value_granularity).round() * value_granularity; - if new_left_relative < 0.0 { - left_relative += value_granularity; - } - ret.push((left_relative + left_base) as f64); - left_relative += scale; - } - return ret; - } -} - -impl + Num> From<(T, T)> for Range { - fn from(value: (T, T)) -> Self { - let value = (value.0.as_(), value.1.as_()); - let (_min, _max) = (value.0.min(value.1), value.0.max(value.1)); - Self(_min, _max) - } -} - -impl> From> for Range { - fn from(value: std::ops::Range) -> Self { - let value = (value.start.as_(), value.end.as_()); - let (_min, _max) = (value.0.min(value.1), value.0.max(value.1)); - Self(_min, _max) - } -} - -// impl RadarData2d -// where -// T: Num + Clone + PartialEq + PartialOrd, -// Raw: ndarray::Data + Clone + ndarray::RawDataClone, -// { -// pub fn mapped(&self, coord: impl Borrow) -> Result, ProjError> { -// let mapper: &Mapper = coord.borrow(); -// self.map_by_fn(|x| mapper.map(x)) -// } - -// pub fn map_by_fn(&self, f: F) -> Result, ProjError> -// where -// F: Fn((f64, f64)) -> Result<(f64, f64), ProjError>, -// { -// let mesh_dim1_len = self.dim1.len(); -// let mesh_dim2_len = self.dim2.len(); - -// let mut d1 = Array2::::zeros((mesh_dim2_len, mesh_dim1_len)); -// let mut d2 = Array2::::zeros((mesh_dim2_len, mesh_dim1_len)); - -// for (i, v) in self.dim1.iter().enumerate() { -// for (j, u) in self.dim2.iter().enumerate() { -// let (x, y) = f((*v, *u))?; -// d1[[j, i]] = x; -// d2[[j, i]] = y; -// } -// } - -// Ok(AfterMapping2d { -// dim1: d1, -// dim2: d2, -// data: self.data.view(), -// coord_type: self.coord_type.clone(), -// }) -// } -// } diff --git a/radar-g/src/coords/proj/mercator.rs b/radar-g/src/coords/proj/mercator.rs deleted file mode 100644 index 244a3bc..0000000 --- a/radar-g/src/coords/proj/mercator.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::coords::Range; - -use super::ProjectionS; -use geo_macros::Prj; - -#[derive(Prj)] -/// A struct representing the Mercator projection. -pub struct Mercator { - /// The central longitude of the projection. - pub central_lon: f64, - /// The false easting of the projection. - pub false_easting: f64, - /// The false northing of the projection. - pub false_northing: f64, - /// The latitude of true scale of the projection. - pub latitude_true_scale: f64, -} - -fn proj_string<'a>(vs: Vec<(&'a str, &'a str)>) -> String { - vs.into_iter() - .map(|(option, value)| format!("+{}={}", option, value)) - .collect::>() - .join(" ") -} - -impl Mercator { - /// Creates a new instance of the `Mercator` projection with default values. - pub fn new( - central_lon: f64, - false_easting: f64, - false_northing: f64, - latitude_true_scale: f64, - ) -> Self { - Self { - central_lon, - false_easting, - false_northing, - latitude_true_scale, - } - } -} - -impl Default for Mercator { - fn default() -> Self { - Self { - central_lon: 0.0, - false_easting: 0.0, - false_northing: 0.0, - latitude_true_scale: 0.0, - } - } -} - -impl ProjectionS for Mercator { - fn build(&self) -> String { - let _central_lon = format!("{:.1}", &self.central_lon); - let _false_easting = format!("{:.1}", &self.false_easting); - let _false_northing = format!("{:.1}", &self.false_northing); - let _ts = format!("{:.1}", &self.latitude_true_scale); - - let input = vec![ - ("proj", "merc"), - ("lon_0", _central_lon.as_str()), - ("x_0", _false_easting.as_str()), - ("y_0", _false_northing.as_str()), - ("lat_ts", _ts.as_str()), - ("units", "m"), - ("ellps", "GRS80"), - ]; - let _proj_string = proj_string(input); - _proj_string - } -} diff --git a/radar-g/src/coords/proj/mod.rs b/radar-g/src/coords/proj/mod.rs deleted file mode 100644 index 1884278..0000000 --- a/radar-g/src/coords/proj/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -use super::{Lat, Lon, Range}; -use proj::Proj; -// use proj5; -use thiserror::Error; -mod mercator; - -pub use mercator::Mercator; - -#[derive(Debug, Clone, Copy)] -pub enum Projs { - PlateCarree, - LambertConformal, - LambertCylindrical, - Mercator, -} - -/// A trait for defining a projection. -pub trait ProjectionS { - /// Returns a proj-string of the projection. - fn build(&self) -> String; -} - -#[derive(Debug, Error)] -pub(super) enum ProjError { - #[error("proj error")] - ProjError(#[from] proj::ProjError), -} - -// pub(super) struct PCS { -// pub lon_range: Range, -// pub lat_range: Range, -// pub proj_param: T, -// // pub proj_target: proj5::CoordinateBuf, -// pub transformer: Proj, -// } - -// impl PCS { -// pub(super) fn new(proj_param: T, lon_range: Option, lat_range: Option) -> Self { -// let (lon_range, lat_range) = proj_param.logic_range(lon_range, lat_range); -// Self { -// lon_range, -// lat_range, -// transformer: Proj::new(proj_param.build().as_str()).unwrap(), -// proj_param: proj_param, -// } -// } - -// pub fn bbox(&self) -> Result<(Range, Range), ProjError> { -// let _proj_transformer = &self.transformer; -// let lb = (self.lon_range.0.to_radians(), self.lat_range.0.to_radians()); -// let rt = (self.lon_range.1.to_radians(), self.lat_range.1.to_radians()); - -// let bl = _proj_transformer.convert(lb)?; -// let rt = _proj_transformer.convert(rt)?; - -// Ok((Range::from((bl.0, rt.0)), Range::from((bl.1, rt.1)))) -// } - -// pub fn map(&self, lon_lat: (Lat, Lon)) -> (f64, f64) { -// let _proj_transformer = &self.transformer; -// let _lon_lat = _proj_transformer -// .convert((lon_lat.0.to_radians(), lon_lat.1.to_radians())) -// .unwrap(); - -// _lon_lat -// } -// } diff --git a/radar-g/src/coords/wgs84.rs b/radar-g/src/coords/wgs84.rs deleted file mode 100644 index b0d526c..0000000 --- a/radar-g/src/coords/wgs84.rs +++ /dev/null @@ -1,88 +0,0 @@ -// use super::proj::{ProjectionS, PCS}; -use super::Coord; -use super::{Lat, Lon, Range}; -use proj::ProjError; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum CoordError { - #[error("")] - ProjError { - #[from] - source: ProjError, - }, -} - -// pub struct LatLonCoord { -// actual: (Range, Range), -// logical: (Range, Range), -// pcs: PCS, -// } - -// impl LatLonCoord { -// /// Creates a new `LatLonCoord` instance. -// /// -// /// # Arguments -// /// -// /// * `lon` - An optional longitude range. -// /// * `lat` - An optional latitude range. -// /// * `actual` - A tuple containing the actual ranges. -// /// * `project` - A projection. -// /// -// /// # Returns -// /// -// /// A new `LatLonCoord` instance. -// pub fn new( -// lon: Option, -// lat: Option, -// actual: ((i32, i32), (i32, i32)), -// // actual: (Range, Range), -// project: T, -// ) -> Self { -// let pcs = PCS::new(project, lon, lat); -// let _box = pcs.bbox().unwrap(); -// Self { -// actual: (Range::from(actual.0), Range::from(actual.1)), -// pcs: pcs, -// logical: _box, -// } -// } - -// pub fn set_actual(&mut self, actual: ((i32, i32), (i32, i32))) { -// self.actual = (Range::from(actual.0), Range::from(actual.1)); -// } - -// pub fn lon_range(&self) -> Range { -// self.pcs.lon_range -// } - -// pub fn lat_range(&self) -> Range { -// self.pcs.lat_range -// } -// } - -// impl Coord for LatLonCoord { -// fn map(&self, axis_1: f64, axis_2: f64) -> super::ScreenCoord { -// let point = self.pcs.map((axis_1, axis_2)); -// let logical_dim1_span = self.logical.0 .1 - self.logical.0 .0; - -// let dim1_rate = (point.0 - self.logical.0 .0) / logical_dim1_span; -// let logical_dim2_span = self.logical.1 .1 - self.logical.1 .0; -// let dim2_rate = (point.1 - self.logical.1 .0) / logical_dim2_span; - -// ( -// (dim1_rate * (self.actual.0 .1 - self.actual.0 .0) as f64) + self.actual.0 .0, -// (dim2_rate * (self.actual.1 .1 - self.actual.1 .0) as f64) + self.actual.1 .0, -// ) -// } - -// fn dim1_range(&self) -> (f64, f64) { -// let v = self.lon_range(); -// (v.0, v.1) -// } - -// fn dim2_range(&self) -> (f64, f64) { -// let v = self.lat_range(); -// (v.0, v.1) -// } -// } diff --git a/radar-g/src/data_utils.rs b/radar-g/src/data_utils.rs deleted file mode 100644 index 6992e09..0000000 --- a/radar-g/src/data_utils.rs +++ /dev/null @@ -1,142 +0,0 @@ -use crate::pipeline::element_imp::ElementImpl::MultiLayerGrid; -use crate::pipeline::element_imp::*; -use crate::utils::*; -use crate::CONFIG; -use abi_stable::traits::IntoOwned; -use num_traits::FromPrimitive; -use radarg_plugin_interface::{CoordType, DataShape, PluginResult, PluginResultType}; -use std::any::Any; -use std::sync::Arc; - -macro_rules! dispatch { - ($block:ident,$conf:ident, $wrap:tt , $fill_value: ident, $( - { - $t:ty | $branch: pat => $v:ident - } - ),+ $(,)?) => { - match $block.data_type { - $( - $branch => { - let mut $v = $wrap::default(); - $v.color_map = $conf.drawers.$v.color_mapper.clone(); - $v.fill_value = <$t>::from_f64($fill_value).unwrap(); - Arc::new($v) as Arc - } - )+ - - _ => { panic!("") } - } - }; -} - -macro_rules! dispatch_polar { - ($block:ident,$conf:ident, $wrap:tt , $fill_value: ident, $center:ident, $( - { - $t:ty | $branch: pat => $v:ident - } - ),+ $(,)?) => { - match $block.data_type { - $( - $branch => { - let mut $v = $wrap::default(); - $v.color_map = $conf.drawers.$v.color_mapper.clone(); - $v.fill_value = <$t>::from_f64($fill_value).unwrap(); - $v.center = $center; - Arc::new($v) as Arc - } - )+ - - _ => { panic!("") } - } - }; -} - -macro_rules! dispatch_3d { - ($block:ident,$conf:ident, $wrap:tt , $fill_value: ident, $( - { - $t:ty | $branch: pat => $v:ident - } - ),+ $(,)?) => { - match $block.data_type { - $( - $branch => { - let mut $v = $wrap::default(); - $v.color_map = $conf.drawers.$v.color_mapper.clone(); - $v.fill_value = <$t>::from_f64($fill_value).unwrap(); - - let mut cfg = MultiLayerGridImpConfig{ - two_d_config: $v, - layer: 0, - }; - Arc::new(cfg) as Arc - } - )+ - - _ => { panic!("") } - } - }; -} - -macro_rules! dis { - ($mac:ident ,$block:ident, $config:ident, $wrap:tt, $fill_value: ident, $($other:ident,)?) => { - $mac!( - $block, $config, $wrap, $fill_value, $($other,)? - { i8|PluginResultType::R => reflectivity }, - { i8|PluginResultType::DBZ => reflectivity }, - { f32|PluginResultType::ZDR => differential_reflectivity }, - { f32|PluginResultType::KDP => specific_differential_phase }, - { f32|PluginResultType::PHIDP => differential_phase }, - { i8 |PluginResultType::V => velocity }, - { i8 |PluginResultType::SW => spectrum_width }, - { f32|PluginResultType::CC => correlation_coefficient }, - { i8 |PluginResultType::HCA => hydrometeor_classification }, - { f32|PluginResultType::VIL => vertically_integrated_liquid }, - { f32|PluginResultType::OHP => one_hour_precipitation }, - { f32|PluginResultType::THP => three_hour_precipitation }, - { f32|PluginResultType::ET => echo_tops }, - { f32|PluginResultType::EB => echo_bases } - ) - }; -} - -type Cfg = Arc; - -pub fn tools(data: &PluginResult) -> (ElementImpl, Cfg) { - 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(); - let fill_value = block.fill_value; - let config = CONFIG.read().unwrap(); - - let imp = match block.coord_type { - CoordType::Polar(loc, range) => { - let center = (loc.x, loc.y); - let cfg = dis!(dispatch_polar, block, config, PolarElementConfig, fill_value, center,); - (PolarElementImp().into(), cfg) - } - CoordType::Cartesian => match block.shape { - DataShape::Cube => { - let cfg = dis!(dispatch_3d, block, config, GridImpConfig, fill_value,); - (MultiLayerGridImp::new().into(), cfg) - } - DataShape::Matrix => ( - GridImp::new().into(), - dis!(dispatch, block, config, GridImpConfig, fill_value,), - ), - _ => panic!("Invalid shape"), - }, - _ => { - panic!("Invalid type") - } - }; - - imp -} diff --git a/radar-g/src/datapool/data.rs b/radar-g/src/datapool/data.rs new file mode 100644 index 0000000..4592405 --- /dev/null +++ b/radar-g/src/datapool/data.rs @@ -0,0 +1 @@ +pub struct GridData {} diff --git a/radar-g/src/datapool/mod.rs b/radar-g/src/datapool/mod.rs new file mode 100644 index 0000000..bb48a85 --- /dev/null +++ b/radar-g/src/datapool/mod.rs @@ -0,0 +1,35 @@ +pub mod data; + +use data::GridData; +use quick_cache::sync::Cache; +use std::path::PathBuf; +use std::sync::Arc; + +pub type Value = Arc; + +pub enum Data { + GridData(GridData), +} + +pub struct DataPool { + pool: Cache>, +} + +impl DataPool { + pub fn new() -> Self { + Self { + pool: Cache::new(10), + } + } + + pub fn get_or_load(&self, path: impl Into) -> Result, ()> { + self.pool.get_or_insert_async(&path.into(), async { + let path = path.into(); + let data = match path.extension().and_then(|ext| ext.to_str()) { + Some("grid") => Data::GridData(GridData::load(&path).await.unwrap()), + _ => panic!("Unsupported file type"), + }; + Ok(Arc::new(data)) + }) + } +} diff --git a/radar-g/src/main.rs b/radar-g/src/main.rs index 382a61e..1eba1e6 100644 --- a/radar-g/src/main.rs +++ b/radar-g/src/main.rs @@ -1,8 +1,6 @@ #![allow(unused)] #![allow(dead_code)] #[macro_use] -mod utils; -#[macro_use] extern crate lazy_static; use config::{Config, Settings}; use gtk::{gio, prelude::SettingsExt}; @@ -14,8 +12,8 @@ use tokio::runtime::Runtime; mod actions; mod components; mod config; -mod coords; mod data; +mod datapool; mod errors; mod pipeline; mod plugin_system; @@ -29,9 +27,6 @@ use tracing_subscriber; use gi::{App as GI, Helper, GL}; -mod data_utils; -mod map_tile; -mod map_tile_utils; mod predefined; mod widgets; diff --git a/radar-g/src/map_tile.rs b/radar-g/src/map_tile.rs deleted file mode 100644 index 8ae4bab..0000000 --- a/radar-g/src/map_tile.rs +++ /dev/null @@ -1,249 +0,0 @@ -use crate::components::messages::MonitorInputMsg; -use crate::components::{MonitorCommand, MonitorModel}; -use crate::coords::Range; -use crate::map_tile_utils::lat_lon_to_zoom; -use crate::pipeline::{Target, TargetType}; -use dirs::cache_dir; -use femtovg::ImageSource; -use futures::future::BoxFuture; -use gtk::ffi::gtk_about_dialog_add_credit_section; -use once_cell::sync::Lazy; -use quick_cache::sync::Cache; -use relm4::{ComponentSender, Sender}; -use reqwest::{Client, Error, Url}; -use slippy_map_tiles::{merc_location_to_tile_coords, BBox, Tile}; -use smallvec::SmallVec; -use sorted_vec::SortedSet; -use std::cell::{Cell, RefCell}; -use std::collections::HashSet; -use std::path::PathBuf; -use std::sync::Arc; -use tokio::sync::Mutex; -use tokio::task; -use tracing::{debug, info}; - -static TILE_CACHE_PATH: Lazy> = Lazy::new(|| { - let new_path = cache_dir() - .unwrap_or(PathBuf::from("./")) - .join("radar-g/tiles"); - - if !new_path.exists() { - info!("Create cache dir: {:?}", new_path); - std::fs::create_dir_all(&new_path).unwrap(); - } - std::sync::Mutex::new(new_path) -}); - -type TileCache = Cache>>; - -pub struct MapTile { - server: String, - api_key: String, - style: String, - client: Client, - onloading: Arc>>, - cache: Arc>, - zoom_level: Cell, -} - -impl Default for MapTile { - fn default() -> Self { - Self { - server: "https://tiles.stadiamaps.com/tiles/".to_string(), - api_key: "06f1aeed-5d91-48e3-9ce5-1e99063f7f73".to_string(), - // style: "stamen_toner".to_string(), - style: "alidade_smooth_dark".to_string(), - client: Client::new(), - onloading: Arc::new(std::sync::Mutex::new(HashSet::new())), - cache: Arc::new(std::sync::Mutex::new(Cache::new(32))), - zoom_level: Cell::new(4), - } - } -} - -impl MapTile { - pub fn new_tiles( - &self, - zoom: u8, - lat_range: (f32, f32), - lon_range: (f32, f32), - ) -> impl Iterator + Sized { - let bbox = BBox::new(lat_range.1, lon_range.0, lat_range.0, lon_range.1).unwrap(); - let tiles = bbox.tiles_for_zoom(zoom); - tiles - } - - fn get_tile_task(&self, tile: &Tile) -> (bool, BoxFuture<'static, Result, Error>>) { - let _cache_path = TILE_CACHE_PATH.lock().unwrap().clone().join(format!( - "{}-{}-{}.png", - tile.zoom(), - tile.x(), - tile.y() - )); - let exists_cache = _cache_path.exists(); - if exists_cache { - let client = self.client.clone(); - let key = self.api_key.clone(); - ( - false, - Box::pin(async move { - info!("Read from cache: {:?}", _cache_path); - let result = tokio::fs::read(_cache_path).await.unwrap(); - Ok(result) - }), - ) - } else { - let base_url = Url::parse(&self.server).unwrap(); - let mut request_url = base_url - .join(&format!("{}/", self.style)) - .unwrap() - .join(&format!("{}/{}/{}@2x.png", tile.zoom(), tile.x(), tile.y())) - .unwrap(); - let client = self.client.clone(); - let key = self.api_key.clone(); - ( - true, - Box::pin(async move { - let result = client - .get(request_url) - .query(&[("api_key", &key)]) - .send() - .await?; - let bytes = result.bytes().await?; - Ok(bytes.to_vec()) - }), - ) - } - } - pub async fn get_tile(&self, tile: &Tile) -> Result, Error> { - let base_url = Url::parse(&self.server).unwrap(); - let mut request_url = base_url - .join(&self.style) - .unwrap() - .join(&format!("{}/{}/{}@2x.png", tile.zoom(), tile.x(), tile.y())) - .unwrap(); - - let result = self - .client - .get(request_url) - .query(&[("api_key", &self.api_key)]) - .send() - .await?; - let bytes = result.bytes().await?; - Ok(bytes.to_vec()) - } - - pub fn set_zoom(&self, zoom: u8) { - self.zoom_level.set(zoom); - } - - fn insert_to_cache(cache: Arc>, result: Vec, tile: Tile) { - let origin = tile.nw_corner(); - let rb = tile.se_corner(); - let bounds = ( - (origin.lon() as f64..rb.lon() as f64).into(), - (origin.lat() as f64..rb.lat() as f64).into(), - ); - let result = Target::new(TargetType::Mem(result), 256.0, 256.0, bounds, None); - let cache = cache.lock().unwrap(); - cache.insert(tile, Arc::new(std::sync::Mutex::new(result))); - } - - async fn save_to_cache_path(result: &Vec, tile: Tile) -> Result<(), std::io::Error> { - let _cache_path = TILE_CACHE_PATH.lock().unwrap().clone(); - let path = _cache_path.join(format!("{}-{}-{}.png", tile.zoom(), tile.x(), tile.y())); - tokio::fs::write(path, result).await - } - - pub fn load_tiles( - &self, - range: ((f32, f32), (f32, f32)), - sender: ComponentSender, - ) -> BoxFuture<'static, ()> { - let zoom = self.zoom_level.get(); - let new_tiles = self.new_tiles(zoom, range.0, range.1); - let cache = (*self.cache).lock().unwrap(); - let mut bindings = self.onloading.lock().unwrap(); - let new_tiles = new_tiles - .filter(|x| cache.peek(x).is_none() && !bindings.contains(x)) - .collect::>(); - - if new_tiles.len() > 0 { - bindings.extend(new_tiles.iter().cloned()); - info!("Load new tiles"); - let tasks = new_tiles - .into_iter() - .map(move |tile| { - let (need_save, _task) = self.get_tile_task(&tile); - let sender = sender.clone(); - let cache = self.cache.clone(); - let onloading = self.onloading.clone(); - task::spawn(async move { - let result = _task.await; - if let Ok(result) = result { - if let Err(e) = Self::save_to_cache_path(&result, tile).await { - info!("Error saving to cache: {}", e); - } - if need_save { - Self::save_to_cache_path(&result, tile); - } - Self::insert_to_cache(cache, result, tile); - onloading.lock().unwrap().remove(&tile); - sender.command_sender().emit(MonitorCommand::LoadedTile); - } - }) - }) - .collect::>(); - return Box::pin(async move { - for task in tasks { - task.await.unwrap(); - } - }); - } else { - info!("No new tiles need to download"); - return Box::pin(async move { - sender.command_sender().emit(MonitorCommand::LoadedTile); - }); - } - } - - pub fn current_tiles( - &self, - range: ((f32, f32), (f32, f32)), - ) -> Vec>> { - let zoom = self.zoom_level.get(); - let current = self.new_tiles(zoom, range.0, range.1); - let mut total_len = 0; - let mut results = Vec::new(); - let mut cached = Vec::new(); - let cache = self.cache.lock().unwrap(); - for tile in current { - total_len += 1; - if let Some(target) = cache.get(&tile) { - results.push(target); - } else { - let center = tile.center_point(); - let mut start_zoom = zoom - 1; - while start_zoom > 0 { - let (tile, (x, y)) = merc_location_to_tile_coords( - center.lon() as f64, - center.lat() as f64, - start_zoom, - ); - let tile = Tile::new(start_zoom, tile.0, tile.1).unwrap(); - if cached.contains(&tile) { - break; - } else { - if let Some(target) = cache.get(&tile) { - results.insert(0, target); - cached.push(tile); - break; - } - } - start_zoom -= 1; - } - } - } - results - } -} diff --git a/radar-g/src/map_tile_utils.rs b/radar-g/src/map_tile_utils.rs deleted file mode 100644 index 3288f3b..0000000 --- a/radar-g/src/map_tile_utils.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub fn lat_lon_to_zoom(lat_range: (f64, f64), lon_range: (f64, f64), w: f32, h: f32) -> u8 { - let lat_diff = lat_range.1 - lat_range.0; - let lon_diff = lon_range.1 - lon_range.0; - let z1 = ((360.0 * w) as f64 / lon_diff / 256.0).log2(); - let z2 = ((180.0 * h) as f64 / lat_diff / 256.0).log2(); - let z = z1.min(z2); - z as u8 -} diff --git a/radar-g/src/utils.rs b/radar-g/src/utils.rs deleted file mode 100644 index 2eb02dc..0000000 --- a/radar-g/src/utils.rs +++ /dev/null @@ -1,604 +0,0 @@ -use chrono::{DateTime, Utc}; -use euclid::Size2D; -use femtovg::Canvas; -use femtovg::Color; -use gtk::glib::{HasParamSpec, ParamSpecInt64, ParamSpecInt64Builder}; -use ndarray::{Array2, ArrayView1}; -use std::{borrow::BorrowMut, num::NonZeroU32}; -use surfman::{ - Connection, Context, ContextAttributeFlags, ContextAttributes, ContextDescriptor, Device, - GLVersion, NativeConnection, NativeContext, SurfaceAccess, SurfaceType, -}; - -use crate::predefined::color_mapper::{BoundaryNorm, BoundaryNormDiscrete, Discrete}; -use crate::RUNTIME; -use std::sync::Arc; -use std::time::Duration; -use tokio::{ - sync::{mpsc, oneshot, Mutex}, - time, -}; - -pub fn meshgrid(x: ArrayView1, y: ArrayView1) -> (Array2, Array2) -where - T: Clone, -{ - let shape = (y.len(), x.len()); - println!("shape: {:?}", shape); - let xx = Array2::from_shape_fn(shape, |(_, j)| x[j].clone()); - let yy = Array2::from_shape_fn(shape, |(i, _)| y[i].clone()); - (xx, yy) -} - -macro_rules! default_cvmapers { - ($({ - $key: ident, $value: expr, $colors: expr, $_ty:ty - }),+ $(,)?) => { - $( - pub fn $key() -> BoundaryNormDiscrete<$_ty> { - let discrete = Discrete::new($colors); - let boundarynorm = BoundaryNorm::new($value, true, None); - BoundaryNormDiscrete::new(discrete, boundarynorm) - } - )+ - }; -} - -default_cvmapers! { - { - create_reflect_default_cvmapper, - 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), - ], - i8 - }, - - { - create_vel_default_cvmapper, - vec![ - -35, -27, -20, -15, -10, -5, -1, 0, 1, 5, 10, 15, 20, 27, - 35, - ], - 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), - ], - i8 - }, - { - create_phidp_default_cvmapper, - 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), - ], - f32 - }, - { - create_zdr_default_cvmapper, - 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), - ], - f32 - }, - { - create_cc_default_cvmapper, - 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), - ], - f32 - }, - { - create_vil_default_cvmapper, - 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), - ], - f32 - }, - { - create_hgt_default_cvmapper, - 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), - ], - f32 - }, - { - create_et_default_cvmapper, - 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), - ], - f32 - }, - { - create_cpc_default_cvmapper, - 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), - ], - i8 - }, - { - create_kdp_default_cvmapper, - 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), - ], - f32 - } -} - -// pub fn create_dbz_boundarynorm() -> BoundaryNorm { -// -// // Discrete::new() -// -// // BoundaryNorm::new() -// -// BoundaryNormDiscrete::new( -// -// ) -// 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_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_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_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_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 estimate_zoom_level( - lat_min: f64, - lon_min: f64, - lat_max: f64, - lon_max: f64, - screen_width: f64, - screen_height: f64, -) -> u8 { - let r: f64 = 6371.0; - let avg_lat = (lat_min + lat_max) / 2.0; - // 将经纬度范围转换为在该纬度下的公里数 - let delta_lon = (lon_max - lon_min) - * (r * std::f64::consts::PI / 180.0) - * (avg_lat * std::f64::consts::PI / 180.0).cos().abs(); - let delta_lat = (lat_max - lat_min) * 111.32; - - // 估算每个像素代表的实际距离(公里/像素) - let km_per_pixel_x = delta_lon / screen_width; - let km_per_pixel_y = delta_lat / screen_height; - - // 选择较小的比例尺 - let km_per_pixel = km_per_pixel_x.min(km_per_pixel_y); - - // 根据比例尺估算Zoom Level - // 这里的比例尺和Zoom Level的对应关系可能需要根据实际地图服务进行调整 - let zoom_level_estimation = 14.0 - km_per_pixel.log10(); - - zoom_level_estimation.round() as u8 -} - -pub fn parse_hex_color(hex: &str) -> Result<(u8, u8, u8), &'static str> { - if hex.starts_with('#') && hex.len() == 7 { - let r = u8::from_str_radix(&hex[1..3], 16); - let g = u8::from_str_radix(&hex[3..5], 16); - let b = u8::from_str_radix(&hex[5..7], 16); - - match (r, g, b) { - (Ok(r), Ok(g), Ok(b)) => Ok((r, g, b)), - _ => Err("Invalid hexadecimal value"), - } - } else { - Err("Invalid color format") - } -}