This commit is contained in:
Tsuki 2024-04-17 18:35:47 +08:00
parent 26939857c9
commit cf3b1fabfc
21 changed files with 819 additions and 462 deletions

View File

@ -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::{AssoElement, Layer}; use crate::widgets::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,24 +15,12 @@ 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)
} }

View File

@ -8,18 +8,16 @@ use super::{
}; };
use crate::components::sidebar::{SideBarInputMsg, SideBarModel}; use crate::components::sidebar::{SideBarInputMsg, SideBarModel};
use crate::data_utils::tools; use crate::data_utils::tools;
use crate::pipeline::element::DataTarget;
use crate::pipeline::element_imp::{Context, ElementInput, GridImpConfig}; 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::runner::Runner;
use crate::pipeline::OffscreenRenderer; use crate::pipeline::{DataTarget, Key};
use crate::pipeline::{KVBuffer, OffscreenRenderer};
use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete}; use crate::predefined::color_mapper::{BoundaryNorm, ColorMapper, ColorMapperComb, Discrete};
use crate::predefined::widgets::ColorBar; use crate::predefined::widgets::ColorBar;
use crate::utils::meshgrid; 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,
@ -28,7 +26,7 @@ use crate::{
}, },
data::MetaInfo, data::MetaInfo,
errors::RenderError, errors::RenderError,
pipeline::{Dispatcher, Pipeline, RenderResult}, pipeline::{Dispatcher, RenderResult},
plugin_system::init_plugin, plugin_system::init_plugin,
widgets::render::Layer, widgets::render::Layer,
CONFIG, PLUGIN_MANAGER, CONFIG, PLUGIN_MANAGER,
@ -85,10 +83,9 @@ pub enum AppMsg {
OpenDialog, OpenDialog,
LayerManager(LayerMsg), LayerManager(LayerMsg),
Layer, Layer,
NewElement(Element), NewElement(Rc<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>;
#[tracker::track] #[tracker::track]
pub struct AppModel { pub struct AppModel {
@ -109,7 +106,11 @@ 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]
elements: Vec<Arc<Mutex<TimeSeriesElement>>>, buffer: Arc<Buffer<Key>>,
#[do_not_track]
file_pool: Arc<KVBuffer<PathBuf, Arc<PluginResult>>>,
#[do_not_track]
elements: Vec<Rc<Element>>,
#[do_not_track] #[do_not_track]
setting: Controller<SettingModel>, setting: Controller<SettingModel>,
} }
@ -228,10 +229,7 @@ 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 {
@ -239,6 +237,9 @@ 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,117 +264,88 @@ impl Component for AppModel {
let mut dispatcher = Rc::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); let data = Self::open_file_only(path.clone());
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 = tools(&data); let imp = tools(&data);
// let element_impl = plugin_result_impl(&data);
let mut renderer = OffscreenRenderer::new(3000, 3000).unwrap();
let mut canvas = renderer.create_canvas();
let mut dialog_cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
let mut context = Context::new(dialog_cms, canvas);
use femtovg::Color; use femtovg::Color;
let config = GridImpConfig {
let mut runner = Runner::new( color_map: ColorMapperComb::BoundaryNormDiscrete(ColorMapper::new(
imp, Discrete::new(vec![
Arc::new(GridImpConfig { Color::rgb(0, 172, 164),
color_map: ColorMapperComb::BoundaryNormDiscrete(ColorMapper::new( Color::rgb(192, 192, 254),
Discrete::new(vec![ Color::rgb(122, 114, 238),
Color::rgb(0, 172, 164), Color::rgb(30, 38, 208),
Color::rgb(192, 192, 254), Color::rgb(166, 252, 168),
Color::rgb(122, 114, 238), Color::rgb(0, 234, 0),
Color::rgb(30, 38, 208), Color::rgb(16, 146, 26),
Color::rgb(166, 252, 168), Color::rgb(252, 244, 100),
Color::rgb(0, 234, 0), Color::rgb(200, 200, 2),
Color::rgb(16, 146, 26), Color::rgb(140, 140, 0),
Color::rgb(252, 244, 100), Color::rgb(254, 172, 172),
Color::rgb(200, 200, 2), Color::rgb(254, 100, 92),
Color::rgb(140, 140, 0), Color::rgb(238, 2, 48),
Color::rgb(254, 172, 172), Color::rgb(212, 142, 254),
Color::rgb(254, 100, 92), Color::rgb(170, 36, 250),
Color::rgb(238, 2, 48), ]),
Color::rgb(212, 142, 254), BoundaryNorm::new(
Color::rgb(170, 36, 250), vec![
]), 0i8, 5i8, 10i8, 15i8, 20i8, 25i8, 30i8, 35i8, 40i8, 45i8,
BoundaryNorm::new( 50i8, 55i8, 60i8, 65i8, 70i8, 75i8,
vec![ ],
0i8, 5i8, 10i8, 15i8, 20i8, 25i8, 30i8, 35i8, 40i8, false,
45i8, 50i8, 55i8, 60i8, 65i8, 70i8, 75i8, Some(-125),
], ),
false, )),
Some(-125), };
), let element = Rc::new(Element::new(
)), "CR",
}), dialog_cms.clone(),
context,
);
let target = runner.run(&data);
let data_target = DataTarget::new(Some(data), target);
let element = Element::create_instant(
InstantElementDrawerType::Prepared(data_target),
dialog_dispatcher.clone(), dialog_dispatcher.clone(),
"ET".to_string(),
)
.get_instance();
let layer = Layer::new(
true, true,
"New Layer".to_string(), Arc::new(config),
AssoElement::Instant(element), path.clone(),
); dialog_buffer.clone(),
dialog_file_pool.clone(),
imp,
));
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,
)); ));
// let data_target = element_impl.render(&data, &mut canvas, &mut dialog_cms); AppMsg::NewElement(element)
// let data_target = DataTarget::new(Some(data), data_target);
// let element = Element::create_instant(
// InstantElementDrawerType::Prepared((data_target, element_impl)),
// dialog_dispatcher.clone(),
// "ET".to_string(),
// )
// .get_instance();
// let layer = Layer::new(
// true,
// "New Layer".to_string(),
// AssoElement::Instant(element),
// );
// dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map()));
// dialog_render_sender.emit(MonitorInputMsg::SetRenderRange(
// lon_start, lon_end, lat_start, lat_end,
// ));
// let layer = Layer::new(true, "New Layer".to_string(), AssoElement::Test);
AppMsg::LayerManager(LayerMsg::Add(layer))
} }
_ => 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,
elements: Vec::with_capacity(20), buffer,
file_pool,
open_dialog: dialog, open_dialog: dialog,
selected_layer: vec![], selected_layer: vec![],
sidebar, sidebar,
elements: vec![],
control, control,
render, render,
layers, layers,
@ -386,7 +358,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);
@ -411,24 +383,7 @@ 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);
@ -446,15 +401,23 @@ 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);

