sync
This commit is contained in:
parent
77d8c1f0eb
commit
58947b9aa1
@ -8,11 +8,6 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::components::sidebar::{SideBarInputMsg, SideBarModel};
|
use crate::components::sidebar::{SideBarInputMsg, SideBarModel};
|
||||||
use crate::data_utils::tools;
|
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::pipeline::{KVBuffer, OffscreenRenderer};
|
||||||
use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete};
|
use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete};
|
||||||
use crate::predefined::widgets::ColorBar;
|
use crate::predefined::widgets::ColorBar;
|
||||||
@ -82,10 +77,10 @@ pub enum AppMsg {
|
|||||||
CloseRequest,
|
CloseRequest,
|
||||||
Close,
|
Close,
|
||||||
OpenDialog,
|
OpenDialog,
|
||||||
LayerManager(LayerMsg),
|
// LayerManager(LayerMsg),
|
||||||
Layer,
|
// Layer,
|
||||||
NewElement(Rc<RefCell<Element>>),
|
// NewElement(Rc<RefCell<Element>>),
|
||||||
DeleteElement(ElementKey),
|
// DeleteElement(ElementKey),
|
||||||
}
|
}
|
||||||
type RcDispatcher = Rc<Dispatcher>;
|
type RcDispatcher = Rc<Dispatcher>;
|
||||||
type ArcDispatcher = Arc<Dispatcher>;
|
type ArcDispatcher = Arc<Dispatcher>;
|
||||||
@ -96,6 +91,8 @@ pub struct AppModel {
|
|||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
cms: CMS,
|
cms: CMS,
|
||||||
waiting_for: Option<DateTime<Utc>>,
|
waiting_for: Option<DateTime<Utc>>,
|
||||||
|
|
||||||
|
// Components
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
open_dialog: Controller<OpenDialog>,
|
open_dialog: Controller<OpenDialog>,
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
@ -104,15 +101,19 @@ pub struct AppModel {
|
|||||||
render: Controller<MonitorModel>,
|
render: Controller<MonitorModel>,
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
sidebar: Controller<SideBarModel>,
|
sidebar: Controller<SideBarModel>,
|
||||||
|
|
||||||
|
// Data
|
||||||
selected_layer: Vec<usize>,
|
selected_layer: Vec<usize>,
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
layers: Rc<RefCell<Vec<Layer>>>,
|
layers: Rc<RefCell<Vec<Layer>>>,
|
||||||
#[do_not_track]
|
// #[do_not_track]
|
||||||
buffer: Arc<Buffer<Key>>,
|
// buffer: Arc<Buffer<Key>>,
|
||||||
|
|
||||||
|
// File Pool
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
file_pool: Arc<KVBuffer<PathBuf, Arc<PluginResult>>>,
|
file_pool: Arc<KVBuffer<PathBuf, Arc<PluginResult>>>,
|
||||||
#[do_not_track]
|
// #[do_not_track]
|
||||||
elements: Vec<Rc<RefCell<Element>>>,
|
// elements: Vec<Rc<RefCell<Element>>>,
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
setting: Controller<SettingModel>,
|
setting: Controller<SettingModel>,
|
||||||
}
|
}
|
||||||
@ -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 file_pool = Arc::new(KVBuffer::new(20));
|
||||||
|
|
||||||
let sidebar =
|
// SideBar Component
|
||||||
SideBarModel::builder()
|
// let sidebar =
|
||||||
.launch(layers.clone())
|
// SideBarModel::builder()
|
||||||
.forward(sender.input_sender(), |msg| {
|
// .launch(layers.clone())
|
||||||
AppMsg::LayerManager(match msg {
|
// .forward(sender.input_sender(), |msg| {
|
||||||
SideBarOutputMsg::SelectLayer(idx) => LayerMsg::Select(idx),
|
// AppMsg::LayerManager(match msg {
|
||||||
SideBarOutputMsg::NewLayer(layer) => LayerMsg::Add(layer),
|
// SideBarOutputMsg::SelectLayer(idx) => LayerMsg::Select(idx),
|
||||||
SideBarOutputMsg::SwitchToTimeSeries(idx) => LayerMsg::SwitchToTime(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,
|
|
||||||
});
|
|
||||||
|
|
||||||
let setting = SettingModel::builder()
|
// // Monitor Component
|
||||||
.launch(())
|
// let render =
|
||||||
.forward(sender.input_sender(), |a| AppMsg::Close);
|
// 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 setting = SettingModel::builder()
|
||||||
let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
// .launch(())
|
||||||
let dialog_buffer = buffer.clone();
|
// .forward(sender.input_sender(), |a| AppMsg::Close);
|
||||||
let dialog_cms = cms.clone();
|
|
||||||
|
|
||||||
let dialog = {
|
// // Background Dispatcher
|
||||||
let dialog_dispatcher = dispatcher.clone();
|
// let mut dispatcher = Arc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1)));
|
||||||
let dialog_sidebar_sender = sidebar.sender().clone();
|
// let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
||||||
let dialog_render_sender = render.sender().clone();
|
// let dialog_buffer = buffer.clone();
|
||||||
let dialog_file_pool = file_pool.clone();
|
// let dialog_cms = cms.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));
|
|
||||||
|
|
||||||
let element = Rc::new(RefCell::new(Element::new(
|
// // File Dialog
|
||||||
"CR",
|
// let dialog = {
|
||||||
dialog_cms.clone(),
|
// let dialog_dispatcher = dispatcher.clone();
|
||||||
dialog_dispatcher.clone(),
|
// let dialog_sidebar_sender = sidebar.sender().clone();
|
||||||
true,
|
// let dialog_render_sender = render.sender().clone();
|
||||||
cfg,
|
// let dialog_file_pool = file_pool.clone();
|
||||||
path.clone(),
|
// OpenDialog::builder()
|
||||||
dialog_buffer.clone(),
|
// .transient_for_native(&root)
|
||||||
dialog_file_pool.clone(),
|
// .launch(OpenDialogSettings::default())
|
||||||
imp,
|
// .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()));
|
// let element = Rc::new(RefCell::new(Element::new(
|
||||||
dialog_render_sender.emit(MonitorInputMsg::SetRenderRange(
|
// "CR",
|
||||||
lon_start, lon_end, lat_start, lat_end,
|
// dialog_cms.clone(),
|
||||||
));
|
// dialog_dispatcher.clone(),
|
||||||
|
// true,
|
||||||
|
// cfg,
|
||||||
|
// path.clone(),
|
||||||
|
// dialog_buffer.clone(),
|
||||||
|
// dialog_file_pool.clone(),
|
||||||
|
// imp,
|
||||||
|
// )));
|
||||||
|
|
||||||
AppMsg::NewElement(element)
|
// dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map()));
|
||||||
}
|
// dialog_render_sender.emit(MonitorInputMsg::SetRenderRange(
|
||||||
_ => AppMsg::Close,
|
// lon_start, lon_end, lat_start, lat_end,
|
||||||
})
|
// ));
|
||||||
};
|
|
||||||
|
// AppMsg::NewElement(element)
|
||||||
|
// }
|
||||||
|
// _ => AppMsg::Close,
|
||||||
|
// })
|
||||||
|
// };
|
||||||
|
|
||||||
let model = AppModel {
|
let model = AppModel {
|
||||||
cms,
|
// cms,
|
||||||
dispatcher,
|
// dispatcher,
|
||||||
waiting_for: None,
|
waiting_for: None,
|
||||||
buffer,
|
// buffer,
|
||||||
file_pool,
|
file_pool,
|
||||||
open_dialog: dialog,
|
// open_dialog: dialog,
|
||||||
selected_layer: vec![],
|
selected_layer: vec![],
|
||||||
sidebar,
|
// sidebar,
|
||||||
elements: vec![],
|
// elements: vec![],
|
||||||
control,
|
control,
|
||||||
render,
|
render,
|
||||||
layers,
|
layers,
|
||||||
|
|||||||
@ -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<f64>) {
|
|
||||||
self.mapper.set_lat_range(lat_range);
|
|
||||||
self.bounds = self.mapper.get_bounds()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_lon_range(&mut self, lon_range: Range<f64>) {
|
|
||||||
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<LineString<f32>> {
|
|
||||||
Some(
|
|
||||||
line.points()
|
|
||||||
.into_iter()
|
|
||||||
.map(|p| self.map((p.x(), p.y())).unwrap())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<Proj> 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<C: ProjectionS> From<C> 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<f64>,
|
|
||||||
lat_range: std::ops::Range<f64>,
|
|
||||||
) -> 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<f64>) -> &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<f64>) -> &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<LineString, ProjError> {
|
|
||||||
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<GCoord> = 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<LineString, ProjError> {
|
|
||||||
let result: Result<LineString, ProjError> =
|
|
||||||
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<F>(
|
|
||||||
&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<GCoord>,
|
|
||||||
) -> 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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<T: Num> {
|
|
||||||
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<f64> {
|
|
||||||
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<T: AsPrimitive<f64> + 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<T: Num + AsPrimitive<f64>> From<std::ops::Range<T>> for Range {
|
|
||||||
fn from(value: std::ops::Range<T>) -> 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<T, Raw> RadarData2d<T, Raw>
|
|
||||||
// where
|
|
||||||
// T: Num + Clone + PartialEq + PartialOrd,
|
|
||||||
// Raw: ndarray::Data<Elem = T> + Clone + ndarray::RawDataClone,
|
|
||||||
// {
|
|
||||||
// pub fn mapped(&self, coord: impl Borrow<Mapper>) -> Result<AfterMapping2d<T>, ProjError> {
|
|
||||||
// let mapper: &Mapper = coord.borrow();
|
|
||||||
// self.map_by_fn(|x| mapper.map(x))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn map_by_fn<F>(&self, f: F) -> Result<AfterMapping2d<T>, 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::<f64>::zeros((mesh_dim2_len, mesh_dim1_len));
|
|
||||||
// let mut d2 = Array2::<f64>::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(),
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@ -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::<Vec<String>>()
|
|
||||||
.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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<T: ProjectionS> {
|
|
||||||
// pub lon_range: Range,
|
|
||||||
// pub lat_range: Range,
|
|
||||||
// pub proj_param: T,
|
|
||||||
// // pub proj_target: proj5::CoordinateBuf,
|
|
||||||
// pub transformer: Proj,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<T: ProjectionS> PCS<T> {
|
|
||||||
// pub(super) fn new(proj_param: T, lon_range: Option<Range>, lat_range: Option<Range>) -> 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
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@ -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<T: ProjectionS> {
|
|
||||||
// actual: (Range, Range),
|
|
||||||
// logical: (Range, Range),
|
|
||||||
// pcs: PCS<T>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<T: ProjectionS> LatLonCoord<T> {
|
|
||||||
// /// 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<Range>,
|
|
||||||
// lat: Option<Range>,
|
|
||||||
// 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<T: ProjectionS> Coord<f64> for LatLonCoord<T> {
|
|
||||||
// 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)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@ -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<dyn Any + Send + Sync>
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
|
|
||||||
_ => { 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<dyn Any + Send + Sync>
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
|
|
||||||
_ => { 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<dyn Any + Send + Sync>
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
|
|
||||||
_ => { 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<dyn Any + Send + Sync>;
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
1
radar-g/src/datapool/data.rs
Normal file
1
radar-g/src/datapool/data.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub struct GridData {}
|
||||||
35
radar-g/src/datapool/mod.rs
Normal file
35
radar-g/src/datapool/mod.rs
Normal file
@ -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<T> = Arc<T>;
|
||||||
|
|
||||||
|
pub enum Data {
|
||||||
|
GridData(GridData),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DataPool {
|
||||||
|
pool: Cache<PathBuf, Value<Data>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataPool {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
pool: Cache::new(10),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_or_load(&self, path: impl Into<PathBuf>) -> Result<Value<Data>, ()> {
|
||||||
|
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))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,6 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod utils;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
use config::{Config, Settings};
|
use config::{Config, Settings};
|
||||||
use gtk::{gio, prelude::SettingsExt};
|
use gtk::{gio, prelude::SettingsExt};
|
||||||
@ -14,8 +12,8 @@ use tokio::runtime::Runtime;
|
|||||||
mod actions;
|
mod actions;
|
||||||
mod components;
|
mod components;
|
||||||
mod config;
|
mod config;
|
||||||
mod coords;
|
|
||||||
mod data;
|
mod data;
|
||||||
|
mod datapool;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
mod plugin_system;
|
mod plugin_system;
|
||||||
@ -29,9 +27,6 @@ use tracing_subscriber;
|
|||||||
|
|
||||||
use gi::{App as GI, Helper, GL};
|
use gi::{App as GI, Helper, GL};
|
||||||
|
|
||||||
mod data_utils;
|
|
||||||
mod map_tile;
|
|
||||||
mod map_tile_utils;
|
|
||||||
mod predefined;
|
mod predefined;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
||||||
|
|||||||
@ -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<std::sync::Mutex<PathBuf>> = 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<Tile, Arc<std::sync::Mutex<Target>>>;
|
|
||||||
|
|
||||||
pub struct MapTile {
|
|
||||||
server: String,
|
|
||||||
api_key: String,
|
|
||||||
style: String,
|
|
||||||
client: Client,
|
|
||||||
onloading: Arc<std::sync::Mutex<HashSet<Tile>>>,
|
|
||||||
cache: Arc<std::sync::Mutex<TileCache>>,
|
|
||||||
zoom_level: Cell<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<Item = Tile> + 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<Vec<u8>, 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<Vec<u8>, 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<std::sync::Mutex<TileCache>>, result: Vec<u8>, 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<u8>, 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<MonitorModel>,
|
|
||||||
) -> 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::<Vec<_>>();
|
|
||||||
|
|
||||||
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::<Vec<_>>();
|
|
||||||
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<Arc<std::sync::Mutex<Target>>> {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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
|
|
||||||
}
|
|
||||||
@ -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<T>(x: ArrayView1<T>, y: ArrayView1<T>) -> (Array2<T>, Array2<T>)
|
|
||||||
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<i8> {
|
|
||||||
//
|
|
||||||
// // 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<f32> {
|
|
||||||
// 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<f32> {
|
|
||||||
// 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<f32> {
|
|
||||||
// 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<f32> {
|
|
||||||
// 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<f32> {
|
|
||||||
// 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<f32> {
|
|
||||||
// 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<f32> {
|
|
||||||
// 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<i8> {
|
|
||||||
// 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<f32> {
|
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user