This commit is contained in:
Tsuki 2024-01-16 21:22:32 +08:00
parent 79189212c2
commit 322461371f
26 changed files with 861 additions and 332 deletions

243
Cargo.lock generated
View File

@ -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",
]

View File

@ -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"

178
back.txt
View File

@ -85,3 +85,181 @@
// Npz,
// BoundaryNorm::default(),
// )
// fn resample(
// &self,
// width_rate: f64,
// height_rate: f64,
// filter_len: f64,
// ) -> Result<RadarData2d<T, OwnedRepr<T>>, 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<ndarray::OwnedRepr<T>, Ix2> =
// Self::_resample(&self.data, width_rate, filter_len);
// let result: ArrayBase<OwnedRepr<T>, Ix2> =
// Self::_resample(&width_filtered.t(), height_rate, filter_len)
// .t()
// .to_owned();
// let new_dim1: ArrayBase<OwnedRepr<f64>, 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<OwnedRepr<f64>, 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<Elem = V>>(
// data: &'a ArrayBase<R, Ix2>,
// rate: f64,
// filter_len: f64,
// ) -> Array2<V>
// where
// V: Num + Clone + AsPrimitive<f64> + 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<V> = 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<T: Num + Clone + PartialEq + PartialOrd>(
// pub Quadtree<i64, RadarData2d<T, OwnedRepr<T>>>,
// );
// impl<T> LevelData<T>
// where
// T: Num + Clone + AsPrimitive<f64> + FromPrimitive + Debug + PartialEq + PartialOrd,
// {
// fn value(
// level_data: Vec<RadarData2d<T, OwnedRepr<T>>>,
// level_num: usize,
// ) -> Vec<RadarData2d<T, OwnedRepr<T>>> {
// if level_num == 0 {
// return level_data;
// }
// let mut result: Vec<RadarData2d<T, OwnedRepr<T>>> =
// 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<T, OwnedRepr<T>>, 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<i64, RadarData2d<T, OwnedRepr<T>>> =
// 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<T>(data: Radar2d<T>, levels: usize) -> Vec<LevelData<T>>
// where
// T: Num + Clone + AsPrimitive<f64> + 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,
}

View File

@ -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(&gtk::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(

View File

View File

@ -1,4 +1,4 @@
mod render_panel;
mod messages;
mod monitor;
mod render_panel;
pub use render_panel::RenderPanelModel;

View File

@ -1,4 +1,3 @@
pub mod monitor;
pub mod render;
pub mod sidebar;
pub use monitor::MonitorModel;

View File

@ -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,15 +52,17 @@ impl SimpleComponent for MonitorModel {
}
}
fn init(
async fn init(
init: Self::Init,
root: &Self::Root,
sender: relm4::ComponentSender<Self>,
) -> relm4::ComponentParts<Self> {
let sidebar: Controller<SideBarModel> = SideBarModel::builder()
root: Self::Root,
sender: relm4::AsyncComponentSender<Self>,
) -> AsyncComponentParts<Self> {
let sidebar: Controller<SideBarModel> =
SideBarModel::builder()
.launch(())
.forward(sender.input_sender(), |msg| match msg {
SideBarOutputMsg::NewLayer(layer) => MonitorInputMsg::AddLayer(layer),
_ => MonitorInputMsg::None,
});
let model = MonitorModel {
sidebar_open: true,
@ -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<Self>) {
async fn update(
&mut self,
msg: Self::Input,
_sender: AsyncComponentSender<Self>,
_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 => {}
}
}
}

View File

@ -1,2 +0,0 @@
pub mod render;
pub use render::*;

View File

@ -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<Mapper>, Option<RenderConfig>);
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<Self>,
) -> relm4::ComponentParts<Self> {
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<Self>) {}
}

View File

@ -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>) -> Self {
init
}
fn update(&mut self, message: Self::Input, sender: FactorySender<Self>) {
match message {}
}
}

View File

@ -1,2 +1,3 @@
pub mod sidebar;
pub use sidebar::*;
pub mod bottom_bar;

View File