View File

@ -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::element::Target; use crate::pipeline::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;

View File

@ -1,5 +1,5 @@
use crate::coords::cms::CMS; use crate::coords::cms::CMS;
use crate::widgets::{Layer, LayerImpl, Render}; use crate::widgets::{Layer, 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};

View File

@ -1,5 +1,4 @@
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;
@ -193,11 +192,7 @@ impl SimpleComponent for SideBarModel {
v.name.clone(), v.name.clone(),
v.visiable, v.visiable,
v.get_thumbnail(), v.get_thumbnail(),
match v.get_associated_element() { LayerStatus::Instance,
AssoElement::TimeSeries(_) => LayerStatus::BindToTime(Utc::now()),
AssoElement::Instant(_) => LayerStatus::Instance,
_ => LayerStatus::Instance,
},
) )
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -221,11 +216,11 @@ impl SimpleComponent for SideBarModel {
v.name.clone(), v.name.clone(),
v.visiable, v.visiable,
v.get_thumbnail(), v.get_thumbnail(),
match v.get_associated_element() { LayerStatus::Instance, // 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<_>>();

View File

@ -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::element::{Target, TargetType}; use crate::pipeline::{Target, TargetType};
use dirs::cache_dir; use dirs::cache_dir;
use femtovg::ImageSource; use femtovg::ImageSource;
use futures::future::BoxFuture; use futures::future::BoxFuture;

View File

@ -1,15 +1,14 @@
use super::element::TargetType;
use super::offscreen_renderer::{CanvasWrapper, OffscreenRenderer}; use super::offscreen_renderer::{CanvasWrapper, OffscreenRenderer};
use crate::{ use crate::CONFIG;
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}");
@ -107,8 +106,8 @@ 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 datetime_format: regex::Regex = Regex::new(r"%[YHMSmd](?:[-/:_]?%[YHMSmd])*").unwrap();
let config = CONFIG.lock().unwrap(); let config = CONFIG.lock().unwrap();
let path_format = config let path_format = config
.plugins .plugins
@ -121,7 +120,7 @@ impl Dispatcher {
} }
path_format.unwrap().get(name).map(|s| { path_format.unwrap().get(name).map(|s| {
let path = s.clone(); let path = s.clone();
let file_path = { FILE_PATH_ROOT.lock().unwrap().clone() }; // let file_path = { file_path_root.lock().unwrap().clone() };
let path = if path.starts_with("./") { let path = if path.starts_with("./") {
let file_root = file_root(&file_path, path.replace("./", "")); let file_root = file_root(&file_path, path.replace("./", ""));
file_root.map(|root| { file_root.map(|root| {
@ -143,7 +142,7 @@ impl Dispatcher {
} }
} }
let need_formated = datetime_format.captures_iter(&path_str).collect::<Vec<_>>(); let need_formated = DATETIME_FORMAT.captures_iter(&path_str).collect::<Vec<_>>();
let mut fore = self.fore_len; let mut fore = self.fore_len;
let mut back = 1; let mut back = 1;

View File

@ -1,4 +1,4 @@
use super::{offscreen_renderer::CanvasWrapper, Dispatcher, Pipeline}; use super::{offscreen_renderer::CanvasWrapper, Dispatcher};
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;

View File

@ -4,11 +4,13 @@ use crate::data::Radar2dRef;
use crate::pipeline::offscreen_renderer::CanvasWrapper; use crate::pipeline::offscreen_renderer::CanvasWrapper;
use crate::predefined::color_mapper::{CMap, ColorMapper, ColorMapperComb, VMap}; use crate::predefined::color_mapper::{CMap, ColorMapper, ColorMapperComb, VMap};
use abi_stable::std_types::RVec; use abi_stable::std_types::RVec;
use femtovg::{Paint, Path}; use femtovg::renderer::OpenGl;
use femtovg::{Canvas, Paint, Path};
use ndarray::{ArrayBase, ArrayView1, ArrayView2, ArrayView3, ArrayViewD, Axis, Ix2, Ix3}; use ndarray::{ArrayBase, ArrayView1, ArrayView2, ArrayView3, ArrayViewD, Axis, Ix2, Ix3};
use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps}; use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps};
use radarg_plugin_interface::{DataShape, PluginResult, VecResult}; use radarg_plugin_interface::{DataShape, PluginResult, VecResult};
use std::any::Any; use std::any::Any;
use std::borrow::BorrowMut;
use std::fmt::Debug; use std::fmt::Debug;
const EARTH_RADIUS: f64 = 6371.0; const EARTH_RADIUS: f64 = 6371.0;
@ -16,11 +18,11 @@ const EARTH_RADIUS: f64 = 6371.0;
macro_rules! impl_element_imp_dispatch { macro_rules! impl_element_imp_dispatch {
($({$Abc: ident, $t:ty},)+) => { ($({$Abc: ident, $t:ty},)+) => {
impl ElementImpl { impl ElementImpl {
pub fn process<'a, T>(&'a self, pub fn process<'a,'b:'a, T>(&self,
dims: (ArrayView2<f64>, ArrayView2<f64>), dims: (ArrayView2<f64>, ArrayView2<f64>),
input: ElementInput<'a, T>, input: ElementInput<'a, T>,
config: &dyn Any, config: &dyn Any,
context: &mut Context context: &mut Context<'b>
) )
where where
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone + 'static, T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone + 'static,
@ -28,7 +30,7 @@ macro_rules! impl_element_imp_dispatch {
match self { match self {
$( $(
Self::$Abc(imp) => { Self::$Abc(imp) => {
let config = config.downcast_ref::<<$t as ElementImp>::Config<T>>().unwrap(); let config = config.downcast_ref::<<$t as ElementImp>::Config<'a, T>>().unwrap();
if let ElementInput::$Abc(data) = input { if let ElementInput::$Abc(data) = input {
imp.process(dims, data, config, context); imp.process(dims, data, config, context);
} else { } else {
@ -39,6 +41,17 @@ macro_rules! impl_element_imp_dispatch {
} }
} }
pub fn output_type(&self,) -> ElementOutput
{
match self {
$(
Self::$Abc(imp) => {
imp.output_type()
}
)+
}
}
} }
}; };
} }
@ -110,33 +123,56 @@ macro_rules! result_to_array {
}; };
} }
pub struct Context { pub struct Context<'a> {
pub cms: CMS, pub cms: CMS,
pub canvas: CanvasWrapper, pub canvas: &'a mut Canvas<OpenGl>,
} }
impl Context { impl<'a> Context<'a> {
pub fn new(cms: CMS, canvas: CanvasWrapper) -> Self { pub fn new<T>(cms: CMS, canvas: &'a mut T) -> Self
Self { cms, canvas } 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> { pub trait ElementImp: Debug + TryFrom<ElementImpl> + Into<ElementImpl> {
type Config<T: Sync + Send + Debug + PartialOrd + PartialEq>; type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq + 'a>: ElementConfig
where
Self: 'a;
type Input<'a, T: 'a> type Input<'a, T: 'a>
where where
Self: 'a; Self: 'a;
fn process<'a, T>(
&'a self, fn process<'a, 'b: 'a, T>(
&self,
dims: (ArrayView2<f64>, ArrayView2<f64>), dims: (ArrayView2<f64>, ArrayView2<f64>),
input: Self::Input<'a, T>, input: Self::Input<'a, T>,
config: &Self::Config<T>, config: &Self::Config<'a, T>,
context: &mut Context, context: &mut Context<'b>,
) where ) where
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone; T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone;
fn output_type(&self) -> ElementOutput;
} }
#[derive(Debug)] pub trait ElementConfig {
fn upcast_ref<'short, 'long: 'short>(&'long self) -> &'short Self {
self
}
}
#[derive(Debug, Clone, Copy)]
pub struct GridImp(); pub struct GridImp();
pub struct GridImpConfig<T> pub struct GridImpConfig<T>
@ -147,12 +183,12 @@ where
} }
impl GridImp { impl GridImp {
fn draw_2d<T>( fn draw_2d<'a, 'b: 'a, T>(
&self, &self,
config: &GridImpConfig<T>, config: &GridImpConfig<T>,
data: ArrayView2<T>, data: ArrayView2<'a, T>,
dims: (ArrayView2<f64>, ArrayView2<f64>), dims: (ArrayView2<f64>, ArrayView2<f64>),
context: &mut Context, context: &mut Context<'b>,
) where ) where
T: PartialEq + PartialOrd + Copy + Clone + Send + Sync + Debug, T: PartialEq + PartialOrd + Copy + Clone + Send + Sync + Debug,
{ {
@ -195,14 +231,15 @@ impl GridImp {
} }
impl ElementImp for GridImp { impl ElementImp for GridImp {
type Config<T: Sync + Send + Debug + PartialOrd + PartialEq> = GridImpConfig<T>; type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq> = GridImpConfig<T> where
T: 'a;
type Input<'a, T: 'a> = ArrayViewD<'a, T>; type Input<'a, T: 'a> = ArrayViewD<'a, T>;
fn process<'a, T>( fn process<'a, 'b: 'a, T>(
&'a self, &self,
dims: (ArrayView2<f64>, ArrayView2<f64>), dims: (ArrayView2<f64>, ArrayView2<f64>),
input: Self::Input<'a, T>, input: Self::Input<'a, T>,
config: &Self::Config<T>, config: &Self::Config<'a, T>,
context: &mut Context, context: &mut Context<'b>,
) where ) where
T: Send + Sync + Debug + PartialOrd + PartialEq + Copy + Clone, T: Send + Sync + Debug + PartialOrd + PartialEq + Copy + Clone,
{ {
@ -214,11 +251,33 @@ impl ElementImp for GridImp {
let data = input.into_dimensionality::<Ix3>().unwrap(); let data = input.into_dimensionality::<Ix3>().unwrap();
} }
} }
fn output_type(&self) -> ElementOutput {
ElementOutput::Target
}
} }
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
pub struct MultiLayerGridImp(); 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,
{
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> pub struct MultiLayerGridImpConfig<T>
where where
T: PartialOrd + PartialEq + Send + Sync + Debug, T: PartialOrd + PartialEq + Send + Sync + Debug,
@ -229,29 +288,28 @@ where
} }
impl ElementImp for MultiLayerGridImp { impl ElementImp for MultiLayerGridImp {
type Config<T: Sync + Send + Debug + PartialOrd + PartialEq> = MultiLayerGridImpConfig<T>; type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq + 'a> =
MultiLayerGridImpConfig<T>;
type Input<'a, T: 'a> = ArrayViewD<'a, T>; type Input<'a, T: 'a> = ArrayViewD<'a, T>;
fn process<'a, T>( fn process<'a, 'b: 'a, T>(
&'a self, &self,
dims: (ArrayView2<f64>, ArrayView2<f64>), dims: (ArrayView2<f64>, ArrayView2<f64>),
input: Self::Input<'a, T>, input: Self::Input<'a, T>,
config: &Self::Config<T>, config: &Self::Config<'a, T>,
context: &mut Context, context: &mut Context<'b>,
) where ) where
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone, T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone,
{ {
let data = input.into_dimensionality::<Ix3>().unwrap(); self.draw(dims, input, config.upcast_ref(), context);
let layer = config.layer; }
let layer_data = data.index_axis(Axis(0), layer);
config fn output_type(&self) -> ElementOutput {
.twod ElementOutput::Target
.process(dims, layer_data.into_dyn(), &config.two_d_config, context);
} }
} }
#[derive(Debug)] #[derive(Debug, Clone, Copy)]
pub struct PolarElementImp(); pub struct PolarElementImp();
pub struct PolarElementConfig<T> pub struct PolarElementConfig<T>
@ -316,13 +374,13 @@ impl PolarElementImp {
Some((final_degree, final_distance)) Some((final_degree, final_distance))
} }
fn draw<T>( fn draw<'a, T>(
&self, &self,
dims: (ArrayView2<f64>, ArrayView2<f64>), dims: (ArrayView2<f64>, ArrayView2<f64>),
center: (f64, f64), center: (f64, f64),
data: ArrayView2<T>, data: ArrayView2<T>,
config: &PolarElementConfig<T>, config: &'a PolarElementConfig<T>,
context: &mut Context, context: &mut Context<'a>,
) where ) where
T: PartialOrd + PartialEq + Send + Sync + Debug + Copy, T: PartialOrd + PartialEq + Send + Sync + Debug + Copy,
{ {
@ -364,28 +422,41 @@ impl PolarElementImp {
} }
impl ElementImp for PolarElementImp { impl ElementImp for PolarElementImp {
type Config<T: Sync + Send + Debug + PartialOrd + PartialEq> = PolarElementConfig<T>; type Config<'a, T: Sync + Send + Debug + PartialOrd + PartialEq> = PolarElementConfig<T> where
T: 'a;
type Input<'a, T: 'a> = ArrayViewD<'a, T>; type Input<'a, T: 'a> = ArrayViewD<'a, T>;
fn process<'a, T>( fn process<'a, 'b: 'a, T>(
&'a self, &self,
dims: (ArrayView2<f64>, ArrayView2<f64>), dims: (ArrayView2<f64>, ArrayView2<f64>),
input: Self::Input<'a, T>, input: Self::Input<'a, T>,
config: &Self::Config<T>, config: &Self::Config<'a, T>,
context: &mut Context, context: &mut Context<'b>,
) where ) where
T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone, T: Sync + Send + Debug + PartialOrd + PartialEq + Copy + Clone,
{ {
let shape = input.shape(); let shape = input.shape();
if shape.len() == 2 { if shape.len() == 2 {
let data = input.into_dimensionality::<Ix2>().unwrap(); let data = input.into_dimensionality::<Ix2>().unwrap();
self.draw(dims, config.center, data, config, context); // self.draw(dims, config.center, data, config, context);
} else if shape.len() == 3 { } else if shape.len() == 3 {
let data = input.into_dimensionality::<Ix3>().unwrap(); let data = input.into_dimensionality::<Ix3>().unwrap();
} }
} }
fn output_type(&self) -> ElementOutput {
ElementOutput::Target
}
} }
#[derive(Debug)] impl<T> ElementConfig for GridImpConfig<T> where T: Sync + Send + Debug + PartialOrd + PartialEq {}
impl<T> ElementConfig for MultiLayerGridImpConfig<T> where
T: Sync + Send + Debug + PartialOrd + PartialEq
{
}
impl<T> ElementConfig for PolarElementConfig<T> where T: Sync + Send + Debug + PartialOrd + PartialEq
{}
#[derive(Debug, Clone, Copy)]
pub enum ElementImpl { pub enum ElementImpl {
Grid(GridImp), Grid(GridImp),
MultiLayerGrid(MultiLayerGridImp), MultiLayerGrid(MultiLayerGridImp),

View File

@ -1,9 +1,9 @@
pub mod dispatcher; pub mod dispatcher;
pub mod element; // pub mod element;
// mod element_impl; // mod element_impl;
// mod new_element; pub mod new_element;
// mod new_element_impl; // mod new_element_impl;
mod new_pipeline; // mod new_pipeline;
pub mod offscreen_renderer; pub mod offscreen_renderer;
// mod predefined; // mod predefined;
pub mod element_imp; pub mod element_imp;
@ -12,7 +12,8 @@ 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;

View File

@ -1,14 +1,22 @@
use super::dispatcher; use super::dispatcher;
use super::new_element_impl::ElementConfig; use super::element_imp::Context;
use super::new_element_impl::ElementImp; use super::element_imp::ElementImpl;
use super::element_imp::ElementOutput;
use super::offscreen_renderer;
use super::offscreen_renderer::CanvasWrapper; use super::offscreen_renderer::CanvasWrapper;
use super::runner::Runner;
use super::Dispatcher; use super::Dispatcher;
use super::RenderResult;
use super::Target;
use crate::coords::cms::CMS; use crate::coords::cms::CMS;
use crate::coords::Range;
use crate::data::MetaInfo;
use crate::pipeline::OffscreenRenderer; use crate::pipeline::OffscreenRenderer;
use crate::widgets::Render;
use crate::PLUGIN_MANAGER; use crate::PLUGIN_MANAGER;
use crate::RUNTIME;
use chrono::prelude::*; use chrono::prelude::*;
use femtovg::ImageFlags;
use femtovg::ImageId;
use futures::future::BoxFuture;
use num_traits::AsPrimitive; use num_traits::AsPrimitive;
use num_traits::FromPrimitive; use num_traits::FromPrimitive;
use num_traits::Num; use num_traits::Num;
@ -16,9 +24,12 @@ use num_traits::NumOps;
use quick_cache::sync::Cache; use quick_cache::sync::Cache;
use radarg_plugin_interface::PluginResult; use radarg_plugin_interface::PluginResult;
use std::any::Any; use std::any::Any;
use std::borrow::BorrowMut;
use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
use std::sync::atomic::AtomicI32; use std::sync::atomic::AtomicI32;
use std::sync::Arc; use std::sync::Arc;
@ -26,171 +37,546 @@ use std::sync::RwLock;
use std::time::Duration; use std::time::Duration;
use tokio::sync::oneshot; use tokio::sync::oneshot;
use tokio::sync::{mpsc, Mutex}; use tokio::sync::{mpsc, Mutex};
use tracing::subscriber;
static ELEMENT_ID: AtomicI32 = AtomicI32::new(0); static ELEMENT_ID: AtomicI32 = AtomicI32::new(0);
pub type ElementID = i32; pub type ElementID = i32;
pub type Buffer<T> = Cache<T, Arc<Mutex<RenderResult>>>; pub type KVBuffer<T, V> = Cache<T, V>;
pub type Buffer<T> = KVBuffer<T, Arc<Mutex<RenderResult>>>;
pub struct Element<T: Eq + Hash + Send + Clone + Copy + 'static, V> #[derive(Debug, Hash, Eq, PartialEq, Clone)]
where pub struct Key {
V: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug, pub id: ElementID,
{
pub id: i32,
pub name: String, pub name: String,
pub description: String, pub root: std::path::PathBuf,
imp: Arc<ElementImp<V>>, pub datetime: Option<DateTime<Utc>>,
buffer: Arc<Mutex<Buffer<T>>>,
config: Arc<RwLock<Box<ElementConfig>>>,
subscribers: Arc<Mutex<HashMap<T, Vec<oneshot::Sender<Arc<Mutex<Vec<u8>>>>>>>>,
cancellers: Arc<Mutex<HashMap<T, oneshot::Sender<()>>>>,
dispatcher: Rc<Dispatcher>,
cms: Arc<Mutex<CMS>>,
} }
impl<T: Eq + Hash + Send + Clone + Copy + 'static, V> Element<T, V> #[derive(Clone, Debug)]
where pub struct Target {
V: Num + NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync + Debug, 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( pub fn new(
name: String, target: TargetType,
description: String, width: f32,
imp: ElementImp<V>, height: f32,
config: Box<ElementConfig>, bounds: (Range, Range),
thumbnail: Option<gtk::gdk::Texture>,
// data: Option<Arc<dyn Any + Send + Sync + 'static>>,
) -> Self {
Self {
target,
width,
height,
bounds,
thumbnail,
// data,
}
}
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 {
data: Option<PluginResult>,
target: Target,
}
impl DataTarget {
pub fn new(data: Option<PluginResult>, target: Target) -> Self {
Self { data, target }
}
pub fn take_data(&mut self) -> Option<PluginResult> {
self.data.take()
}
pub fn data(&self) -> Option<&PluginResult> {
self.data.as_ref()
}
pub fn mut_data(&mut self) -> Option<&mut PluginResult> {
self.data.as_mut()
}
}
#[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<RenderResult>>>>>>>,
cancellers: Arc<Mutex<HashMap<Key, oneshot::Sender<()>>>>,
current_key: Option<Key>,
dispatcher: Rc<Dispatcher>,
buffer: Arc<Buffer<Key>>,
file_pool: Arc<KVBuffer<PathBuf, Arc<PluginResult>>>,
cms: CMS,
}
pub enum ElementEvent<'a> {
Init,
DateTime(DateTime<Utc>),
Key(&'a Key),
}
impl Element {
pub fn new(
name: impl Into<String>,
cms: CMS, cms: CMS,
dispatcher: Rc<Dispatcher>, dispatcher: Rc<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 { ) -> Self {
let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed); let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Element { Element {
id, id,
name, name: name.into(),
description, cache,
imp: Arc::new(imp), imp,
buffer: Arc::new(Mutex::new(Buffer::new(100))), config,
root,
subscribers: Arc::new(Mutex::new(HashMap::new())), subscribers: Arc::new(Mutex::new(HashMap::new())),
config: Arc::new(RwLock::new(config)),
cancellers: Arc::new(Mutex::new(HashMap::new())), cancellers: Arc::new(Mutex::new(HashMap::new())),
cms: Arc::new(Mutex::new(cms)), cms: cms,
current_key: None,
buffer,
file_pool,
dispatcher, dispatcher,
} }
} }
pub fn new_with_buffer( pub fn r<'a>(&self, event: ElementEvent<'a>, render: &Render) {
name: String, let need_cache = self.cache;
description: String, let format = self.imp.output_type();
imp: ElementImp<V>,
buffer: Buffer<T>,
config: Box<ElementConfig>,
cms: CMS,
dispatcher: Rc<Dispatcher>,
) -> Self {
let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
Element {
id,
name,
description,
imp: Arc::new(imp),
buffer: Arc::new(Mutex::new(buffer)),
subscribers: Arc::new(Mutex::new(HashMap::new())),
config: Arc::new(RwLock::new(config)),
cancellers: Arc::new(Mutex::new(HashMap::new())),
cms: Arc::new(Mutex::new(cms)),
dispatcher,
}
}
pub async fn get(&self, key: T) -> Arc<Mutex<RenderResult>> { match event {
{ ElementEvent::Init => {
let cache = self.buffer.lock().await; let data = self.file_pool.get(&self.root);
if cache.peek(&key).is_some() { if let Some(data) = data {}
return cache.get(&key).unwrap(); }
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);
} }
} }
// match key {
// ElementEvent::Init => {
// let data = self.get_file(&self.root);
// }
// ElementEvent::DateTime(key) => {
// let key = &Key {
// id: self.id,
// name: self.name.clone(),
// root: self.root.clone(),
// datetime: Some(key),
// };
// if self.cache {
// if let ElementOutput::Target = self.imp.output_type() {
// let target = self.run(key.to_owned()).await;
// // if let Some(target) = target {
// // let mut target = target.lock().await;
// // let target = target.get_mut_target();
// // render.draw_img(target);
// // }
// } else {
// let path = (&*self.dispatcher).borrow_mut().get_single_path(
// &self.name,
// key.datetime.to_owned().unwrap(),
// true,
// );
// if let Some(path) = path {
// let data = self.get_file(path);
// let mut _canvas = render.get_canvas();
// let mut canvas = _canvas.as_mut().unwrap();
// let cms = render.create_cms();
// let context = Context::new(cms, canvas);
// let mut runner = Runner::new(self.imp, self.config.clone(), context);
// runner.run_without_target(&data);
// }
// }
// } else {
// let path = (&*self.dispatcher).borrow_mut().get_single_path(
// &self.name,
// key.datetime.to_owned().unwrap(),
// true,
// );
// if let Some(path) = path {
// let data = self.get_file(path);
// let mut _canvas = render.get_canvas();
// let mut canvas = _canvas.as_mut().unwrap();
// let cms = render.create_cms();
// let context = Context::new(cms, canvas);
// let mut runner = Runner::new(self.imp, self.config.clone(), context);
// runner.run_without_target(&data);
// }
// }
// }
// ElementEvent::Data(data) => {
// let mut _canvas = render.get_canvas();
// let mut canvas = _canvas.as_mut().unwrap();
// let cms = render.create_cms();
// let context = Context::new(cms, canvas);
// let mut runner = Runner::new(self.imp, self.config.clone(), context);
// runner.run_without_target(&data);
// }
// }
}
fn _rrrr(&self, data: &PluginResult, need_cache: bool, output_type: ElementOutput) {
match output_type {
ElementOutput::Target => {}
_ => {}
}
}
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()
}
async fn run(&self, key: Key) -> Option<Arc<Mutex<RenderResult>>> {
{ {
let mut subscribers = self.subscribers.lock().await; let cache = &self.buffer;
let (tx, rx) = oneshot::channel(); if cache.peek(&key).is_some() {
if subscribers.contains_key(&key) { return Some(cache.get(&key).unwrap());
subscribers.get_mut(&key).unwrap().push(tx); }
}
let datetime = key.datetime.unwrap();
let dispatcher = (&*self.dispatcher);
let current_path = dispatcher.get_single_path(&self.name, datetime, true);
let paths = dispatcher.get_path(&self.name, datetime, true, 3, &self.root);
if let Some(paths) = paths {
paths.iter().for_each(|(p, d)| {
let key = self.generate_key(d.to_owned());
let f = self._run(p, &key);
let handle = tokio::task::spawn(f);
});
}
if let Some(path) = current_path {
let key = self.generate_key(datetime);
let f = self._run(path, &key);
let handle = tokio::task::spawn(f);
let result = handle.await.unwrap();
Some(result)
} else {
None
}
}
fn generate_key(&self, datetime: DateTime<Utc>) -> Key {
Key {
id: self.id,
name: self.name.clone(),
root: self.root.clone(),
datetime: Some(datetime),
}
}
fn _run(
&self,
p: impl AsRef<std::path::Path>,
key: &Key,
) -> BoxFuture<'static, Arc<Mutex<RenderResult>>> {
let (tx, rx) = oneshot::channel();
let buffer = self.buffer.clone();
let config = self.config.clone();
let canceller = self.cancellers.clone();
let subscriber = self.subscribers.clone();
let mut dialog_cms = self.cms.clone();
let mut dialog_config = self.config.clone();
let mut dialog_imp = self.imp.clone();
let _key = key.to_owned();
Box::pin(async move {
let key = &_key;
let mut subscribers = subscriber.lock().await;
if subscribers.contains_key(key) {
subscribers.get_mut(key).unwrap().push(tx);
drop(subscribers); drop(subscribers);
} else { } else {
let (canceller_tx, canceller_rx) = oneshot::channel(); let (canceller_tx, canceller_rx) = oneshot::channel();
subscribers.insert(key, vec![tx]); subscribers.insert(key.to_owned(), vec![tx]);
drop(subscribers); drop(subscribers);
{ let mut cancellers = canceller.lock().await;
let mut cancellers = self.cancellers.lock().await; cancellers.insert(key.clone(), canceller_tx);
cancellers.insert(key, canceller_tx); drop(cancellers);
}
let buffer = self.buffer.clone();
let config = self.config.clone();
let imp = self.imp.clone();
let cancellers = self.cancellers.clone();
let subscribers = self.subscribers.clone();
use tokio::task; use tokio::task;
let key = key.to_owned();
tokio::spawn(async move { tokio::spawn(async move {
let new_key = key.clone();
tokio::select! { tokio::select! {
_ = async move { _ = async move {
tokio::time::sleep(Duration::new(5, 0)).await;
let handle = task::spawn_blocking(move || { let handle = task::spawn_blocking(move || {
let config = config.read().unwrap(); let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap();
let config: &ElementConfig = &*(*config); let mut canvas = offscreen_renderer.create_canvas();
let mut context = Context::new(dialog_cms, &mut canvas);
let mut runner = Runner::new(dialog_imp, dialog_config, context);
let loader = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap(); let loader = PLUGIN_MANAGER.get_plugin_by_name("etws_loader").unwrap();
let mut loaded_data = loader.load(path.as_ref().into()).unwrap(); let mut loaded_data = loader.load("".into()).unwrap();
let meta = loaded_data.meta.clone().into(); let meta = loaded_data.meta.clone().into();
let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap();
// imp.render() let target = runner.run(&loaded_data);
RenderResult::new(
DataTarget::new(Some(loaded_data), target),
meta
)
}); });
let result = handle.await.unwrap(); let result = handle.await.unwrap();
let bf = Arc::new(Mutex::new(result));
{ buffer.insert(key.clone(), bf.clone());
let bf = Arc::new(Mutex::new(result)); let mut subscribers = subscriber.lock().await;
buffer.lock().await.insert(key, bf.clone()); for tx in subscribers.remove(&key).unwrap() {
let mut subscribers = subscribers.lock().await; let _ = tx.send(bf.clone());
for tx in subscribers.remove(&key).unwrap() {
let _ = tx.send(bf.clone());
}
} }
} => {} } => {}
_ = canceller_rx => {} _ = canceller_rx => {}
} }
let mut cancellers = cancellers.lock().await; let mut cancellers = canceller.lock().await;
cancellers.remove(&key); cancellers.remove(&new_key);
}); });
} }
rx.await.unwrap() rx.await.unwrap()
} })
} }
pub async fn cancel_task_for_timestamp(&self, key: T) { fn key(&self) -> String {
let mut cancellers = self.cancellers.lock().await; format!("{}-{}", self.id, self.name)
if let Some(canceller) = cancellers.remove(&key) {
let _ = canceller.send(()); // 发送取消信号
}
}
pub async fn cancel_all_tasks(&self) {
let mut cancellers = self.cancellers.lock().await;
for (_timestamp, canceller) in cancellers.drain() {
let _ = canceller.send(()); // 发送取消信号
}
} }
} }
pub trait ElementImpl: Debug + Send + Sync + 'static {
type Config;
fn render(
&self,
data: &PluginResult,
canvas: &mut CanvasWrapper,
cms: &mut CMS,
config: &Self::Config,
) -> Target;
}

