From b21529c2b94e3f20d4fa39c79cbc1306a1c65bd4 Mon Sep 17 00:00:00 2001 From: Tsuki Date: Mon, 11 Mar 2024 18:35:09 +0800 Subject: [PATCH] sync --- Cargo.lock | 1 + Cargo.toml | 1 + src/components/monitor/messages.rs | 6 -- src/components/monitor/monitor.rs | 86 ++++++++++++++++++++----- src/main.rs | 1 + src/map_tile.rs | 54 ++++++++++++++++ src/predefined/mod.rs | 2 +- src/widgets/render/exterior/imp.rs | 1 - src/widgets/render/imp.rs | 14 ++++ src/widgets/render/interior/imp.rs | 2 +- src/widgets/render/interior/map_tile.rs | 30 --------- src/widgets/render/interior/mod.rs | 13 +++- src/widgets/render/mod.rs | 24 ++++++- 13 files changed, 176 insertions(+), 59 deletions(-) create mode 100644 src/map_tile.rs delete mode 100644 src/widgets/render/interior/map_tile.rs diff --git a/Cargo.lock b/Cargo.lock index f0c060d..b48f084 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -550,6 +550,7 @@ dependencies = [ "tracing", "tracing-subscriber", "tracker", + "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3c358a8..b982c84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,6 +92,7 @@ imgref = "1.10.1" rgb = "0.8.37" slippy-map-tiles = "0.16.0" reqwest = "0.11.25" +url = "2.5.0" [build-dependencies] diff --git a/src/components/monitor/messages.rs b/src/components/monitor/messages.rs index 16ec1c2..61a0e75 100644 --- a/src/components/monitor/messages.rs +++ b/src/components/monitor/messages.rs @@ -10,12 +10,9 @@ pub enum MonitorInputMsg { NewElement((ElementKey, ElementID)), AddWidget(Box), RemoveWidget, - AddLayer(Layer), - RemoveLayer(String), AddMetaItem(HashMap), ClearMetaItems, UpdateMetaItem(HashMap), - UpdateLayer((String, Box)), RefreshLayerList, SetRenderRange(f64, f64, f64, f64), None, @@ -27,9 +24,6 @@ impl Debug for MonitorInputMsg { MonitorInputMsg::SetRenderRange(_, _, _, _) => write!(f, "MonitorInputMsg::SetRenderRange"), MonitorInputMsg::RefreshLayerList => write!(f, "MonitorInputMsg::RefreshLayerList"), MonitorInputMsg::NewElement(_) => write!(f, "MonitorInputMsg::NewElement"), - MonitorInputMsg::AddLayer(_) => write!(f, "MonitorInputMsg::AddLayer"), - MonitorInputMsg::RemoveLayer(_) => write!(f, "MonitorInputMsg::RemoveLayer"), - MonitorInputMsg::UpdateLayer(_) => write!(f, "MonitorInputMsg::UpdateLayer"), MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"), MonitorInputMsg::AddWidget(_) => write!(f, "MonitorInputMsg::AddWidget"), MonitorInputMsg::RemoveWidget => write!(f, "MonitorInputMsg::RemoveWidget"), diff --git a/src/components/monitor/monitor.rs b/src/components/monitor/monitor.rs index 52b3d63..6615340 100644 --- a/src/components/monitor/monitor.rs +++ b/src/components/monitor/monitor.rs @@ -18,13 +18,20 @@ use std::collections::HashMap; use std::rc::Rc; use std::sync::{Arc, Mutex}; +use tokio::task; use super::sidebar::{sidebar::SideBarModel, SideBarInputMsg, SideBarOutputMsg}; +use crate::map_tile::MapTile; use adw::prelude::*; +use femtovg::ImageId; use relm4::{component::Component, *}; +use slippy_map_tiles::Tile; +use tracing::instrument::WithSubscriber; +use crate::coords::Range; +use crate::pipeline::element::Target; #[derive(Debug)] pub enum MonitorCommand { - // NewLayer(Layer), + LoadTile(Tile, Vec, (f64,f64), (Range, Range)), None, } #[tracker::track] @@ -33,6 +40,10 @@ pub struct MonitorModel { render_range: (f64, f64, f64, f64), sidebar_open: bool, sidebar_width: i32, + #[do_not_track] + map_tile_getter: Arc, + #[do_not_track] + tiles: Rc>>, new_layer: i8, #[no_eq] widgets: Vec, @@ -86,6 +97,37 @@ impl Component for MonitorModel { connect_render_status_notify[sender] => move |r| { sender.output(MonitorOutputMsg::LayerRenderFinished); }, + set_tiles: model.tiles.clone(), + connect_range_changing_notify[sender] => move |r| { + let ((x1 , x2), (y1,y2))= r.render_range(); + let w = r.width() as f32; + let h = r.height() as f32; + let map_tile_getter = map_tile_getter.clone(); + let new_tiles = map_tile_getter.new_tiles(3 ,(y1 as f32,y2 as f32),(x1 as f32,x2 as f32)); + + let tiles = (*tiles).borrow(); + let new_tiles = new_tiles.filter(|x| !tiles.contains_key(x)).collect::>(); + + if new_tiles.len() > 0 { + let new_sender = sender.clone(); + sender.oneshot_command(async move { + for tile in new_tiles { + let map_tile_getter = map_tile_getter.clone(); + let sender = new_sender.clone(); + task::spawn(async move { + let result = map_tile_getter.get_tile(&tile).await; + if let Ok(result) = result { + let origin = tile.nw_corner(); + let rb = tile.se_corner(); + let bounds = ((origin.lon() as f64..rb.lon() as f64).into(), (origin.lat() as f64..rb.lat() as f64).into()); + sender.command_sender().emit(MonitorCommand::LoadTile(tile, result,(origin.lon() as f64, origin.lat() as f64), bounds)); + } + }); + } + MonitorCommand::None + }); + } + }, set_interior_layers: model.layers.clone(), }, add_overlay=>k::Button{ @@ -107,15 +149,16 @@ impl Component for MonitorModel { } } - fn update_with_view(&mut self, widgets: &mut Self::Widgets, message: Self::Input, sender: ComponentSender, root: &Self::Root) { + fn update_with_view( + &mut self, + widgets: &mut Self::Widgets, + message: Self::Input, + sender: ComponentSender, + root: &Self::Root, + ) { self.reset(); match message { - MonitorInputMsg::AddLayer(layer) => { - self.layers.borrow_mut().push(layer); - let raw_id = self.get_new_layer(); - self.set_new_layer(*raw_id + 1); - self.sidebar.sender().send(SideBarInputMsg::RefreshList); - } + MonitorInputMsg::RefreshLayerList => { self.sidebar.sender().send(SideBarInputMsg::RefreshList); widgets.renderer.queue_render(); @@ -123,8 +166,8 @@ impl Component for MonitorModel { MonitorInputMsg::AddMetaItem(map) => { self.sidebar.emit(SideBarInputMsg::AddMetaItems(map)) } - MonitorInputMsg::SetRenderRange(lon_start,lon_end,lat_start,lat_end)=>{ - self.set_render_range((lat_start,lat_end,lon_start,lon_end)); + MonitorInputMsg::SetRenderRange(lon_start, lon_end, lat_start, lat_end) => { + self.set_render_range((lat_start, lat_end, lon_start, lon_end)); } MonitorInputMsg::ClearMetaItems => self.sidebar.emit(SideBarInputMsg::ClearMetaItems), MonitorInputMsg::UpdateMetaItem(map) => { @@ -157,7 +200,6 @@ impl Component for MonitorModel { let sidebar: Controller = SideBarModel::builder() .launch(init.clone()) .forward(sender.input_sender(), move |msg| match msg { - SideBarOutputMsg::NewLayer(layer) => MonitorInputMsg::AddLayer(layer), SideBarOutputMsg::SwitchToTimeSeries(layer) => { sidebar_sender.output(MonitorOutputMsg::LayerSwitchToTime(layer)); MonitorInputMsg::None @@ -173,27 +215,39 @@ impl Component for MonitorModel { render_range: (4.0, 53.3, 73.3, 135.0), new_layer: 0, widgets: vec![], + tiles: Rc::new(RefCell::new(HashMap::new())), render_cfg, sidebar_open: true, sidebar_width: 400, layers: init, + map_tile_getter: Arc::new(MapTile::default()), sidebar, tracker: 0, }; + let map_tile_getter = model.map_tile_getter.clone(); + let tiles = model.tiles.clone(); + let widgets = view_output! {}; ComponentParts { model, widgets } } - fn update_cmd( + fn update_cmd_with_view( &mut self, - msg: Self::CommandOutput, - _sender: ComponentSender, - _root: &Self::Root, + widgets: &mut Self::Widgets, + message: Self::CommandOutput, + sender: ComponentSender, + root: &Self::Root, ) { self.reset(); - match msg { + match message { + MonitorCommand::LoadTile(key, ref tile, origin, bounds) => { + let target = widgets.renderer.load_img_mem(&tile,origin,(256f32,256f32), bounds).unwrap(); + self.tiles.borrow_mut().insert(key, target); + widgets.render.queue_draw(); + } _ => {} } + self.update_view(widgets, sender); } } diff --git a/src/main.rs b/src/main.rs index 7f7b016..2857c51 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,6 +28,7 @@ mod widgets; mod data_utils; mod predefined; mod map_tile_utils; +mod map_tile; const APP_ID: &str = "org.tsuki.radar_g"; static RUNTIME: SafeLazy = diff --git a/src/map_tile.rs b/src/map_tile.rs new file mode 100644 index 0000000..6a46071 --- /dev/null +++ b/src/map_tile.rs @@ -0,0 +1,54 @@ +use crate::map_tile_utils::lat_lon_to_zoom; +use femtovg::ImageSource; +use reqwest::{Client, Error, Url}; +use slippy_map_tiles::{BBox, merc_location_to_tile_coords, Tile}; +use crate::coords::Range; + +pub struct MapTile { + server: String, + api_key: String, + style: String, + client: Client, +} + +impl Default for MapTile{ + fn default() -> Self { + Self{ + server: "https://tiles.stadiamaps.com/tiles/".to_string(), + api_key: "06f1aeed-5d91-48e3-9ce5-1e99063f7f73".to_string(), + style: "stamen_toner/".to_string(), + client: Client::new(), + } + } +} + +impl MapTile { + + pub fn new_tiles(&self, zoom: u8, lat_range: (f32, f32), lon_range: (f32, f32)) -> impl Iterator + Sized { + let bbox= BBox::new(lat_range.1 , lon_range.0, lat_range.0, lon_range.1).unwrap(); + let tiles = bbox.tiles_for_zoom(zoom); + tiles + } + pub async fn get_tile( + &self, + tile: &Tile + ) -> Result, Error> + { + let base_url = Url::parse(&self.server).unwrap(); + // let zoom = lat_lon_to_zoom(lat_range, lat_range, w, h); + let mut request_url = base_url + .join(&self.style) + .unwrap() + .join(&format!("{}/{}/{}.png", tile.zoom(), tile.x(), tile.y())) + .unwrap(); + + let result = self + .client + .get(request_url) + .query(&[("api_key", &self.api_key)]) + .send() + .await?; + let bytes = result.bytes().await?; + Ok(bytes.to_vec()) + } +} diff --git a/src/predefined/mod.rs b/src/predefined/mod.rs index 4df6fb4..69ed738 100644 --- a/src/predefined/mod.rs +++ b/src/predefined/mod.rs @@ -1 +1 @@ -mod map_tile; \ No newline at end of file +pub mod map_tile; \ No newline at end of file diff --git a/src/widgets/render/exterior/imp.rs b/src/widgets/render/exterior/imp.rs index 5e4272d..7ac841f 100644 --- a/src/widgets/render/exterior/imp.rs +++ b/src/widgets/render/exterior/imp.rs @@ -3,7 +3,6 @@ use gtk::glib; use gtk::subclass::prelude::*; use std::cell::RefCell; - #[derive(Default)] pub struct ExteriorWidget { } diff --git a/src/widgets/render/imp.rs b/src/widgets/render/imp.rs index 79b6a0c..e127777 100644 --- a/src/widgets/render/imp.rs +++ b/src/widgets/render/imp.rs @@ -3,14 +3,17 @@ use super::interior::InteriorWidget; use super::{Layer, WindowCoord}; use crate::coords::proj::Mercator; use crate::coords::Mapper; +use crate::pipeline::element::Target; use femtovg::{Canvas, Color, FontId, Renderer}; use gtk::glib::{self, prelude::*, Properties}; use gtk::subclass::prelude::*; use gtk::traits::{GLAreaExt, WidgetExt}; use std::cell::{Cell, RefCell}; +use std::collections::HashMap; use std::num::NonZeroU32; use std::rc::Rc; use std::sync::{Arc, Mutex}; +use slippy_map_tiles::Tile; #[derive(Debug, Default, Clone, Copy, PartialEq)] pub struct RenderConfig { @@ -48,10 +51,13 @@ pub struct RenderStatus { pub struct Render { #[property(get, set)] render_status: Cell, + #[property(get, set)] + range_changing: Cell, pub(super) exterior: RefCell, pub(super) interior: RefCell, pub(super) canvas: RefCell>>, pub(super) glow_context: RefCell>, + pub(super) tiles: RefCell>>>, pub config: RefCell, pub status: RefCell, pub mapper: RefCell, @@ -61,6 +67,7 @@ pub struct Render { impl Default for Render { fn default() -> Self { Self { + range_changing: Cell::new(0.0), render_status: Cell::new(0), exterior: RefCell::new(ExteriorWidget::default()), interior: RefCell::new(InteriorWidget::default()), @@ -68,6 +75,7 @@ impl Default for Render { interior_layers: RefCell::new(Rc::new(RefCell::new(Vec::new()))), config: RefCell::new(RenderConfig::default()), status: RefCell::new(RenderStatus::default()), + tiles: RefCell::new(Rc::new(RefCell::new(HashMap::new()))), mapper: RefCell::new(Mercator::default().into()), canvas: RefCell::new(None), } @@ -152,6 +160,12 @@ impl GLAreaImpl for Render { (w, h) }; + let tiles = self.tiles.borrow().borrow(); + + for tile in tiles.values() { + + } + let render_range = self.status.borrow().view_range.clone(); if let Some(((lat1, lat2), (lon1, lon2))) = render_range { let mut status = self.status.borrow_mut(); diff --git a/src/widgets/render/interior/imp.rs b/src/widgets/render/interior/imp.rs index 0ab72da..563a69d 100644 --- a/src/widgets/render/interior/imp.rs +++ b/src/widgets/render/interior/imp.rs @@ -2,7 +2,7 @@ use super::super::WindowCoord; use gtk::glib; use gtk::subclass::prelude::*; use std::cell::RefCell; - +use std::sync::{Arc, Mutex}; use super::layers::Layer; #[derive(Default)] diff --git a/src/widgets/render/interior/map_tile.rs b/src/widgets/render/interior/map_tile.rs deleted file mode 100644 index 2a3e916..0000000 --- a/src/widgets/render/interior/map_tile.rs +++ /dev/null @@ -1,30 +0,0 @@ -pub(super) struct MapTile { - server: Option, - lat_range: (f64, f64), - lon_range: (f64, f64), - zoom: u8, -} - -impl MapTile{ - pub fn new(server: Option, lat_range: (f64, f64), lon_range: (f64, f64), zoom: u8) -> MapTile { - MapTile { - server, - lat_range, - lon_range, - zoom, - } - } - - pub fn get_server(&self) -> Option { - self.server.clone() - } - - pub fn get_lat_range(&self) -> (f64, f64) { - self.lat_range - } - - pub fn get_lon_range(&self) -> (f64, f64) { - self.lon_range - } -} - diff --git a/src/widgets/render/interior/mod.rs b/src/widgets/render/interior/mod.rs index 7171fda..dd0769a 100644 --- a/src/widgets/render/interior/mod.rs +++ b/src/widgets/render/interior/mod.rs @@ -1,11 +1,18 @@ mod imp; mod layers; -mod map_tile; + +use gtk::subclass::prelude::ObjectSubclassIsExt; use super::super::Render; -use femtovg::{renderer::OpenGl, Canvas}; -pub use layers::{Layer, LayerImpl, LayerImplSync, AssoElement}; +use crate::RUNTIME; +use core_extensions::SelfOps; +use femtovg::{renderer::OpenGl, Canvas, ImageFlags}; +use femtovg::{Paint, Path}; +pub use layers::{AssoElement, Layer, LayerImpl, LayerImplSync}; +use relm4::channel; use std::cell::Ref; +use tokio::task; +use tokio::task::LocalSet; use super::imp::{RenderConfig, RenderStatus}; diff --git a/src/widgets/render/mod.rs b/src/widgets/render/mod.rs index 654ca3f..15abc27 100644 --- a/src/widgets/render/mod.rs +++ b/src/widgets/render/mod.rs @@ -8,7 +8,7 @@ pub mod widget; // pub use self::cms::CMS; use crate::coords::cms::CMS; pub use self::imp::{RenderConfig, RenderMotion, RenderStatus}; -use crate::coords::Mapper; +use crate::coords::{Mapper, Range}; use adw::prelude::{GLAreaExt, GestureDragExt}; use geo_types::LineString; use glib::clone; @@ -17,8 +17,13 @@ use gtk::traits::WidgetExt; use gtk::{EventControllerScrollFlags, Inhibit}; pub use interior::*; use std::cell::{Ref, RefCell, RefMut}; +use std::collections::HashMap; use std::rc::Rc; use std::sync::{Arc, Mutex}; +use femtovg::ImageFlags; +use slippy_map_tiles::Tile; +use crate::errors::PipelineError; +use crate::pipeline::element::{Target, TargetType}; pub type WindowCoord = (f32, f32); @@ -64,6 +69,7 @@ impl Render { status.scale = y as f32; status.motion = RenderMotion::Scale; }); + r.set_range_changing(0.0); r.queue_render(); Inhibit(false) } @@ -78,6 +84,7 @@ impl Render { s.translate = Some((-ox as f32 * dpi , oy as f32 * dpi)); s.motion = RenderMotion::Translate; }); + r.set_range_changing(0.0); r.queue_render(); })); @@ -205,6 +212,21 @@ impl Render { pub fn set_view(&self, range: (f64, f64, f64, f64)) { self.imp().set_view(range); + self.set_range_changing(range.0 + range.1); + // self.set_range(range); self.queue_render(); } + + pub fn set_tiles(&self, tiles: Rc>>) { + self.imp().tiles.replace(tiles); + self.queue_render(); + } + + pub fn load_img_mem(&self, img: &[u8], origin:(f64,f64),size :(f32,f32), bounds: (Range, Range)) -> Result { + let mut canvas = self.get_canvas(); + let cvs = canvas.as_mut().unwrap(); + let img_id = cvs.load_image_mem(img, ImageFlags::empty()).unwrap(); + let (width, height) = size; + Ok(Target::new(TargetType::ImageId(img_id), width, height, bounds, None, None)) + } }