@ -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<MyListItem, gtk::SingleSelection>,
list_view_wrapper: TypedListView<LayerItem, gtk::SingleSelection>,
bottom_bar_vec: FactoryVecDeque<BottomBarModel>,
}
#[derive(Debug)]
pub enum Msg {
Append,
Remove,
OnlyShowEven(bool),
RefreshList(Vec<Layer>),
}
#[derive(Debug)]
@ -36,9 +43,20 @@ impl SimpleComponent for SideBarModel {
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
set_margin_all: 5,
gtk::Notebook {
set_vexpand: true,
append_page:(&page_1, Some(&label)),
gtk::Paned{
set_orientation: gtk::Orientation::Vertical,
set_position: 300,
#[wrap(Some)]
set_start_child = &gtk::Box{
set_orientation: gtk::Orientation::Vertical,
set_spacing: 5,
#[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,11 +73,24 @@ impl SimpleComponent for SideBarModel {
).unwrap()
},
},
gtk::ScrolledWindow {
},
#[wrap(Some)]
set_end_child=&gtk::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]
my_view -> gtk::ListView {}
counter_box -> gtk::Box{}
}
},
}
}
@ -68,33 +100,33 @@ impl SimpleComponent for SideBarModel {
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
// Initialize the ListView wrapper
let mut list_view_wrapper: TypedListView<MyListItem, gtk::SingleSelection> =
let mut list_view_wrapper: TypedListView<LayerItem, gtk::SingleSelection> =
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(&gtk::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(&gtk::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<Self>) {
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);
}
}

View File