View File

@ -1,4 +1,3 @@
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;
@ -15,6 +14,8 @@ 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,
@ -36,7 +37,7 @@ impl OffscreenRenderer {
let mut device = connection.create_device(&adapter)?; let mut device = connection.create_device(&adapter)?;
let descriptor = device.create_context_descriptor(&surfman::ContextAttributes { let descriptor = device.create_context_descriptor(&surfman::ContextAttributes {
version: surfman::GLVersion::new(4, 1), version: surfman::GLVersion::new(3, 3),
flags: ContextAttributeFlags::ALPHA flags: ContextAttributeFlags::ALPHA
.union(ContextAttributeFlags::DEPTH) .union(ContextAttributeFlags::DEPTH)
.union(ContextAttributeFlags::STENCIL), .union(ContextAttributeFlags::STENCIL),
@ -196,3 +197,15 @@ 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
}
}

View File

@ -1,7 +1,8 @@
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(

View File

@ -1,10 +1,11 @@
use std::{any::Any, sync::Arc}; use std::{any::Any, sync::Arc};
use femtovg::RenderTarget; use femtovg::{renderer::OpenGl, Canvas, RenderTarget};
use gl::types::GLvoid; use gl::types::GLvoid;
use image::Rgba; use image::Rgba;
use ndarray::{ArrayView1, ArrayViewD}; use ndarray::{Array2, ArrayBase, ArrayView1, ArrayViewD};
use radarg_plugin_interface::{PluginResult, VecResult}; use radarg_plugin_interface::{PluginResult, VecResult};
use smallvec::Array;
use crate::{ use crate::{
pipeline::{ pipeline::{
@ -34,14 +35,14 @@ macro_rules! impl_for_runner {
}; };
} }
pub struct Runner { pub struct Runner<'a> {
imp: ElementImpl, imp: ElementImpl,
config: Arc<dyn Any>, config: Arc<dyn Any>,
context: Context, context: Context<'a>,
} }
impl Runner { impl<'a> Runner<'a> {
pub fn new(imp: ElementImpl, config: Arc<dyn Any>, context: Context) -> Self { pub fn new(imp: ElementImpl, config: Arc<dyn Any>, context: Context<'a>) -> Self {
Self { Self {
imp, imp,
config, config,
@ -50,6 +51,49 @@ impl Runner {
} }
pub fn run(&mut self, data: &PluginResult) -> Target { 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 block = data.blocks.first().unwrap();
let data = &block.data; let data = &block.data;
let dims = &block.dimension_values; let dims = &block.dimension_values;
@ -71,17 +115,10 @@ impl Runner {
let size = block.size.to_owned().to_vec(); let size = block.size.to_owned().to_vec();
let config = &*self.config; let config = &*self.config;
let imp: &ElementImpl = &self.imp; let imp: &ElementImpl = &self.imp;
let context: &mut Context = &mut self.context; let context = &mut self.context;
let cms = &mut context.cms; let cms = &mut context.cms;
let canvas = &mut context.canvas; let canvas = &mut context.canvas;
let (w, h) = (canvas.width(), canvas.height()); let (w, h) = (canvas.width(), canvas.height());
use femtovg::{ImageFlags, PixelFormat::Rgba8};
let new_img = canvas
.create_image_empty(w as usize, h as usize, Rgba8, ImageFlags::empty())
.expect("Can't Create Image");
canvas.image_size(new_img).unwrap();
canvas.set_render_target(RenderTarget::Image(new_img));
let lat_start = dims.1.view().first().unwrap().clone(); let lat_start = dims.1.view().first().unwrap().clone();
let lat_end = dims.1.view().last().unwrap().clone(); let lat_end = dims.1.view().last().unwrap().clone();
@ -112,35 +149,7 @@ impl Runner {
{ U64 }, { U64 },
{ U32 }, { U32 },
); );
context.canvas.flush(); context.canvas.flush();
dims
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);
}
let d1_start = (dims.0.view()).first().unwrap().clone();
let d1_end = (dims.0.view()).last().unwrap().clone();
let d2_start = dims.1.view().first().unwrap().clone();
let d2_end = dims.1.view().last().unwrap().clone();
context.canvas.set_render_target(RenderTarget::Screen);
Target::new(
TargetType::NativeBuffer(pixels),
w as f32,
h as f32,
((d1_start, d1_end).into(), (d2_start, d2_end).into()),
None,
)
} }
} }

View File

@ -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::{AssoElement, Layer}; use crate::widgets::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,17 +39,6 @@ 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()

View File

@ -4,7 +4,7 @@ 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::element::{Target, TargetType}; use crate::pipeline::new_element::{Target, TargetType};
use femtovg::{Canvas, Color, FontId, Paint, Renderer}; use femtovg::{Canvas, Color, FontId, Paint, Renderer};
use gtk::glib::{self, prelude::*, Properties}; use gtk::glib::{self, prelude::*, Properties};
use gtk::prelude::*; use gtk::prelude::*;

View File

@ -1,30 +1,19 @@
use super::super::Render; use super::super::Render;
use crate::coords::cms::CMS;
use crate::errors::PipelineError; use crate::errors::PipelineError;
use crate::pipeline::element::{self, Target}; use crate::pipeline::new_element::{self, Target};
use crate::pipeline::offscreen_renderer::CanvasWrapper; use crate::pipeline::new_element::{Element, ElementEvent};
use chrono::{prelude::*, DateTime}; use crate::RUNTIME;
use femtovg::{renderer::OpenGl, Canvas}; use femtovg::{renderer::OpenGl, Canvas};
use std::rc::Rc;
use std::{ use std::{
fmt::Debug, fmt::Debug,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
type PrepareFunc = Arc< #[derive(Clone, Copy, Debug)]
Mutex< pub enum ElementType {
Option< Asso,
Box<dyn FnOnce(LayerImplSync, Arc<Mutex<CanvasWrapper>>, CMS) -> Target + Sync + Send>, Indenpendent,
>,
>,
>;
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)]
@ -32,8 +21,8 @@ pub struct Layer {
pub visiable: bool, pub visiable: bool,
pub alpha: f32, pub alpha: f32,
pub name: String, pub name: String,
associated_element: AssoElement, element_type: ElementType,
time: Option<DateTime<Utc>>, element: Rc<Element>,
} }
impl Debug for Layer { impl Debug for Layer {
@ -44,64 +33,29 @@ 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(visiable: bool, layer_name: String, element: AssoElement) -> Self { pub fn new(
visiable: bool,
layer_name: String,
element: Rc<Element>,
element_type: ElementType,
) -> Self {
Layer { Layer {
alpha: 1.0, alpha: 1.0,
visiable, visiable,
name: layer_name, name: layer_name,
associated_element: element, element,
time: None, element_type,
} }
} }
pub fn set_time(&mut self, time: DateTime<Utc>) { pub(super) fn draw(
self.time = Some(time); &mut self,
} render: &Render,
window_size: (f32, f32),
pub fn draw(&mut self, render: &Render, window_size: (f32, f32)) -> Result<(), PipelineError> { ) -> Result<(), PipelineError> {
if self.visiable { if self.visiable {
match self.associated_element { self.element.r(ElementEvent::Init, 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(());
} }
@ -119,16 +73,4 @@ 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;
}
} }

View File

@ -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::{AssoElement, Layer, LayerImpl, LayerImplSync}; pub use layers::{ElementType, Layer};
use relm4::channel; use relm4::channel;
use std::cell::Ref; use std::cell::Ref;
use tokio::task; use tokio::task;

View File

@ -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::element::{Target, TargetType}; use crate::pipeline::{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;

View File

@ -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, LayerImpl, Render}; use super::super::{Layer, 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};

View File

@ -1,6 +1,6 @@
use super::Render; use super::Render;
use crate::coords::cms::CMS; use crate::coords::cms::CMS;
use crate::pipeline::element::Target; use crate::pipeline::Target;
use femtovg::{renderer::OpenGl, Canvas}; use femtovg::{renderer::OpenGl, Canvas};
pub trait DataRenderer { pub trait DataRenderer {