diff --git a/_build.rs b/build.rs similarity index 82% rename from _build.rs rename to build.rs index 43dcf67..33c8818 100644 --- a/_build.rs +++ b/build.rs @@ -2,6 +2,6 @@ fn main() { glib_build_tools::compile_resources( &["src/resources"], "src/resources/resources.gresource.xml", - "monitor.gresource", + "p.gresource", ); } diff --git a/src/assets/Roboto-Bold.ttf b/src/assets/Roboto-Bold.ttf new file mode 100644 index 0000000..aaf374d Binary files /dev/null and b/src/assets/Roboto-Bold.ttf differ diff --git a/src/assets/Roboto-Light.ttf b/src/assets/Roboto-Light.ttf new file mode 100644 index 0000000..664e1b2 Binary files /dev/null and b/src/assets/Roboto-Light.ttf differ diff --git a/src/assets/Roboto-Regular.ttf b/src/assets/Roboto-Regular.ttf new file mode 100644 index 0000000..3e6e2e7 Binary files /dev/null and b/src/assets/Roboto-Regular.ttf differ diff --git a/src/assets/amiri-regular.ttf b/src/assets/amiri-regular.ttf new file mode 100644 index 0000000..0fa885b Binary files /dev/null and b/src/assets/amiri-regular.ttf differ diff --git a/src/assets/entypo.ttf b/src/assets/entypo.ttf new file mode 100644 index 0000000..fc305d2 Binary files /dev/null and b/src/assets/entypo.ttf differ diff --git a/src/coords/mapper.rs b/src/coords/mapper.rs index e099531..8770503 100644 --- a/src/coords/mapper.rs +++ b/src/coords/mapper.rs @@ -1,21 +1,20 @@ +use super::{proj::ProjectionS, Range}; use geo_types::{coord, Coord as GCoord, LineString}; use proj::{Proj, ProjError}; -use std::ops::Range; - -use super::proj::ProjectionS; +use std::ops; pub struct Mapper { proj: Proj, - range: (Range, Range), + pub range: (Range, Range), bounds: (f64, f64, f64, f64), } impl From for Mapper { fn from(proj: Proj) -> Self { - let default_range: (Range, Range) = (-180.0..180.0, -90.0..90.0); + let default_range: (Range, Range) = ((-180.0..180.0).into(), (-90.0..90.0).into()); let bounds = Self::bound(&proj, default_range.clone()).unwrap(); Self { proj: proj, - range: default_range, + range: (default_range.0.into(), default_range.1.into()), bounds, } } @@ -29,9 +28,13 @@ impl From for Mapper { } impl Mapper { - pub fn new(proj: Proj, lon_range: Range, lat_range: Range) -> Self { - let bounds = Self::bound(&proj, (lon_range.clone(), lat_range.clone())).unwrap(); - let range = (lon_range, lat_range); + pub fn new( + proj: Proj, + lon_range: std::ops::Range, + lat_range: std::ops::Range, + ) -> Self { + let bounds = Self::bound(&proj, (lon_range.clone().into(), lat_range.clone().into())).unwrap(); + let range = (lon_range.into(), lat_range.into()); Self { proj: proj, range, @@ -50,22 +53,19 @@ impl Mapper { Ok((x, y)) } - pub fn set_lon_range(&mut self, range: Range) { - self.range.0 = range; + pub fn set_lon_range(&mut self, range: std::ops::Range) { + self.range.0 = range.into(); self.bounds = Self::bound(&self.proj, self.range.clone()).unwrap(); } - pub fn set_lat_range(&mut self, range: Range) { - self.range.1 = range; + pub fn set_lat_range(&mut self, range: std::ops::Range) { + self.range.1 = range.into(); self.bounds = Self::bound(&self.proj, self.range.clone()).unwrap(); } - fn bound( - proj: &Proj, - range: (Range, Range), - ) -> Result<(f64, f64, f64, f64), ProjError> { - let left_bottom = proj.convert((range.0.start.to_radians(), range.1.start.to_radians()))?; - let right_top = proj.convert((range.0.end.to_radians(), range.1.end.to_radians()))?; + fn bound(proj: &Proj, range: (Range, Range)) -> Result<(f64, f64, f64, f64), ProjError> { + let left_bottom = proj.convert((range.0 .0.to_radians(), range.1 .0.to_radians()))?; + let right_top = proj.convert((range.0 .1.to_radians(), range.1 .1.to_radians()))?; Ok((left_bottom.0, right_top.0, left_bottom.1, right_top.1)) } @@ -81,7 +81,7 @@ impl Mapper { let delta2 = 0.5; let depth = 16; let mut res: Vec = Vec::new(); - res.push(l.start); + res.push(p.start); self.resample_line_to( start_projected, end_projected, @@ -94,7 +94,7 @@ impl Mapper { depth, &mut res, )?; - res.push(l.end); + res.push(p.end); result.extend(res); } diff --git a/src/coords/mod.rs b/src/coords/mod.rs index 43f08f1..eef14a0 100644 --- a/src/coords/mod.rs +++ b/src/coords/mod.rs @@ -5,7 +5,7 @@ pub mod proj; pub mod wgs84; pub use mapper::Mapper; -pub use wgs84::LatLonCoord; +// pub use wgs84::LatLonCoord; pub type ScreenCoord = (f64, f64); type Lat = f64; @@ -114,6 +114,14 @@ impl + Num> From<(T, T)> for Range { } } +impl> From> for Range { + fn from(value: std::ops::Range) -> Self { + let value = (value.start.as_(), value.end.as_()); + let (_min, _max) = (value.0.min(value.1), value.0.max(value.1)); + Self(_min, _max) + } +} + // impl RadarData2d // where // T: Num + Clone + PartialEq + PartialOrd, diff --git a/src/coords/proj/mercator.rs b/src/coords/proj/mercator.rs index 1847715..8de54b6 100644 --- a/src/coords/proj/mercator.rs +++ b/src/coords/proj/mercator.rs @@ -8,10 +8,6 @@ use geo_macros::Prj; pub struct Mercator { /// The central longitude of the projection. pub central_lon: f64, - /// The minimum latitude of the projection. - pub min_latitude: f64, - /// The maximum latitude of the projection. - pub max_latitude: f64, /// The false easting of the projection. pub false_easting: f64, /// The false northing of the projection. @@ -32,8 +28,6 @@ impl Mercator { pub fn new() -> Self { Self { central_lon: 0.0, - min_latitude: -82.0, - max_latitude: 82.0, false_easting: 0.0, false_northing: 0.0, latitude_true_scale: 0.0, @@ -61,20 +55,4 @@ impl ProjectionS for Mercator { _proj_string } - fn logic_range(&self, lon_range: Option, lat_range: Option) -> (Range, Range) { - let lon_range = lon_range.unwrap_or(Range { - 0: -180f64, - 1: 180f64, - }); - let lat_range = lat_range.unwrap_or(Range { - 0: self.min_latitude, - 1: self.max_latitude, - }); - - let lat_range = Range { - 0: lat_range.0.max(self.min_latitude), - 1: lat_range.1.min(self.max_latitude), - }; - (lon_range, lat_range) - } } diff --git a/src/coords/proj/mod.rs b/src/coords/proj/mod.rs index 4cf882d..c715de0 100644 --- a/src/coords/proj/mod.rs +++ b/src/coords/proj/mod.rs @@ -18,18 +18,6 @@ pub enum Projs { pub trait ProjectionS { /// Returns a proj-string of the projection. fn build(&self) -> String; - - /// Returns the logical range of the projection. - /// In common, different projections have different logical ranges. - /// # Arguments - /// - /// * `lon_range` - An optional longitude range. - /// * `lat_range` - An optional latitude range. - /// - /// # Returns - /// - /// A tuple containing the longitude and latitude ranges. - fn logic_range(&self, lon_range: Option, lat_range: Option) -> (Range, Range); } #[derive(Debug, Error)] @@ -38,42 +26,42 @@ pub(super) enum ProjError { ProjError(#[from] proj::ProjError), } -pub(super) struct PCS { - pub lon_range: Range, - pub lat_range: Range, - pub proj_param: T, - // pub proj_target: proj5::CoordinateBuf, - pub transformer: Proj, -} +// pub(super) struct PCS { +// pub lon_range: Range, +// pub lat_range: Range, +// pub proj_param: T, +// // pub proj_target: proj5::CoordinateBuf, +// pub transformer: Proj, +// } -impl PCS { - pub(super) fn new(proj_param: T, lon_range: Option, lat_range: Option) -> Self { - let (lon_range, lat_range) = proj_param.logic_range(lon_range, lat_range); - Self { - lon_range, - lat_range, - transformer: Proj::new(proj_param.build().as_str()).unwrap(), - proj_param: proj_param, - } - } +// impl PCS { +// pub(super) fn new(proj_param: T, lon_range: Option, lat_range: Option) -> Self { +// let (lon_range, lat_range) = proj_param.logic_range(lon_range, lat_range); +// Self { +// lon_range, +// lat_range, +// transformer: Proj::new(proj_param.build().as_str()).unwrap(), +// proj_param: proj_param, +// } +// } - pub fn bbox(&self) -> Result<(Range, Range), ProjError> { - let _proj_transformer = &self.transformer; - let lb = (self.lon_range.0.to_radians(), self.lat_range.0.to_radians()); - let rt = (self.lon_range.1.to_radians(), self.lat_range.1.to_radians()); +// pub fn bbox(&self) -> Result<(Range, Range), ProjError> { +// let _proj_transformer = &self.transformer; +// let lb = (self.lon_range.0.to_radians(), self.lat_range.0.to_radians()); +// let rt = (self.lon_range.1.to_radians(), self.lat_range.1.to_radians()); - let bl = _proj_transformer.convert(lb)?; - let rt = _proj_transformer.convert(rt)?; +// let bl = _proj_transformer.convert(lb)?; +// let rt = _proj_transformer.convert(rt)?; - Ok((Range::from((bl.0, rt.0)), Range::from((bl.1, rt.1)))) - } +// Ok((Range::from((bl.0, rt.0)), Range::from((bl.1, rt.1)))) +// } - pub fn map(&self, lon_lat: (Lat, Lon)) -> (f64, f64) { - let _proj_transformer = &self.transformer; - let _lon_lat = _proj_transformer - .convert((lon_lat.0.to_radians(), lon_lat.1.to_radians())) - .unwrap(); +// pub fn map(&self, lon_lat: (Lat, Lon)) -> (f64, f64) { +// let _proj_transformer = &self.transformer; +// let _lon_lat = _proj_transformer +// .convert((lon_lat.0.to_radians(), lon_lat.1.to_radians())) +// .unwrap(); - _lon_lat - } -} +// _lon_lat +// } +// } diff --git a/src/coords/wgs84.rs b/src/coords/wgs84.rs index 6ad5f50..b0d526c 100644 --- a/src/coords/wgs84.rs +++ b/src/coords/wgs84.rs @@ -1,4 +1,4 @@ -use super::proj::{ProjectionS, PCS}; +// use super::proj::{ProjectionS, PCS}; use super::Coord; use super::{Lat, Lon, Range}; use proj::ProjError; @@ -13,76 +13,76 @@ pub enum CoordError { }, } -pub struct LatLonCoord { - actual: (Range, Range), - logical: (Range, Range), - pcs: PCS, -} +// pub struct LatLonCoord { +// actual: (Range, Range), +// logical: (Range, Range), +// pcs: PCS, +// } -impl LatLonCoord { - /// Creates a new `LatLonCoord` instance. - /// - /// # Arguments - /// - /// * `lon` - An optional longitude range. - /// * `lat` - An optional latitude range. - /// * `actual` - A tuple containing the actual ranges. - /// * `project` - A projection. - /// - /// # Returns - /// - /// A new `LatLonCoord` instance. - pub fn new( - lon: Option, - lat: Option, - actual: ((i32, i32), (i32, i32)), - // actual: (Range, Range), - project: T, - ) -> Self { - let pcs = PCS::new(project, lon, lat); - let _box = pcs.bbox().unwrap(); - Self { - actual: (Range::from(actual.0), Range::from(actual.1)), - pcs: pcs, - logical: _box, - } - } +// impl LatLonCoord { +// /// Creates a new `LatLonCoord` instance. +// /// +// /// # Arguments +// /// +// /// * `lon` - An optional longitude range. +// /// * `lat` - An optional latitude range. +// /// * `actual` - A tuple containing the actual ranges. +// /// * `project` - A projection. +// /// +// /// # Returns +// /// +// /// A new `LatLonCoord` instance. +// pub fn new( +// lon: Option, +// lat: Option, +// actual: ((i32, i32), (i32, i32)), +// // actual: (Range, Range), +// project: T, +// ) -> Self { +// let pcs = PCS::new(project, lon, lat); +// let _box = pcs.bbox().unwrap(); +// Self { +// actual: (Range::from(actual.0), Range::from(actual.1)), +// pcs: pcs, +// logical: _box, +// } +// } - pub fn set_actual(&mut self, actual: ((i32, i32), (i32, i32))) { - self.actual = (Range::from(actual.0), Range::from(actual.1)); - } +// pub fn set_actual(&mut self, actual: ((i32, i32), (i32, i32))) { +// self.actual = (Range::from(actual.0), Range::from(actual.1)); +// } - pub fn lon_range(&self) -> Range { - self.pcs.lon_range - } +// pub fn lon_range(&self) -> Range { +// self.pcs.lon_range +// } - pub fn lat_range(&self) -> Range { - self.pcs.lat_range - } -} +// pub fn lat_range(&self) -> Range { +// self.pcs.lat_range +// } +// } -impl Coord for LatLonCoord { - fn map(&self, axis_1: f64, axis_2: f64) -> super::ScreenCoord { - let point = self.pcs.map((axis_1, axis_2)); - let logical_dim1_span = self.logical.0 .1 - self.logical.0 .0; +// impl Coord for LatLonCoord { +// fn map(&self, axis_1: f64, axis_2: f64) -> super::ScreenCoord { +// let point = self.pcs.map((axis_1, axis_2)); +// let logical_dim1_span = self.logical.0 .1 - self.logical.0 .0; - let dim1_rate = (point.0 - self.logical.0 .0) / logical_dim1_span; - let logical_dim2_span = self.logical.1 .1 - self.logical.1 .0; - let dim2_rate = (point.1 - self.logical.1 .0) / logical_dim2_span; +// let dim1_rate = (point.0 - self.logical.0 .0) / logical_dim1_span; +// let logical_dim2_span = self.logical.1 .1 - self.logical.1 .0; +// let dim2_rate = (point.1 - self.logical.1 .0) / logical_dim2_span; - ( - (dim1_rate * (self.actual.0 .1 - self.actual.0 .0) as f64) + self.actual.0 .0, - (dim2_rate * (self.actual.1 .1 - self.actual.1 .0) as f64) + self.actual.1 .0, - ) - } +// ( +// (dim1_rate * (self.actual.0 .1 - self.actual.0 .0) as f64) + self.actual.0 .0, +// (dim2_rate * (self.actual.1 .1 - self.actual.1 .0) as f64) + self.actual.1 .0, +// ) +// } - fn dim1_range(&self) -> (f64, f64) { - let v = self.lon_range(); - (v.0, v.1) - } +// fn dim1_range(&self) -> (f64, f64) { +// let v = self.lon_range(); +// (v.0, v.1) +// } - fn dim2_range(&self) -> (f64, f64) { - let v = self.lat_range(); - (v.0, v.1) - } -} +// fn dim2_range(&self) -> (f64, f64) { +// let v = self.lat_range(); +// (v.0, v.1) +// } +// } diff --git a/src/main.rs b/src/main.rs index 4026357..1289855 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ use coords::proj::Mercator; use coords::Mapper; use data::{Npz, Radar2d}; +use femtovg::{Color, Paint}; use gtk::prelude::*; use gtk::{gio, glib, Application, ApplicationWindow}; use std::ptr; @@ -10,7 +11,6 @@ mod errors; mod monitor; mod pipeline; mod render; -mod tree; mod window; use monitor::Monitor; use render::{BackgroundConfig, BackgroundWidget, ForegroundConfig, ForegroundWidget, Render}; @@ -29,8 +29,11 @@ fn main() -> glib::ExitCode { .or_else(|_| libloading::os::windows::Library::open_already_loaded("epoxy-0.dll")) .unwrap(); + gio::resources_register_include!("p.gresource") + .expect("Failed to register resources."); + epoxy::load_with(|name| { - unsafe { library.get::<_>(name.as_bytes()) } + unsafe { library.get::<>(name.as_bytes()) } .map(|symbol| *symbol) .unwrap_or(ptr::null()) }); @@ -52,16 +55,20 @@ fn build_ui(app: &Application) { .title("My GTK App") .build(); - let mut background_config = BackgroundConfig::new(); + let mut background_config = BackgroundConfig::new() + .change_painter(Paint::color(Color::white())) + .change_show_lat_lines(true) + .change_show_lon_lines(true); let mut foreground_config = ForegroundConfig::new(); let background_widget = BackgroundWidget::new(background_config); let foreground_widget = ForegroundWidget::new(foreground_config); let render = Render::new(background_widget, foreground_widget); - let path = "/Users/ruomu/projects/cinrad_g/test2.npz"; + let path = "/Users/tsuki/projects/radar-g/test2.npz"; let data = Radar2d::::load(path, Npz).unwrap(); let projection = Mercator::new(); + let mut mapper: Mapper = projection.into(); mapper.set_lat_range(29.960..30.764); mapper.set_lon_range(120.038..120.965); diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs index e2834f3..5e7ba5e 100644 --- a/src/pipeline/mod.rs +++ b/src/pipeline/mod.rs @@ -1,9 +1,10 @@ use anyhow::{Ok, Result}; -use femtovg; +use femtovg::{self}; use geo_types::{line_string, LineString}; use image::RgbImage; -use ndarray::Array2; -use num_traits::Num; +use ndarray::parallel::prelude::*; +use ndarray::{Array2, ArrayView2}; +use num_traits::{Num, AsPrimitive, FromPrimitive}; use crate::{ coords::Mapper, @@ -18,22 +19,34 @@ impl Color { } } +impl From for Color { + fn from(value: femtovg::Color) -> Self { + Self(value) + } +} + pub trait Pipeline { type Output; fn run(&self, input: T) -> Result; } -pub struct ProjPipe { - pub mapper: Mapper, +pub struct ProjPipe<'a> { + pub mapper: &'a Mapper, } -impl Pipeline> for ProjPipe +impl<'a> ProjPipe<'a> { + pub fn new(mapper: &'a Mapper) -> Self { + Self { mapper } + } +} + +impl<'a, 'b: 'a, T, Raw> Pipeline<&'b RadarData2d> for ProjPipe<'a> where T: Num + Clone + PartialEq + PartialOrd, Raw: ndarray::Data + Clone + ndarray::RawDataClone, { type Output = Array2; - fn run(&self, input: RadarData2d) -> Result { + fn run(&self, input: &'b RadarData2d) -> Result { let dim1 = input.dim1.view(); let dim2 = input.dim2.view(); @@ -92,3 +105,26 @@ impl ShadePipe { &self.colors[left] } } + +impl<'a, T, Raw> Pipeline<&'a RadarData2d> for ShadePipe +where + T: Num + PartialEq + PartialOrd + Clone + FromPrimitive, + Raw: ndarray::Data + Clone + ndarray::RawDataClone, +{ + type Output = Array2>; + + fn run(&self, input: &'a RadarData2d) -> Result>> { + let data = input.data.view(); + + let result = data.mapv(|v| { + if T::from_i8(-125).unwrap() == v { + None + } else { + let color = self.get_color(v); + Some(color.0) + } + }); + + Ok(result) + } +} diff --git a/src/render/background/imp.rs b/src/render/background/imp.rs index 62de6da..b20355b 100644 --- a/src/render/background/imp.rs +++ b/src/render/background/imp.rs @@ -9,8 +9,8 @@ use std::cell::RefCell; pub struct BackgroundConfig { pub show_lat_lines: bool, pub show_lon_lines: bool, - pub lat_lines: Vec>, - pub lon_lines: Vec>, + pub lat_lines: Vec, + pub lon_lines: Vec, pub painter: Paint, } diff --git a/src/render/background/mod.rs b/src/render/background/mod.rs index cfaace7..6a89465 100644 --- a/src/render/background/mod.rs +++ b/src/render/background/mod.rs @@ -1,9 +1,9 @@ mod imp; -use crate::render::WindowCoord; -use femtovg::{renderer::OpenGl, Canvas, Path}; +use crate::coords::{Mapper, Range}; +use femtovg::{renderer::OpenGl, Canvas, Color, Paint, Path}; +use geo_types::{line_string, LineString, Point}; use glib::subclass::types::ObjectSubclassIsExt; -use gtk::{ffi::gtk_widget_get_width, glib, graphene::Rect, prelude::SnapshotExtManual}; -use std::ops::Range; +use std::cell::Ref; pub use self::imp::BackgroundConfig; @@ -25,36 +25,122 @@ impl BackgroundWidget { this } - fn mesh_lines(&self, canvas: &mut Canvas) { + fn draw_lines>>( + &self, + canvas: &mut Canvas, + line_painter: &Paint, + p: V, + ) { + p.into_iter().for_each(|line| { + let mut path = Path::new(); + let points: Vec> = line.points().collect(); + path.move_to(points[0].x() as f32, points[0].y() as f32); + points[1..].into_iter().for_each(|p| { + path.line_to(p.x() as f32, p.y() as f32); + }); + canvas.stroke_path(&mut path, line_painter); + }); + } + + fn mesh_lines( + &self, + canvas: &mut Canvas, + canvas_width: f32, + canvas_height: f32, + mapper: Ref<'_, Mapper>, + bound: (Range, Range), + ) { let imp = self.imp(); let line_painter = &imp.config.borrow().painter; - if imp.config.borrow().show_lat_lines { - for lat_line in imp.config.borrow().lat_lines.iter() { - let mut path = Path::new(); - lat_line.iter().for_each(|v| { - let (x, y) = *v; - path.move_to(x, y); - }); - canvas.stroke_path(&mut path, line_painter); - } + let (left, right) = (bound.0 .0, bound.0 .1); + let (bottom, top) = (bound.1 .0, bound.1 .1); + let config = imp.config.borrow(); + + if config.show_lat_lines { + let r = config.lat_lines.iter().map(|lat| { + let line = LineString::new(vec![(left, *lat).into(), (right, *lat).into()]); + let result = mapper.map_line(&line).unwrap(); + LineString::new( + result + .points() + .map(|p| (p.x() as f32 * canvas_width, p.y() as f32 * canvas_height).into()) + .collect(), + ) + }); + + self.draw_lines(canvas, line_painter, r); + } + + if config.show_lat_lines { + config.lat_lines.iter().for_each(|lat| { + let mut paint = Paint::color(Color::white()); + paint.set_font_size(35.0); + paint.set_line_width(1.0); + let text_location = mapper.map((left, *lat)).unwrap(); + + let _ = canvas.stroke_text( + text_location.0 as f32 * canvas_width, + text_location.1 as f32 * canvas_height, + format!("{:.2} N", lat), + &paint, + ); + }); + } + + if config.show_lon_lines { + config.lon_lines.iter().for_each(|lon| { + let mut paint = Paint::color(Color::white()); + paint.set_font_size(35.0); + paint.set_line_width(1.0); + let text_location = mapper.map((*lon, top + 0.1)).unwrap(); + + let _ = canvas.stroke_text( + text_location.0 as f32 * canvas_width, + text_location.1 as f32 * canvas_height, + format!("{:.2}", lon), + &paint, + ); + }); + } + + if imp.config.borrow().show_lon_lines { + let r = config.lon_lines.iter().map(|lon| { + let line = LineString::new(vec![(*lon, bottom).into(), (*lon, top).into()]); + let result = mapper.map_line(&line).unwrap(); + LineString::new( + result + .points() + .map(|p| (p.x() as f32 * canvas_width, p.y() as f32 * canvas_height).into()) + .collect(), + ) + }); + + self.draw_lines(canvas, line_painter, r); } - if imp.config.borrow().show_lon_lines {} } - pub fn draw(&self, canvas: &mut Canvas, scale: f32, dpi: i32) { - let canvas_widht = canvas.width(); + pub fn draw( + &self, + canvas: &mut Canvas, + scale: f32, + dpi: i32, + mapper: Ref<'_, Mapper>, + bound: (Range, Range), + ) { + let canvas_width = canvas.width(); let canvas_height = canvas.height(); + let config = self.imp().config.borrow(); - self.mesh_lines(canvas); + self.mesh_lines(canvas, canvas_width, canvas_height, mapper, bound); } - pub fn set_lat_lines(&self, lat_lines: Vec>) { + pub fn set_lat_lines(&self, lat_lines: Vec) { let imp = self.imp(); imp.config.borrow_mut().lat_lines = lat_lines; } - pub fn set_lon_lines(&self, lon_lines: Vec>) { + pub fn set_lon_lines(&self, lon_lines: Vec) { let imp = self.imp(); imp.config.borrow_mut().lon_lines = lon_lines; } diff --git a/src/render/foreground/imp.rs b/src/render/foreground/imp.rs index 92b3cbf..9e5d47f 100644 --- a/src/render/foreground/imp.rs +++ b/src/render/foreground/imp.rs @@ -1,5 +1,5 @@ use crate::render::{imp, WindowCoord}; -use femtovg::{ImageId, Paint}; +use femtovg::{ImageId, Paint, Color}; use geo_macros::Prj; use geo_types::LineString; use gtk::glib; @@ -29,6 +29,7 @@ pub struct ForegroundWidget { pub(super) dim2: RefCell>>, pub(super) image: RefCell>, pub(super) data: RefCell>>, + pub(super) color: RefCell>>>, } #[glib::object_subclass] diff --git a/src/render/foreground/mod.rs b/src/render/foreground/mod.rs index b968331..f075299 100644 --- a/src/render/foreground/mod.rs +++ b/src/render/foreground/mod.rs @@ -1,9 +1,8 @@ mod imp; use crate::coords::Mapper; -use crate::tree::get; use femtovg::{renderer::OpenGl, Canvas, Path}; -use femtovg::{Color, FontId, ImageFlags, Paint}; -use geo_types::LineString; +use femtovg::{Color, FontId, ImageFlags, ImageId, Paint}; +use geo_types::{LineString, Point}; use glib::subclass::types::ObjectSubclassIsExt; use gtk::glib; use ndarray::{s, Array2, Axis, Zip}; @@ -34,12 +33,12 @@ impl ForegroundWidget { let canvas_height = canvas.height(); let config = self.imp().config.borrow(); - println!("Resize: {} {}", canvas.width(), canvas.height()); + let colors = self.imp().color.borrow(); + let data = self.imp().data.borrow(); - let mut img = self.imp().image.borrow_mut(); - - if img.is_none() { - let mut img_id = canvas + if self.imp().image.borrow().is_none() { + println!("rebuild image"); + let img_id = canvas .create_image_empty( canvas_width as usize, canvas_height as usize, @@ -47,44 +46,75 @@ impl ForegroundWidget { ImageFlags::empty(), ) .unwrap(); - canvas.save(); - canvas.reset(); - if let Ok(size) = canvas.image_size(img_id) { - // canvas.set_render_target(femtovg::RenderTarget::Image(img_id)); - canvas.clear_rect(0, 0, size.0 as u32, size.1 as u32, Color::rgb(255, 255, 0)); + if let Ok(v) = canvas.image_size(img_id) { + println!("create image: {:?}", v); + canvas.set_render_target(femtovg::RenderTarget::Image(img_id)); + let colors = self.imp().color.borrow(); + let data = self.imp().data.borrow(); + if colors.is_some() && data.is_some() { + for (i, c) in colors + .as_ref() + .unwrap() + .t() + .iter() + .zip(data.as_ref().unwrap().iter()) + { + if i.is_none() { + continue; + } + let pts = c.points().collect::>(); + let first_point = pts[0]; + let mut path = Path::new(); + path.move_to( + first_point.x() as f32 * v.0 as f32 + 0.8, + first_point.y() as f32 * v.1 as f32 + 0.8, + ); - img.replace(img_id); + pts[1..].into_iter().for_each(|p| { + path.line_to(p.x() as f32 * v.0 as f32, p.y() as f32 * v.1 as f32) + }); + let c = i.unwrap(); + canvas.fill_path(&path, &Paint::color(c)); + } + } + + self.imp().image.replace(Some(img_id)); } - - canvas.restore(); - canvas.reset(); } - let img = canvas - .load_image_file("test.png", ImageFlags::NEAREST) - .unwrap(); + canvas.set_render_target(femtovg::RenderTarget::Screen); let mut path = Path::new(); - path.rect(0.0, 0.0, canvas_width, canvas_height); + canvas.fill_path( &path, - &Paint::image(img, 0.0, 0.0, canvas_width, canvas_height, 0.0, 1.0), + &Paint::image( + self.imp().image.borrow().as_ref().unwrap().to_owned(), + 0.0, + 0.0, + canvas_width, + canvas_height, + 0.0, + 1.0, + ), ); - - canvas.flush(); } - pub(super) fn set_dims(&mut self, dims: (Array2, Array2)) { + pub(super) fn set_dims(&self, dims: (Array2, Array2)) { self.imp().dim1.replace(Some(dims.0)); self.imp().dim2.replace(Some(dims.1)); } - // pub(super) fn set_image(&mut self, image: Vec) { - // self.imp().image.replace(Some(image)); - // } + pub(super) fn set_image(&self, image: ImageId) { + self.imp().image.replace(Some(image)); + } - pub(super) fn set_data(&mut self, data: Array2) { + pub fn set_colors(&self, colors: Array2>) { + self.imp().color.replace(Some(colors)); + } + + pub fn set_data(&self, data: Array2) { self.imp().data.replace(Some(data)); } } diff --git a/src/render/imp.rs b/src/render/imp.rs index 36b9667..59bdeec 100644 --- a/src/render/imp.rs +++ b/src/render/imp.rs @@ -3,7 +3,7 @@ use super::foreground::ForegroundWidget; use super::WindowCoord; use crate::coords::proj::Mercator; use crate::coords::Mapper; -use femtovg::{Color, Paint, Path}; +use femtovg::{Color, Paint, Path, FontId}; use gtk::glib; use gtk::subclass::prelude::*; use gtk::traits::{GLAreaExt, WidgetExt}; @@ -20,6 +20,12 @@ pub struct RenderConfig { pub transform: WindowCoord, } +struct Fonts { + sans: FontId, + bold: FontId, + light: FontId, +} + pub struct Render { pub(super) background: RefCell, pub(super) foreground: RefCell, @@ -81,24 +87,42 @@ impl GLAreaImpl for Render { let canvas = canvas.as_mut().unwrap(); let dpi = self.obj().scale_factor(); - let w = self.obj().width(); - let h = self.obj().width(); + let w = canvas.width(); + let h = canvas.height(); let configs = self.config.borrow(); canvas.clear_rect( 0, 0, - (w * dpi) as u32, - (h * dpi) as u32, + (w as i32 * dpi) as u32, + (h as i32 * dpi) as u32, Color::rgba(0, 0, 0, 255), ); - // self.background.borrow().draw(canvas, configs.scale, dpi); + let mapper = self.mapper.borrow(); + let (lon_range, lat_range) = mapper.range.clone(); + + { + let background_widget = self.background.borrow_mut(); + background_widget.set_lat_lines(lat_range.key_points(5)); + } + { + let background_widget = self.background.borrow_mut(); + background_widget.set_lon_lines(lon_range.key_points(10)); + } self.foreground .borrow() .draw(canvas, configs.scale, dpi, self.mapper.borrow()); + self.background.borrow().draw( + canvas, + configs.scale, + dpi, + self.mapper.borrow(), + (lon_range, lat_range), + ); + canvas.flush(); true @@ -113,6 +137,7 @@ impl Render { if self.canvas.borrow().is_some() { return; } + let widget = self.obj(); widget.attach_buffers(); @@ -131,7 +156,8 @@ impl Render { (renderer, glow::NativeFramebuffer(id)) }; renderer.set_screen_target(Some(fbo)); - let canvas = Canvas::new(renderer).expect("Cannot create canvas"); + let mut canvas = Canvas::new(renderer).expect("Cannot create canvas"); + canvas.add_font_dir("/Users/tsuki/projects/radar-g/src/assets").unwrap(); self.canvas.replace(Some(canvas)); } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 256e114..ddfbb6a 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,15 +1,17 @@ mod background; mod foreground; mod imp; -use std::fmt::Debug; - use crate::coords::Mapper; use crate::data::{MultiDimensionData, RadarData2d}; +use crate::pipeline::ProjPipe; +use crate::pipeline::{Pipeline, ShadePipe}; +use std::fmt::Debug; pub use self::background::{BackgroundConfig, BackgroundWidget}; pub use self::foreground::{ForegroundConfig, ForegroundWidget}; use self::imp::RenderConfig; use crate::data::DownSampleMeth; +use femtovg::Color; pub use glib::subclass::prelude::*; use image::RgbImage; use ndarray::{self, s, Array2, Axis, Dimension, Ix2, Zip}; @@ -70,45 +72,37 @@ impl Render { { assert!(data.dim1.shape().len() == data.dim2.shape().len()); + let levels: Vec = vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65] + .into_iter() + .map(|b| T::from_i8(b).unwrap()) + .collect(); + let 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), + ]; + let mapper = self.imp().mapper.borrow(); - // data.downsample((801 * 2 / 3, 947 * 2 / 3), DownSampleMeth::VAR); + + let pjp = ProjPipe::new(&mapper); + let rrp = ShadePipe::new(levels, colors.into_iter().map(|v| v.into()).collect()); + + let rainbow = pjp.run(&data).unwrap(); + self.imp().foreground.borrow_mut().set_data(rainbow); + let pbow:Array2> = rrp.run(&data).unwrap(); + self.imp().foreground.borrow_mut().set_colors(pbow); Ok(()) } -} - -// let levels: Vec = vec![0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65]; -// let 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), -// ]; - -// let c = d.map(|v| { -// let c = get(&levels, &colors, *v); -// image::Rgb([ -// (c.r * 255.0) as u8, -// (c.g * 255.0) as u8, -// (c.b * 255.0) as u8, -// ]) -// }); - -// let mut img = RgbImage::from_fn(927, 801, |x, y| c[[y as usize, x as usize]]); - -// img.save("test.png").unwrap(); - -// self.imp() -// .foreground -// .borrow_mut() -// .set_dims((meshed.dim1, meshed.dim2)); +} \ No newline at end of file diff --git a/src/resources/Roboto-Bold.ttf b/src/resources/Roboto-Bold.ttf new file mode 100644 index 0000000..aaf374d Binary files /dev/null and b/src/resources/Roboto-Bold.ttf differ diff --git a/src/resources/Roboto-Light.ttf b/src/resources/Roboto-Light.ttf new file mode 100644 index 0000000..664e1b2 Binary files /dev/null and b/src/resources/Roboto-Light.ttf differ diff --git a/src/resources/Roboto-Regular.ttf b/src/resources/Roboto-Regular.ttf new file mode 100644 index 0000000..3e6e2e7 Binary files /dev/null and b/src/resources/Roboto-Regular.ttf differ diff --git a/src/resources/amiri-regular.ttf b/src/resources/amiri-regular.ttf new file mode 100644 index 0000000..0fa885b Binary files /dev/null and b/src/resources/amiri-regular.ttf differ diff --git a/src/resources/entypo.ttf b/src/resources/entypo.ttf new file mode 100644 index 0000000..fc305d2 Binary files /dev/null and b/src/resources/entypo.ttf differ diff --git a/src/resources/resources.gresource.xml b/src/resources/resources.gresource.xml index b6aa1ed..9c3db4e 100644 --- a/src/resources/resources.gresource.xml +++ b/src/resources/resources.gresource.xml @@ -1,6 +1,6 @@ - monitor.ui + Roboto-Bold.ttf diff --git a/src/tree.rs b/src/tree.rs deleted file mode 100644 index a163714..0000000 --- a/src/tree.rs +++ /dev/null @@ -1,23 +0,0 @@ -use femtovg::Color; -use num_traits::Num; - -pub fn get(levels: &Vec, colors: &Vec, v: T) -> V -where - T: Num + PartialOrd + Copy, -{ - let len = levels.len(); - - let mut left = 0; - let mut right = len - 1; - - while left < right - 1 { - let middle = (right + left) / 2; - if v > levels[middle] { - left = middle; - } else { - right = middle; - } - } - - colors[left] -}