@ -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<MonitorModel>,
// monitor: Controller<MonitorModel>,
monitor: AsyncController<MonitorModel>,
}
#[relm4::component(pub)]
@ -26,7 +32,8 @@ impl SimpleComponent for RenderPanelModel {
root: &Self::Root,
sender: relm4::ComponentSender<Self>,
) -> relm4::ComponentParts<Self> {
let monitor: Controller<MonitorModel> = MonitorModel::builder()
let monitor: AsyncController<MonitorModel> = MonitorModel::builder()
.launch(())
.forward(sender.input_sender(), |msg| {});

View File

@ -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<T> = RadarData2d<T, OwnedRepr<T>>;
@ -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<P: AsRef<Path>>(&self, path: P) -> Result<T, DataError>;
}
#[async_trait]
pub trait AsyncDataLoader<V, T>
where
V: Num + Clone + PartialEq + PartialOrd,
T: MultiDimensionData<V> + Send + Sync,
{
async fn load<P: AsRef<Path> + Send>(&self, path: P) -> Result<T, DataError>;
}
pub struct Npz;
impl Npz {
#[inline]
fn load_1d<T: Num + Deserialize>(
fn load_1d<T: Num + Deserialize, R: std::io::Read + Seek>(
&self,
// path: &Path,
data: &mut NpzArchive<BufReader<std::fs::File>>,
data: &mut NpzArchive<R>,
name: &str,
) -> Result<Array1<T>, 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<T: Num + Deserialize>(
fn load_2d<T: Num + Deserialize, R: std::io::Read + Seek>(
&self,
// path: &Path,
data: &mut NpzArchive<BufReader<std::fs::File>>,
data: &mut NpzArchive<R>,
name: &str,
) -> Result<Array2<T>, DataError> {
// let mut data = npyz::npz::NpzArchive::open(path)?;
@ -320,9 +329,9 @@ where
{
fn load<P: AsRef<Path>>(&self, path: P) -> Result<RadarData2d<T, OwnedRepr<T>>, DataError> {
let mut data: NpzArchive<BufReader<std::fs::File>> = npyz::npz::NpzArchive::open(path)?;
let dim1 = self.load_1d::<f64>(&mut data, "lon")?;
let dim2 = self.load_1d::<f64>(&mut data, "lat")?;
let value = self.load_2d::<T>(&mut data, "value")?;
let dim1 = self.load_1d::<f64, BufReader<std::fs::File>>(&mut data, "lon")?;
let dim2 = self.load_1d::<f64, BufReader<std::fs::File>>(&mut data, "lat")?;
let value = self.load_2d::<T, BufReader<std::fs::File>>(&mut data, "value")?;
Ok(RadarData2d {
dim1: dim1,
@ -334,6 +343,47 @@ where
}
}
impl<T> AsyncDataLoader<T, RadarData2d<T, OwnedRepr<T>>> 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<Output = Result<RadarData2d<T, OwnedRepr<T>>, DataError>>
+ core::marker::Send
+ 'async_trait,
>,
>
where
P: 'async_trait + AsRef<Path> + 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::<f64, Cursor<Vec<u8>>>(&mut data, "lon")?;
let dim2 = self.load_1d::<f64, Cursor<Vec<u8>>>(&mut data, "lat")?;
let value = self.load_2d::<T, Cursor<Vec<u8>>>(&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,

View File

@ -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)]

View File

@ -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<Runtime> =
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).
{

View File

@ -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,7 +119,8 @@ impl GLAreaImpl for Render {
fn render(&self, context: &gtk::gdk::GLContext) -> bool {
self.ensure_canvas();
let configs = self.config.borrow();
{
let mut canvas = self.canvas.borrow_mut();
let canvas = canvas.as_mut().unwrap();
@ -127,8 +128,6 @@ impl GLAreaImpl for Render {
let w = canvas.width();
let h = canvas.height();
let configs = self.config.borrow();
canvas.clear_rect(
0,
0,
@ -136,6 +135,7 @@ impl GLAreaImpl for Render {
(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);
self.interior.borrow().draw(
c,
canvas,
&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();
}
true
}
}
@ -219,6 +217,7 @@ impl Render {
canvas
.add_font_dir("/Users/tsuki/projects/radar-g/src/assets")
.unwrap();
self.canvas.replace(Some(canvas));
}

View File

@ -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<dyn FnOnce(Arc<Layer>, Render) -> Pin<Box<dyn Future<Output = ()>>> + Sync + Send>;
type DrawFunc = Box<dyn Fn(&Layer, Render, (f32, f32)) + Send + Sync>;
type LayerImplSync = Box<dyn LayerImpl + Send + Sync>;
#[derive(Clone)]
pub struct Layer {
pub visiable: bool,
pub name: String,
snapshot: Option<gtk::gdk::Texture>,
target: RefCell<Option<Target>>,
imp: RefCell<Option<Arc<dyn LayerImpl>>>,
draw: Arc<dyn Fn(&Self, &mut Canvas<OpenGl>, &Render, (f32, f32))>,
prepare: Arc<Option<PrepareFunc>>,
imp: RefCell<Option<Arc<LayerImplSync>>>,
draw: Arc<DrawFunc>,
}
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<OpenGl>, render: &Render) -> Option<Target>;
fn draw(&self, render: Render) -> Option<Target>;
}
impl Layer {
pub fn new<
F: 'static + Fn(&Self, &mut Canvas<OpenGl>, &Render, (f32, f32)),
IMP: LayerImpl + 'static,
FU: Future<Output = ()> + 'static,
F: 'static + Fn(&Self, Render, (f32, f32)) + Send + Sync,
PREPARE: FnOnce(Arc<Layer>, Render) -> FU + Send + Sync + 'static,
IMP: LayerImpl + Sync + Send + 'static,
>(
visiable: bool,
draw: F,
layer_name: String,
prepare: Option<PREPARE>,
imp: Option<IMP>,
) -> Self {
Layer {
visiable,
target: RefCell::new(None),
draw: Arc::new(draw),
imp: RefCell::new(imp.map(|x| Arc::new(x) as Arc<dyn LayerImpl>)),
name: layer_name,
snapshot: None,
// prepare: Arc::new(prepare),
prepare: Arc::new(prepare.map(|p| {
Box::new(
move |layer: Arc<Layer>, render: Render| -> Pin<Box<dyn Future<Output = ()>>> {
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<dyn LayerImpl + Send + Sync>)),
),
}
}
pub fn draw(&self, canvas: &mut Canvas<OpenGl>, 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<Option<Arc<dyn LayerImpl>>> {
pub fn get_imp(&self) -> Ref<Option<Arc<LayerImplSync>>> {
let im = self.imp.borrow();
im
}

View File

@ -23,19 +23,15 @@ impl InteriorWidget {
this
}
pub fn draw(
&self,
layers: &Vec<Layer>,
canvas: &mut Canvas<OpenGl>,
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));
}
}
}

View File

@ -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<femtovg::Canvas<femtovg::renderer::OpenGl>>> {
self.imp().canvas.borrow_mut()
}
pub fn set_cfg(&self, cfg: RenderConfig) {
self.imp().config.replace(cfg);
}

View File

@ -2,7 +2,7 @@ use std::fmt::Debug;
use femtovg::Color;
use num_traits::NumOps;
pub trait ColorMapper<T: NumOps + PartialOrd> : Debug {
pub trait ColorMapper<T: NumOps + PartialOrd> : Debug + Send + Sync {
fn map_value_to_color(&self, value: T, invalid_value: T) -> Option<femtovg::Color>;
}
@ -65,7 +65,7 @@ impl<T: NumOps + PartialOrd> BoundaryNorm<T> {
}
}
impl<T: NumOps + PartialOrd + Debug> ColorMapper<T> for BoundaryNorm<T> {
impl<T: NumOps + PartialOrd + Debug + Send + Sync> ColorMapper<T> for BoundaryNorm<T> {
fn map_value_to_color(&self, value: T, invalid_value: T) -> Option<femtovg::Color> {
self.map_value_to_color(value, invalid_value)
}

View File

@ -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<Path>) -> Self {
let geojson = std::fs::read_to_string(path).unwrap();
let json = geojson.parse::<GeoJson>().unwrap();
Self::map_layer_with_geojson(json)
}
impl MapRender {
pub fn test(geojson: &GeoJson, canvas: &mut Canvas<OpenGl>, 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<crate::render::Target> {
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<crate::render::Target> {
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
}
}

View File

@ -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<T: NumOps + PartialOrd + Copy, CMAP: ColorMapper<T>> GridFieldRenderer<CMAP
window_size: (f32, f32),
fill_value: T,
) {
let shape = data.shape();
let (rows, cols) = (shape[0], shape[1]);
let (dim1, dim2) = dims;
@ -96,12 +96,10 @@ where
CMAP: ColorMapper<T>,
{
type Data = Radar2d<T>;
fn render(
&self,
render: &Render,
canvas: &mut femtovg::Canvas<femtovg::renderer::OpenGl>,
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<CMAP, T>
where
T: Num + NumOps + PartialOrd + Copy + Clone,
T: Num + NumOps + PartialOrd + Copy + Clone + Send + Sync + Debug,
CMAP: ColorMapper<T>,
{
renderer: GridFieldRenderer<CMAP, T>,
@ -155,7 +153,7 @@ pub type DbzGridLayerImpl = GridLayerImpl<BoundaryNorm<i8>, i8>;
impl<CMAP, T> GridLayerImpl<CMAP, T>
where
T: Num + NumOps + PartialOrd + Copy + Clone,
T: Num + NumOps + PartialOrd + Copy + Clone + Send + Sync + Debug,
CMAP: ColorMapper<T>,
{
pub fn new(renderer: GridFieldRenderer<CMAP, T>, data: Radar2d<T>) -> Self {
@ -165,14 +163,10 @@ where
impl<CMAP, T> LayerImpl for GridLayerImpl<CMAP, T>
where
T: Num + NumOps + PartialOrd + Copy + Clone + Debug,
T: Num + NumOps + PartialOrd + Copy + Clone + Debug + Send + Sync,
CMAP: ColorMapper<T> + Debug,
{
fn draw(
&self,
canvas: &mut femtovg::Canvas<femtovg::renderer::OpenGl>,
render: &Render,
) -> Option<Target> {
Some(self.renderer.render(render, canvas, &self.data))
fn draw(&self, render: Render) -> Option<Target> {
Some(self.renderer.render(render, &self.data))
}
}

View File

@ -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<T, CMAP>(data: Radar2d<T>, color_map: CMAP) -> Self
pub fn grid_render_layer<T, CMAP>(data: Radar2d<T>, 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<T> + '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<Layer>, 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<T, CMAP, LOADER>(
path: impl AsRef<Path>,
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<T> + 'static,
LOADER: DataLoader<T, Radar2d<T>>,
{
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<T, CMAP, LOADER>(
path: impl AsRef<Path> + 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<T> + 'static,
LOADER: AsyncDataLoader<T, Radar2d<T>>,
{
let data = loader.load(path).await.unwrap();
self::Layer::grid_render_layer(data, layer_name, color_map)
}
}

View File

@ -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<OpenGl>,
data: &Self::Data,
) -> Target;
fn render(&self, render: Render, data: &Self::Data) -> Target;
}