diff --git a/Cargo.lock b/Cargo.lock index a60d311..359f147 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,13 +78,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -149,8 +149,8 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "proc-macro2 1.0.63", - "quote 1.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", "regex", "rustc-hash", "shlex", @@ -208,6 +208,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "bzip2" version = "0.4.4" @@ -308,6 +314,7 @@ name = "cinrad_g" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "cairo-rs", "epoxy", "femtovg", @@ -322,11 +329,13 @@ dependencies = [ "glue", "gtk4", "image", + "lazy_static", "libadwaita", "libloading 0.8.0", "ndarray", "npyz", "num-traits", + "once_cell", "plotters", "plotters-backend", "proj", @@ -335,6 +344,7 @@ dependencies = [ "quadtree_rs", "relm4", "relm4-components", + "relm4-icons", "rstar", "shapefile", "svg", @@ -941,9 +951,9 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -1075,9 +1085,9 @@ dependencies = [ name = "geo-macros" version = "0.1.0" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -1239,8 +1249,8 @@ dependencies = [ "heck", "proc-macro-crate", "proc-macro-error", - "proc-macro2 1.0.63", - "quote 1.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] @@ -1380,8 +1390,8 @@ dependencies = [ "anyhow", "proc-macro-crate", "proc-macro-error", - "proc-macro2 1.0.63", - "quote 1.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", ] @@ -1404,6 +1414,24 @@ dependencies = [ "system-deps", ] +[[package]] +name = "gvdb" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7139233c0ecb66f285c47a3c1c02b35c8d52a42ca4c7448d0163e5637bb4bd3" +dependencies = [ + "byteorder", + "flate2", + "lazy_static", + "memmap2", + "quick-xml", + "safe-transmute", + "serde", + "serde_json", + "walkdir", + "zvariant", +] + [[package]] name = "half" version = "2.2.1" @@ -1730,6 +1758,15 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memmap2" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49388d20533534cd19360ad3d6a7dadc885944aa802ba3995040c5ec11288c6" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -1930,9 +1967,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "pango" @@ -2055,9 +2092,9 @@ checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" dependencies = [ "pest", "pest_meta", - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2086,9 +2123,9 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2185,8 +2222,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.63", - "quote 1.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", "syn 1.0.109", "version_check", ] @@ -2197,8 +2234,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", "version_check", ] @@ -2219,9 +2256,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" dependencies = [ "unicode-ident", ] @@ -2293,6 +2330,16 @@ dependencies = [ "num", ] +[[package]] +name = "quick-xml" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b9228215d82c7b61490fec1de287136b5de6f5700f6e58ea9ad61a7964ca51" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quote" version = "0.6.13" @@ -2304,11 +2351,11 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.29" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "573015e8ab27661678357f27dc26460738fd2b6c86e46f386fde94cb5d913105" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ - "proc-macro2 1.0.63", + "proc-macro2 1.0.76", ] [[package]] @@ -2420,15 +2467,25 @@ dependencies = [ "tracker", ] +[[package]] +name = "relm4-icons" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e28bcc718a587bcfa31b034e0b8f4efe5b70e945b7de9d7d154b45357a0dadc" +dependencies = [ + "gtk4", + "gvdb", +] + [[package]] name = "relm4-macros" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ad8d946cf33654b1df3e2e7d1c4952a154f008368cdda03a99c1840a6fcab3b" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2500,6 +2557,12 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +[[package]] +name = "safe-transmute" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98a01dab6acf992653be49205bdd549f32f17cb2803e8eacf1560bf97259aae8" + [[package]] name = "same-file" version = "1.0.6" @@ -2542,9 +2605,9 @@ version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2661,6 +2724,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.7.0" @@ -2702,19 +2771,19 @@ version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", "unicode-ident", ] [[package]] name = "syn" -version = "2.0.29" +version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", "unicode-ident", ] @@ -2781,9 +2850,9 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2820,8 +2889,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", + "bytes", "num_cpus", "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2888,9 +2970,9 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -2917,9 +2999,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca029746fbe0efda3298205de77bf759d7fef23ac97902641e0b49a623b0455f" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", ] [[package]] @@ -3053,9 +3135,9 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -3065,7 +3147,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "quote 1.0.29", + "quote 1.0.35", "wasm-bindgen-macro-support", ] @@ -3075,9 +3157,9 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2 1.0.63", - "quote 1.0.29", - "syn 2.0.29", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3394,3 +3476,40 @@ checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" dependencies = [ "simd-adler32", ] + +[[package]] +name = "zvariant" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44b291bee0d960c53170780af148dca5fa260a63cdd24f1962fa82e03e53338c" +dependencies = [ + "byteorder", + "libc", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "3.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934d7a7dfc310d6ee06c87ffe88ef4eca7d3e37bb251dece2ef93da8f17d8ecd" +dependencies = [ + "proc-macro-crate", + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 1.0.109", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" +dependencies = [ + "proc-macro2 1.0.76", + "quote 1.0.35", + "syn 1.0.109", +] diff --git a/Cargo.toml b/Cargo.toml index 1c881fe..5a71bed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,14 +40,17 @@ topojson = "0.5.1" geojson = "0.24.1" plotters = "0.3.5" plotters-backend = "0.3.5" -tokio = "1.35.1" +tokio = { version = "1.35.1", features = ["time", "fs", "io-std", "macros", "num_cpus", "bytes", "io-util"] } +async-trait = "0.1.77" +lazy_static = "1.4.0" +once_cell = "1.19.0" +relm4-icons = "0.6.0" # plotters-cairo = "0.5.0" [build-dependencies] glib-build-tools = "0.17.0" - [dependencies.geo-macros] path = "geo-macros" diff --git a/back.txt b/back.txt index 772c9b3..24a753e 100644 --- a/back.txt +++ b/back.txt @@ -85,3 +85,181 @@ // Npz, // BoundaryNorm::default(), // ) + + + +// fn resample( +// &self, +// width_rate: f64, +// height_rate: f64, +// filter_len: f64, +// ) -> Result>, DataError> { +// let width_rate = width_rate.min(1.0); +// let height_rate = height_rate.min(1.0); +// match self.coord_type { +// CoordType::Polar => Err(DataError::FormatError), +// CoordType::LatLon => { +// let width_filtered: ArrayBase, Ix2> = +// Self::_resample(&self.data, width_rate, filter_len); + +// let result: ArrayBase, Ix2> = +// Self::_resample(&width_filtered.t(), height_rate, filter_len) +// .t() +// .to_owned(); + +// let new_dim1: ArrayBase, Ix1> = Self::_resample( +// &Array2::from_shape_vec((1, self.dim1.len()), self.dim1.to_vec()).unwrap(), +// width_rate, +// filter_len, +// ) +// .slice(s![0, ..]) +// .to_owned(); + +// let new_dim2: ArrayBase, Ix1> = Self::_resample( +// &Array2::from_shape_vec((1, self.dim2.len()), self.dim2.to_vec()).unwrap(), +// height_rate, +// filter_len, +// ) +// .slice(s![0, ..]) +// .to_owned(); + +// Ok(RadarData2d { +// dim1: new_dim1, +// dim2: new_dim2, +// data: result, +// coord_type: self.coord_type.to_owned(), +// }) +// } +// } +// } + +// fn _resample<'a, V, R: ndarray::Data>( +// data: &'a ArrayBase, +// rate: f64, +// filter_len: f64, +// ) -> Array2 +// where +// V: Num + Clone + AsPrimitive + FromPrimitive, +// { +// let ori_width = data.ncols(); +// let ori_height = data.nrows(); + +// let new_width = (ori_width as f64 * rate).ceil() as usize; +// let mut result: Array2 = Array2::zeros((ori_height, new_width)); +// (0..ori_height).into_iter().for_each(|height| { +// for width in 0..new_width { +// let center_x = (width as f64 + 0.5) / new_width as f64 * ori_width as f64; +// let filter_start = center_x - filter_len / 2.0; +// let start_idx = (filter_start - 0.5).ceil() as usize; + +// let mut value_sum = 0.0; +// let mut filter_sum = 0.0; + +// for i in 0..filter_len as usize { +// let input_x = start_idx + i; +// let weight = windowed_sinc( +// (input_x as f64 + 0.5 - center_x) * rate, +// (input_x as f64 + 0.5 - filter_start) / filter_len, +// ); +// value_sum += weight * data[[height, input_x.clamp(0, ori_width - 1)]].as_(); +// filter_sum += weight; +// } + +// result[[height, width]] = V::from_f64(value_sum / filter_sum).unwrap(); +// } +// }); +// result +// } + +// pub struct LevelData( +// pub Quadtree>>, +// ); + +// impl LevelData +// where +// T: Num + Clone + AsPrimitive + FromPrimitive + Debug + PartialEq + PartialOrd, +// { +// fn value( +// level_data: Vec>>, +// level_num: usize, +// ) -> Vec>> { +// if level_num == 0 { +// return level_data; +// } + +// let mut result: Vec>> = +// Vec::with_capacity(level_data.len() * 4); + +// let results = level_data +// .iter() +// .flat_map(|v| v.split().into_iter().map(|x| x.value_to_owned())); + +// result.extend(results); + +// return Self::value(result, level_num - 1); +// } + +// fn new(data: &RadarData2d>, level: usize, rate: f64) -> Self { +// // let rate = 1.0 / level as f64; +// let resampled = data.resample(rate, rate, 2.0).unwrap(); +// let blocks = Self::value(vec![resampled], level); +// let mut tree: Quadtree>> = +// quadtree_rs::Quadtree::new(level); + +// blocks.into_iter().for_each(|block| { +// tree.insert( +// AreaBuilder::default() +// .anchor(quadtree_rs::point::Point { +// x: *block.dim1.first().unwrap() as i64, +// y: *block.dim2.first().unwrap() as i64, +// }) +// .dimensions((block.dim1.len() as i64, block.dim2.len() as i64)) +// .build() +// .unwrap(), +// block, +// ); +// }); + +// Self(tree) +// } +// } + +// pub fn levels(data: Radar2d, levels: usize) -> Vec> +// where +// T: Num + Clone + AsPrimitive + FromPrimitive + Debug, +// T: PartialEq + PartialOrd, +// { +// let numerator = 1.0 / levels as f64; +// (0..levels) +// .into_iter() +// .map(|level| LevelData::new(&data, level + 1, 1.0 - level as f64 * numerator)) +// .collect() +// } + + + + + +#[inline] +fn windowed_sinc(x: f64, y: f64) -> f64 { + let x = x * PI; + let sinc = if x != 0.0 { f64::sin(x) / x } else { 1.0 }; + let window = if 0f64 <= y && y <= 1.0 { + 1.0 - (y - 0.5).abs() * 2.0 + } else { + 0f64 + }; + sinc * window +} + +pub enum DownSampleMeth { + STD, + MEAN, + VAR, +} + +#[derive(Clone, Copy, Debug)] +pub enum CoordType { + Polar, + LatLon, +} \ No newline at end of file diff --git a/src/components/app.rs b/src/components/app.rs index 4a28a93..0a61bb6 100644 --- a/src/components/app.rs +++ b/src/components/app.rs @@ -59,21 +59,6 @@ impl SimpleComponent for AppModel { gtk::Inhibit(true) } } - // main_window = gtk::ApplicationWindow { - // set_default_width: 1200, - // set_default_height: 900, - // set_focus_on_click:true, - // set_titlebar: Some(>k::HeaderBar::new()), - // gtk::Box{ - // set_orientation: gtk::Orientation::Vertical, - // set_valign:gtk::Align::Fill, - - // }, - // connect_close_request[sender] => move |_| { - // sender.input(AppMsg::CloseRequest); - // gtk::Inhibit(true) - // } - // } } fn init( diff --git a/src/components/monitor/render/render.rs b/src/components/monitor/render/render.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/components/render_panel/mod.rs b/src/components/render_panel/mod.rs index 0e01fa3..7818869 100644 --- a/src/components/render_panel/mod.rs +++ b/src/components/render_panel/mod.rs @@ -1,4 +1,4 @@ -mod render_panel; mod messages; mod monitor; +mod render_panel; pub use render_panel::RenderPanelModel; diff --git a/src/components/render_panel/monitor/mod.rs b/src/components/render_panel/monitor/mod.rs index c41e0b7..4a039e0 100644 --- a/src/components/render_panel/monitor/mod.rs +++ b/src/components/render_panel/monitor/mod.rs @@ -1,4 +1,3 @@ pub mod monitor; -pub mod render; pub mod sidebar; pub use monitor::MonitorModel; diff --git a/src/components/render_panel/monitor/monitor.rs b/src/components/render_panel/monitor/monitor.rs index 182fa0e..933b21c 100644 --- a/src/components/render_panel/monitor/monitor.rs +++ b/src/components/render_panel/monitor/monitor.rs @@ -1,11 +1,18 @@ use crate::{ components::render_panel::messages::{MonitorInputMsg, MonitorOutputMsg}, - render::{Layer, Render}, + data::Npz, + render::{predefined::color_mapper::BoundaryNorm, Layer, Render}, }; +use std::sync::Arc; -use super::{render::render::RenderModel, sidebar::{sidebar::SideBarModel, SideBarOutputMsg}}; +use super::sidebar::{sidebar::SideBarModel, Msg, SideBarOutputMsg}; use adw::prelude::*; -use relm4::*; +use gtk::subclass::root; +use relm4::{ + component::{AsyncComponent, AsyncComponentParts}, + loading_widgets::LoadingWidgets, + *, +}; pub struct MonitorModel { sidebar_open: bool, sidebar_width: i32, @@ -17,11 +24,12 @@ pub struct MonitorWidgets { paned: gtk::Paned, } -#[relm4::component(pub)] -impl SimpleComponent for MonitorModel { +#[relm4::component(async, pub)] +impl AsyncComponent for MonitorModel { type Init = (); type Output = MonitorOutputMsg; type Input = MonitorInputMsg; + type CommandOutput = (); view! { adw::BreakpointBin { @@ -44,16 +52,18 @@ impl SimpleComponent for MonitorModel { } } - fn init( + async fn init( init: Self::Init, - root: &Self::Root, - sender: relm4::ComponentSender, - ) -> relm4::ComponentParts { - let sidebar: Controller = SideBarModel::builder() - .launch(()) - .forward(sender.input_sender(), |msg| match msg { - SideBarOutputMsg::NewLayer(layer) => MonitorInputMsg::AddLayer(layer), - }); + root: Self::Root, + sender: relm4::AsyncComponentSender, + ) -> AsyncComponentParts { + let sidebar: Controller = + SideBarModel::builder() + .launch(()) + .forward(sender.input_sender(), |msg| match msg { + SideBarOutputMsg::NewLayer(layer) => MonitorInputMsg::AddLayer(layer), + _ => MonitorInputMsg::None, + }); let model = MonitorModel { sidebar_open: true, sidebar_width: 400, @@ -62,10 +72,16 @@ impl SimpleComponent for MonitorModel { }; let widgets = view_output! {}; - ComponentParts { model, widgets } + AsyncComponentParts { model, widgets } } - fn update(&mut self, msg: Self::Input, _sender: ComponentSender) { + async fn update( + &mut self, + msg: Self::Input, + _sender: AsyncComponentSender, + _root: &Self::Root, + ) { + tokio::time::sleep(std::time::Duration::from_millis(100)).await; match msg { MonitorInputMsg::AddLayer(layer) => { self.layers.push(layer); @@ -73,6 +89,10 @@ impl SimpleComponent for MonitorModel { .output_sender() .send(MonitorOutputMsg::LayerAdded(0)) .unwrap(); + + self.sidebar + .sender() + .send(Msg::RefreshList(self.layers.clone())); } MonitorInputMsg::RemoveLayer(index) => { self.layers.remove(index); @@ -91,5 +111,4 @@ impl SimpleComponent for MonitorModel { MonitorInputMsg::None => {} } } - } diff --git a/src/components/render_panel/monitor/render/mod.rs b/src/components/render_panel/monitor/render/mod.rs deleted file mode 100644 index 60b6792..0000000 --- a/src/components/render_panel/monitor/render/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod render; -pub use render::*; diff --git a/src/components/render_panel/monitor/render/render.rs b/src/components/render_panel/monitor/render/render.rs deleted file mode 100644 index 0c0c343..0000000 --- a/src/components/render_panel/monitor/render/render.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::coords::proj::Mercator; -use crate::coords::Mapper; -use crate::render::{Render, RenderConfig}; -use relm4::*; - -pub struct RenderModel { - config: RenderConfig, - mapper: Mapper, -} - -#[relm4::component(pub)] -impl SimpleComponent for RenderModel { - type Init = (Option, Option); - type Output = (); - type Input = (); - - view! { - Render{ - set_mapper = model.mapper.clone(), - set_cfg = model.config.clone(), - } - } - - fn init( - init: Self::Init, - root: &Self::Root, - sender: relm4::ComponentSender, - ) -> relm4::ComponentParts { - let (mapper, config) = init; - let config = config.unwrap_or(RenderConfig::default()); - let mapper = mapper.unwrap_or(Mercator::default().into()); - - let model = RenderModel { config, mapper }; - let widgets = view_output!(); - - ComponentParts { model, widgets } - } - - fn update(&mut self, msg: Self::Input, _sender: ComponentSender) {} -} diff --git a/src/components/render_panel/monitor/sidebar/bottom_bar.rs b/src/components/render_panel/monitor/sidebar/bottom_bar.rs new file mode 100644 index 0000000..a0f1351 --- /dev/null +++ b/src/components/render_panel/monitor/sidebar/bottom_bar.rs @@ -0,0 +1,51 @@ +use gtk::prelude::*; +use relm4::{ + factory::FactoryView, + gtk, + prelude::{DynamicIndex, FactoryComponent}, + FactorySender, +}; + +use super::Msg; + +#[derive(Debug)] +pub enum TestMsg { + Delete, + MoveUp, + MoveDown, + Add, +} + +pub struct BottomBarModel { + icon: String, + msg: TestMsg, +} + +#[relm4::factory(pub)] +impl FactoryComponent for BottomBarModel { + type ParentWidget = gtk::Box; + type ParentInput = Msg; + type Input = (); + type Output = TextMsg; + type Init = BottomBarModel; + type CommandOutput = (); + + view! { + #[root] + gtk::Box{ + gtk::Button{ + #[wrap(Some)] + set_icon_name= model.icon.as_str(), + } + } + + } + + fn init_model(init: Self::Init, index: &DynamicIndex, sender: FactorySender) -> Self { + init + } + + fn update(&mut self, message: Self::Input, sender: FactorySender) { + match message {} + } +} diff --git a/src/components/render_panel/monitor/sidebar/mod.rs b/src/components/render_panel/monitor/sidebar/mod.rs index 3ec0fd0..6208f22 100644 --- a/src/components/render_panel/monitor/sidebar/mod.rs +++ b/src/components/render_panel/monitor/sidebar/mod.rs @@ -1,2 +1,3 @@ pub mod sidebar; pub use sidebar::*; +pub mod bottom_bar; diff --git a/src/components/render_panel/monitor/sidebar/sidebar.rs b/src/components/render_panel/monitor/sidebar/sidebar.rs index e5fc836..e45f31e 100644 --- a/src/components/render_panel/monitor/sidebar/sidebar.rs +++ b/src/components/render_panel/monitor/sidebar/sidebar.rs @@ -1,23 +1,30 @@ use glib::clone; +use gtk::prelude::WidgetExt; use gtk::prelude::*; use relm4::{ binding::{Binding, U8Binding}, + factory::{DynamicIndex, FactoryComponent, FactorySender, FactoryVecDeque}, prelude::*, typed_list_view::{RelmListItem, TypedListView}, RelmObjectExt, }; -use crate::{chart::Chart, render::{Layer, predefined::color_mapper::BoundaryNorm}, data::Npz}; +use crate::{ + chart::Chart, + data::Npz, + render::{predefined::color_mapper::BoundaryNorm, Layer}, +}; + +use super::bottom_bar::BottomBarModel; pub struct SideBarModel { counter: u8, - list_view_wrapper: TypedListView, + list_view_wrapper: TypedListView, + bottom_bar_vec: FactoryVecDeque, } #[derive(Debug)] pub enum Msg { - Append, - Remove, - OnlyShowEven(bool), + RefreshList(Vec), } #[derive(Debug)] @@ -32,13 +39,24 @@ impl SimpleComponent for SideBarModel { type Input = Msg; view! { - gtk::Box { + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + set_margin_all: 5, + + gtk::Paned{ set_orientation: gtk::Orientation::Vertical, + set_position: 300, + #[wrap(Some)] + set_start_child = >k::Box{ + set_orientation: gtk::Orientation::Vertical, set_spacing: 5, - set_margin_all: 5, - gtk::Notebook { - set_vexpand: true, - append_page:(&page_1, Some(&label)), + #[local] + top_panel -> gtk::Notebook{}, + gtk::Button { + set_label: "Add Layers", + connect_clicked[sender] => move |_| { + }, }, gtk::Button { set_label: "Add Layer", @@ -47,6 +65,7 @@ impl SimpleComponent for SideBarModel { SideBarOutputMsg::NewLayer( Layer::grid_render_layer_with_path( "/users/tsuki/projects/radar-g/test2.npz", + "DBZ".to_string(), Npz, BoundaryNorm::default(), ) @@ -54,13 +73,26 @@ impl SimpleComponent for SideBarModel { ).unwrap() }, }, - gtk::ScrolledWindow { - set_vexpand: true, - #[local_ref] - my_view -> gtk::ListView {} - } + }, + + #[wrap(Some)] + set_end_child=>k::Box{ + set_orientation: gtk::Orientation::Vertical, + set_vexpand: true, + set_hexpand: true, + #[local] + bottom_panel -> gtk::Notebook{ + set_margin_top: 10, + set_margin_bottom: 10, + }, + #[local_ref] + counter_box -> gtk::Box{} } - } + }, + + + } + } fn init( init: Self::Init, @@ -68,33 +100,33 @@ impl SimpleComponent for SideBarModel { sender: ComponentSender, ) -> ComponentParts { // Initialize the ListView wrapper - let mut list_view_wrapper: TypedListView = + let mut list_view_wrapper: TypedListView = TypedListView::with_sorting(); - // Add a filter and disable it - list_view_wrapper.add_filter(|item| item.value % 2 == 0); - list_view_wrapper.set_filter_status(0, false); + let bottom_bar_vec = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender()); let model = SideBarModel { counter: 0, list_view_wrapper, + bottom_bar_vec, }; - let my_view = &model.list_view_wrapper.view; - let page_1 = gtk::Box::builder() - .orientation(gtk::Orientation::Vertical) + let my_view = &model.list_view_wrapper.view; + let top_panel = gtk::Notebook::builder().vexpand(true).build(); + top_panel.append_page(&Chart::new(), Some(>k::Label::new(Some("Chart")))); + + let bottom_panel = gtk::Notebook::builder().vexpand(true).build(); + let layer_page = gtk::ScrolledWindow::builder() .vexpand(true) .hexpand(true) .build(); - let chart = Chart::new(); + let counter_box = model.bottom_bar_vec.widgets(); - chart.connect_resize(clone!(@weak chart as my_view => move |_, w,h|{ - my_view.set_height_request((w as f32 / 16.0 * 3.0) as i32); - })); - - page_1.append(&chart); - let label = gtk::Label::new(Some("Page 1")); + layer_page.set_child(Some(my_view)); + layer_page.set_margin_horizontal(5); + layer_page.set_margin_vertical(3); + bottom_panel.append_page(&layer_page, Some(>k::Label::new(Some("Layers")))); let widgets = view_output!(); ComponentParts { model, widgets } @@ -102,49 +134,33 @@ impl SimpleComponent for SideBarModel { fn update(&mut self, message: Self::Input, sender: ComponentSender) { match message { - Msg::Append => { - // Add 10 items - for _ in 0..10 { - self.counter = self.counter.wrapping_add(1); - self.list_view_wrapper.append(MyListItem::new(self.counter)); + Msg::RefreshList(layers) => { + for layer in layers { + self.list_view_wrapper + .append(LayerItem::new(layer.name, true)); } - - // Count up the first item - let first_item = self.list_view_wrapper.get(0).unwrap(); - let first_binding = &mut first_item.borrow_mut().binding; - let mut guard = first_binding.guard(); - *guard += 1; - } - Msg::Remove => { - // Remove the second item - self.list_view_wrapper.remove(1); - } - Msg::OnlyShowEven(show_only_even) => { - // Disable or enable the first filter - self.list_view_wrapper.set_filter_status(0, show_only_even); } } } } #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] -struct MyListItem { - value: u8, - binding: U8Binding, +struct LayerItem { + layer_name: String, + visiable: bool, } -impl MyListItem { - fn new(value: u8) -> Self { +impl LayerItem { + fn new(name: String, visiable: bool) -> Self { Self { - value, - binding: U8Binding::new(0), + layer_name: name, + visiable, } } } struct Widgets { label: gtk::Label, - label2: gtk::Label, button: gtk::CheckButton, } @@ -154,7 +170,7 @@ impl Drop for Widgets { } } -impl RelmListItem for MyListItem { +impl RelmListItem for LayerItem { type Root = gtk::Box; type Widgets = Widgets; @@ -162,34 +178,28 @@ impl RelmListItem for MyListItem { relm4::view! { my_box = gtk::Box { #[name = "label"] - gtk::Label, - - #[name = "label2"] - gtk::Label, - + gtk::Label{ + set_halign: gtk::Align::Start, + }, + gtk::Label{ + set_hexpand: true, + }, #[name = "button"] - gtk::CheckButton, + gtk::CheckButton{ + set_halign: gtk::Align::End, + }, } } - let widgets = Widgets { - label, - label2, - button, - }; + let widgets = Widgets { label, button }; (my_box, widgets) } fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) { - let Widgets { - label, - label2, - button, - } = widgets; + let Widgets { label, button } = widgets; - label.set_label(&format!("Value: {} ", self.value)); - label2.add_write_only_binding(&self.binding, "label"); - button.set_active(self.value % 2 == 0); + label.set_label(&format!("Layer: {} ", &self.layer_name)); + button.set_active(self.visiable); } } diff --git a/src/components/render_panel/render_panel.rs b/src/components/render_panel/render_panel.rs index 8eae91a..b06fedf 100644 --- a/src/components/render_panel/render_panel.rs +++ b/src/components/render_panel/render_panel.rs @@ -1,9 +1,15 @@ use super::messages::RenderInputMsg; -use gtk::prelude::*; use super::monitor::MonitorModel; -use relm4::*; +use gtk::prelude::*; +use relm4::component::AsyncComponentController; +use relm4::{ + component::{AsyncComponent, AsyncController}, + RelmWidgetExt, *, +}; + pub struct RenderPanelModel { - monitor: Controller, + // monitor: Controller, + monitor: AsyncController, } #[relm4::component(pub)] @@ -26,7 +32,8 @@ impl SimpleComponent for RenderPanelModel { root: &Self::Root, sender: relm4::ComponentSender, ) -> relm4::ComponentParts { - let monitor: Controller = MonitorModel::builder() + + let monitor: AsyncController = MonitorModel::builder() .launch(()) .forward(sender.input_sender(), |msg| {}); diff --git a/src/data/mod.rs b/src/data/mod.rs index cbca551..cb56a7d 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -1,12 +1,14 @@ use crate::errors::DataError; -use image::RgbImage; +use async_trait::async_trait; use ndarray::{ - s, Array, Array1, Array2, Array3, ArrayBase, Axis, DataMut, Dimension, Ix1, Ix2, OwnedRepr, - RawDataClone, ViewRepr, + s, Array1, Array2, Array3, ArrayBase, DataMut, Dimension, Ix1, Ix2, OwnedRepr, RawDataClone, }; use npyz::{npz::NpzArchive, Deserialize}; use num_traits::{AsPrimitive, FromPrimitive, Num}; +use std::io::{Cursor, Seek}; use std::{self, f64::consts::PI, fmt::Debug, io::BufReader, path::Path}; +use tokio::fs::File; +use tokio::io::{self, AsyncReadExt}; pub type Radar2d = RadarData2d>; @@ -107,7 +109,6 @@ where *self.dim2.last().unwrap(), output_shape.0, ); - // let mut dim2 = Array1::zeros(output_shape.0); output.iter_mut().enumerate().for_each(|(s, vv)| { let ri = s / output_shape.1; @@ -280,13 +281,21 @@ where fn load>(&self, path: P) -> Result; } +#[async_trait] +pub trait AsyncDataLoader +where + V: Num + Clone + PartialEq + PartialOrd, + T: MultiDimensionData + Send + Sync, +{ + async fn load + Send>(&self, path: P) -> Result; +} + pub struct Npz; impl Npz { #[inline] - fn load_1d( + fn load_1d( &self, - // path: &Path, - data: &mut NpzArchive>, + data: &mut NpzArchive, name: &str, ) -> Result, DataError> { // let mut data = npyz::npz::NpzArchive::open(path)?; @@ -296,10 +305,10 @@ impl Npz { Ok(Array1::from_shape_vec(b.len(), b).unwrap()) } #[inline] - fn load_2d( + fn load_2d( &self, // path: &Path, - data: &mut NpzArchive>, + data: &mut NpzArchive, name: &str, ) -> Result, DataError> { // let mut data = npyz::npz::NpzArchive::open(path)?; @@ -320,9 +329,9 @@ where { fn load>(&self, path: P) -> Result>, DataError> { let mut data: NpzArchive> = npyz::npz::NpzArchive::open(path)?; - let dim1 = self.load_1d::(&mut data, "lon")?; - let dim2 = self.load_1d::(&mut data, "lat")?; - let value = self.load_2d::(&mut data, "value")?; + let dim1 = self.load_1d::>(&mut data, "lon")?; + let dim2 = self.load_1d::>(&mut data, "lat")?; + let value = self.load_2d::>(&mut data, "value")?; Ok(RadarData2d { dim1: dim1, @@ -334,6 +343,47 @@ where } } +impl AsyncDataLoader>> for Npz +where + T: Num + Clone + Deserialize + FromPrimitive, + T: PartialEq + PartialOrd + Send + Sync, +{ + fn load<'life0, 'async_trait, P>( + &'life0 self, + path: P, + ) -> core::pin::Pin< + Box< + dyn core::future::Future>, DataError>> + + core::marker::Send + + 'async_trait, + >, + > + where + P: 'async_trait + AsRef + Send, + 'life0: 'async_trait, + Self: 'async_trait, + { + Box::pin(async { + let mut f = File::open(path).await?; + let mut buffer = Vec::new(); + f.read_to_end(&mut buffer).await?; + + let mut data = npyz::npz::NpzArchive::new(Cursor::new(buffer))?; + let dim1 = self.load_1d::>>(&mut data, "lon")?; + let dim2 = self.load_1d::>>(&mut data, "lat")?; + let value = self.load_2d::>>(&mut data, "value")?; + + Ok(RadarData2d { + dim1: dim1, + dim2: dim2, + fill_value: T::from_f64(-125.0).unwrap(), + data: value, + coord_type: CoordType::LatLon, + }) + }) + } +} + // fn resample( // &self, // width_rate: f64, diff --git a/src/errors.rs b/src/errors.rs index 19aa46a..36d7615 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -6,10 +6,7 @@ pub enum DataError { #[error("value")] FormatError, #[error("")] - IOError { - #[from] - source: std::io::Error, - }, + IOError(#[from] std::io::Error), } #[derive(Debug, Error)] diff --git a/src/main.rs b/src/main.rs index d5c140c..b4a0018 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use gtk::prelude::*; use gtk::{gio, glib, Application, ApplicationWindow}; use relm4::menu; use relm4::RelmApp; +use tokio::runtime::Runtime; use std::ptr; mod chart; mod components; @@ -14,9 +15,13 @@ mod pipeline; mod render; mod window; use components::app::{AppMode, AppModel}; +use once_cell::sync::Lazy; const APP_ID: &str = "org.gtk_rs.HelloWorld2"; +static RUNTIME: Lazy = + Lazy::new(|| Runtime::new().expect("Setting up tokio runtime needs to succeed.")); + fn main() { // Load GL pointers from epoxy (GL context management library used by GTK). { diff --git a/src/render/imp.rs b/src/render/imp.rs index b8291e4..05d460b 100644 --- a/src/render/imp.rs +++ b/src/render/imp.rs @@ -3,7 +3,7 @@ use super::interior::InteriorWidget; use super::{Layer, WindowCoord}; use crate::coords::proj::Mercator; use crate::coords::Mapper; -use femtovg::{Canvas, Color, FontId}; +use femtovg::{Canvas, Color, FontId, Renderer}; use gtk::glib; use gtk::subclass::prelude::*; use gtk::traits::{GLAreaExt, WidgetExt}; @@ -119,23 +119,23 @@ impl GLAreaImpl for Render { fn render(&self, context: >k::gdk::GLContext) -> bool { self.ensure_canvas(); - - let mut canvas = self.canvas.borrow_mut(); - let canvas = canvas.as_mut().unwrap(); - - let dpi = self.obj().scale_factor(); - let w = canvas.width(); - let h = canvas.height(); - let configs = self.config.borrow(); + { + let mut canvas = self.canvas.borrow_mut(); + let canvas = canvas.as_mut().unwrap(); - canvas.clear_rect( - 0, - 0, - (w as i32 * dpi) as u32, - (h as i32 * dpi) as u32, - Color::rgba(0, 0, 0, 255), - ); + let dpi = self.obj().scale_factor(); + let w = canvas.width(); + let h = canvas.height(); + + canvas.clear_rect( + 0, + 0, + (w as i32 * dpi) as u32, + (h as i32 * dpi) as u32, + Color::rgba(0, 0, 0, 255), + ); + } { let mut status = self.status.borrow_mut(); @@ -170,20 +170,18 @@ impl GLAreaImpl for Render { } } - let c = &(*self.interior_layers.borrow()); + self.interior + .borrow() + .draw(c, &self.obj(), self.status.borrow(), configs); + { + let mut canvas = self.canvas.borrow_mut(); + let canvas = canvas.as_mut().unwrap(); + self.exterior.borrow().draw(canvas, &self.obj()); + canvas.flush(); + } - self.interior.borrow().draw( - c, - canvas, - &self.obj(), - self.status.borrow(), - configs, - ); - self.exterior.borrow().draw(canvas, &self.obj()); - - canvas.flush(); true } } @@ -219,6 +217,7 @@ impl Render { canvas .add_font_dir("/Users/tsuki/projects/radar-g/src/assets") .unwrap(); + self.canvas.replace(Some(canvas)); } diff --git a/src/render/interior/layers.rs b/src/render/interior/layers.rs index d156ad3..18a412d 100644 --- a/src/render/interior/layers.rs +++ b/src/render/interior/layers.rs @@ -1,19 +1,31 @@ use crate::{coords::Range, render::Render}; +use femtovg::Paint; use femtovg::{renderer::OpenGl, Canvas, ImageId}; +use ndarray::AssignElem; use std::{ cell::{Ref, RefCell}, - fmt::Debug, sync::Arc, + fmt::Debug, + future::Future, + pin::Pin, + sync::{Arc, Mutex}, }; +type PrepareFunc = + Box, Render) -> Pin>> + Sync + Send>; +type DrawFunc = Box; +type LayerImplSync = Box; + #[derive(Clone)] pub struct Layer { pub visiable: bool, + pub name: String, + snapshot: Option, target: RefCell>, - imp: RefCell>>, - draw: Arc, &Render, (f32, f32))>, + prepare: Arc>, + imp: RefCell>>, + draw: Arc, } - impl Debug for Layer { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Layer") @@ -25,32 +37,53 @@ impl Debug for Layer { } pub trait LayerImpl: Debug { - fn draw(&self, canvas: &mut Canvas, render: &Render) -> Option; + fn draw(&self, render: Render) -> Option; } impl Layer { pub fn new< - F: 'static + Fn(&Self, &mut Canvas, &Render, (f32, f32)), - IMP: LayerImpl + 'static, + FU: Future + 'static, + F: 'static + Fn(&Self, Render, (f32, f32)) + Send + Sync, + PREPARE: FnOnce(Arc, Render) -> FU + Send + Sync + 'static, + IMP: LayerImpl + Sync + Send + 'static, >( visiable: bool, draw: F, + layer_name: String, + prepare: Option, imp: Option, ) -> Self { Layer { visiable, target: RefCell::new(None), - draw: Arc::new(draw), - imp: RefCell::new(imp.map(|x| Arc::new(x) as Arc)), + name: layer_name, + snapshot: None, + // prepare: Arc::new(prepare), + prepare: Arc::new(prepare.map(|p| { + Box::new( + move |layer: Arc, render: Render| -> Pin>> { + Box::pin(p(layer, render)) + }, + ) as PrepareFunc + })), + draw: Arc::new(Box::new(draw)), + imp: RefCell::new( + imp.map(|x| Arc::new(Box::new(x) as Box)), + ), } } - pub fn draw(&self, canvas: &mut Canvas, render: &Render, window_size: (f32, f32)) { + pub fn draw(&self, render: &Render, window_size: (f32, f32)) { if self.visiable { - (self.draw)(self, canvas, render, window_size); + let drawer = &self.draw; + drawer(self, render.clone(), window_size); } } + pub fn get_prepare(&self) -> Option<&PrepareFunc> { + self.prepare.as_ref().as_ref() + } + pub fn set_render_target(&self, target: Target) { *self.target.borrow_mut() = Some(target); } @@ -59,7 +92,7 @@ impl Layer { self.target.borrow().clone() } - pub fn get_imp(&self) -> Ref>> { + pub fn get_imp(&self) -> Ref>> { let im = self.imp.borrow(); im } diff --git a/src/render/interior/mod.rs b/src/render/interior/mod.rs index 7c1492a..aa496a7 100644 --- a/src/render/interior/mod.rs +++ b/src/render/interior/mod.rs @@ -23,19 +23,15 @@ impl InteriorWidget { this } - pub fn draw( &self, layers: &Vec, - canvas: &mut Canvas, render: &Render, status: Ref<'_, RenderStatus>, _c: Ref<'_, RenderConfig>, ) { - - let (x, y) = (canvas.width(), canvas.height()); for layer in layers.iter().filter(|x| x.visiable) { - layer.draw(canvas, &render, (x, y)); + layer.draw(render, (1000.0, 1000.0)); } } } diff --git a/src/render/mod.rs b/src/render/mod.rs index aa43ced..ae07117 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,20 +1,24 @@ mod cms; -mod imp; mod exterior; +mod imp; mod interior; pub mod predefined; mod renders; use self::cms::CMS; pub use self::imp::{RenderConfig, RenderMotion, RenderStatus}; use crate::coords::Mapper; +use crate::RUNTIME; use adw::prelude::{GLAreaExt, GestureDragExt}; use geo_types::LineString; use glib::clone; +pub use glib::subclass::prelude::*; use gtk::traits::WidgetExt; use gtk::{EventControllerScrollFlags, Inhibit}; -use std::cell::Ref; -pub use glib::subclass::prelude::*; pub use interior::{Layer, LayerImpl, Target}; +use relm4::once_cell::sync::Lazy; +use std::cell::{Ref, RefCell, RefMut}; +use std::sync::{Arc, Mutex}; +use tokio::runtime::Runtime; pub(super) type WindowCoord = (f32, f32); @@ -41,7 +45,6 @@ impl Render { this.set_mapper(mapper); } - let pointer_location_detecture = gtk::EventControllerMotion::new(); pointer_location_detecture.connect_motion( clone!( @weak this as r => move |_context, x, y| { @@ -104,6 +107,10 @@ impl Render { f(&mut cfg); } + pub fn get_canvas(&self) -> RefMut<'_, Option>> { + self.imp().canvas.borrow_mut() + } + pub fn set_cfg(&self, cfg: RenderConfig) { self.imp().config.replace(cfg); } diff --git a/src/render/predefined/color_mapper.rs b/src/render/predefined/color_mapper.rs index d39c6ae..47a86ad 100644 --- a/src/render/predefined/color_mapper.rs +++ b/src/render/predefined/color_mapper.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; use femtovg::Color; use num_traits::NumOps; -pub trait ColorMapper : Debug { +pub trait ColorMapper : Debug + Send + Sync { fn map_value_to_color(&self, value: T, invalid_value: T) -> Option; } @@ -65,7 +65,7 @@ impl BoundaryNorm { } } -impl ColorMapper for BoundaryNorm { +impl ColorMapper for BoundaryNorm { fn map_value_to_color(&self, value: T, invalid_value: T) -> Option { self.map_value_to_color(value, invalid_value) } diff --git a/src/render/predefined/gis.rs b/src/render/predefined/gis.rs index 3d070aa..b4e7a26 100644 --- a/src/render/predefined/gis.rs +++ b/src/render/predefined/gis.rs @@ -1,15 +1,71 @@ +use crate::coords::Range; +use std::borrow::BorrowMut; +use std::path::Path; + use crate::coords::Mapper; -use crate::render::Render; +use crate::render::{Layer, LayerImpl, Render}; use femtovg::renderer::OpenGl; use femtovg::{Canvas, Paint}; use geo_types::LineString; use geojson::GeoJson; -pub struct MapRender; +impl Layer { + pub fn map_layer_with_geojson_by_path(path: impl AsRef) -> Self { + let geojson = std::fs::read_to_string(path).unwrap(); + let json = geojson.parse::().unwrap(); + Self::map_layer_with_geojson(json) + } -impl MapRender { - pub fn test(geojson: &GeoJson, canvas: &mut Canvas, render: &Render) { + pub fn map_layer_with_geojson(json: GeoJson) -> Self { + let mut layer = Layer::new( + true, + |s, render, _| { + if let Some(renderer) = s.get_imp().as_ref() { + renderer.draw(render.clone()); + } + }, + "Map".into(), + Some(|_, _| async {}), + Some(GeoJsonMapImpl::new(json)), + ); + layer + } + + pub fn meshgrid_layer() -> Self { + let mut layer = Layer::new( + true, + |s, render, _| { + if let Some(renderer) = s.get_imp().as_ref() { + renderer.draw(render.clone()); + } + }, + "MeshGrid".into(), + Some(|_, _| async {}), + Some(MeshGridImpl), + ); + + layer + } +} + +#[derive(Debug)] +struct GeoJsonMapImpl { + geojson: GeoJson, +} + +impl GeoJsonMapImpl { + fn new(json: GeoJson) -> Self { + Self { geojson: json } + } +} + +impl LayerImpl for GeoJsonMapImpl { + fn draw(&self, render: Render) -> Option { let paint = Paint::color(femtovg::Color::rgb(255, 255, 255)); + let geojson = &self.geojson; + + let mut canvas = render.get_canvas(); + let canvas = canvas.as_mut().unwrap(); if let GeoJson::FeatureCollection(ref feature_collection) = geojson { for feature in &feature_collection.features { @@ -59,5 +115,45 @@ impl MapRender { }); } } + None + } +} + +#[derive(Debug)] +struct MeshGridImpl; + +impl LayerImpl for MeshGridImpl { + fn draw(&self, render: Render) -> Option { + let mut canvas = render.get_canvas(); + let canvas = canvas.as_mut().unwrap(); + + let (lon_range, lat_range) = render.render_range(); + let (lon_range, lat_range): (Range, Range) = (lon_range.into(), lat_range.into()); + + let lon_keypoints = lon_range.key_points(10); + let lat_keypoints = lat_range.key_points(5); + + for lon in lon_keypoints.iter() { + let mut path = femtovg::Path::new(); + render + .map((*lon, lat_range.0)) + .map(|(x, y)| path.move_to(x, y)); + render + .map((*lon, lat_range.1)) + .map(|(x, y)| path.line_to(x, y)); + canvas.stroke_path(&mut path, &Paint::color(femtovg::Color::rgb(255, 255, 255))); + } + for lat in lat_keypoints.iter() { + let mut path = femtovg::Path::new(); + render + .map((lon_range.0, *lat)) + .map(|(x, y)| path.move_to(x, y)); + render + .map((lon_range.1, *lat)) + .map(|(x, y)| path.line_to(x, y)); + canvas.stroke_path(&mut path, &Paint::color(femtovg::Color::rgb(255, 255, 255))); + } + + None } } diff --git a/src/render/predefined/grid_field_renderer.rs b/src/render/predefined/grid_field_renderer.rs index 69ad322..72f98de 100644 --- a/src/render/predefined/grid_field_renderer.rs +++ b/src/render/predefined/grid_field_renderer.rs @@ -3,12 +3,13 @@ use femtovg::{ImageFlags, Paint, Path, PixelFormat::Rgba8, RenderTarget}; use geo_types::LineString; use ndarray::ArrayView2; use num_traits::{Num, NumOps}; -use std::{marker::PhantomData, fmt::Debug}; +use std::{fmt::Debug, marker::PhantomData}; use super::super::renders::DataRenderer; use crate::{ data::Radar2d, - utils::meshgrid, render::{Render, Target, LayerImpl}, + render::{LayerImpl, Render, Target}, + utils::meshgrid, }; #[derive(Debug)] @@ -37,7 +38,6 @@ impl> GridFieldRenderer, { type Data = Radar2d; - fn render( - &self, - render: &Render, - canvas: &mut femtovg::Canvas, - data: &Self::Data, - ) -> Target { + fn render(&self, render: Render, data: &Self::Data) -> Target { + let mut canvas = render.get_canvas(); + let canvas = canvas.as_mut().unwrap(); + let new_img = canvas .create_image_empty(3000, 3000, Rgba8, ImageFlags::empty()) .expect("Can't Create Image"); @@ -116,7 +114,7 @@ where self.draw_2d( canvas, _data, - render, + &render, (_dim1.view(), _dim2.view()), (3000.0, 3000.0), data.fill_value, @@ -144,7 +142,7 @@ where #[derive(Debug)] pub struct GridLayerImpl where - T: Num + NumOps + PartialOrd + Copy + Clone, + T: Num + NumOps + PartialOrd + Copy + Clone + Send + Sync + Debug, CMAP: ColorMapper, { renderer: GridFieldRenderer, @@ -155,7 +153,7 @@ pub type DbzGridLayerImpl = GridLayerImpl, i8>; impl GridLayerImpl where - T: Num + NumOps + PartialOrd + Copy + Clone, + T: Num + NumOps + PartialOrd + Copy + Clone + Send + Sync + Debug, CMAP: ColorMapper, { pub fn new(renderer: GridFieldRenderer, data: Radar2d) -> Self { @@ -165,14 +163,10 @@ where impl LayerImpl for GridLayerImpl where - T: Num + NumOps + PartialOrd + Copy + Clone + Debug, + T: Num + NumOps + PartialOrd + Copy + Clone + Debug + Send + Sync, CMAP: ColorMapper + Debug, { - fn draw( - &self, - canvas: &mut femtovg::Canvas, - render: &Render, - ) -> Option { - Some(self.renderer.render(render, canvas, &self.data)) + fn draw(&self, render: Render) -> Option { + Some(self.renderer.render(render, &self.data)) } } diff --git a/src/render/predefined/layers.rs b/src/render/predefined/layers.rs index e95d068..ef6ae7e 100644 --- a/src/render/predefined/layers.rs +++ b/src/render/predefined/layers.rs @@ -1,10 +1,11 @@ -use femtovg::Paint; +use femtovg::{renderer::OpenGl, Canvas, Paint}; use num_traits::{Num, NumOps}; use std::path::Path; +use std::sync::Arc; use crate::{ - data::{DataLoader, Radar2d}, - render::Layer + data::{AsyncDataLoader, DataLoader, Radar2d}, + render::{Layer, Render}, }; use super::{ @@ -13,18 +14,20 @@ use super::{ }; impl Layer { - pub fn grid_render_layer(data: Radar2d, color_map: CMAP) -> Self + pub fn grid_render_layer(data: Radar2d, layer_name: String, color_map: CMAP) -> Self where - T: std::fmt::Debug + Num + NumOps + PartialOrd + Copy + Clone + 'static, + T: std::fmt::Debug + Num + NumOps + PartialOrd + Copy + Clone + 'static + Send + Sync, CMAP: ColorMapper + 'static, { Self::new( true, - |s, c, render, _| { + |s, render, _| { if let Some(target) = s.render_target() { + let mut c = render.get_canvas(); + let c = c.as_mut().unwrap(); if let Ok(_) = c.image_size(target.target) { - let (x, y) = target.size(render); - let (ox, oy) = target.origin(render); + let (x, y) = target.size(&render); + let (ox, oy) = target.origin(&render); let painter = Paint::image(target.target, ox, oy, x, y, 0.0, 1.0); let mut path = femtovg::Path::new(); path.rect(ox, oy, x, y); @@ -32,36 +35,60 @@ impl Layer { } } else { if let Some(renderer) = s.get_imp().as_ref() { - let img = renderer.draw(c, render).unwrap(); + let img = renderer.draw(render.clone()).unwrap(); + + let mut c = render.get_canvas(); + let c = c.as_mut().unwrap(); if let Ok(_) = c.image_size(img.target) { - let (x, y) = img.size(render); - let (ox, oy) = img.origin(render); + let (x, y) = img.size(&render); + let (ox, oy) = img.origin(&render); println!("{} {} {} {}", x, y, ox, oy); let painter = Paint::image(img.target, ox, oy, x, y, 0.0, 1.0); let mut path = femtovg::Path::new(); path.rect(ox, oy, x, y); s.set_render_target(img); c.fill_path(&path, &painter); - c.flush(); } } } }, + layer_name, + Some(|s: Arc, render: Render| async move { + if let None = s.render_target() { + if let Some(renderer) = s.get_imp().as_ref() {} + } + }), Some(GridLayerImpl::new(GridFieldRenderer::new(color_map), data)), ) } pub fn grid_render_layer_with_path( path: impl AsRef, + layer_name: String, loader: LOADER, color_map: CMAP, ) -> Self where - T: Num + NumOps + PartialOrd + Copy + Clone + 'static + std::fmt::Debug, + T: Num + NumOps + PartialOrd + Copy + Clone + 'static + std::fmt::Debug + Sync + Send, CMAP: ColorMapper + 'static, LOADER: DataLoader>, { let data = loader.load(path).unwrap(); - self::Layer::grid_render_layer(data, color_map) + self::Layer::grid_render_layer(data, layer_name, color_map) + } + + pub async fn grid_render_layer_with_path_async( + path: impl AsRef + Send, + layer_name: String, + loader: LOADER, + color_map: CMAP, + ) -> Self + where + T: Num + NumOps + PartialOrd + Copy + Clone + 'static + std::fmt::Debug + Send + Sync, + CMAP: ColorMapper + 'static, + LOADER: AsyncDataLoader>, + { + let data = loader.load(path).await.unwrap(); + self::Layer::grid_render_layer(data, layer_name, color_map) } } diff --git a/src/render/renders.rs b/src/render/renders.rs index a524246..2c4c86b 100644 --- a/src/render/renders.rs +++ b/src/render/renders.rs @@ -1,13 +1,8 @@ -use femtovg::{renderer::OpenGl, Canvas}; -use super::Target; use super::Render; +use super::Target; +use femtovg::{renderer::OpenGl, Canvas}; pub trait DataRenderer { type Data; - fn render( - &self, - render: &Render, - canvas: &mut Canvas, - data: &Self::Data, - ) -> Target; + fn render(&self, render: Render, data: &Self::Data) -> Target; }