Compare commits
No commits in common. "rebuild" and "master" have entirely different histories.
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -529,7 +529,6 @@ dependencies = [
|
|||||||
"core_extensions",
|
"core_extensions",
|
||||||
"crossbeam",
|
"crossbeam",
|
||||||
"dirs",
|
"dirs",
|
||||||
"enum_dispatch",
|
|
||||||
"epoxy",
|
"epoxy",
|
||||||
"euclid",
|
"euclid",
|
||||||
"femtovg",
|
"femtovg",
|
||||||
@ -987,7 +986,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.8.3",
|
"libloading 0.7.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1033,18 +1032,6 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "enum_dispatch"
|
|
||||||
version = "0.3.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8f33313078bb8d4d05a2733a94ac4c2d8a0df9a2b84424ebf4f33bfc224a890e"
|
|
||||||
dependencies = [
|
|
||||||
"once_cell",
|
|
||||||
"proc-macro2 1.0.76",
|
|
||||||
"quote 1.0.35",
|
|
||||||
"syn 2.0.48",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_logger"
|
name = "env_logger"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
|
|||||||
@ -72,7 +72,6 @@ reqwest = "0.11.25"
|
|||||||
url = "2.5.0"
|
url = "2.5.0"
|
||||||
quick_cache = "0.4.1"
|
quick_cache = "0.4.1"
|
||||||
fns = "0.0.7"
|
fns = "0.0.7"
|
||||||
enum_dispatch = "0.3.12"
|
|
||||||
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
|
|||||||
@ -7,7 +7,7 @@ use relm4::actions::{AccelsPlus, ActionablePlus, RelmAction, RelmActionGroup};
|
|||||||
use relm4::{ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent};
|
use relm4::{ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent};
|
||||||
|
|
||||||
use crate::components::app::{AppModel, AppMsg, LayerMsg};
|
use crate::components::app::{AppModel, AppMsg, LayerMsg};
|
||||||
use crate::widgets::Layer;
|
use crate::widgets::{AssoElement, Layer};
|
||||||
|
|
||||||
relm4::new_action_group!(pub LayerActionGroup, "layer");
|
relm4::new_action_group!(pub LayerActionGroup, "layer");
|
||||||
relm4::new_stateless_action!(pub AddLayerAction, LayerActionGroup, "add");
|
relm4::new_stateless_action!(pub AddLayerAction, LayerActionGroup, "add");
|
||||||
@ -15,12 +15,24 @@ relm4::new_stateless_action!(pub RemoveLayerAction, LayerActionGroup, "remove");
|
|||||||
relm4::new_stateless_action!(pub MoveLayerAction, LayerActionGroup, "move");
|
relm4::new_stateless_action!(pub MoveLayerAction, LayerActionGroup, "move");
|
||||||
|
|
||||||
pub fn register_layer_actions<W: AsRef<gtk::Widget>>(widget: W, sender: ComponentSender<AppModel>) {
|
pub fn register_layer_actions<W: AsRef<gtk::Widget>>(widget: W, sender: ComponentSender<AppModel>) {
|
||||||
|
let add_action: RelmAction<AddLayerAction> = {
|
||||||
|
let sender = sender.clone();
|
||||||
|
RelmAction::new_stateless(move |_| {
|
||||||
|
sender.input(AppMsg::LayerManager(LayerMsg::Add(Layer::new(
|
||||||
|
true,
|
||||||
|
"Test".to_string(),
|
||||||
|
AssoElement::Test,
|
||||||
|
))))
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let remove_action: RelmAction<RemoveLayerAction> = {
|
let remove_action: RelmAction<RemoveLayerAction> = {
|
||||||
let sender = sender.clone();
|
let sender = sender.clone();
|
||||||
RelmAction::new_stateless(move |_| sender.input(AppMsg::LayerManager(LayerMsg::Remove(0))))
|
RelmAction::new_stateless(move |_| sender.input(AppMsg::LayerManager(LayerMsg::Remove(0))))
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut group: RelmActionGroup<LayerActionGroup> = RelmActionGroup::new();
|
let mut group: RelmActionGroup<LayerActionGroup> = RelmActionGroup::new();
|
||||||
|
group.add_action(add_action);
|
||||||
group.add_action(remove_action);
|
group.add_action(remove_action);
|
||||||
group.register_for_widget(widget)
|
group.register_for_widget(widget)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,17 +7,13 @@ use super::{
|
|||||||
ControlPanelOutputMsg, TimelineMsg,
|
ControlPanelOutputMsg, TimelineMsg,
|
||||||
};
|
};
|
||||||
use crate::components::sidebar::{SideBarInputMsg, SideBarModel};
|
use crate::components::sidebar::{SideBarInputMsg, SideBarModel};
|
||||||
use crate::data_utils::tools;
|
use crate::pipeline::{GridElementImpl, OffscreenRenderer};
|
||||||
use crate::pipeline::element_imp::{Context, ElementInput, GridImpConfig};
|
|
||||||
use crate::pipeline::new_element::Buffer;
|
|
||||||
use crate::pipeline::new_element::Element;
|
|
||||||
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;
|
use crate::predefined::widgets::ColorBar;
|
||||||
use crate::utils::meshgrid;
|
use crate::widgets::{AssoElement, DynamicCol};
|
||||||
use crate::widgets::{DynamicCol, ElementType};
|
use crate::{
|
||||||
|
actions::register_layer_actions,
|
||||||
|
pipeline::element::{Element, InstantElement, InstantElementDrawerType, TimeSeriesElement},
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
coords::{
|
coords::{
|
||||||
cms::CMS,
|
cms::CMS,
|
||||||
@ -26,20 +22,20 @@ use crate::{
|
|||||||
},
|
},
|
||||||
data::MetaInfo,
|
data::MetaInfo,
|
||||||
errors::RenderError,
|
errors::RenderError,
|
||||||
pipeline::{Dispatcher, RenderResult},
|
pipeline::{utils::data_to_element, Dispatcher, Pipeline, RenderResult},
|
||||||
plugin_system::init_plugin,
|
plugin_system::init_plugin,
|
||||||
widgets::render::Layer,
|
widgets::render::Layer,
|
||||||
CONFIG, PLUGIN_MANAGER,
|
CONFIG, PLUGIN_MANAGER,
|
||||||
};
|
};
|
||||||
|
use crate::{data_utils::plugin_result_impl, pipeline::element::DataTarget};
|
||||||
use abi_stable::std_types::RStr;
|
use abi_stable::std_types::RStr;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
use gtk::glib::clone;
|
use gtk::glib::clone;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use ndarray::{ArrayView1, ArrayViewD};
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use radarg_plugin_interface::{PluginResult, VecResult};
|
use radarg_plugin_interface::PluginResult;
|
||||||
use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup};
|
use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup};
|
||||||
use relm4::*;
|
use relm4::*;
|
||||||
use relm4::{gtk, Component, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent};
|
use relm4::{gtk, Component, ComponentParts, ComponentSender, RelmWidgetExt, SimpleComponent};
|
||||||
@ -83,15 +79,15 @@ pub enum AppMsg {
|
|||||||
OpenDialog,
|
OpenDialog,
|
||||||
LayerManager(LayerMsg),
|
LayerManager(LayerMsg),
|
||||||
Layer,
|
Layer,
|
||||||
NewElement(Rc<RefCell<Element>>),
|
NewElement(Element),
|
||||||
DeleteElement(ElementKey),
|
DeleteElement(ElementKey),
|
||||||
}
|
}
|
||||||
|
pub type Buffer = Rc<RefCell<HashMap<String, BTreeMap<DateTime<Utc>, Option<RenderResult>>>>>;
|
||||||
type RcDispatcher = Rc<Dispatcher>;
|
type RcDispatcher = Rc<Dispatcher>;
|
||||||
type ArcDispatcher = Arc<Dispatcher>;
|
|
||||||
#[tracker::track]
|
#[tracker::track]
|
||||||
pub struct AppModel {
|
pub struct AppModel {
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
dispatcher: ArcDispatcher,
|
dispatcher: RcDispatcher,
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
cms: CMS,
|
cms: CMS,
|
||||||
waiting_for: Option<DateTime<Utc>>,
|
waiting_for: Option<DateTime<Utc>>,
|
||||||
@ -107,11 +103,7 @@ pub struct AppModel {
|
|||||||
#[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>>,
|
elements: Vec<Arc<Mutex<TimeSeriesElement>>>,
|
||||||
#[do_not_track]
|
|
||||||
file_pool: Arc<KVBuffer<PathBuf, Arc<PluginResult>>>,
|
|
||||||
#[do_not_track]
|
|
||||||
elements: Vec<Rc<RefCell<Element>>>,
|
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
setting: Controller<SettingModel>,
|
setting: Controller<SettingModel>,
|
||||||
}
|
}
|
||||||
@ -189,12 +181,12 @@ impl Component for AppModel {
|
|||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
#[name="paned"]
|
#[name="paned"]
|
||||||
set_child_paned = >k::Paned{
|
set_child_paned = >k::Paned{
|
||||||
#[local_ref]
|
#[local_ref]
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_start_child=render->gtk::Frame{},
|
set_start_child=render->gtk::Frame{},
|
||||||
#[local_ref]
|
#[local_ref]
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_end_child=sidebar->gtk::Box{},
|
set_end_child=sidebar->gtk::Box{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -230,7 +222,10 @@ impl Component for AppModel {
|
|||||||
root: Self::Root,
|
root: Self::Root,
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
let layers = Rc::new(RefCell::new(vec![]));
|
let layers = Rc::new(RefCell::new(vec![
|
||||||
|
Layer::new(true, "Layer 1".to_string(), AssoElement::Test),
|
||||||
|
Layer::new(true, "Layer 2".to_string(), AssoElement::Test),
|
||||||
|
]));
|
||||||
let control = ControlPanelModel::builder().launch(layers.clone()).forward(
|
let control = ControlPanelModel::builder().launch(layers.clone()).forward(
|
||||||
sender.input_sender(),
|
sender.input_sender(),
|
||||||
|msg| match msg {
|
|msg| match msg {
|
||||||
@ -238,9 +233,6 @@ impl Component for AppModel {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let buffer = Arc::new(Buffer::new(100));
|
|
||||||
let file_pool = Arc::new(KVBuffer::new(20));
|
|
||||||
|
|
||||||
let sidebar =
|
let sidebar =
|
||||||
SideBarModel::builder()
|
SideBarModel::builder()
|
||||||
.launch(layers.clone())
|
.launch(layers.clone())
|
||||||
@ -263,62 +255,60 @@ impl Component for AppModel {
|
|||||||
.launch(())
|
.launch(())
|
||||||
.forward(sender.input_sender(), |a| AppMsg::Close);
|
.forward(sender.input_sender(), |a| AppMsg::Close);
|
||||||
|
|
||||||
let mut dispatcher = Arc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1)));
|
let mut dispatcher = Rc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1)));
|
||||||
let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
||||||
let dialog_buffer = buffer.clone();
|
|
||||||
let dialog_cms = cms.clone();
|
|
||||||
|
|
||||||
let dialog = {
|
let dialog = {
|
||||||
let dialog_dispatcher = dispatcher.clone();
|
let dialog_dispatcher = dispatcher.clone();
|
||||||
let dialog_sidebar_sender = sidebar.sender().clone();
|
let dialog_sidebar_sender = sidebar.sender().clone();
|
||||||
let dialog_render_sender = render.sender().clone();
|
let dialog_render_sender = render.sender().clone();
|
||||||
let dialog_file_pool = file_pool.clone();
|
|
||||||
OpenDialog::builder()
|
OpenDialog::builder()
|
||||||
.transient_for_native(&root)
|
.transient_for_native(&root)
|
||||||
.launch(OpenDialogSettings::default())
|
.launch(OpenDialogSettings::default())
|
||||||
.forward(sender.input_sender(), move |response| match response {
|
.forward(sender.input_sender(), move |response| match response {
|
||||||
OpenDialogResponse::Accept(path) => {
|
OpenDialogResponse::Accept(path) => {
|
||||||
*FILE_PATH_ROOT.lock().unwrap() = path.clone();
|
*FILE_PATH_ROOT.lock().unwrap() = path.clone();
|
||||||
let data = Self::open_file_only(path.clone());
|
let data = Self::open_file_only(path);
|
||||||
let meta: MetaInfo = (&data.meta).clone().into();
|
let meta: MetaInfo = (&data.meta).clone().into();
|
||||||
let (lat_start, lat_end) = meta.lat_range.unwrap();
|
let (lat_start, lat_end) = meta.lat_range.unwrap();
|
||||||
let (lon_start, lon_end) = meta.lon_range.unwrap();
|
let (lon_start, lon_end) = meta.lon_range.unwrap();
|
||||||
let (imp, cfg) = tools(&data);
|
let element_impl = plugin_result_impl(&data);
|
||||||
dialog_file_pool.insert(path.clone(), Arc::new(data));
|
let mut renderer = OffscreenRenderer::new(3000, 3000).unwrap();
|
||||||
|
let mut canvas = renderer.create_canvas();
|
||||||
let element = Rc::new(RefCell::new(Element::new(
|
let mut dialog_cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
||||||
"CR",
|
let data_target = element_impl.render(&data, &mut canvas, &mut dialog_cms);
|
||||||
dialog_cms.clone(),
|
let data_target = DataTarget::new(Some(data), data_target);
|
||||||
|
let element = Element::create_instant(
|
||||||
|
InstantElementDrawerType::Prepared((data_target, element_impl)),
|
||||||
dialog_dispatcher.clone(),
|
dialog_dispatcher.clone(),
|
||||||
false,
|
"ET".to_string(),
|
||||||
cfg,
|
)
|
||||||
path.clone(),
|
.get_instance();
|
||||||
dialog_buffer.clone(),
|
let layer = Layer::new(
|
||||||
dialog_file_pool.clone(),
|
true,
|
||||||
imp,
|
"New Layer".to_string(),
|
||||||
)));
|
AssoElement::Instant(element),
|
||||||
|
);
|
||||||
dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map()));
|
dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map()));
|
||||||
dialog_render_sender.emit(MonitorInputMsg::SetRenderRange(
|
dialog_render_sender.emit(MonitorInputMsg::SetRenderRange(
|
||||||
lon_start, lon_end, lat_start, lat_end,
|
lon_start, lon_end, lat_start, lat_end,
|
||||||
));
|
));
|
||||||
|
|
||||||
AppMsg::NewElement(element)
|
AppMsg::LayerManager(LayerMsg::Add(layer))
|
||||||
}
|
}
|
||||||
_ => AppMsg::Close,
|
_ => AppMsg::Close,
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let buffer: Buffer = Rc::new(RefCell::new(HashMap::new()));
|
||||||
let model = AppModel {
|
let model = AppModel {
|
||||||
cms,
|
cms,
|
||||||
dispatcher,
|
dispatcher,
|
||||||
waiting_for: None,
|
waiting_for: None,
|
||||||
buffer,
|
elements: Vec::with_capacity(20),
|
||||||
file_pool,
|
|
||||||
open_dialog: dialog,
|
open_dialog: dialog,
|
||||||
selected_layer: vec![],
|
selected_layer: vec![],
|
||||||
sidebar,
|
sidebar,
|
||||||
elements: vec![],
|
|
||||||
control,
|
control,
|
||||||
render,
|
render,
|
||||||
layers,
|
layers,
|
||||||
@ -331,7 +321,7 @@ impl Component for AppModel {
|
|||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
let mut group = RelmActionGroup::<FileActionGroup>::new();
|
let mut group = RelmActionGroup::<FileActionGroup>::new();
|
||||||
relm4::main_application().set_accelerators_for_action::<OpenAction>(&["<primary>O"]);
|
relm4::main_application().set_accelerators_for_action::<OpenAction>(&["<primary>O"]);
|
||||||
// register_layer_actions(&widgets.main_window, sender.clone());
|
register_layer_actions(&widgets.main_window, sender.clone());
|
||||||
let action: RelmAction<OpenAction> = {
|
let action: RelmAction<OpenAction> = {
|
||||||
RelmAction::new_stateless(move |_| {
|
RelmAction::new_stateless(move |_| {
|
||||||
sender.input(AppMsg::OpenDialog);
|
sender.input(AppMsg::OpenDialog);
|
||||||
@ -356,7 +346,24 @@ impl Component for AppModel {
|
|||||||
(*self.layers).borrow_mut().push(layer);
|
(*self.layers).borrow_mut().push(layer);
|
||||||
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
||||||
}
|
}
|
||||||
LayerMsg::SwitchToTime(idx) => {}
|
LayerMsg::SwitchToTime(idx) => {
|
||||||
|
let mut layer = (*self.layers).borrow_mut();
|
||||||
|
let switched_layer = layer.get_mut(idx).unwrap();
|
||||||
|
let asso_element = switched_layer.pop_associated_element();
|
||||||
|
|
||||||
|
if let AssoElement::Instant(e) = asso_element {
|
||||||
|
let dispatcher = self.dispatcher.clone();
|
||||||
|
let cms = self.cms.clone();
|
||||||
|
let (mut series, start_time) = e.to_time_series(dispatcher, cms);
|
||||||
|
switched_layer.set_time(start_time);
|
||||||
|
series.register(start_time).unwrap();
|
||||||
|
let element = Arc::new(Mutex::new(series));
|
||||||
|
switched_layer
|
||||||
|
.set_associated_element(AssoElement::TimeSeries(element.clone()));
|
||||||
|
self.elements.push(element);
|
||||||
|
}
|
||||||
|
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
||||||
|
}
|
||||||
|
|
||||||
LayerMsg::Select(idx) => {
|
LayerMsg::Select(idx) => {
|
||||||
self.set_selected_layer(idx);
|
self.set_selected_layer(idx);
|
||||||
@ -374,23 +381,15 @@ impl Component for AppModel {
|
|||||||
LayerMsg::Remove(idx) => {
|
LayerMsg::Remove(idx) => {
|
||||||
let mut layers = (*self.layers).borrow_mut();
|
let mut layers = (*self.layers).borrow_mut();
|
||||||
let mut layer = layers.remove(idx);
|
let mut layer = layers.remove(idx);
|
||||||
|
if let AssoElement::TimeSeries(e) = layer.pop_associated_element() {
|
||||||
|
let size = Arc::strong_count(&e);
|
||||||
|
}
|
||||||
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AppMsg::CloseRequest => {
|
AppMsg::CloseRequest => {
|
||||||
relm4::main_application().quit();
|
relm4::main_application().quit();
|
||||||
}
|
}
|
||||||
AppMsg::NewElement(element) => {
|
|
||||||
let new_layer = Layer::new(
|
|
||||||
true,
|
|
||||||
"New Layer".to_string(),
|
|
||||||
element.clone(),
|
|
||||||
ElementType::Indenpendent,
|
|
||||||
);
|
|
||||||
_sender.input(AppMsg::LayerManager(LayerMsg::Add(new_layer)));
|
|
||||||
self.elements.push(element);
|
|
||||||
self.render.sender().send(MonitorInputMsg::RefreshRender);
|
|
||||||
}
|
|
||||||
AppMsg::Close => {}
|
AppMsg::Close => {}
|
||||||
AppMsg::OpenDialog => {
|
AppMsg::OpenDialog => {
|
||||||
self.open_dialog.emit(OpenDialogMsg::Open);
|
self.open_dialog.emit(OpenDialogMsg::Open);
|
||||||
@ -426,9 +425,8 @@ impl AppModel {
|
|||||||
.load(RStr::from_str(path.as_ref().to_str().unwrap()))
|
.load(RStr::from_str(path.as_ref().to_str().unwrap()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let block = result.blocks.first().unwrap();
|
let block = result.blocks.first().unwrap();
|
||||||
// data_to_element(block, dispatcher, cms)
|
data_to_element(block, dispatcher, cms)
|
||||||
// .map(|v| (Some(Box::new(result) as Box<dyn Any + Send + Sync>), v))
|
.map(|v| (Some(Box::new(result) as Box<dyn Any + Send + Sync>), v))
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_file_only(path: impl AsRef<std::path::Path>) -> PluginResult {
|
fn open_file_only(path: impl AsRef<std::path::Path>) -> PluginResult {
|
||||||
|
|||||||
@ -22,7 +22,7 @@ use tracing::*;
|
|||||||
use crate::coords::Range;
|
use crate::coords::Range;
|
||||||
use crate::map_tile::MapTile;
|
use crate::map_tile::MapTile;
|
||||||
use crate::map_tile_utils::lat_lon_to_zoom;
|
use crate::map_tile_utils::lat_lon_to_zoom;
|
||||||
use crate::pipeline::Target;
|
use crate::pipeline::element::Target;
|
||||||
use crate::utils::estimate_zoom_level;
|
use crate::utils::estimate_zoom_level;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use femtovg::ImageId;
|
use femtovg::ImageId;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::widgets::{Layer, Render};
|
use crate::widgets::{Layer, LayerImpl, Render};
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas};
|
||||||
use gtk::Align;
|
use gtk::Align;
|
||||||
use std::{fmt::Debug, rc::Rc};
|
use std::{fmt::Debug, rc::Rc};
|
||||||
|
|||||||
@ -12,12 +12,12 @@ pub enum OutputMsg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct PathItem {
|
pub struct PathItem {
|
||||||
title: &'static str,
|
title: String,
|
||||||
path: String,
|
path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PathItem {
|
impl PathItem {
|
||||||
pub fn new(title: &'static str, path: String) -> Self {
|
pub fn new(title: String, path: String) -> Self {
|
||||||
Self { title, path }
|
Self { title, path }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use super::dispatcher_list::PathItem;
|
use super::dispatcher_list::PathItem;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
config::PATH_FORMATS,
|
||||||
data::{self, CoordType, Radar2d},
|
data::{self, CoordType, Radar2d},
|
||||||
predefined::color_mapper::BoundaryNorm,
|
predefined::color_mapper::BoundaryNorm,
|
||||||
widgets::render::Layer,
|
widgets::render::Layer,
|
||||||
@ -99,15 +100,15 @@ impl SimpleComponent for SettingModel {
|
|||||||
.forward(sender.input_sender(), |msg| match msg {
|
.forward(sender.input_sender(), |msg| match msg {
|
||||||
_ => SettingMsg::SaveConfig,
|
_ => SettingMsg::SaveConfig,
|
||||||
});
|
});
|
||||||
// {
|
{
|
||||||
// let config = CONFIG.lock().unwrap();
|
let config = CONFIG.lock().unwrap();
|
||||||
// let etws_config = config.plugins.get("etws_loader").unwrap();
|
let etws_config = config.plugins.get("etws_loader").unwrap();
|
||||||
// // let paths = etws_config.path_formats.as_ref().unwrap_or(&PATH_FORMATS);
|
let paths = etws_config.path_formats.as_ref().unwrap_or(&PATH_FORMATS);
|
||||||
// let mut list_guard = path_list.guard();
|
let mut list_guard = path_list.guard();
|
||||||
// for p in paths {
|
for p in paths {
|
||||||
// list_guard.push_back(PathItem::new(p.0, p.1.clone()));
|
list_guard.push_back(PathItem::new(p.0.clone(), p.1.clone()));
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
let model = SettingModel { path_list };
|
let model = SettingModel { path_list };
|
||||||
|
|
||||||
let my_view = model.path_list.widget();
|
let my_view = model.path_list.widget();
|
||||||
@ -117,22 +118,22 @@ impl SimpleComponent for SettingModel {
|
|||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
|
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
|
||||||
// match msg {
|
match msg {
|
||||||
// SettingMsg::PathFormats((plugin, (k, v))) => {
|
SettingMsg::PathFormats((plugin, (k, v))) => {
|
||||||
// let mut config = CONFIG.lock().unwrap();
|
let mut config = CONFIG.lock().unwrap();
|
||||||
// let mut pluging_cfg = config.plugins.get_mut(&plugin).unwrap();
|
let mut pluging_cfg = config.plugins.get_mut(&plugin).unwrap();
|
||||||
// if pluging_cfg.path_formats.is_none() {
|
if pluging_cfg.path_formats.is_none() {
|
||||||
// pluging_cfg.path_formats = Some(HashMap::new());
|
pluging_cfg.path_formats = Some(HashMap::new());
|
||||||
// }
|
}
|
||||||
// pluging_cfg.path_formats.as_mut().unwrap().insert(&k, v);
|
pluging_cfg.path_formats.as_mut().unwrap().insert(k, v);
|
||||||
// let mut list_guard = self.path_list.guard();
|
let mut list_guard = self.path_list.guard();
|
||||||
// // list_guard.push_back(PathItem::new(k, v));
|
// list_guard.push_back(PathItem::new(k, v));
|
||||||
// }
|
}
|
||||||
// SettingMsg::SaveConfig => {
|
SettingMsg::SaveConfig => {
|
||||||
// let mut config = CONFIG.lock().unwrap();
|
let mut config = CONFIG.lock().unwrap();
|
||||||
// config.save();
|
config.save();
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::actions::*;
|
use crate::actions::*;
|
||||||
|
use crate::widgets::AssoElement;
|
||||||
use abi_stable::type_level::trait_marker::Hash;
|
use abi_stable::type_level::trait_marker::Hash;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use glib_macros::clone;
|
use glib_macros::clone;
|
||||||
@ -192,7 +193,11 @@ impl SimpleComponent for SideBarModel {
|
|||||||
v.name.clone(),
|
v.name.clone(),
|
||||||
v.visiable,
|
v.visiable,
|
||||||
v.get_thumbnail(),
|
v.get_thumbnail(),
|
||||||
LayerStatus::Instance,
|
match v.get_associated_element() {
|
||||||
|
AssoElement::TimeSeries(_) => LayerStatus::BindToTime(Utc::now()),
|
||||||
|
AssoElement::Instant(_) => LayerStatus::Instance,
|
||||||
|
_ => LayerStatus::Instance,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -216,11 +221,11 @@ impl SimpleComponent for SideBarModel {
|
|||||||
v.name.clone(),
|
v.name.clone(),
|
||||||
v.visiable,
|
v.visiable,
|
||||||
v.get_thumbnail(),
|
v.get_thumbnail(),
|
||||||
LayerStatus::Instance, // match v.get_associated_element() {
|
match v.get_associated_element() {
|
||||||
// // AssoElement::TimeSeries(_) => LayerStatus::BindToTime(Utc::now()),
|
AssoElement::TimeSeries(_) => LayerStatus::BindToTime(Utc::now()),
|
||||||
// // AssoElement::Instant(_) => LayerStatus::Instance,
|
AssoElement::Instant(_) => LayerStatus::Instance,
|
||||||
// _ => LayerStatus::Instance,
|
_ => LayerStatus::Instance,
|
||||||
//
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|||||||
270
src/config.rs
270
src/config.rs
@ -1,238 +1,41 @@
|
|||||||
use crate::errors::ConfigError;
|
use crate::errors::ConfigError;
|
||||||
use crate::predefined::color_mapper::{
|
|
||||||
BoundaryNorm, BoundaryNormDiscrete, ColorMapper, ColorMapperComb, Discrete,
|
|
||||||
};
|
|
||||||
use crate::utils::{
|
|
||||||
create_cc_default_cvmapper, create_hgt_default_cvmapper, create_kdp_default_cvmapper,
|
|
||||||
create_reflect_default_cvmapper, create_vel_default_cvmapper, create_vil_default_cvmapper,
|
|
||||||
parse_hex_color,
|
|
||||||
};
|
|
||||||
use dirs;
|
use dirs;
|
||||||
use gtk::ResponseType::No;
|
|
||||||
use num_traits::{AsPrimitive, FromPrimitive};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::{collections::HashMap, env, io::Write, path::PathBuf};
|
use std::{collections::HashMap, env, io::Write, path::PathBuf};
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
macro_rules! cvmap {
|
lazy_static! {
|
||||||
($config:ident,
|
pub static ref PATH_FORMATS: HashMap<String, String> = {
|
||||||
$({
|
let mut map = HashMap::new();
|
||||||
$cmap: literal, $vmap: literal, $value: expr
|
map.insert("R".to_string(), String::new());
|
||||||
},)+
|
map.insert("V".to_string(), String::new());
|
||||||
) => {
|
map.insert("SW".to_string(), String::new());
|
||||||
match ($config.cmap.as_str(), $config.vmap.as_str()) {
|
map.insert("CC".to_string(), String::new());
|
||||||
$(
|
map.insert("ZDR".to_string(), String::new());
|
||||||
($cmap, $vmap) => {
|
map.insert("PHIDP".to_string(), String::new());
|
||||||
$value
|
map.insert("KDP".to_string(), String::new());
|
||||||
}
|
map.insert("HCA".to_string(), String::new());
|
||||||
)+
|
map.insert("DBZ".to_string(), String::new());
|
||||||
_ => {
|
map.insert("QPE".to_string(), String::new());
|
||||||
panic!("Invalid color and value mapping")
|
map.insert("QPF".to_string(), String::new());
|
||||||
}
|
map.insert("VIL".to_string(), String::new());
|
||||||
}
|
map.insert("OHP".to_string(), String::new());
|
||||||
|
map.insert("THP".to_string(), String::new());
|
||||||
|
map.insert("ET".to_string(), String::new());
|
||||||
|
map.insert("EB".to_string(), String::new());
|
||||||
|
map
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! drawers {
|
|
||||||
($m:ident, $({
|
|
||||||
$key: literal, $a: ident
|
|
||||||
},)+) => {
|
|
||||||
{
|
|
||||||
let mut defa = Drawers::default();
|
|
||||||
$(
|
|
||||||
let $a = {
|
|
||||||
let kv = $m.remove($key);
|
|
||||||
if let Some(v) = kv {
|
|
||||||
defa.$a = v.try_into()?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
)+
|
|
||||||
// Drawers {
|
|
||||||
// $(
|
|
||||||
// $a,
|
|
||||||
// )+
|
|
||||||
// }
|
|
||||||
defa
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Settings {
|
|
||||||
pub plugin_config: Vec<PluginConfig>,
|
|
||||||
pub drawers: Drawers,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Drawers {
|
|
||||||
pub reflectivity: DrawerConfig<i8>,
|
|
||||||
pub velocity: DrawerConfig<i8>,
|
|
||||||
pub spectrum_width: DrawerConfig<i8>,
|
|
||||||
pub correlation_coefficient: DrawerConfig<f32>,
|
|
||||||
pub differential_reflectivity: DrawerConfig<f32>,
|
|
||||||
pub differential_phase: DrawerConfig<f32>,
|
|
||||||
pub specific_differential_phase: DrawerConfig<f32>,
|
|
||||||
pub hydrometeor_classification: DrawerConfig<i8>,
|
|
||||||
pub radar_rainfall_accumulation: DrawerConfig<f32>,
|
|
||||||
pub radar_rainfall_forecast: DrawerConfig<f32>,
|
|
||||||
pub vertically_integrated_liquid: DrawerConfig<f32>,
|
|
||||||
pub one_hour_precipitation: DrawerConfig<f32>,
|
|
||||||
pub three_hour_precipitation: DrawerConfig<f32>,
|
|
||||||
pub echo_tops: DrawerConfig<f32>,
|
|
||||||
pub echo_bases: DrawerConfig<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Drawers {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
reflectivity: DrawerConfig {
|
|
||||||
title: "Reflectivity",
|
|
||||||
color_mapper: create_reflect_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
velocity: DrawerConfig {
|
|
||||||
title: "Velocity",
|
|
||||||
color_mapper: create_vel_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
spectrum_width: DrawerConfig {
|
|
||||||
title: "Spectrum Width",
|
|
||||||
color_mapper: ColorMapperComb::default(),
|
|
||||||
},
|
|
||||||
|
|
||||||
correlation_coefficient: DrawerConfig {
|
|
||||||
title: "Correlation Coefficient",
|
|
||||||
color_mapper: create_cc_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
differential_reflectivity: DrawerConfig {
|
|
||||||
title: "Differential Reflectivity",
|
|
||||||
color_mapper: create_kdp_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
differential_phase: DrawerConfig {
|
|
||||||
title: "Differential Phase",
|
|
||||||
color_mapper: create_kdp_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
specific_differential_phase: DrawerConfig {
|
|
||||||
title: "Specific Differential Phase",
|
|
||||||
color_mapper: create_kdp_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
hydrometeor_classification: DrawerConfig {
|
|
||||||
title: "Hydrometeor Classification",
|
|
||||||
color_mapper: ColorMapperComb::default(),
|
|
||||||
},
|
|
||||||
|
|
||||||
radar_rainfall_accumulation: DrawerConfig {
|
|
||||||
title: "Radar Rainfall Accumulation",
|
|
||||||
color_mapper: create_vil_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
radar_rainfall_forecast: DrawerConfig {
|
|
||||||
title: "Radar Rainfall Forecast",
|
|
||||||
color_mapper: create_vil_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
vertically_integrated_liquid: DrawerConfig {
|
|
||||||
title: "Vertically Integrated Liquid",
|
|
||||||
color_mapper: create_vil_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
one_hour_precipitation: DrawerConfig {
|
|
||||||
title: "One Hour Precipitation",
|
|
||||||
color_mapper: create_vil_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
three_hour_precipitation: DrawerConfig {
|
|
||||||
title: "Three Hour Precipitation",
|
|
||||||
color_mapper: create_vil_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
echo_tops: DrawerConfig {
|
|
||||||
title: "Echo Tops",
|
|
||||||
color_mapper: create_hgt_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
|
|
||||||
echo_bases: DrawerConfig {
|
|
||||||
title: "Echo Bases",
|
|
||||||
color_mapper: create_hgt_default_cvmapper().into(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
pub struct DrawerConfig<T>
|
|
||||||
where
|
|
||||||
T: PartialEq + PartialOrd + Debug + Clone,
|
|
||||||
{
|
|
||||||
pub title: &'static str,
|
|
||||||
pub color_mapper: ColorMapperComb<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
||||||
pub struct SeDrawerConfig {
|
|
||||||
pub cmap: String,
|
|
||||||
pub vmap: String,
|
|
||||||
pub colors: Option<Vec<String>>,
|
|
||||||
pub values: Option<Vec<f32>>,
|
|
||||||
pub extrand: Option<bool>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> TryFrom<SeDrawerConfig> for DrawerConfig<T>
|
|
||||||
where
|
|
||||||
T: FromPrimitive + PartialEq + PartialOrd + Debug + Copy + 'static,
|
|
||||||
f32: AsPrimitive<T>,
|
|
||||||
{
|
|
||||||
type Error = &'static str;
|
|
||||||
fn try_from(value: SeDrawerConfig) -> Result<Self, Self::Error> {
|
|
||||||
let boundaries = value
|
|
||||||
.values
|
|
||||||
.map(|x| x.iter().map(|x| x.as_()).collect::<Vec<T>>())
|
|
||||||
.unwrap();
|
|
||||||
let colors = if let Some(v) = value.colors {
|
|
||||||
let mut colors = Vec::new();
|
|
||||||
for value in v.iter() {
|
|
||||||
let (r, g, b) = parse_hex_color(value)?;
|
|
||||||
colors.push(femtovg::Color::rgb(r, g, b));
|
|
||||||
}
|
|
||||||
Some(colors)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let c = cvmap!(
|
|
||||||
value,
|
|
||||||
{
|
|
||||||
"boundary_norm", "discrete",
|
|
||||||
ColorMapper::new(
|
|
||||||
Discrete::new(colors.unwrap()),
|
|
||||||
BoundaryNorm::new(boundaries, value.extrand.unwrap_or(false), T::from_f32(-125.0)),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
title: "Reflectivity",
|
|
||||||
color_mapper: c.into(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub plugins: Vec<PluginConfig>,
|
pub plugins: HashMap<String, PluginConfig>,
|
||||||
pub drawer_config: HashMap<String, SeDrawerConfig>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct PluginConfig {
|
pub struct PluginConfig {
|
||||||
pub version: String,
|
pub version: String,
|
||||||
pub name: String,
|
pub path_formats: Option<HashMap<String, String>>,
|
||||||
pub publisher: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
@ -281,32 +84,3 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Config> for Settings {
|
|
||||||
type Error = &'static str;
|
|
||||||
fn try_from(value: Config) -> Result<Self, Self::Error> {
|
|
||||||
let mut map = value.drawer_config;
|
|
||||||
let c = drawers!(map,
|
|
||||||
{"reflectivity", reflectivity},
|
|
||||||
{"velocity", velocity},
|
|
||||||
{"spectrum_width", spectrum_width},
|
|
||||||
{"correlation_coefficient", correlation_coefficient},
|
|
||||||
{"differential_reflectivity", differential_reflectivity},
|
|
||||||
{"differential_phase", differential_phase},
|
|
||||||
{"specific_differential_phase", specific_differential_phase},
|
|
||||||
{"hydrometeor_classification", hydrometeor_classification},
|
|
||||||
{"radar_rainfall_accumulation", radar_rainfall_accumulation},
|
|
||||||
{"radar_rainfall_forecast", radar_rainfall_forecast},
|
|
||||||
{"vertically_integrated_liquid", vertically_integrated_liquid},
|
|
||||||
{"one_hour_precipitation", one_hour_precipitation},
|
|
||||||
{"three_hour_precipitation", three_hour_precipitation},
|
|
||||||
{"echo_tops", echo_tops},
|
|
||||||
{"echo_bases", echo_bases},
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
plugin_config: value.plugins,
|
|
||||||
drawers: c,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use crate::coords::Mapper;
|
use crate::coords::Mapper;
|
||||||
use epoxy::XOR;
|
|
||||||
use geo_types::LineString;
|
use geo_types::LineString;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
@ -49,18 +48,6 @@ impl CMS {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fore_map(&self, loc: (f32, f32)) -> Option<(f64, f64)> {
|
|
||||||
let (x, y) = loc;
|
|
||||||
let (x, y) = (x as f64, y as f64);
|
|
||||||
|
|
||||||
let (x, y) = (
|
|
||||||
self.bounds.0 + x * (self.bounds.1 - self.bounds.0),
|
|
||||||
self.bounds.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>> {
|
pub fn ring_map(&self, line: &LineString) -> Option<LineString<f32>> {
|
||||||
Some(
|
Some(
|
||||||
line.points()
|
line.points()
|
||||||
|
|||||||
@ -18,20 +18,6 @@ pub type Radar2dRef<'a, T> = RadarData2d<T, ViewRepr<&'a T>, ViewRepr<&'a f64>,
|
|||||||
pub type Radar3dRef<'a, T> =
|
pub type Radar3dRef<'a, T> =
|
||||||
RadarData3d<T, ViewRepr<&'a T>, ViewRepr<&'a f64>, ViewRepr<&'a f64>, ViewRepr<&'a f64>>;
|
RadarData3d<T, ViewRepr<&'a T>, ViewRepr<&'a f64>, ViewRepr<&'a f64>, ViewRepr<&'a f64>>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum DataType {
|
|
||||||
F64,
|
|
||||||
I64,
|
|
||||||
U64,
|
|
||||||
F32,
|
|
||||||
I32,
|
|
||||||
U32,
|
|
||||||
I16,
|
|
||||||
U16,
|
|
||||||
I8,
|
|
||||||
U8,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum CoordType {
|
pub enum CoordType {
|
||||||
Polar,
|
Polar,
|
||||||
|
|||||||
@ -1,79 +1,44 @@
|
|||||||
use crate::pipeline::element_imp::*;
|
use crate::pipeline::element::ElementImpl;
|
||||||
|
use crate::pipeline::GridElementImpl;
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
use crate::CONFIG;
|
|
||||||
use radarg_plugin_interface::{CoordType, DataShape, PluginResult, PluginResultType};
|
use radarg_plugin_interface::{CoordType, DataShape, PluginResult, PluginResultType};
|
||||||
use std::any::Any;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
macro_rules! data_to_grid {
|
||||||
macro_rules! dispatch {
|
($_type:ident,$(($branch:path ,$boundary_norm: expr)),+) => {
|
||||||
($block:ident,$conf:ident, $wrap:tt , $fill_value: ident, $(
|
match $_type {
|
||||||
{
|
|
||||||
$t:ty | $branch: pat => $v:ident
|
|
||||||
}
|
|
||||||
),+ $(,)?) => {
|
|
||||||
match $block.data_type {
|
|
||||||
$(
|
$(
|
||||||
$branch => {
|
$branch => {
|
||||||
let mut $v = $wrap::default();
|
let element_impl = GridElementImpl::new($boundary_norm);
|
||||||
$v.color_map = $conf.drawers.$v.color_mapper.clone();
|
Arc::new(element_impl)
|
||||||
$v.fill_value = <$t>::from_f64($fill_value);
|
|
||||||
Arc::new($v) as Arc<dyn Any + Send + Sync>
|
|
||||||
}
|
}
|
||||||
)+
|
),+
|
||||||
|
_ => panic!("Invalid type")
|
||||||
_ => { panic!("") }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
pub fn plugin_result_impl(a: &PluginResult) -> Arc<dyn ElementImpl> {
|
||||||
macro_rules! dis {
|
let block = a.blocks.first().unwrap();
|
||||||
($block:ident, $config:ident, $wrap:tt, $fill_value: ident) => {
|
match block.coord_type {
|
||||||
dispatch!(
|
|
||||||
$block, $config, $wrap, $fill_value,
|
|
||||||
{ i8|PluginResultType::R => reflectivity },
|
|
||||||
{ i8|PluginResultType::DBZ => reflectivity },
|
|
||||||
{ f32|PluginResultType::ZDR => differential_reflectivity },
|
|
||||||
{ f32|PluginResultType::KDP => specific_differential_phase },
|
|
||||||
{ i8|PluginResultType::PHIDP => differential_phase }
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tools(data: &PluginResult) -> (ElementImpl, Arc<dyn Any + Send + Sync>) {
|
|
||||||
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 => {
|
|
||||||
let cfg = dis!(block, config, PolarElementConfig, fill_value);
|
|
||||||
(PolarElementImp().into(), cfg)
|
|
||||||
}
|
|
||||||
CoordType::Cartesian => {
|
CoordType::Cartesian => {
|
||||||
let cfg = dis!(block, config, GridImpConfig, fill_value);
|
let _type = block.data_type;
|
||||||
(
|
data_to_grid!(
|
||||||
match block.shape {
|
_type,
|
||||||
DataShape::Cube => MultiLayerGridImp().into(),
|
(PluginResultType::R, create_dbz_boundarynorm()),
|
||||||
DataShape::Matrix => GridImp().into(),
|
(PluginResultType::V, create_vel_boundarynorm()),
|
||||||
_ => panic!("Invalid shape"),
|
(PluginResultType::CC, create_cc_boundarynorm()),
|
||||||
},
|
(PluginResultType::ZDR, create_zdr_boundarynorm()),
|
||||||
cfg,
|
(PluginResultType::PHIDP, create_phidp_boundarynorm()),
|
||||||
|
(PluginResultType::KDP, create_kdp_boundarynorm()),
|
||||||
|
(PluginResultType::DBZ, create_dbz_boundarynorm()),
|
||||||
|
(PluginResultType::VIL, create_vil_boundarynorm()),
|
||||||
|
(PluginResultType::OHP, create_vil_boundarynorm()),
|
||||||
|
(PluginResultType::THP, create_vil_boundarynorm()),
|
||||||
|
(PluginResultType::ET, create_et_boundarynorm())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
CoordType::Other | CoordType::Polar => {
|
||||||
panic!("Invalid type")
|
panic!("Invalid type");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
imp
|
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/main.rs
14
src/main.rs
@ -4,11 +4,12 @@
|
|||||||
mod utils;
|
mod utils;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
use config::{Config, Settings};
|
use config::Config;
|
||||||
use gtk::{gio, prelude::SettingsExt};
|
use gtk::{
|
||||||
|
gio::{self, Settings},
|
||||||
|
prelude::SettingsExt,
|
||||||
|
};
|
||||||
use plugin_system::{init_plugin, PluginManager};
|
use plugin_system::{init_plugin, PluginManager};
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::sync::RwLock;
|
|
||||||
use std::{ptr, sync::Mutex};
|
use std::{ptr, sync::Mutex};
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
mod actions;
|
mod actions;
|
||||||
@ -33,15 +34,14 @@ mod map_tile;
|
|||||||
mod map_tile_utils;
|
mod map_tile_utils;
|
||||||
mod predefined;
|
mod predefined;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
// mod element_imp;
|
|
||||||
|
|
||||||
|
#[cfg(target_env = "msvc")]
|
||||||
declare_surfman!();
|
declare_surfman!();
|
||||||
|
|
||||||
const APP_ID: &str = "org.tsuki.radar_g";
|
const APP_ID: &str = "org.tsuki.radar_g";
|
||||||
static RUNTIME: SafeLazy<Runtime> =
|
static RUNTIME: SafeLazy<Runtime> =
|
||||||
SafeLazy::new(|| Runtime::new().expect("Setting up tokio runtime needs to succeed."));
|
SafeLazy::new(|| Runtime::new().expect("Setting up tokio runtime needs to succeed."));
|
||||||
static CONFIG: SafeLazy<RwLock<Settings>> =
|
static CONFIG: SafeLazy<Mutex<Config>> = SafeLazy::new(|| Mutex::new(Config::from_env().unwrap()));
|
||||||
SafeLazy::new(|| RwLock::new(Config::from_env().unwrap().try_into().unwrap()));
|
|
||||||
static PLUGIN_MANAGER: SafeLazy<PluginManager> = SafeLazy::new(|| PluginManager::new().unwrap());
|
static PLUGIN_MANAGER: SafeLazy<PluginManager> = SafeLazy::new(|| PluginManager::new().unwrap());
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::components::messages::MonitorInputMsg;
|
|||||||
use crate::components::{MonitorCommand, MonitorModel};
|
use crate::components::{MonitorCommand, MonitorModel};
|
||||||
use crate::coords::Range;
|
use crate::coords::Range;
|
||||||
use crate::map_tile_utils::lat_lon_to_zoom;
|
use crate::map_tile_utils::lat_lon_to_zoom;
|
||||||
use crate::pipeline::{Target, TargetType};
|
use crate::pipeline::element::{Target, TargetType};
|
||||||
use dirs::cache_dir;
|
use dirs::cache_dir;
|
||||||
use femtovg::ImageSource;
|
use femtovg::ImageSource;
|
||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
|
use super::element::TargetType;
|
||||||
use super::offscreen_renderer::{CanvasWrapper, OffscreenRenderer};
|
use super::offscreen_renderer::{CanvasWrapper, OffscreenRenderer};
|
||||||
use crate::CONFIG;
|
use crate::{
|
||||||
|
components::app::{Buffer, FILE_PATH_ROOT},
|
||||||
|
CONFIG,
|
||||||
|
};
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::{cell::Ref, collections::HashMap, path::PathBuf};
|
use std::{cell::Ref, collections::HashMap, path::PathBuf};
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
|
|
||||||
static DATETIME_FORMAT: Lazy<Regex> =
|
|
||||||
Lazy::new(|| Regex::new(r"(?:%[YHMSmd](?:[-/:_]?%[YHMSmd])*)").unwrap());
|
|
||||||
|
|
||||||
static REREMAP: Lazy<HashMap<&str, &str>> = Lazy::new(|| {
|
static REREMAP: Lazy<HashMap<&str, &str>> = Lazy::new(|| {
|
||||||
let mut map = HashMap::new();
|
let mut map = HashMap::new();
|
||||||
map.insert("%Y", r"\d{4}");
|
map.insert("%Y", r"\d{4}");
|
||||||
@ -63,42 +64,41 @@ impl Dispatcher {
|
|||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let datetime_format: regex::Regex =
|
let datetime_format: regex::Regex =
|
||||||
Regex::new(r"(?:%[YHMSmd](?:[-/:_]?%[YHMSmd])*)").unwrap();
|
Regex::new(r"(?:%[YHMSmd](?:[-/:_]?%[YHMSmd])*)").unwrap();
|
||||||
let config = CONFIG.read().unwrap();
|
let config = CONFIG.lock().unwrap();
|
||||||
// let path_format = config
|
let path_format = config
|
||||||
// .plugins
|
.plugins
|
||||||
// .get("etws_loader")
|
.get("etws_loader")
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .path_formats
|
.path_formats
|
||||||
// .as_ref();
|
.as_ref();
|
||||||
return None;
|
if path_format.is_none() {
|
||||||
// if path_format.is_none() {
|
return None;
|
||||||
// return None;
|
}
|
||||||
// }
|
let c = path_format.unwrap().get(name).map(|s| {
|
||||||
// let c = path_format.unwrap().get(name).map(|s| {
|
let path = s.clone();
|
||||||
// let path = s.clone();
|
let need_formated = datetime_format.captures_iter(&path).collect::<Vec<_>>();
|
||||||
// let need_formated = datetime_format.captures_iter(&path).collect::<Vec<_>>();
|
let mut result_path = path.clone();
|
||||||
// let mut result_path = path.clone();
|
|
||||||
//
|
for need_format in need_formated.iter() {
|
||||||
// for need_format in need_formated.iter() {
|
let fmt = need_format.get(0).unwrap().as_str();
|
||||||
// let fmt = need_format.get(0).unwrap().as_str();
|
let t = current_time.format(fmt).to_string();
|
||||||
// let t = current_time.format(fmt).to_string();
|
result_path = result_path.replace(fmt, &t);
|
||||||
// result_path = result_path.replace(fmt, &t);
|
}
|
||||||
// }
|
result_path
|
||||||
// result_path
|
});
|
||||||
// });
|
if let Some(c) = c {
|
||||||
// if let Some(c) = c {
|
if check_existed {
|
||||||
// if check_existed {
|
if std::path::Path::new(&c).exists() {
|
||||||
// if std::path::Path::new(&c).exists() {
|
Some(c)
|
||||||
// Some(c)
|
} else {
|
||||||
// } else {
|
None
|
||||||
// None
|
}
|
||||||
// }
|
} else {
|
||||||
// } else {
|
Some(c)
|
||||||
// Some(c)
|
}
|
||||||
// }
|
} else {
|
||||||
// } else {
|
None
|
||||||
// None
|
}
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_path(
|
pub fn get_path(
|
||||||
@ -107,96 +107,94 @@ impl Dispatcher {
|
|||||||
current_time: DateTime<Utc>,
|
current_time: DateTime<Utc>,
|
||||||
check_existed: bool,
|
check_existed: bool,
|
||||||
mut max_retry_time: usize,
|
mut max_retry_time: usize,
|
||||||
file_path: &PathBuf,
|
|
||||||
) -> Option<Vec<(String, DateTime<Utc>)>> {
|
) -> Option<Vec<(String, DateTime<Utc>)>> {
|
||||||
let config = CONFIG.read().unwrap();
|
let datetime_format: regex::Regex = Regex::new(r"%[YHMSmd](?:[-/:_]?%[YHMSmd])*").unwrap();
|
||||||
|
let config = CONFIG.lock().unwrap();
|
||||||
|
let path_format = config
|
||||||
|
.plugins
|
||||||
|
.get("etws_loader")
|
||||||
|
.unwrap()
|
||||||
|
.path_formats
|
||||||
|
.as_ref();
|
||||||
|
if path_format.is_none() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
path_format.unwrap().get(name).map(|s| {
|
||||||
|
let path = s.clone();
|
||||||
|
let file_path = { FILE_PATH_ROOT.lock().unwrap().clone() };
|
||||||
|
let path = if path.starts_with("./") {
|
||||||
|
let file_root = file_root(&file_path, path.replace("./", ""));
|
||||||
|
file_root.map(|root| {
|
||||||
|
let splited = path.split_at(2);
|
||||||
|
root.join(PathBuf::from(splited.1))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Some(PathBuf::from(path))
|
||||||
|
};
|
||||||
|
|
||||||
return None;
|
let mut result_paths = Vec::new();
|
||||||
// let path_format = config
|
if let Some(path_uninit) = path {
|
||||||
// .plugins
|
let mut path_str = path_uninit.to_string_lossy().to_string();
|
||||||
// .get("etws_loader")
|
let prefixs = get_prefix(&file_path, &path_str);
|
||||||
// .unwrap()
|
|
||||||
// .path_formats
|
for (idx, prefix) in prefixs.iter().enumerate() {
|
||||||
// .as_ref();
|
if let Some(s) = prefix.as_ref() {
|
||||||
// if path_format.is_none() {
|
path_str = path_str.replacen("{prefix}", &s, 1);
|
||||||
// return None;
|
}
|
||||||
// }
|
}
|
||||||
// path_format.unwrap().get(name).map(|s| {
|
|
||||||
// let path = s.clone();
|
let need_formated = datetime_format.captures_iter(&path_str).collect::<Vec<_>>();
|
||||||
// // let file_path = { file_path_root.lock().unwrap().clone() };
|
let mut fore = self.fore_len;
|
||||||
// let path = if path.starts_with("./") {
|
let mut back = 1;
|
||||||
// let file_root = file_root(&file_path, path.replace("./", ""));
|
|
||||||
// file_root.map(|root| {
|
while fore > 0 {
|
||||||
// let splited = path.split_at(2);
|
let mut result_path = path_str.clone();
|
||||||
// root.join(PathBuf::from(splited.1))
|
let t = current_time - self.step * fore as i32;
|
||||||
// })
|
for need_format in need_formated.iter() {
|
||||||
// } else {
|
let fmt = need_format.get(0).unwrap().as_str();
|
||||||
// Some(PathBuf::from(path))
|
let t = t.format(fmt).to_string();
|
||||||
// };
|
result_path = result_path.replace(fmt, &t);
|
||||||
//
|
}
|
||||||
// let mut result_paths = Vec::new();
|
|
||||||
// if let Some(path_uninit) = path {
|
if check_existed {
|
||||||
// let mut path_str = path_uninit.to_string_lossy().to_string();
|
// if max_retry_time == 0 {
|
||||||
// let prefixs = get_prefix(&file_path, &path_str);
|
// break;
|
||||||
//
|
// }
|
||||||
// for (idx, prefix) in prefixs.iter().enumerate() {
|
if !std::path::Path::new(&result_path).exists() {
|
||||||
// if let Some(s) = prefix.as_ref() {
|
} else {
|
||||||
// path_str = path_str.replacen("{prefix}", &s, 1);
|
result_paths.push((result_path.clone(), t));
|
||||||
// }
|
}
|
||||||
// }
|
} else {
|
||||||
//
|
result_paths.push((result_path.clone(), t));
|
||||||
// let need_formated = DATETIME_FORMAT.captures_iter(&path_str).collect::<Vec<_>>();
|
}
|
||||||
// let mut fore = self.fore_len;
|
fore = fore - 1;
|
||||||
// let mut back = 1;
|
}
|
||||||
//
|
|
||||||
// while fore > 0 {
|
while back < self.back_len + 1 {
|
||||||
// let mut result_path = path_str.clone();
|
let mut result_path = path_str.clone();
|
||||||
// let t = current_time - self.step * fore as i32;
|
let t = current_time + self.step * back as i32;
|
||||||
// for need_format in need_formated.iter() {
|
for need_format in need_formated.iter() {
|
||||||
// let fmt = need_format.get(0).unwrap().as_str();
|
let fmt = need_format.get(0).unwrap().as_str();
|
||||||
// let t = t.format(fmt).to_string();
|
let t = t.format(fmt).to_string();
|
||||||
// result_path = result_path.replace(fmt, &t);
|
result_path = result_path.replace(fmt, &t);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// if check_existed {
|
if check_existed {
|
||||||
// // if max_retry_time == 0 {
|
// if max_retry_time == 0 {
|
||||||
// // break;
|
// break;
|
||||||
// // }
|
// }
|
||||||
// if !std::path::Path::new(&result_path).exists() {
|
if !std::path::Path::new(&result_path).exists() {
|
||||||
// } else {
|
} else {
|
||||||
// result_paths.push((result_path.clone(), t));
|
result_paths.push((result_path.clone(), t));
|
||||||
// }
|
}
|
||||||
// } else {
|
} else {
|
||||||
// result_paths.push((result_path.clone(), t));
|
result_paths.push((result_path.clone(), t));
|
||||||
// }
|
}
|
||||||
// fore = fore - 1;
|
back = back + 1;
|
||||||
// }
|
}
|
||||||
//
|
}
|
||||||
// while back < self.back_len + 1 {
|
result_paths
|
||||||
// let mut result_path = path_str.clone();
|
})
|
||||||
// let t = current_time + self.step * back as i32;
|
|
||||||
// for need_format in need_formated.iter() {
|
|
||||||
// let fmt = need_format.get(0).unwrap().as_str();
|
|
||||||
// let t = t.format(fmt).to_string();
|
|
||||||
// result_path = result_path.replace(fmt, &t);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if check_existed {
|
|
||||||
// // if max_retry_time == 0 {
|
|
||||||
// // break;
|
|
||||||
// // }
|
|
||||||
// if !std::path::Path::new(&result_path).exists() {
|
|
||||||
// } else {
|
|
||||||
// result_paths.push((result_path.clone(), t));
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// result_paths.push((result_path.clone(), t));
|
|
||||||
// }
|
|
||||||
// back = back + 1;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// result_paths
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use super::{offscreen_renderer::CanvasWrapper, Dispatcher};
|
use super::{offscreen_renderer::CanvasWrapper, Dispatcher, Pipeline};
|
||||||
use crate::components::Widget;
|
use crate::components::Widget;
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::coords::Range;
|
use crate::coords::Range;
|
||||||
@ -101,7 +101,7 @@ pub struct TimeSeriesElement {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum InstantElementDrawerType {
|
pub enum InstantElementDrawerType {
|
||||||
Draw(DrawFunc),
|
Draw(DrawFunc),
|
||||||
Prepared(DataTarget),
|
Prepared((DataTarget, Arc<dyn ElementImpl>)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for InstantElementDrawerType {
|
impl Debug for InstantElementDrawerType {
|
||||||
@ -141,7 +141,7 @@ impl InstantElement {
|
|||||||
InstantElementDrawerType::Draw(ref func) => {
|
InstantElementDrawerType::Draw(ref func) => {
|
||||||
func(render);
|
func(render);
|
||||||
}
|
}
|
||||||
InstantElementDrawerType::Prepared(ref mut target) => {
|
InstantElementDrawerType::Prepared((ref mut target, _)) => {
|
||||||
render.draw_img(target);
|
render.draw_img(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,21 +157,21 @@ impl InstantElement {
|
|||||||
cms: CMS,
|
cms: CMS,
|
||||||
) -> (TimeSeriesElement, DateTime<Utc>) {
|
) -> (TimeSeriesElement, DateTime<Utc>) {
|
||||||
// let imp = Arc::new(InstantElementImpl::new(self));
|
// let imp = Arc::new(InstantElementImpl::new(self));
|
||||||
// if let InstantElementDrawerType::Prepared(mut target) = self.draw_type {
|
if let InstantElementDrawerType::Prepared((mut target, imp)) = self.draw_type {
|
||||||
// let mut time_series = TimeSeriesElement::new(imp, dispatcher, cms, self.key);
|
let mut time_series = TimeSeriesElement::new(imp, dispatcher, cms, self.key);
|
||||||
// let data = target.take_data().unwrap();
|
let data = target.take_data().unwrap();
|
||||||
// let time_stamp = data.blocks.first().unwrap().datetime;
|
let time_stamp = data.blocks.first().unwrap().datetime;
|
||||||
// let meta_info: MetaInfo = data.meta.clone().into();
|
let meta_info: MetaInfo = data.meta.clone().into();
|
||||||
// use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
// let time = Utc.timestamp_opt(time_stamp, 0).unwrap();
|
let time = Utc.timestamp_opt(time_stamp, 0).unwrap();
|
||||||
// (*time_series.buffer)
|
(*time_series.buffer)
|
||||||
// .lock()
|
.lock()
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .insert(time, Some(RenderResult::new(target, meta_info)));
|
.insert(time, Some(RenderResult::new(target, meta_info)));
|
||||||
// (time_series, time)
|
(time_series, time)
|
||||||
// } else {
|
} else {
|
||||||
panic!("InstantElementDrawerType is not prepared");
|
panic!("InstantElementDrawerType is not prepared");
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,486 +0,0 @@
|
|||||||
use super::Target;
|
|
||||||
use crate::coords::cms::CMS;
|
|
||||||
use crate::data::Radar2dRef;
|
|
||||||
use crate::pipeline::offscreen_renderer::CanvasWrapper;
|
|
||||||
use crate::predefined::color_mapper::{CMap, ColorMapper, ColorMapperComb, VMap};
|
|
||||||
use abi_stable::std_types::RVec;
|
|
||||||
use femtovg::renderer::OpenGl;
|
|
||||||
use femtovg::{Canvas, Paint, Path};
|
|
||||||
use ndarray::{ArrayBase, ArrayView1, ArrayView2, ArrayView3, ArrayViewD, Axis, Ix2, Ix3};
|
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps};
|
|
||||||
use radarg_plugin_interface::{DataShape, PluginResult, VecResult};
|
|
||||||
use std::any::Any;
|
|
||||||
use std::borrow::BorrowMut;
|
|
||||||
use std::fmt::Debug;
|
|
||||||
|
|
||||||
const EARTH_RADIUS: f64 = 6371.0;
|
|
||||||
|
|
||||||
macro_rules! impl_element_imp_dispatch {
|
|
||||||
($({$Abc: ident, $t:ty},)+) => {
|
|
||||||
impl ElementImpl {
|
|
||||||
pub fn process<'a,'b:'a, T>(&self,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
input: ElementInput<'a, T>,
|
|
||||||
config: &dyn Any,
|
|
||||||
context: &mut Context<'b>
|
|
||||||
)
|
|
||||||
where
|
|
||||||
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone + FromPrimitive + 'static,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
$(
|
|
||||||
Self::$Abc(imp) => {
|
|
||||||
let config = config.downcast_ref::<<$t as ElementImp>::Config<'a, T>>().unwrap();
|
|
||||||
if let ElementInput::$Abc(data) = input {
|
|
||||||
imp.process(dims, data, config, context);
|
|
||||||
} else {
|
|
||||||
panic!("Invalid input type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn output_type(&self,) -> ElementOutput
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
$(
|
|
||||||
Self::$Abc(imp) => {
|
|
||||||
imp.output_type()
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_element_try_from_dispatch {
|
|
||||||
($({ $Abc: ident, $t:ty},)+) => {
|
|
||||||
$(
|
|
||||||
impl TryFrom<ElementImpl> for $t {
|
|
||||||
type Error = &'static str;
|
|
||||||
fn try_from(value: ElementImpl) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
ElementImpl::$Abc(imp) => Ok(imp),
|
|
||||||
_ => Err("Invalid type"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_element_into_dispatch {
|
|
||||||
($({ $Abc: ident, $t:ty},)+) => {
|
|
||||||
$(
|
|
||||||
impl From<$t> for ElementImpl {
|
|
||||||
fn from(value: $t) -> Self {
|
|
||||||
Self::$Abc(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_element_input_into_dispatch {
|
|
||||||
($({$Abc: ident, $t: ty},)+) => {
|
|
||||||
$(
|
|
||||||
impl<'a, T> From<$t> for ElementInput<'a, T> {
|
|
||||||
fn from(value: $t) -> Self {
|
|
||||||
Self::$Abc(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! for_all_variants {
|
|
||||||
($macro: tt) => {
|
|
||||||
$macro! {
|
|
||||||
{Grid, GridImp},
|
|
||||||
{MultiLayerGrid, MultiLayerGridImp},
|
|
||||||
{Polar, PolarElementImp},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! result_to_array {
|
|
||||||
($v: ident, $shape: expr) => {
|
|
||||||
match $v {
|
|
||||||
VecResult::I16(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::U8(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::I8(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::Bool(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::F32(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::F64(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::I32(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::I64(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::U32(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
VecResult::U64(v) => ArrayViewD::from_shape($shape, v.as_ref()).unwrap(),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Context<'a> {
|
|
||||||
pub cms: CMS,
|
|
||||||
pub canvas: &'a mut Canvas<OpenGl>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Context<'a> {
|
|
||||||
pub fn new<T>(cms: CMS, canvas: &'a mut T) -> Self
|
|
||||||
where
|
|
||||||
T: BorrowMut<Canvas<OpenGl>> + 'a,
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
cms,
|
|
||||||
canvas: canvas.borrow_mut(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum ElementOutput {
|
|
||||||
Target,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ElementImp: Debug + TryFrom<ElementImpl> + Into<ElementImpl> {
|
|
||||||
type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq + 'a + Clone + FromPrimitive>: ElementConfig
|
|
||||||
where
|
|
||||||
Self: 'a;
|
|
||||||
type Input<'a, T: 'a>
|
|
||||||
where
|
|
||||||
Self: 'a;
|
|
||||||
|
|
||||||
fn process<'a, 'b: 'a, T>(
|
|
||||||
&self,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
input: Self::Input<'a, T>,
|
|
||||||
config: &Self::Config<'a, T>,
|
|
||||||
context: &mut Context<'b>,
|
|
||||||
) where
|
|
||||||
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone + FromPrimitive;
|
|
||||||
|
|
||||||
fn output_type(&self) -> ElementOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ElementConfig {
|
|
||||||
fn upcast_ref<'short, 'long: 'short>(&'long self) -> &'short Self {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct GridImp();
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct GridImpConfig<T>
|
|
||||||
where
|
|
||||||
T: PartialOrd + PartialEq + Send + Sync + Debug + Clone,
|
|
||||||
{
|
|
||||||
pub color_map: ColorMapperComb<T>,
|
|
||||||
pub fill_value: T
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GridImp {
|
|
||||||
fn draw_2d<'a, 'b: 'a, T>(
|
|
||||||
&self,
|
|
||||||
config: &GridImpConfig<T>,
|
|
||||||
data: ArrayView2<'a, T>,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
context: &mut Context<'b>,
|
|
||||||
) where
|
|
||||||
T: PartialEq + PartialOrd + Copy + Clone + Send + Sync + Debug,
|
|
||||||
{
|
|
||||||
let cms = &context.cms;
|
|
||||||
let canvas = &mut context.canvas;
|
|
||||||
let shape = data.shape();
|
|
||||||
let mapper = &config.color_map;
|
|
||||||
let (rows, cols) = (shape[0], shape[1]);
|
|
||||||
let (dim1, dim2) = dims;
|
|
||||||
|
|
||||||
let d1_s = dim1[[0, 0]];
|
|
||||||
let d1_e = dim1[[0, cols - 1]];
|
|
||||||
|
|
||||||
let d2_s = dim2[[0, 0]];
|
|
||||||
let d2_e = dim2[[rows - 1, 0]];
|
|
||||||
|
|
||||||
for r in 0..rows - 1 {
|
|
||||||
for c in 0..cols - 1 {
|
|
||||||
let lb_lat = dim2[[r, c]];
|
|
||||||
let lb_lon = dim1[[r, c]];
|
|
||||||
|
|
||||||
let rt_lat = dim2[[r + 1, c + 1]];
|
|
||||||
let rt_lon = dim1[[r + 1, c + 1]];
|
|
||||||
let v = &data[[r, c]];
|
|
||||||
if v == &config.fill_value {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let mapped_color = mapper.color(*v);
|
|
||||||
if mapped_color.is_none() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (ox, oy) = cms.map((lb_lon, lb_lat)).unwrap();
|
|
||||||
let (rx, ry) = cms.map((rt_lon, rt_lat)).unwrap();
|
|
||||||
|
|
||||||
let mut path = Path::new();
|
|
||||||
path.rect(ox, oy, (rx - ox) * 1.5, (ry - oy) * 1.5);
|
|
||||||
canvas.fill_path(&path, &Paint::color(mapped_color.unwrap()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementImp for GridImp {
|
|
||||||
type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq + Clone + FromPrimitive> = GridImpConfig<T> where
|
|
||||||
T: 'a;
|
|
||||||
type Input<'a, T: 'a> = ArrayViewD<'a, T>;
|
|
||||||
fn process<'a, 'b: 'a, T>(
|
|
||||||
&self,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
input: Self::Input<'a, T>,
|
|
||||||
config: &Self::Config<'a, T>,
|
|
||||||
context: &mut Context<'b>,
|
|
||||||
) where
|
|
||||||
T: Send + Sync + Debug + PartialOrd + PartialEq + Copy + Clone + FromPrimitive,
|
|
||||||
{
|
|
||||||
let shape = input.shape();
|
|
||||||
if shape.len() == 2 {
|
|
||||||
let data = input.into_dimensionality::<Ix2>().unwrap();
|
|
||||||
let target = self.draw_2d(config, data, dims, context);
|
|
||||||
} else if shape.len() == 3 {
|
|
||||||
let data = input.into_dimensionality::<Ix3>().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> ElementOutput {
|
|
||||||
ElementOutput::Target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct MultiLayerGridImp();
|
|
||||||
|
|
||||||
impl MultiLayerGridImp {
|
|
||||||
fn draw<'a, 'b: 'a, T>(
|
|
||||||
&self,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
data: ArrayViewD<'a, T>,
|
|
||||||
config: &MultiLayerGridImpConfig<T>,
|
|
||||||
context: &mut Context<'b>,
|
|
||||||
) where
|
|
||||||
T: PartialOrd + PartialEq + Send + Sync + Debug + Copy + FromPrimitive,
|
|
||||||
{
|
|
||||||
let two = config.twod.clone();
|
|
||||||
let _layer = data.into_dimensionality::<Ix3>().unwrap();
|
|
||||||
let data = _layer.index_axis(Axis(0), config.layer).into_dyn();
|
|
||||||
|
|
||||||
two.process(dims, data, &config.two_d_config, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MultiLayerGridImpConfig<T>
|
|
||||||
where
|
|
||||||
T: PartialOrd + PartialEq + Send + Sync + Debug + Clone,
|
|
||||||
{
|
|
||||||
twod: GridImp,
|
|
||||||
two_d_config: GridImpConfig<T>,
|
|
||||||
layer: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementImp for MultiLayerGridImp {
|
|
||||||
type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq + Clone + FromPrimitive + 'a> =
|
|
||||||
MultiLayerGridImpConfig<T>;
|
|
||||||
type Input<'a, T: 'a> = ArrayViewD<'a, T>;
|
|
||||||
|
|
||||||
fn process<'a, 'b: 'a, T>(
|
|
||||||
&self,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
input: Self::Input<'a, T>,
|
|
||||||
config: &Self::Config<'a, T>,
|
|
||||||
context: &mut Context<'b>,
|
|
||||||
) where
|
|
||||||
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone + FromPrimitive,
|
|
||||||
{
|
|
||||||
self.draw(dims, input, config.upcast_ref(), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> ElementOutput {
|
|
||||||
ElementOutput::Target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct PolarElementImp();
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct PolarElementConfig<T>
|
|
||||||
where
|
|
||||||
T: PartialOrd + PartialEq + Send + Sync + Debug + Clone + FromPrimitive,
|
|
||||||
{
|
|
||||||
pub color_map: ColorMapperComb<T>,
|
|
||||||
pub fill_value: T,
|
|
||||||
pub center: (f64, f64),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PolarElementImp {
|
|
||||||
fn closest_value(&self, x: f64, dpi: f64) -> f64 {
|
|
||||||
let n_floor = (x / dpi).floor() as i64;
|
|
||||||
let value_at_n_floor = n_floor as f64 * dpi;
|
|
||||||
let value_at_n_floor_plus_one = (n_floor + 1) as f64 * dpi;
|
|
||||||
if (x - value_at_n_floor).abs() < (value_at_n_floor_plus_one - x).abs() {
|
|
||||||
value_at_n_floor
|
|
||||||
} else {
|
|
||||||
value_at_n_floor_plus_one
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map_to_polar(
|
|
||||||
&self,
|
|
||||||
center: (f64, f64),
|
|
||||||
dpi: (f64, f64),
|
|
||||||
max_r: f64,
|
|
||||||
point: (f64, f64),
|
|
||||||
) -> Option<(f64, f64)> {
|
|
||||||
let (center_lon, center_lat) = center;
|
|
||||||
let (lon, lat) = point;
|
|
||||||
|
|
||||||
let center_lon_rad = center_lon.to_radians();
|
|
||||||
let center_lat_rad = center_lat.to_radians();
|
|
||||||
let lon_rad = lon.to_radians();
|
|
||||||
let lat_rad = lat.to_radians();
|
|
||||||
|
|
||||||
let delta_lat = lat_rad - center_lat_rad;
|
|
||||||
let delta_lon = lon_rad - center_lon_rad;
|
|
||||||
|
|
||||||
let a = (delta_lat / 2.0).sin().powi(2)
|
|
||||||
+ center_lat_rad.cos() * lat_rad.cos() * (delta_lon / 2.0).sin().powi(2);
|
|
||||||
|
|
||||||
let c = 2.0 * a.sqrt().atan2((1.0 - a).sqrt());
|
|
||||||
|
|
||||||
let distance = EARTH_RADIUS * c * 1000.0;
|
|
||||||
|
|
||||||
if distance > max_r + dpi.1 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let x = delta_lon.cos() * lat_rad.sin();
|
|
||||||
let y = center_lat_rad.cos() * lat_rad.sin()
|
|
||||||
- center_lat_rad.sin() * lat_rad.cos() * delta_lon.cos();
|
|
||||||
let ori_degree = y.atan2(x).to_degrees();
|
|
||||||
let degree = (ori_degree + 360.0) % 360.0;
|
|
||||||
|
|
||||||
let distance_dpi = dpi.1;
|
|
||||||
let degree_dpi = dpi.0;
|
|
||||||
let final_degree = self.closest_value(degree, degree_dpi);
|
|
||||||
let final_distance = self.closest_value(distance, distance_dpi);
|
|
||||||
Some((final_degree, final_distance))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw<'a, T>(
|
|
||||||
&self,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
center: (f64, f64),
|
|
||||||
data: ArrayView2<T>,
|
|
||||||
config: &'a PolarElementConfig<T>,
|
|
||||||
context: &mut Context<'a>,
|
|
||||||
) where
|
|
||||||
T: PartialOrd + PartialEq + Send + Sync + Debug + Copy + FromPrimitive,
|
|
||||||
{
|
|
||||||
let canvas = &mut context.canvas;
|
|
||||||
let mapper = &context.cms;
|
|
||||||
let start_point = mapper.fore_map((0.0, 0.0));
|
|
||||||
|
|
||||||
let dpi = (
|
|
||||||
dims.0[[0, 1]] - dims.0[[0, 0]],
|
|
||||||
dims.1[[1, 1]] - dims.1[[1, 0]],
|
|
||||||
);
|
|
||||||
|
|
||||||
let (azs, rs) = dims;
|
|
||||||
|
|
||||||
let (w, h) = (canvas.width(), canvas.height());
|
|
||||||
|
|
||||||
for x in 0..w {
|
|
||||||
for y in 0..h {
|
|
||||||
let map_point = mapper.fore_map((x as f32 / w as f32, y as f32 / h as f32));
|
|
||||||
if map_point.is_none() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if let Some((_x, _y)) = self.map_to_polar(center, dpi, 0.0, map_point.unwrap()) {
|
|
||||||
let (_x, _y) = (_x as usize, _y as usize);
|
|
||||||
let value = data[[_x, _y]];
|
|
||||||
let color = config.color_map.color(value);
|
|
||||||
|
|
||||||
if color.is_none() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut path = Path::new();
|
|
||||||
path.rect(x as f32, y as f32, 1.0, 1.0);
|
|
||||||
canvas.fill_path(&path, &Paint::color(color.unwrap()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementImp for PolarElementImp {
|
|
||||||
type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq + Clone + FromPrimitive> = PolarElementConfig<T> where
|
|
||||||
T: 'a;
|
|
||||||
type Input<'a, T: 'a> = ArrayViewD<'a, T>;
|
|
||||||
fn process<'a, 'b: 'a, T>(
|
|
||||||
&self,
|
|
||||||
dims: (ArrayView2<f64>, ArrayView2<f64>),
|
|
||||||
input: Self::Input<'a, T>,
|
|
||||||
config: &Self::Config<'a, T>,
|
|
||||||
context: &mut Context<'b>,
|
|
||||||
) where
|
|
||||||
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone + FromPrimitive,
|
|
||||||
{
|
|
||||||
let shape = input.shape();
|
|
||||||
if shape.len() == 2 {
|
|
||||||
let data = input.into_dimensionality::<Ix2>().unwrap();
|
|
||||||
// self.draw(dims, config.center, data, config, context);
|
|
||||||
} else if shape.len() == 3 {
|
|
||||||
let data = input.into_dimensionality::<Ix3>().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_type(&self) -> ElementOutput {
|
|
||||||
ElementOutput::Target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> ElementConfig for GridImpConfig<T> where
|
|
||||||
T: Sync + Send + Debug + PartialOrd + PartialEq + Clone
|
|
||||||
{
|
|
||||||
}
|
|
||||||
impl<T> ElementConfig for MultiLayerGridImpConfig<T> where
|
|
||||||
T: Sync + Send + Debug + PartialOrd + PartialEq + Clone
|
|
||||||
{
|
|
||||||
}
|
|
||||||
impl<T> ElementConfig for PolarElementConfig<T> where
|
|
||||||
T: Sync + Send + Debug + PartialOrd + PartialEq + Clone + FromPrimitive
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum ElementImpl {
|
|
||||||
Grid(GridImp),
|
|
||||||
MultiLayerGrid(MultiLayerGridImp),
|
|
||||||
Polar(PolarElementImp),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ElementInput<'a, T> {
|
|
||||||
Grid(ArrayViewD<'a, T>),
|
|
||||||
MultiLayerGrid(ArrayViewD<'a, T>),
|
|
||||||
Polar(ArrayViewD<'a, T>),
|
|
||||||
}
|
|
||||||
|
|
||||||
for_all_variants!(impl_element_into_dispatch);
|
|
||||||
for_all_variants!(impl_element_try_from_dispatch);
|
|
||||||
for_all_variants!(impl_element_imp_dispatch);
|
|
||||||
@ -58,7 +58,7 @@ where
|
|||||||
panic!("Vector data is not supported")
|
panic!("Vector data is not supported")
|
||||||
}
|
}
|
||||||
DataShape::Matrix => {
|
DataShape::Matrix => {
|
||||||
let data: Radar2d<T> = first_block.clone().into();
|
let data:Radar2d<T> = first_block.clone().into();
|
||||||
let data = data.as_ref();
|
let data = data.as_ref();
|
||||||
let result = self.renderer.render(canvas, cms, &data, (3000.0, 3000.0));
|
let result = self.renderer.render(canvas, cms, &data, (3000.0, 3000.0));
|
||||||
result
|
result
|
||||||
|
|||||||
@ -1,19 +1,14 @@
|
|||||||
pub mod dispatcher;
|
pub mod dispatcher;
|
||||||
// pub mod element;
|
pub mod element;
|
||||||
// mod element_impl;
|
mod element_impl;
|
||||||
pub mod new_element;
|
mod new_pipeline;
|
||||||
// mod new_element_impl;
|
|
||||||
// mod new_pipeline;
|
|
||||||
pub mod offscreen_renderer;
|
pub mod offscreen_renderer;
|
||||||
// mod predefined;
|
mod predefined;
|
||||||
pub mod element_imp;
|
|
||||||
mod renders;
|
mod renders;
|
||||||
pub mod runner;
|
pub mod utils;
|
||||||
// pub mod utils;
|
|
||||||
|
|
||||||
pub use dispatcher::Dispatcher;
|
pub use dispatcher::Dispatcher;
|
||||||
// pub use element::*;
|
pub use element::*;
|
||||||
// pub use element_impl::*;
|
pub use element_impl::*;
|
||||||
// pub use new_pipeline::Pipeline;
|
pub use new_pipeline::Pipeline;
|
||||||
pub use new_element::*;
|
|
||||||
pub use offscreen_renderer::OffscreenRenderer;
|
pub use offscreen_renderer::OffscreenRenderer;
|
||||||
|
|||||||
@ -1,468 +0,0 @@
|
|||||||
use super::dispatcher;
|
|
||||||
use super::element_imp::Context;
|
|
||||||
use super::element_imp::ElementImpl;
|
|
||||||
use super::element_imp::ElementOutput;
|
|
||||||
use super::offscreen_renderer;
|
|
||||||
use super::offscreen_renderer::CanvasWrapper;
|
|
||||||
use super::runner;
|
|
||||||
use super::runner::Runner;
|
|
||||||
use super::Dispatcher;
|
|
||||||
use crate::coords::cms::CMS;
|
|
||||||
use crate::coords::Range;
|
|
||||||
use crate::data::MetaInfo;
|
|
||||||
use crate::pipeline::OffscreenRenderer;
|
|
||||||
use crate::widgets::Render;
|
|
||||||
use crate::PLUGIN_MANAGER;
|
|
||||||
use crate::RUNTIME;
|
|
||||||
use chrono::prelude::*;
|
|
||||||
use femtovg::ImageFlags;
|
|
||||||
use femtovg::ImageId;
|
|
||||||
use futures::future::BoxFuture;
|
|
||||||
use glow::HasContext;
|
|
||||||
use num_traits::AsPrimitive;
|
|
||||||
use num_traits::FromPrimitive;
|
|
||||||
use num_traits::Num;
|
|
||||||
use num_traits::NumOps;
|
|
||||||
use quick_cache::sync::Cache;
|
|
||||||
use radarg_plugin_interface::PluginResult;
|
|
||||||
use std::any::Any;
|
|
||||||
use std::borrow::BorrowMut;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt::Debug;
|
|
||||||
use std::hash::Hash;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::atomic::AtomicI32;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::RwLock;
|
|
||||||
use std::time::Duration;
|
|
||||||
use tokio::sync::oneshot;
|
|
||||||
use tokio::sync::{mpsc, Mutex};
|
|
||||||
use tracing::subscriber;
|
|
||||||
|
|
||||||
static ELEMENT_ID: AtomicI32 = AtomicI32::new(0);
|
|
||||||
pub type ElementID = i32;
|
|
||||||
pub type KVBuffer<T, V> = Cache<T, V>;
|
|
||||||
pub type Buffer<T> = KVBuffer<T, Arc<RwLock<RenderResult>>>;
|
|
||||||
|
|
||||||
pub type Data = Arc<PluginResult>;
|
|
||||||
|
|
||||||
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
|
|
||||||
pub struct Key {
|
|
||||||
pub id: ElementID,
|
|
||||||
pub name: String,
|
|
||||||
pub root: std::path::PathBuf,
|
|
||||||
pub datetime: Option<DateTime<Utc>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Target {
|
|
||||||
pub target: TargetType,
|
|
||||||
pub thumbnail: Option<gtk::gdk::Texture>,
|
|
||||||
pub width: f32,
|
|
||||||
pub height: f32,
|
|
||||||
pub bounds: (Range, Range),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
|
|
||||||
pub enum TargetType {
|
|
||||||
ImageId(ImageId),
|
|
||||||
Mem(Vec<u8>),
|
|
||||||
NativeBuffer(Vec<u8>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Target {
|
|
||||||
pub fn new(
|
|
||||||
target: TargetType,
|
|
||||||
width: f32,
|
|
||||||
height: f32,
|
|
||||||
bounds: (Range, Range),
|
|
||||||
thumbnail: Option<gtk::gdk::Texture>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
target,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
bounds,
|
|
||||||
thumbnail,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn size(&self, cms: &Render) -> (f32, f32) {
|
|
||||||
let (x, y) = self.bounds;
|
|
||||||
|
|
||||||
let p1 = (x.0, y.0);
|
|
||||||
let p2 = (x.1, y.1);
|
|
||||||
|
|
||||||
let (x1, y1) = cms.map(p1).unwrap();
|
|
||||||
let (x2, y2) = cms.map(p2).unwrap();
|
|
||||||
|
|
||||||
((x2 - x1).abs(), (y2 - y1).abs())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn native_buffer_to_native_texture(
|
|
||||||
&self,
|
|
||||||
gl: &glow::Context,
|
|
||||||
flags: ImageFlags,
|
|
||||||
) -> glow::NativeTexture {
|
|
||||||
if let TargetType::NativeBuffer(ref mem) = self.target {
|
|
||||||
use glow::*;
|
|
||||||
let texture = unsafe {
|
|
||||||
let id = gl.create_texture().unwrap();
|
|
||||||
gl.bind_texture(glow::TEXTURE_2D, Some(id));
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1);
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 3000 as i32);
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_SKIP_PIXELS, 0);
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_SKIP_ROWS, 0);
|
|
||||||
id
|
|
||||||
};
|
|
||||||
let width = 3000; // 纹理宽度
|
|
||||||
let height = 3000; // 纹理高度
|
|
||||||
unsafe {
|
|
||||||
gl.tex_image_2d(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
0, // level
|
|
||||||
glow::RGBA as i32, // internal_format
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
0, // border
|
|
||||||
glow::RGBA, // format
|
|
||||||
glow::UNSIGNED_BYTE, // type
|
|
||||||
Some(&mem), // pixels
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.contains(ImageFlags::GENERATE_MIPMAPS) {
|
|
||||||
if flags.contains(ImageFlags::NEAREST) {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_MIN_FILTER,
|
|
||||||
glow::NEAREST_MIPMAP_NEAREST as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_MIN_FILTER,
|
|
||||||
glow::LINEAR_MIPMAP_LINEAR as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if flags.contains(ImageFlags::NEAREST) {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_MIN_FILTER,
|
|
||||||
glow::NEAREST as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_MIN_FILTER,
|
|
||||||
glow::LINEAR as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.contains(ImageFlags::NEAREST) {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_MAG_FILTER,
|
|
||||||
glow::NEAREST as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_MAG_FILTER,
|
|
||||||
glow::LINEAR as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.contains(ImageFlags::REPEAT_X) {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_WRAP_S,
|
|
||||||
glow::REPEAT as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_WRAP_S,
|
|
||||||
glow::CLAMP_TO_EDGE as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.contains(ImageFlags::REPEAT_Y) {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_WRAP_T,
|
|
||||||
glow::REPEAT as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unsafe {
|
|
||||||
gl.tex_parameter_i32(
|
|
||||||
glow::TEXTURE_2D,
|
|
||||||
glow::TEXTURE_WRAP_T,
|
|
||||||
glow::CLAMP_TO_EDGE as i32,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 4);
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 0);
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_SKIP_PIXELS, 0);
|
|
||||||
gl.pixel_store_i32(glow::UNPACK_SKIP_ROWS, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if flags.contains(ImageFlags::GENERATE_MIPMAPS) {
|
|
||||||
unsafe {
|
|
||||||
gl.generate_mipmap(glow::TEXTURE_2D);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
gl.bind_texture(glow::TEXTURE_2D, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
return texture;
|
|
||||||
} else {
|
|
||||||
panic!("Target is not mem");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn origin(&self, cms: &Render) -> (f32, f32) {
|
|
||||||
let (x, y) = self.bounds;
|
|
||||||
let p1 = (x.0, y.1);
|
|
||||||
cms.map(p1).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_target(&mut self, target: TargetType) {
|
|
||||||
self.target = target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DataTarget {
|
|
||||||
pub data: Option<Data>,
|
|
||||||
target: Target,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DataTarget {
|
|
||||||
pub fn new(data: Option<Data>, target: Target) -> Self {
|
|
||||||
Self { data, target }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct RenderResult {
|
|
||||||
target: DataTarget,
|
|
||||||
meta_info: MetaInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RenderResult {
|
|
||||||
pub fn new(target: DataTarget, meta_info: MetaInfo) -> Self {
|
|
||||||
Self { target, meta_info }
|
|
||||||
}
|
|
||||||
pub fn get_meta_info(&self) -> MetaInfo {
|
|
||||||
self.meta_info.clone()
|
|
||||||
}
|
|
||||||
pub fn get_mut_target(&mut self) -> &mut Target {
|
|
||||||
&mut self.target.target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Element {
|
|
||||||
pub id: i32,
|
|
||||||
pub name: String,
|
|
||||||
pub cache: bool,
|
|
||||||
root: std::path::PathBuf,
|
|
||||||
config: Arc<dyn Any + Send + Sync>,
|
|
||||||
imp: ElementImpl,
|
|
||||||
subscribers: Arc<Mutex<HashMap<Key, Vec<oneshot::Sender<Arc<Mutex<PluginResult>>>>>>>,
|
|
||||||
cancellers: Arc<Mutex<HashMap<Key, oneshot::Sender<()>>>>,
|
|
||||||
current_key: Option<Key>,
|
|
||||||
dispatcher: Arc<Dispatcher>,
|
|
||||||
buffer: Arc<Buffer<Key>>,
|
|
||||||
file_pool: Arc<KVBuffer<PathBuf, Arc<PluginResult>>>,
|
|
||||||
current_target: Option<Arc<RwLock<RenderResult>>>,
|
|
||||||
cms: CMS,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub enum ElementEvent<'a> {
|
|
||||||
Init,
|
|
||||||
Draw,
|
|
||||||
DateTime(DateTime<Utc>),
|
|
||||||
Key(&'a Key),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Element {
|
|
||||||
pub fn new(
|
|
||||||
name: impl Into<String>,
|
|
||||||
cms: CMS,
|
|
||||||
dispatcher: Arc<Dispatcher>,
|
|
||||||
cache: bool,
|
|
||||||
config: Arc<dyn Any + Send + Sync>,
|
|
||||||
root: std::path::PathBuf,
|
|
||||||
buffer: Arc<Buffer<Key>>,
|
|
||||||
file_pool: Arc<KVBuffer<PathBuf, Arc<PluginResult>>>,
|
|
||||||
imp: ElementImpl,
|
|
||||||
) -> Self {
|
|
||||||
let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
Element {
|
|
||||||
id,
|
|
||||||
name: name.into(),
|
|
||||||
cache,
|
|
||||||
imp,
|
|
||||||
config,
|
|
||||||
root,
|
|
||||||
subscribers: Arc::new(Mutex::new(HashMap::new())),
|
|
||||||
cancellers: Arc::new(Mutex::new(HashMap::new())),
|
|
||||||
cms: cms,
|
|
||||||
current_key: None,
|
|
||||||
buffer,
|
|
||||||
file_pool,
|
|
||||||
current_target: None,
|
|
||||||
dispatcher,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn r<'b>(&mut self, event: ElementEvent<'b>, render: &Render) {
|
|
||||||
let need_cache = self.cache;
|
|
||||||
let output_type = self.imp.output_type();
|
|
||||||
|
|
||||||
fn _init(
|
|
||||||
this: &mut Element,
|
|
||||||
need_cache: bool,
|
|
||||||
output_type: ElementOutput,
|
|
||||||
render: &Render,
|
|
||||||
) {
|
|
||||||
let data = this.file_pool.get(&this.root);
|
|
||||||
if let Some(data) = data {
|
|
||||||
let target = this._rrrr(data, need_cache, output_type, render);
|
|
||||||
if let Some(target) = target {
|
|
||||||
let time = target.meta_info.datetime.unwrap();
|
|
||||||
let key = this.generate_key(time);
|
|
||||||
let target = Arc::new(RwLock::new(target));
|
|
||||||
this.buffer.insert(key, target.clone());
|
|
||||||
this.current_target = Some(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match event {
|
|
||||||
ElementEvent::Init => {
|
|
||||||
_init(self, need_cache, output_type, render);
|
|
||||||
}
|
|
||||||
ElementEvent::Draw => {
|
|
||||||
if let Some(current) = self.current_target.as_ref() {
|
|
||||||
let mut img = current.write().unwrap();
|
|
||||||
let mut img = img.get_mut_target();
|
|
||||||
render.draw_img(img);
|
|
||||||
} else {
|
|
||||||
_init(self, need_cache, output_type, render);
|
|
||||||
if let ElementOutput::Target = output_type {
|
|
||||||
let mut _img = self.current_target.as_ref().unwrap();
|
|
||||||
let mut img = _img.write().unwrap();
|
|
||||||
let mut img = img.get_mut_target();
|
|
||||||
render.draw_img(img);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ElementEvent::DateTime(time) => {
|
|
||||||
let path = self.dispatcher.get_single_path(&self.name, time, true);
|
|
||||||
path.map(|path| {
|
|
||||||
// let data = self.file_pool.get(&path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementEvent::Key(key) => {
|
|
||||||
self.buffer.get(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn insert_target_to_buffer(&self, key: Key, render_result: RenderResult) {
|
|
||||||
let result = Arc::new(RwLock::new(render_result));
|
|
||||||
self.buffer.insert(key, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn _rrrr(
|
|
||||||
&self,
|
|
||||||
data: Data,
|
|
||||||
need_cache: bool,
|
|
||||||
output_type: ElementOutput,
|
|
||||||
render: &Render,
|
|
||||||
) -> Option<RenderResult> {
|
|
||||||
match output_type {
|
|
||||||
ElementOutput::Target => {
|
|
||||||
use tokio::task;
|
|
||||||
let cms = self.cms.clone();
|
|
||||||
let imp = self.imp.clone();
|
|
||||||
let config = self.config.clone();
|
|
||||||
|
|
||||||
let handle = task::spawn_blocking(move || {
|
|
||||||
let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap();
|
|
||||||
let mut canvas = offscreen_renderer.create_canvas();
|
|
||||||
let mut context = Context::new(cms, &mut canvas);
|
|
||||||
let mut runner = Runner::new(imp, config, context);
|
|
||||||
let target = runner.run(&data);
|
|
||||||
let meta = data.meta.clone().into();
|
|
||||||
Some(RenderResult::new(DataTarget::new(Some(data), target), meta))
|
|
||||||
});
|
|
||||||
let result = RUNTIME.block_on(handle).ok().flatten();
|
|
||||||
result
|
|
||||||
// let result = RUNTIME.spawn(async {handle.await});
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {
|
|
||||||
let mut canvas = render.get_canvas();
|
|
||||||
let mut canvas = canvas.as_mut().unwrap();
|
|
||||||
let mut context = Context::new(self.cms.clone(), &mut canvas);
|
|
||||||
let mut runner = Runner::new(self.imp, self.config.clone(), context);
|
|
||||||
runner.run_without_target(&data);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_file(&self, path: impl AsRef<std::path::Path>) -> PluginResult {
|
|
||||||
let loader = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap();
|
|
||||||
let path = path.as_ref().as_os_str().to_str().unwrap();
|
|
||||||
let mut loaded_data = loader.load(path.into()).unwrap();
|
|
||||||
|
|
||||||
loaded_data
|
|
||||||
}
|
|
||||||
|
|
||||||
fn current_key(&self) -> Key {
|
|
||||||
self.current_key.clone().unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generate_key(&self, datetime: DateTime<Utc>) -> Key {
|
|
||||||
Key {
|
|
||||||
id: self.id,
|
|
||||||
name: self.name.clone(),
|
|
||||||
root: self.root.clone(),
|
|
||||||
datetime: Some(datetime),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn key(&self) -> String {
|
|
||||||
format!("{}-{}", self.id, self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,104 +0,0 @@
|
|||||||
use super::{
|
|
||||||
new_element::ElementImpl, offscreen_renderer::CanvasWrapper, predefined::GridFieldRenderer,
|
|
||||||
renders::DataRenderer, Target,
|
|
||||||
};
|
|
||||||
use crate::{
|
|
||||||
data::{Radar2d, Radar3d},
|
|
||||||
predefined::color_mapper::{BoundaryNorm, ColorMapper},
|
|
||||||
};
|
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps};
|
|
||||||
use radarg_plugin_interface::{DataShape, PluginResult};
|
|
||||||
use std::{any::Any, fmt::Debug, marker::PhantomData};
|
|
||||||
|
|
||||||
macro_rules! create_element_imp {
|
|
||||||
($imp: expr) => {{
|
|
||||||
let c: ElementImp = $imp.into();
|
|
||||||
c
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! element {
|
|
||||||
($generic:ident,$(($branch:tt,$imp:ty)),+) => {
|
|
||||||
pub(super) type ElementConfig = dyn Any + Send + Sync + 'static;
|
|
||||||
|
|
||||||
pub enum ElementImp<$generic>
|
|
||||||
where
|
|
||||||
$generic: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
|
|
||||||
{
|
|
||||||
$(
|
|
||||||
$branch($imp),
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<$generic> ElementImp<$generic>
|
|
||||||
where
|
|
||||||
$generic: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
|
|
||||||
{
|
|
||||||
pub fn render(
|
|
||||||
&self,
|
|
||||||
data: &PluginResult,
|
|
||||||
canvas: &mut CanvasWrapper,
|
|
||||||
cms: &mut crate::coords::cms::CMS,
|
|
||||||
config: &ElementConfig) -> Target
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
$(
|
|
||||||
ElementImp::$branch(imp) => imp.render(data,canvas,cms,config.downcast_ref::<<$imp as ElementImpl>::Config>().unwrap()),
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$(
|
|
||||||
impl<$generic> From<$imp> for ElementImp<$generic>
|
|
||||||
where
|
|
||||||
$generic: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
|
|
||||||
{
|
|
||||||
fn from(imp: $imp) -> Self {
|
|
||||||
ElementImp::$branch(imp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)+
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// element!(T, (Grid, GridElementImpl<T>));
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct GridElementImpl {}
|
|
||||||
|
|
||||||
impl GridElementImpl {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ElementImpl for GridElementImpl {
|
|
||||||
type Config = GridFieldRenderer<BoundaryNorm<T>, T>;
|
|
||||||
fn render(
|
|
||||||
&self,
|
|
||||||
data: &PluginResult,
|
|
||||||
canvas: &mut CanvasWrapper,
|
|
||||||
cms: &mut crate::coords::cms::CMS,
|
|
||||||
config: &Self::Config<T>,
|
|
||||||
) -> super::Target {
|
|
||||||
let first_block = data.blocks.first().unwrap();
|
|
||||||
match first_block.shape {
|
|
||||||
DataShape::Vector => {
|
|
||||||
panic!("Vector data is not supported")
|
|
||||||
}
|
|
||||||
DataShape::Matrix => {
|
|
||||||
let data: Radar2d<T> = first_block.clone().into();
|
|
||||||
let data = data.as_ref();
|
|
||||||
let result = config.render(canvas, cms, &data, (3000.0, 3000.0));
|
|
||||||
result
|
|
||||||
}
|
|
||||||
DataShape::Cube => {
|
|
||||||
let data: Radar3d<T> = first_block.clone().into();
|
|
||||||
let data = data.index_axis(ndarray::Axis(0), 0);
|
|
||||||
let result = config.render(canvas, cms, &data, (3000.0, 3000.0));
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -2,7 +2,7 @@ use super::{
|
|||||||
dispatcher::Dispatcher,
|
dispatcher::Dispatcher,
|
||||||
element::{DataTarget, RenderResult},
|
element::{DataTarget, RenderResult},
|
||||||
offscreen_renderer::{CanvasWrapper, OffscreenRenderer},
|
offscreen_renderer::{CanvasWrapper, OffscreenRenderer},
|
||||||
// utils::data_to_element,
|
utils::data_to_element,
|
||||||
};
|
};
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::pipeline::element::Target;
|
use crate::pipeline::element::Target;
|
||||||
@ -29,6 +29,18 @@ use tokio::{
|
|||||||
task,
|
task,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// #[derive(Clone, Debug)]
|
||||||
|
// pub struct RenderResult {
|
||||||
|
// target: Target,
|
||||||
|
// meta_info: MetaInfo,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl RenderResult {
|
||||||
|
// pub fn new(target: Target, meta_info: MetaInfo) -> Self {
|
||||||
|
// Self { target, meta_info }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
type RenderR = Result<RenderResult, RenderError>;
|
type RenderR = Result<RenderResult, RenderError>;
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
pool: Vec<BoxFuture<'static, ()>>,
|
pool: Vec<BoxFuture<'static, ()>>,
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use super::utils::*;
|
||||||
|
use crate::pipeline::element::Target;
|
||||||
use euclid::Size2D;
|
use euclid::Size2D;
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas};
|
||||||
use gl;
|
use gl;
|
||||||
@ -14,8 +16,6 @@ use surfman::{
|
|||||||
NativeConnection, NativeDevice,
|
NativeConnection, NativeDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Target;
|
|
||||||
|
|
||||||
pub struct OffscreenRenderer {
|
pub struct OffscreenRenderer {
|
||||||
context: Arc<RwLock<Context>>,
|
context: Arc<RwLock<Context>>,
|
||||||
device: Device,
|
device: Device,
|
||||||
@ -197,15 +197,3 @@ impl BorrowMut<Canvas<OpenGl>> for CanvasWrapper {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<Canvas<OpenGl>> for CanvasWrapper {
|
|
||||||
fn as_ref(&self) -> &Canvas<OpenGl> {
|
|
||||||
&self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsMut<Canvas<OpenGl>> for CanvasWrapper {
|
|
||||||
fn as_mut(&mut self) -> &mut Canvas<OpenGl> {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
|
use crate::pipeline::element::Target;
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas};
|
||||||
|
|
||||||
use super::Target;
|
|
||||||
|
|
||||||
pub trait DataRenderer<'a> {
|
pub trait DataRenderer<'a> {
|
||||||
type Data;
|
type Data;
|
||||||
fn render(
|
fn render(
|
||||||
|
|||||||
@ -1,154 +0,0 @@
|
|||||||
use std::{any::Any, sync::Arc};
|
|
||||||
|
|
||||||
use femtovg::{renderer::OpenGl, Canvas, RenderTarget};
|
|
||||||
use gl::types::GLvoid;
|
|
||||||
use image::Rgba;
|
|
||||||
use ndarray::{Array2, ArrayBase, ArrayView1, ArrayViewD};
|
|
||||||
use radarg_plugin_interface::{PluginResult, VecResult};
|
|
||||||
use smallvec::Array;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
pipeline::{
|
|
||||||
element_imp::{ElementInput, GridImpConfig},
|
|
||||||
TargetType,
|
|
||||||
},
|
|
||||||
utils::meshgrid,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
element_imp::{Context, ElementImp, ElementImpl},
|
|
||||||
Target,
|
|
||||||
};
|
|
||||||
|
|
||||||
macro_rules! impl_for_runner {
|
|
||||||
($imp:ident, $data:ident, $dims:expr, $size:ident, $config:ident, $context:ident, $({$t:tt},)+) => {
|
|
||||||
match $data {
|
|
||||||
$(
|
|
||||||
$t(ref v) => {
|
|
||||||
let input = ArrayViewD::from_shape($size, v.as_ref()).unwrap();
|
|
||||||
let data = ElementInput::Grid(input);
|
|
||||||
$imp.process($dims, data, $config, $context );
|
|
||||||
}
|
|
||||||
|
|
||||||
)+
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Runner<'a> {
|
|
||||||
imp: ElementImpl,
|
|
||||||
config: Arc<dyn Any>,
|
|
||||||
context: Context<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Runner<'a> {
|
|
||||||
pub fn new(imp: ElementImpl, config: Arc<dyn Any>, context: Context<'a>) -> Self {
|
|
||||||
Self {
|
|
||||||
imp,
|
|
||||||
config,
|
|
||||||
context,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self, data: &PluginResult) -> Target {
|
|
||||||
use femtovg::{ImageFlags, PixelFormat::Rgba8};
|
|
||||||
let canvas = &mut self.context.canvas;
|
|
||||||
let (w, h) = (canvas.width(), canvas.height());
|
|
||||||
|
|
||||||
let new_img = canvas
|
|
||||||
.create_image_empty(w as usize, h as usize, Rgba8, ImageFlags::empty())
|
|
||||||
.expect("Can't Create Image");
|
|
||||||
canvas.image_size(new_img).unwrap();
|
|
||||||
canvas.set_render_target(RenderTarget::Image(new_img));
|
|
||||||
|
|
||||||
// Drawing
|
|
||||||
let dims = self.run_without_target(data);
|
|
||||||
|
|
||||||
// Reading Pixels
|
|
||||||
let mut pixels: Vec<u8> = vec![0; w as usize * h as usize * 4];
|
|
||||||
unsafe {
|
|
||||||
gl::ReadPixels(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
w as i32,
|
|
||||||
h as i32,
|
|
||||||
gl::RGBA,
|
|
||||||
gl::UNSIGNED_BYTE,
|
|
||||||
pixels.as_mut_ptr() as *mut GLvoid,
|
|
||||||
);
|
|
||||||
debug_assert_eq!(gl::GetError(), gl::NO_ERROR);
|
|
||||||
}
|
|
||||||
self.context.canvas.set_render_target(RenderTarget::Screen);
|
|
||||||
let d1_start = (dims.0.view()).first().unwrap().clone();
|
|
||||||
let d1_end = (dims.0.view()).last().unwrap().clone();
|
|
||||||
let d2_start = dims.1.view().first().unwrap().clone();
|
|
||||||
let d2_end = dims.1.view().last().unwrap().clone();
|
|
||||||
|
|
||||||
Target::new(
|
|
||||||
TargetType::NativeBuffer(pixels),
|
|
||||||
w as f32,
|
|
||||||
h as f32,
|
|
||||||
((d1_start, d1_end).into(), (d2_start, d2_end).into()),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_without_target(&mut self, data: &PluginResult) -> (Array2<f64>, Array2<f64>) {
|
|
||||||
let block = data.blocks.first().unwrap();
|
|
||||||
let data = &block.data;
|
|
||||||
let dims = &block.dimension_values;
|
|
||||||
|
|
||||||
let dims = if dims.len() == 3 {
|
|
||||||
let (a, b) = (
|
|
||||||
ArrayView1::from(dims[2].as_ref()),
|
|
||||||
ArrayView1::from(dims[1].as_ref()),
|
|
||||||
);
|
|
||||||
meshgrid(a, b)
|
|
||||||
} else {
|
|
||||||
let (a, b) = (
|
|
||||||
ArrayView1::from(dims[1].as_ref()),
|
|
||||||
ArrayView1::from(dims[0].as_ref()),
|
|
||||||
);
|
|
||||||
meshgrid(a, b)
|
|
||||||
};
|
|
||||||
|
|
||||||
let size = block.size.to_owned().to_vec();
|
|
||||||
let config = &*self.config;
|
|
||||||
let imp: &ElementImpl = &self.imp;
|
|
||||||
let context = &mut self.context;
|
|
||||||
let cms = &mut context.cms;
|
|
||||||
let canvas = &mut context.canvas;
|
|
||||||
let (w, h) = (canvas.width(), canvas.height());
|
|
||||||
|
|
||||||
let lat_start = dims.1.view().first().unwrap().clone();
|
|
||||||
let lat_end = dims.1.view().last().unwrap().clone();
|
|
||||||
|
|
||||||
let lon_start = dims.0.view().first().unwrap().clone();
|
|
||||||
let lon_end = dims.0.view().last().unwrap().clone();
|
|
||||||
|
|
||||||
cms.set_lat_range(lat_start..lat_end);
|
|
||||||
cms.set_lon_range(lon_start..lon_end);
|
|
||||||
|
|
||||||
use VecResult::*;
|
|
||||||
|
|
||||||
impl_for_runner!(
|
|
||||||
imp,
|
|
||||||
data,
|
|
||||||
(dims.0.view(), dims.1.view()),
|
|
||||||
size,
|
|
||||||
config,
|
|
||||||
context,
|
|
||||||
{ I32 },
|
|
||||||
{ F64 },
|
|
||||||
{ I64 },
|
|
||||||
{ F32 },
|
|
||||||
{ I8 },
|
|
||||||
{ U8 },
|
|
||||||
{ I16 },
|
|
||||||
{ U64 },
|
|
||||||
{ U32 },
|
|
||||||
);
|
|
||||||
context.canvas.flush();
|
|
||||||
dims
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -73,10 +73,9 @@ impl PluginManager {
|
|||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
registered_plugins: HashMap::new(),
|
registered_plugins: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
for (plugin_name, config) in CONFIG.lock().unwrap().plugins.iter() {
|
||||||
for plugin in CONFIG.read().unwrap().plugin_config.iter() {
|
if let Ok((id, p)) = init_plugin(plugin_name.to_owned()) {
|
||||||
if let Ok((id, p)) = init_plugin(plugin.name.to_owned()) {
|
println!("Loaded plugin: {}", plugin_name);
|
||||||
println!("Loaded plugin: {}", plugin.name);
|
|
||||||
this.registered_plugins.insert(id, p);
|
this.registered_plugins.insert(id, p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,276 +1,117 @@
|
|||||||
use abi_stable::type_level::trait_marker::Default;
|
|
||||||
use femtovg::Color;
|
|
||||||
use image::imageops::ColorMap;
|
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, NumOps};
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
pub type BoundaryNormDiscrete<T> = ColorMapper<T, Discrete, BoundaryNorm<T>>;
|
use femtovg::Color;
|
||||||
macro_rules! color_mapper_comb {
|
use num_traits::{AsPrimitive, FromPrimitive, NumOps};
|
||||||
($comb: ident, $($key: tt,)+) => {
|
pub trait ColorMapper<T: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64>>:
|
||||||
|
Debug + Send + Sync
|
||||||
|
{
|
||||||
|
fn map_value_to_color(&self, value: T, invalid: T) -> Option<femtovg::Color>;
|
||||||
|
|
||||||
impl<T: PartialEq + PartialOrd + Debug + Clone> $comb<T> {
|
fn map_min_to_max(&self) -> Vec<femtovg::Color>;
|
||||||
|
|
||||||
pub fn color(&self, value: T) -> Option<femtovg::Color> {
|
fn labels(&self) -> Vec<String>;
|
||||||
match self {
|
|
||||||
$(
|
|
||||||
Self::$key(mapper) => mapper.color(value),
|
|
||||||
)+
|
|
||||||
|
|
||||||
_ => None,
|
fn min_max(&self) -> (T, T);
|
||||||
}
|
fn invalid(&self) -> T;
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<BoundaryNormDiscrete<T>> for $comb<T>
|
|
||||||
where
|
|
||||||
T: PartialEq + PartialOrd + Debug + Clone,
|
|
||||||
{
|
|
||||||
fn from(v: BoundaryNormDiscrete<T>) -> Self {
|
|
||||||
Self::BoundaryNormDiscrete(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ColorMapperComb<T: PartialEq + PartialOrd + Debug + Clone> {
|
pub struct BoundaryNorm<T: NumOps + PartialOrd> {
|
||||||
BoundaryNormDiscrete(BoundaryNormDiscrete<T>),
|
|
||||||
Unknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> std::default::Default for ColorMapperComb<T>
|
|
||||||
where
|
|
||||||
T: PartialEq + PartialOrd + Debug + Clone,
|
|
||||||
{
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::Unknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
color_mapper_comb!(ColorMapperComb, BoundaryNormDiscrete,);
|
|
||||||
|
|
||||||
pub trait VMap {
|
|
||||||
type Ty;
|
|
||||||
fn map(&self, v: Self::Ty) -> Option<f32>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CMap {
|
|
||||||
fn map(&self, v: f32) -> femtovg::Color;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ColorMapper<T, CMAP, VMAP>
|
|
||||||
where
|
|
||||||
CMAP: CMap + Clone,
|
|
||||||
VMAP: VMap<Ty = T> + Clone,
|
|
||||||
{
|
|
||||||
cmap: CMAP,
|
|
||||||
vmap: VMAP,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, CMAP, VMAP> ColorMapper<T, CMAP, VMAP>
|
|
||||||
where
|
|
||||||
T: PartialEq + PartialOrd,
|
|
||||||
CMAP: CMap + Clone,
|
|
||||||
VMAP: VMap<Ty = T> + Clone,
|
|
||||||
{
|
|
||||||
pub fn new(cmap: CMAP, vmap: VMAP) -> Self {
|
|
||||||
Self { cmap, vmap }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn color(&self, value: T) -> Option<femtovg::Color> {
|
|
||||||
self.vmap.map(value).map(|v| self.cmap.map(v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct BoundaryNorm<T: PartialOrd + PartialEq> {
|
|
||||||
boundaries: Vec<T>,
|
boundaries: Vec<T>,
|
||||||
extrand: bool,
|
extrand: bool,
|
||||||
invalid_value: Option<T>,
|
colors: Vec<femtovg::Color>,
|
||||||
|
invalid_value: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: PartialEq + PartialOrd> BoundaryNorm<T> {
|
impl Default for BoundaryNorm<i8> {
|
||||||
pub fn new(boundaries: Vec<T>, extrand: bool, invalid_value: Option<T>) -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
boundaries: vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65],
|
||||||
|
extrand: true,
|
||||||
|
colors: vec![
|
||||||
|
Color::rgb(0, 172, 164),
|
||||||
|
Color::rgb(192, 192, 254),
|
||||||
|
Color::rgb(122, 114, 238),
|
||||||
|
Color::rgb(30, 38, 208),
|
||||||
|
Color::rgb(166, 252, 168),
|
||||||
|
Color::rgb(0, 234, 0),
|
||||||
|
Color::rgb(16, 146, 26),
|
||||||
|
Color::rgb(252, 244, 100),
|
||||||
|
Color::rgb(200, 200, 2),
|
||||||
|
Color::rgb(140, 140, 0),
|
||||||
|
Color::rgb(254, 172, 172),
|
||||||
|
Color::rgb(254, 100, 92),
|
||||||
|
Color::rgb(238, 2, 48),
|
||||||
|
Color::rgb(212, 142, 254),
|
||||||
|
Color::rgb(170, 36, 250),
|
||||||
|
],
|
||||||
|
invalid_value: -125,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NumOps + PartialOrd> BoundaryNorm<T> {
|
||||||
|
pub fn new(
|
||||||
|
boundaries: Vec<T>,
|
||||||
|
colors: Vec<femtovg::Color>,
|
||||||
|
extrand: bool,
|
||||||
|
invalid_value: T,
|
||||||
|
) -> Self {
|
||||||
|
// assert_eq!(boundaries.len(), colors.len() + 1);
|
||||||
|
BoundaryNorm {
|
||||||
boundaries,
|
boundaries,
|
||||||
extrand,
|
extrand,
|
||||||
|
colors,
|
||||||
invalid_value,
|
invalid_value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> VMap for BoundaryNorm<T>
|
pub fn map_value_to_color(&self, value: T, invalid_value: T) -> Option<femtovg::Color> {
|
||||||
where
|
|
||||||
T: PartialOrd + PartialEq + Debug,
|
|
||||||
{
|
|
||||||
type Ty = T;
|
|
||||||
fn map(&self, v: Self::Ty) -> Option<f32> {
|
|
||||||
let mut index = 0;
|
let mut index = 0;
|
||||||
if let Some(invalid_value) = &self.invalid_value {
|
if value == invalid_value {
|
||||||
if v == *invalid_value {
|
return None;
|
||||||
return None;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, boundary) in self.boundaries.iter().enumerate() {
|
for (i, boundary) in self.boundaries.iter().enumerate() {
|
||||||
if v < *boundary {
|
if value < *boundary {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
index = i;
|
index = i;
|
||||||
}
|
}
|
||||||
|
index = index.saturating_sub(1).min(self.colors.len() - 1);
|
||||||
Some(index as f32 / self.boundaries.len() as f32)
|
Some(self.colors[index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl<T> ColorMapper<T> for BoundaryNorm<T>
|
||||||
pub struct Gradient {}
|
where
|
||||||
|
T: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
|
||||||
|
{
|
||||||
|
fn map_value_to_color(&self, value: T, invalid_value: T) -> Option<femtovg::Color> {
|
||||||
|
self.map_value_to_color(value, invalid_value)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
fn min_max(&self) -> (T, T) {
|
||||||
pub struct Discrete {
|
(
|
||||||
colors: Vec<femtovg::Color>,
|
self.boundaries.first().unwrap().clone(),
|
||||||
}
|
self.boundaries.last().unwrap().clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
impl Discrete {
|
fn invalid(&self) -> T {
|
||||||
pub fn new(colors: Vec<femtovg::Color>) -> Self {
|
self.invalid_value.clone()
|
||||||
Self { colors }
|
}
|
||||||
|
|
||||||
|
fn map_min_to_max(&self) -> Vec<femtovg::Color> {
|
||||||
|
self.boundaries
|
||||||
|
.iter()
|
||||||
|
.map(|x| self.map_value_to_color(*x, self.invalid_value).unwrap())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn labels(&self) -> Vec<String> {
|
||||||
|
self.boundaries
|
||||||
|
.iter()
|
||||||
|
.map(|x| format!("{:.2}", x.as_()))
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CMap for Discrete {
|
|
||||||
fn map(&self, v: f32) -> Color {
|
|
||||||
let size = (self.colors.len() as f32 * v) as usize;
|
|
||||||
self.colors.get(size).unwrap().clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[derive(Debug, Clone)]
|
|
||||||
// pub struct BoundaryNorm<T: NumOps + PartialOrd> {
|
|
||||||
// boundaries: Vec<T>,
|
|
||||||
// extrand: bool,
|
|
||||||
// colors: Vec<femtovg::Color>,
|
|
||||||
// invalid_value: T,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Default for BoundaryNorm<i8> {
|
|
||||||
// fn default() -> Self {
|
|
||||||
// Self {
|
|
||||||
// boundaries: vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65],
|
|
||||||
// extrand: true,
|
|
||||||
// colors: vec![
|
|
||||||
// Color::rgb(0, 172, 164),
|
|
||||||
// Color::rgb(192, 192, 254),
|
|
||||||
// Color::rgb(122, 114, 238),
|
|
||||||
// Color::rgb(30, 38, 208),
|
|
||||||
// Color::rgb(166, 252, 168),
|
|
||||||
// Color::rgb(0, 234, 0),
|
|
||||||
// Color::rgb(16, 146, 26),
|
|
||||||
// Color::rgb(252, 244, 100),
|
|
||||||
// Color::rgb(200, 200, 2),
|
|
||||||
// Color::rgb(140, 140, 0),
|
|
||||||
// Color::rgb(254, 172, 172),
|
|
||||||
// Color::rgb(254, 100, 92),
|
|
||||||
// Color::rgb(238, 2, 48),
|
|
||||||
// Color::rgb(212, 142, 254),
|
|
||||||
// Color::rgb(170, 36, 250),
|
|
||||||
// ],
|
|
||||||
// invalid_value: -125,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl<T: NumOps + PartialOrd> BoundaryNorm<T> {
|
|
||||||
// pub fn new(
|
|
||||||
// boundaries: Vec<T>,
|
|
||||||
// colors: Vec<femtovg::Color>,
|
|
||||||
// extrand: bool,
|
|
||||||
// invalid_value: T,
|
|
||||||
// ) -> Self {
|
|
||||||
// // assert_eq!(boundaries.len(), colors.len() + 1);
|
|
||||||
// BoundaryNorm {
|
|
||||||
// boundaries,
|
|
||||||
// extrand,
|
|
||||||
// colors,
|
|
||||||
// invalid_value,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn map_value_to_color(&self, value: f64, invalid_value: f64) -> Option<femtovg::Color> {
|
|
||||||
// let mut index = 0;
|
|
||||||
// if value == invalid_value {
|
|
||||||
// return None;
|
|
||||||
// }
|
|
||||||
// for (i, boundary) in self.boundaries.iter().enumerate() {
|
|
||||||
// if value < *boundary {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// index = i;
|
|
||||||
// }
|
|
||||||
// index = index.saturating_sub(1).min(self.colors.len() - 1);
|
|
||||||
// Some(self.colors[index])
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl<T> ColorMapper for BoundaryNorm<T>
|
|
||||||
// where
|
|
||||||
// T: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug,
|
|
||||||
// {
|
|
||||||
//
|
|
||||||
// type Ty<V> = T;
|
|
||||||
// fn map_value_to_color<T>(&self, value: Self::Ty<T>, invalid_value: Self::Ty<T>) -> Option<femtovg::Color> {
|
|
||||||
// self.map_value_to_color(value, invalid_value)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn min_max(&self) -> (f64, f64) {
|
|
||||||
// (
|
|
||||||
// self.boundaries.first().unwrap().clone().as_(),
|
|
||||||
// self.boundaries.last().unwrap().clone().as_(),
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn invalid(&self) -> f64 {
|
|
||||||
// self.invalid_value.clone().as_()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn map_min_to_max(&self) -> Vec<femtovg::Color> {
|
|
||||||
// self.boundaries
|
|
||||||
// .iter()
|
|
||||||
// .map(|x| self.map_value_to_color(*x, self.invalid_value).unwrap())
|
|
||||||
// .collect()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub struct BoundaryNorm();
|
|
||||||
//
|
|
||||||
// impl ColorMapper for BoundaryNorm {
|
|
||||||
// type Ty<T> = T;
|
|
||||||
// fn map_value_to_color<T>(&self, value: Self::Ty<T>, invalid: T) -> Option<femtovg::Color> {
|
|
||||||
// let mut index = 0;
|
|
||||||
// if value == invalid_value {
|
|
||||||
// return None;
|
|
||||||
// }
|
|
||||||
// for (i, boundary) in self.boundaries.iter().enumerate() {
|
|
||||||
// if value < *boundary {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// index = i;
|
|
||||||
// }
|
|
||||||
// index = index.saturating_sub(1).min(self.colors.len() - 1);
|
|
||||||
// Some(self.colors[index])
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn map_min_to_max(&self) -> Vec<femtovg::Color> {
|
|
||||||
// vec![]
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn min_max(&self) -> (f64, f64) {
|
|
||||||
// (0.0, 0.0)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn invalid(&self) -> f64 {
|
|
||||||
// 0.0
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::components::widget::{Widget, WidgetType};
|
use crate::components::widget::{Widget, WidgetType};
|
||||||
use crate::predefined::color_mapper::ColorMapper;
|
use crate::predefined::color_mapper::ColorMapper;
|
||||||
use crate::widgets::Layer;
|
use crate::widgets::{AssoElement, Layer};
|
||||||
use femtovg::{renderer::OpenGl, Canvas, Color, Paint, Path};
|
use femtovg::{renderer::OpenGl, Canvas, Color, Paint, Path};
|
||||||
use num_traits::*;
|
use num_traits::*;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
@ -39,6 +39,17 @@ impl Widget for ColorBar {
|
|||||||
|
|
||||||
let first = layers.first().unwrap();
|
let first = layers.first().unwrap();
|
||||||
|
|
||||||
|
match first.get_associated_element() {
|
||||||
|
AssoElement::Instant(i) => {
|
||||||
|
let imp = i.imp();
|
||||||
|
}
|
||||||
|
AssoElement::TimeSeries(t) => {
|
||||||
|
let c = t.lock().unwrap();
|
||||||
|
let imp = c.imp();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
// for ((i, color), label) in self
|
// for ((i, color), label) in self
|
||||||
// .color_list
|
// .color_list
|
||||||
// .iter()
|
// .iter()
|
||||||
|
|||||||
431
src/utils.rs
431
src/utils.rs
@ -1,16 +1,17 @@
|
|||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use euclid::Size2D;
|
|
||||||
use femtovg::Canvas;
|
|
||||||
use femtovg::Color;
|
use femtovg::Color;
|
||||||
use gtk::glib::{HasParamSpec, ParamSpecInt64, ParamSpecInt64Builder};
|
use gtk::glib::{HasParamSpec, ParamSpecInt64, ParamSpecInt64Builder};
|
||||||
use ndarray::{Array2, ArrayView1};
|
|
||||||
use std::{borrow::BorrowMut, num::NonZeroU32};
|
use std::{borrow::BorrowMut, num::NonZeroU32};
|
||||||
|
|
||||||
|
use euclid::Size2D;
|
||||||
|
use femtovg::Canvas;
|
||||||
|
use ndarray::{Array2, ArrayView1};
|
||||||
use surfman::{
|
use surfman::{
|
||||||
Connection, Context, ContextAttributeFlags, ContextAttributes, ContextDescriptor, Device,
|
Connection, Context, ContextAttributeFlags, ContextAttributes, ContextDescriptor, Device,
|
||||||
GLVersion, NativeConnection, NativeContext, SurfaceAccess, SurfaceType,
|
GLVersion, NativeConnection, NativeContext, SurfaceAccess, SurfaceType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::predefined::color_mapper::{BoundaryNorm, BoundaryNormDiscrete, Discrete};
|
use crate::predefined::color_mapper::BoundaryNorm;
|
||||||
use crate::RUNTIME;
|
use crate::RUNTIME;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -30,24 +31,11 @@ where
|
|||||||
(xx, yy)
|
(xx, yy)
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! default_cvmapers {
|
pub fn create_dbz_boundarynorm() -> BoundaryNorm<i8> {
|
||||||
($({
|
BoundaryNorm::new(
|
||||||
$key: ident, $value: expr, $colors: expr, $_ty:ty
|
vec![
|
||||||
}),+ $(,)?) => {
|
-5, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75,
|
||||||
$(
|
],
|
||||||
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![
|
vec![
|
||||||
Color::rgb(23, 174, 165),
|
Color::rgb(23, 174, 165),
|
||||||
Color::rgb(198, 195, 253),
|
Color::rgb(198, 195, 253),
|
||||||
@ -66,14 +54,16 @@ default_cvmapers! {
|
|||||||
Color::rgb(150, 0, 180),
|
Color::rgb(150, 0, 180),
|
||||||
Color::rgb(139, 0, 255),
|
Color::rgb(139, 0, 255),
|
||||||
],
|
],
|
||||||
i8
|
true,
|
||||||
},
|
-125,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
{
|
pub fn create_vel_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
create_vel_default_cvmapper,
|
BoundaryNorm::new(
|
||||||
vec![
|
vec![
|
||||||
-35, -27, -20, -15, -10, -5, -1, 0, 1, 5, 10, 15, 20, 27,
|
-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,
|
35.0,
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Color::rgb(0, 224, 255),
|
Color::rgb(0, 224, 255),
|
||||||
@ -91,10 +81,13 @@ default_cvmapers! {
|
|||||||
Color::rgb(208, 112, 0),
|
Color::rgb(208, 112, 0),
|
||||||
Color::rgb(255, 0, 0),
|
Color::rgb(255, 0, 0),
|
||||||
],
|
],
|
||||||
i8
|
true,
|
||||||
},
|
-125.0,
|
||||||
{
|
)
|
||||||
create_phidp_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_phidp_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![
|
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,
|
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,
|
292.0, 314.0, 359.0,
|
||||||
@ -116,10 +109,13 @@ default_cvmapers! {
|
|||||||
Color::rgb(255, 31, 0),
|
Color::rgb(255, 31, 0),
|
||||||
Color::rgb(193, 0, 0),
|
Color::rgb(193, 0, 0),
|
||||||
],
|
],
|
||||||
f32
|
true,
|
||||||
},
|
-125.0,
|
||||||
{
|
)
|
||||||
create_zdr_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_zdr_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![
|
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,
|
-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,
|
||||||
],
|
],
|
||||||
@ -138,10 +134,13 @@ default_cvmapers! {
|
|||||||
Color::rgb(220, 240, 220),
|
Color::rgb(220, 240, 220),
|
||||||
Color::rgb(0, 192, 39),
|
Color::rgb(0, 192, 39),
|
||||||
],
|
],
|
||||||
f32
|
true,
|
||||||
},
|
-125.0,
|
||||||
{
|
)
|
||||||
create_cc_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_cc_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![
|
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,
|
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,
|
||||||
],
|
],
|
||||||
@ -162,10 +161,13 @@ default_cvmapers! {
|
|||||||
Color::rgb(255, 31, 0),
|
Color::rgb(255, 31, 0),
|
||||||
Color::rgb(193, 0, 0),
|
Color::rgb(193, 0, 0),
|
||||||
],
|
],
|
||||||
f32
|
true,
|
||||||
},
|
-125.0,
|
||||||
{
|
)
|
||||||
create_vil_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_vil_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![
|
vec![
|
||||||
1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35., 40., 45., 50., 55., 60., 65., 70.,
|
1.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 35., 40., 45., 50., 55., 60., 65., 70.,
|
||||||
],
|
],
|
||||||
@ -185,10 +187,13 @@ default_cvmapers! {
|
|||||||
Color::rgb(0, 0, 255),
|
Color::rgb(0, 0, 255),
|
||||||
Color::rgb(255, 255, 255),
|
Color::rgb(255, 255, 255),
|
||||||
],
|
],
|
||||||
f32
|
true,
|
||||||
},
|
-125.0,
|
||||||
{
|
)
|
||||||
create_hgt_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_hgt_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![
|
vec![
|
||||||
0.0, 2.0, 3.0, 5.0, 6.0, 8.0, 9.0, 11., 12., 14., 15., 17., 18., 20., 21.,
|
0.0, 2.0, 3.0, 5.0, 6.0, 8.0, 9.0, 11., 12., 14., 15., 17., 18., 20., 21.,
|
||||||
],
|
],
|
||||||
@ -204,14 +209,17 @@ default_cvmapers! {
|
|||||||
Color::rgb(0, 239, 0),
|
Color::rgb(0, 239, 0),
|
||||||
Color::rgb(254, 191, 0),
|
Color::rgb(254, 191, 0),
|
||||||
Color::rgb(255, 255, 0),
|
Color::rgb(255, 255, 0),
|
||||||
Color::rgb(174, 0, 0),
|
Color::rgb(174, 0, 0),
|
||||||
Color::rgb(255, 0, 0),
|
Color::rgb(255, 0, 0),
|
||||||
Color::rgb(255, 255, 255),
|
Color::rgb(255, 255, 255),
|
||||||
],
|
],
|
||||||
f32
|
true,
|
||||||
},
|
-125.0,
|
||||||
{
|
)
|
||||||
create_et_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_et_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![
|
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,
|
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,
|
18.0, 20.0, 21.0,
|
||||||
@ -236,10 +244,13 @@ default_cvmapers! {
|
|||||||
Color::rgb(205, 0, 0),
|
Color::rgb(205, 0, 0),
|
||||||
Color::rgb(139, 0, 0),
|
Color::rgb(139, 0, 0),
|
||||||
],
|
],
|
||||||
f32
|
true,
|
||||||
},
|
-125.0,
|
||||||
{
|
)
|
||||||
create_cpc_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_cpc_boundarynorm() -> BoundaryNorm<i8> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
||||||
vec![
|
vec![
|
||||||
Color::rgb(201, 196, 191),
|
Color::rgb(201, 196, 191),
|
||||||
@ -254,10 +265,13 @@ default_cvmapers! {
|
|||||||
Color::rgb(55, 90, 165),
|
Color::rgb(55, 90, 165),
|
||||||
Color::rgb(187, 165, 204),
|
Color::rgb(187, 165, 204),
|
||||||
],
|
],
|
||||||
i8
|
true,
|
||||||
},
|
-125,
|
||||||
{
|
)
|
||||||
create_kdp_default_cvmapper,
|
}
|
||||||
|
|
||||||
|
pub fn create_kdp_boundarynorm() -> BoundaryNorm<f32> {
|
||||||
|
BoundaryNorm::new(
|
||||||
vec![
|
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,
|
-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,
|
||||||
],
|
],
|
||||||
@ -279,285 +293,11 @@ default_cvmapers! {
|
|||||||
Color::rgb(187, 0, 58),
|
Color::rgb(187, 0, 58),
|
||||||
Color::rgb(253, 6, 253),
|
Color::rgb(253, 6, 253),
|
||||||
],
|
],
|
||||||
f32
|
true,
|
||||||
}
|
-125.0,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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(
|
pub fn estimate_zoom_level(
|
||||||
lat_min: f64,
|
lat_min: f64,
|
||||||
lon_min: f64,
|
lon_min: f64,
|
||||||
@ -587,18 +327,3 @@ pub fn estimate_zoom_level(
|
|||||||
|
|
||||||
zoom_level_estimation.round() as u8
|
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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -4,9 +4,8 @@ use super::{Layer, WindowCoord};
|
|||||||
use crate::coords::proj::Mercator;
|
use crate::coords::proj::Mercator;
|
||||||
use crate::coords::Mapper;
|
use crate::coords::Mapper;
|
||||||
use crate::map_tile::MapTile;
|
use crate::map_tile::MapTile;
|
||||||
use crate::pipeline::new_element::{Target, TargetType};
|
use crate::pipeline::element::{Target, TargetType};
|
||||||
use femtovg::{Canvas, Color, FontId, Paint, Renderer};
|
use femtovg::{Canvas, Color, FontId, Paint, Renderer};
|
||||||
use glow::HasContext;
|
|
||||||
use gtk::glib::{self, prelude::*, Properties};
|
use gtk::glib::{self, prelude::*, Properties};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
|
|||||||
@ -1,20 +1,30 @@
|
|||||||
use super::super::Render;
|
use super::super::Render;
|
||||||
|
use crate::coords::cms::CMS;
|
||||||
use crate::errors::PipelineError;
|
use crate::errors::PipelineError;
|
||||||
use crate::pipeline::new_element::{self, Target};
|
use crate::pipeline::element::{self, Target};
|
||||||
use crate::pipeline::new_element::{Element, ElementEvent};
|
use crate::pipeline::offscreen_renderer::CanvasWrapper;
|
||||||
use crate::RUNTIME;
|
use chrono::{prelude::*, DateTime};
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas};
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
type PrepareFunc = Arc<
|
||||||
pub enum ElementType {
|
Mutex<
|
||||||
Asso,
|
Option<
|
||||||
Indenpendent,
|
Box<dyn FnOnce(LayerImplSync, Arc<Mutex<CanvasWrapper>>, CMS) -> Target + Sync + Send>,
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
>;
|
||||||
|
type DrawFunc = Arc<dyn Fn(&Layer, Render, (f32, f32)) + Send + Sync>;
|
||||||
|
pub type LayerImplSync = Arc<Mutex<Box<dyn LayerImpl + Send + Sync>>>;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum AssoElement {
|
||||||
|
TimeSeries(Arc<Mutex<element::TimeSeriesElement>>),
|
||||||
|
Instant(element::InstantElement),
|
||||||
|
Test,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -22,8 +32,8 @@ pub struct Layer {
|
|||||||
pub visiable: bool,
|
pub visiable: bool,
|
||||||
pub alpha: f32,
|
pub alpha: f32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
element_type: ElementType,
|
associated_element: AssoElement,
|
||||||
element: Rc<RefCell<Element>>,
|
time: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Layer {
|
impl Debug for Layer {
|
||||||
@ -34,30 +44,64 @@ impl Debug for Layer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LayerImpl: Debug {
|
||||||
|
fn draw(&self, canvas: &mut Canvas<OpenGl>, cms: &CMS) -> Option<Target>;
|
||||||
|
}
|
||||||
|
|
||||||
impl Layer {
|
impl Layer {
|
||||||
pub fn new(
|
pub fn new(visiable: bool, layer_name: String, element: AssoElement) -> Self {
|
||||||
visiable: bool,
|
|
||||||
layer_name: String,
|
|
||||||
element: Rc<RefCell<Element>>,
|
|
||||||
element_type: ElementType,
|
|
||||||
) -> Self {
|
|
||||||
Layer {
|
Layer {
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
visiable,
|
visiable,
|
||||||
name: layer_name,
|
name: layer_name,
|
||||||
element,
|
associated_element: element,
|
||||||
element_type,
|
time: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn draw(
|
pub fn set_time(&mut self, time: DateTime<Utc>) {
|
||||||
&mut self,
|
self.time = Some(time);
|
||||||
render: &Render,
|
}
|
||||||
window_size: (f32, f32),
|
|
||||||
) -> Result<(), PipelineError> {
|
pub fn draw(&mut self, render: &Render, window_size: (f32, f32)) -> Result<(), PipelineError> {
|
||||||
if self.visiable {
|
if self.visiable {
|
||||||
let mut element = self.element.borrow_mut();
|
match self.associated_element {
|
||||||
element.r(ElementEvent::Draw, render);
|
AssoElement::Instant(ref mut e) => {
|
||||||
|
e.render(render);
|
||||||
|
}
|
||||||
|
AssoElement::TimeSeries(ref e) => {
|
||||||
|
let mut e = e.lock().unwrap();
|
||||||
|
let mut buffer = e.buffer.lock().unwrap();
|
||||||
|
let mut result = buffer.get_mut(&self.time.unwrap()).map(|x| x.as_mut());
|
||||||
|
|
||||||
|
if result.is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(result) = result.unwrap() {
|
||||||
|
let target = result.get_mut_target();
|
||||||
|
|
||||||
|
// let mut canvas = render.get_canvas();
|
||||||
|
// let mut canvas = canvas.as_mut().unwrap();
|
||||||
|
// let (ox, oy) = target.origin(render);
|
||||||
|
// let (x, y) = target.size(render);
|
||||||
|
|
||||||
|
render.draw_img(target);
|
||||||
|
|
||||||
|
// let result_id = match target.target {
|
||||||
|
// TargetType::ImageId(id) => id,
|
||||||
|
// TargetType::Mem(ref mem) => {
|
||||||
|
// let converted = canvas
|
||||||
|
// .load_image_mem(mem, femtovg::ImageFlags::empty())
|
||||||
|
// .unwrap();
|
||||||
|
// target.set_target(TargetType::ImageId(converted));
|
||||||
|
// converted
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,4 +119,16 @@ impl Layer {
|
|||||||
pub fn change_visiable(&mut self, visiable: bool) {
|
pub fn change_visiable(&mut self, visiable: bool) {
|
||||||
self.visiable = visiable;
|
self.visiable = visiable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pop_associated_element(&mut self) -> AssoElement {
|
||||||
|
std::mem::replace(&mut self.associated_element, AssoElement::Test)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_associated_element(&self) -> &AssoElement {
|
||||||
|
&self.associated_element
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_associated_element(&mut self, element: AssoElement) {
|
||||||
|
self.associated_element = element;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use core_extensions::SelfOps;
|
|||||||
use femtovg::{renderer::OpenGl, Canvas, ImageFlags};
|
use femtovg::{renderer::OpenGl, Canvas, ImageFlags};
|
||||||
use femtovg::{Paint, Path};
|
use femtovg::{Paint, Path};
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
pub use layers::{ElementType, Layer};
|
pub use layers::{AssoElement, Layer, LayerImpl, LayerImplSync};
|
||||||
use relm4::channel;
|
use relm4::channel;
|
||||||
use std::cell::Ref;
|
use std::cell::Ref;
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crate::coords::cms::CMS;
|
|||||||
use crate::coords::{Mapper, Range};
|
use crate::coords::{Mapper, Range};
|
||||||
use crate::errors::PipelineError;
|
use crate::errors::PipelineError;
|
||||||
use crate::map_tile::MapTile;
|
use crate::map_tile::MapTile;
|
||||||
use crate::pipeline::{Target, TargetType};
|
use crate::pipeline::element::{Target, TargetType};
|
||||||
use adw::prelude::{GLAreaExt, GestureDragExt};
|
use adw::prelude::{GLAreaExt, GestureDragExt};
|
||||||
use femtovg::ImageFlags;
|
use femtovg::ImageFlags;
|
||||||
use geo_types::LineString;
|
use geo_types::LineString;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::coords::Range;
|
|||||||
use std::borrow::BorrowMut;
|
use std::borrow::BorrowMut;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use super::super::{Layer, Render};
|
use super::super::{Layer, LayerImpl, Render};
|
||||||
use crate::coords::Mapper;
|
use crate::coords::Mapper;
|
||||||
use femtovg::renderer::OpenGl;
|
use femtovg::renderer::OpenGl;
|
||||||
use femtovg::{Canvas, Paint};
|
use femtovg::{Canvas, Paint};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use super::Render;
|
use super::Render;
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::pipeline::Target;
|
use crate::pipeline::element::Target;
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas};
|
||||||
|
|
||||||
pub trait DataRenderer {
|
pub trait DataRenderer {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user