Compare commits
No commits in common. "master" and "opengl" have entirely different histories.
115
Cargo.lock
generated
115
Cargo.lock
generated
@ -513,6 +513,7 @@ dependencies = [
|
|||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
|
"serde",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-targets 0.52.0",
|
"windows-targets 0.52.0",
|
||||||
]
|
]
|
||||||
@ -530,6 +531,7 @@ dependencies = [
|
|||||||
"crossbeam",
|
"crossbeam",
|
||||||
"dirs",
|
"dirs",
|
||||||
"epoxy",
|
"epoxy",
|
||||||
|
"etws_loader",
|
||||||
"euclid",
|
"euclid",
|
||||||
"femtovg",
|
"femtovg",
|
||||||
"flate2",
|
"flate2",
|
||||||
@ -550,7 +552,7 @@ dependencies = [
|
|||||||
"indexmap",
|
"indexmap",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libadwaita",
|
"libadwaita",
|
||||||
"libloading 0.8.3",
|
"libloading 0.8.0",
|
||||||
"ndarray",
|
"ndarray",
|
||||||
"npyz",
|
"npyz",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@ -986,7 +988,7 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libloading 0.7.4",
|
"libloading 0.8.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1073,6 +1075,24 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "etws_loader"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"abi_stable",
|
||||||
|
"anyhow",
|
||||||
|
"byteorder",
|
||||||
|
"chrono",
|
||||||
|
"flate2",
|
||||||
|
"nom",
|
||||||
|
"nom-derive",
|
||||||
|
"num-traits",
|
||||||
|
"radarg_plugin_interface",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "euclid"
|
name = "euclid"
|
||||||
version = "0.22.9"
|
version = "0.22.9"
|
||||||
@ -1115,20 +1135,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "femtovg"
|
name = "femtovg"
|
||||||
version = "0.9.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad3cf7e8f8e3c684b418c2640c931afc8bbc7ebe547bed6bf64170f1f51d57c9"
|
checksum = "5a3a2d0ff0df09856a5c1c89cc83863a1f0f994c55452186621bb57a01f270b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
"fnv",
|
"fnv",
|
||||||
|
"generational-arena",
|
||||||
"glow",
|
"glow",
|
||||||
"image",
|
"image",
|
||||||
"imgref",
|
"imgref",
|
||||||
"log",
|
|
||||||
"lru",
|
"lru",
|
||||||
"rgb",
|
"rgb",
|
||||||
"rustybuzz",
|
"rustybuzz",
|
||||||
"slotmap",
|
|
||||||
"unicode-bidi",
|
"unicode-bidi",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@ -1744,9 +1763,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glow"
|
name = "glow"
|
||||||
version = "0.13.1"
|
version = "0.12.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1"
|
checksum = "807edf58b70c0b5b2181dd39fe1839dbdb3ba02645630dc5f753e23da307f762"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"slotmap",
|
"slotmap",
|
||||||
@ -2329,12 +2348,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libloading"
|
name = "libloading"
|
||||||
version = "0.8.3"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
|
checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"windows-targets 0.52.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2389,9 +2408,9 @@ checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lru"
|
name = "lru"
|
||||||
version = "0.12.3"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
|
checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mach"
|
name = "mach"
|
||||||
@ -2607,6 +2626,28 @@ dependencies = [
|
|||||||
"minimal-lexical",
|
"minimal-lexical",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom-derive"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ff943d68b88d0b87a6e0d58615e8fa07f9fd5a1319fa0a72efc1f62275c79a7"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
"nom-derive-impl",
|
||||||
|
"rustversion",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom-derive-impl"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd0b9a93a84b0d3ec3e70e02d332dc33ac6dfac9cde63e17fcb77172dededa62"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.76",
|
||||||
|
"quote 1.0.35",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "npyz"
|
name = "npyz"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
@ -3658,18 +3699,24 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustybuzz"
|
name = "rustversion"
|
||||||
version = "0.13.0"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88117946aa1bfb53c2ae0643ceac6506337f44887f8c9fbfb43587b1cc52ba49"
|
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustybuzz"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "162bdf42e261bee271b3957691018634488084ef577dddeb6420a9684cab2a6a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 1.3.2",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"ttf-parser 0.20.0",
|
"ttf-parser 0.18.1",
|
||||||
"unicode-bidi-mirroring",
|
"unicode-bidi-mirroring",
|
||||||
"unicode-ccc",
|
"unicode-ccc",
|
||||||
"unicode-properties",
|
"unicode-general-category",
|
||||||
"unicode-script",
|
"unicode-script",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3916,9 +3963,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slotmap"
|
name = "slotmap"
|
||||||
version = "1.0.7"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a"
|
checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
@ -4523,6 +4570,12 @@ version = "0.17.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
|
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ttf-parser"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ttf-parser"
|
name = "ttf-parser"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
@ -4555,15 +4608,21 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi-mirroring"
|
name = "unicode-bidi-mirroring"
|
||||||
version = "0.2.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23cb788ffebc92c5948d0e997106233eeb1d8b9512f93f41651f52b6c5f5af86"
|
checksum = "56d12260fb92d52f9008be7e4bca09f584780eb2266dc8fecc6a192bec561694"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ccc"
|
name = "unicode-ccc"
|
||||||
version = "0.2.0"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1df77b101bcc4ea3d78dafc5ad7e4f58ceffe0b2b16bf446aeb50b6cb4157656"
|
checksum = "cc2520efa644f8268dce4dcd3050eaa7fc044fca03961e9998ac7e2e92b77cf1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-general-category"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
@ -4580,12 +4639,6 @@ dependencies = [
|
|||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-properties"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-script"
|
name = "unicode-script"
|
||||||
version = "0.5.5"
|
version = "0.5.5"
|
||||||
|
|||||||
12
Cargo.toml
12
Cargo.toml
@ -20,11 +20,11 @@ quadtree_rs = "0.1.2"
|
|||||||
proj-sys = "0.23.1"
|
proj-sys = "0.23.1"
|
||||||
glib-macros = "0.19.2"
|
glib-macros = "0.19.2"
|
||||||
svg = "0.13.1"
|
svg = "0.13.1"
|
||||||
libloading = "0.8.3"
|
libloading = "0.8.0"
|
||||||
glue = "0.8.7"
|
glue = "0.8.7"
|
||||||
epoxy = "0.1.0"
|
epoxy = "0.1.0"
|
||||||
femtovg = "0.9.0"
|
femtovg = "0.7.1"
|
||||||
glow = "0.13.1"
|
glow = "0.12.2"
|
||||||
proj = "0.27.2"
|
proj = "0.27.2"
|
||||||
image = "0.24.7"
|
image = "0.24.7"
|
||||||
anyhow = "1.0.72"
|
anyhow = "1.0.72"
|
||||||
@ -82,10 +82,10 @@ path = "geo-macros"
|
|||||||
[dependencies.radarg_plugin_interface]
|
[dependencies.radarg_plugin_interface]
|
||||||
path = "radarg_plugin_interface"
|
path = "radarg_plugin_interface"
|
||||||
|
|
||||||
#[dependencies.etws_loader]
|
[dependencies.etws_loader]
|
||||||
#path = "etws_loader"
|
path = "etws_loader"
|
||||||
|
|
||||||
[dependencies.adw]
|
[dependencies.adw]
|
||||||
package = "libadwaita"
|
package = "libadwaita"
|
||||||
version = "0.6.0"
|
version = "*"
|
||||||
features = ["v1_4"]
|
features = ["v1_4"]
|
||||||
|
|||||||
@ -29,10 +29,6 @@ paned>separator {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
font-size: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lv {
|
.lv {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,24 +89,15 @@ impl Plugin for ETWSLoader {
|
|||||||
CoordType::Other
|
CoordType::Other
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let lat = b.info.dimension_values.get(0).unwrap();
|
||||||
|
let lon = b.info.dimension_values.get(1).unwrap();
|
||||||
|
lat_range = [lat[0], lat[lat.len() - 1]];
|
||||||
|
lon_range = [lon[0], lon[lon.len() - 1]];
|
||||||
|
|
||||||
let shape = match b.info.dimension_size.len() {
|
let shape = match b.info.dimension_size.len() {
|
||||||
1 => radarg_plugin_interface::DataShape::Vector,
|
1 => radarg_plugin_interface::DataShape::Vector,
|
||||||
2 => {
|
2 => radarg_plugin_interface::DataShape::Matrix,
|
||||||
let lat = b.info.dimension_values.get(0).unwrap();
|
_ => radarg_plugin_interface::DataShape::Scalar,
|
||||||
let lon = b.info.dimension_values.get(1).unwrap();
|
|
||||||
lat_range = [lat[0], lat[lat.len() - 1]];
|
|
||||||
lon_range = [lon[0], lon[lon.len() - 1]];
|
|
||||||
radarg_plugin_interface::DataShape::Matrix
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let lat = b.info.dimension_values.get(1).unwrap();
|
|
||||||
let lon = b.info.dimension_values.get(2).unwrap();
|
|
||||||
lat_range = [lat[0], lat[lat.len() - 1]];
|
|
||||||
lon_range = [lon[0], lon[lon.len() - 1]];
|
|
||||||
radarg_plugin_interface::DataShape::Cube
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let data_type = match b.info.value_name.as_str() {
|
let data_type = match b.info.value_name.as_str() {
|
||||||
@ -124,7 +115,6 @@ impl Plugin for ETWSLoader {
|
|||||||
"HCA" => PluginResultType::HCA,
|
"HCA" => PluginResultType::HCA,
|
||||||
"QPE" => PluginResultType::QPE,
|
"QPE" => PluginResultType::QPE,
|
||||||
"QPF" => PluginResultType::QPF,
|
"QPF" => PluginResultType::QPF,
|
||||||
"FR" => PluginResultType::DBZ,
|
|
||||||
_ => PluginResultType::Unknown,
|
_ => PluginResultType::Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -197,7 +187,7 @@ mod tests {
|
|||||||
|
|
||||||
fn test() {
|
fn test() {
|
||||||
let result =
|
let result =
|
||||||
Record::parse_from_path("/Volumes/data2/RadarArray/HangZhou/radarData/OutputProducts/RadarProducts/FuseDataX/20220727/ZJHZAA_20220727200000_FR.dat.gz")
|
Record::parse_from_path("/Volumes/data2/RadarArray/HangZhou/radarData/OutputProducts/RadarProducts/BasicProductsX/20230624/20230624000800/ZJHZAA_20230624000800_VIL.dat.gz")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -15,7 +15,4 @@ icons = [
|
|||||||
"home-filled",
|
"home-filled",
|
||||||
"settings-filled",
|
"settings-filled",
|
||||||
"save-filled",
|
"save-filled",
|
||||||
"timer-filled",
|
|
||||||
"eye-filled",
|
|
||||||
"eye-off-filled",
|
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use abi_stable::{
|
use abi_stable::{
|
||||||
std_types::{RBoxError, RVec},
|
std_types::{ RBoxError, RVec},
|
||||||
StableAbi,
|
StableAbi,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -18,6 +18,7 @@ pub enum Error {
|
|||||||
Many(RVec<Error>),
|
Many(RVec<Error>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Display for Error {
|
impl Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@ -32,15 +33,15 @@ impl Display for Error {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
Error::Custom(e) => Display::fmt(e, f),
|
Error::Custom(e) => Display::fmt(e, f),
|
||||||
Error::Many(list) => {
|
Error::Many(list) => {
|
||||||
for e in list {
|
for e in list {
|
||||||
writeln!(f, "{}", e)?;
|
writeln!(f, "{}", e)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
_ => Ok(()),
|
_ => { Ok(())}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,9 +50,9 @@ pub enum VecResult {
|
|||||||
#[derive(StableAbi, Clone, Copy, Debug)]
|
#[derive(StableAbi, Clone, Copy, Debug)]
|
||||||
#[sabi(impl_InterfaceType(Sync, Send, Debug))]
|
#[sabi(impl_InterfaceType(Sync, Send, Debug))]
|
||||||
pub enum DataShape {
|
pub enum DataShape {
|
||||||
|
Scalar,
|
||||||
Vector,
|
Vector,
|
||||||
Matrix,
|
Matrix,
|
||||||
Cube,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use gtk::gio::SimpleAction;
|
|
||||||
use gtk::prelude::{BoxExt, ButtonExt, GtkWindowExt, OrientableExt};
|
|
||||||
use relm4::actions::{AccelsPlus, ActionablePlus, RelmAction, RelmActionGroup};
|
|
||||||
use relm4::{ComponentParts, ComponentSender, RelmApp, RelmWidgetExt, SimpleComponent};
|
|
||||||
|
|
||||||
use crate::components::app::{AppModel, AppMsg, LayerMsg};
|
|
||||||
use crate::widgets::{AssoElement, Layer};
|
|
||||||
|
|
||||||
relm4::new_action_group!(pub LayerActionGroup, "layer");
|
|
||||||
relm4::new_stateless_action!(pub AddLayerAction, LayerActionGroup, "add");
|
|
||||||
relm4::new_stateless_action!(pub RemoveLayerAction, LayerActionGroup, "remove");
|
|
||||||
relm4::new_stateless_action!(pub MoveLayerAction, LayerActionGroup, "move");
|
|
||||||
|
|
||||||
pub fn register_layer_actions<W: AsRef<gtk::Widget>>(widget: W, sender: ComponentSender<AppModel>) {
|
|
||||||
let add_action: RelmAction<AddLayerAction> = {
|
|
||||||
let sender = sender.clone();
|
|
||||||
RelmAction::new_stateless(move |_| {
|
|
||||||
sender.input(AppMsg::LayerManager(LayerMsg::Add(Layer::new(
|
|
||||||
true,
|
|
||||||
"Test".to_string(),
|
|
||||||
AssoElement::Test,
|
|
||||||
))))
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let remove_action: RelmAction<RemoveLayerAction> = {
|
|
||||||
let sender = sender.clone();
|
|
||||||
RelmAction::new_stateless(move |_| sender.input(AppMsg::LayerManager(LayerMsg::Remove(0))))
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut group: RelmActionGroup<LayerActionGroup> = RelmActionGroup::new();
|
|
||||||
group.add_action(add_action);
|
|
||||||
group.add_action(remove_action);
|
|
||||||
group.register_for_widget(widget)
|
|
||||||
}
|
|
||||||
@ -1,4 +1,3 @@
|
|||||||
use super::sidebar::SideBarOutputMsg;
|
|
||||||
use super::{
|
use super::{
|
||||||
control_panel::{ControlPanelInputMsg, ControlPanelModel},
|
control_panel::{ControlPanelInputMsg, ControlPanelModel},
|
||||||
messages::{MonitorInputMsg, MonitorOutputMsg},
|
messages::{MonitorInputMsg, MonitorOutputMsg},
|
||||||
@ -6,14 +5,12 @@ use super::{
|
|||||||
setting::SettingModel,
|
setting::SettingModel,
|
||||||
ControlPanelOutputMsg, TimelineMsg,
|
ControlPanelOutputMsg, TimelineMsg,
|
||||||
};
|
};
|
||||||
use crate::components::sidebar::{SideBarInputMsg, SideBarModel};
|
use crate::data_utils::plugin_result_impl;
|
||||||
use crate::pipeline::{GridElementImpl, OffscreenRenderer};
|
use crate::pipeline::element::{
|
||||||
use crate::predefined::widgets::ColorBar;
|
Element, InstantElement, InstantElementDrawerType, TimeSeriesElement,
|
||||||
use crate::widgets::{AssoElement, DynamicCol};
|
|
||||||
use crate::{
|
|
||||||
actions::register_layer_actions,
|
|
||||||
pipeline::element::{Element, InstantElement, InstantElementDrawerType, TimeSeriesElement},
|
|
||||||
};
|
};
|
||||||
|
use crate::pipeline::{GridElementImpl, OffscreenRenderer};
|
||||||
|
use crate::widgets::AssoElement;
|
||||||
use crate::{
|
use crate::{
|
||||||
coords::{
|
coords::{
|
||||||
cms::CMS,
|
cms::CMS,
|
||||||
@ -27,7 +24,6 @@ use crate::{
|
|||||||
widgets::render::Layer,
|
widgets::render::Layer,
|
||||||
CONFIG, PLUGIN_MANAGER,
|
CONFIG, PLUGIN_MANAGER,
|
||||||
};
|
};
|
||||||
use crate::{data_utils::plugin_result_impl, pipeline::element::DataTarget};
|
|
||||||
use abi_stable::std_types::RStr;
|
use abi_stable::std_types::RStr;
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
@ -63,24 +59,15 @@ pub static FILE_PATH_ROOT: Lazy<Mutex<PathBuf>> = Lazy::new(|| Mutex::new(PathBu
|
|||||||
|
|
||||||
pub type ElementKey = String;
|
pub type ElementKey = String;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum LayerMsg {
|
|
||||||
Add(Layer),
|
|
||||||
Remove(usize),
|
|
||||||
SwitchToTime(usize),
|
|
||||||
Select(Vec<usize>),
|
|
||||||
RemoveSelected,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum AppMsg {
|
pub enum AppMsg {
|
||||||
CloseRequest,
|
CloseRequest,
|
||||||
Close,
|
Close,
|
||||||
OpenDialog,
|
OpenDialog,
|
||||||
LayerManager(LayerMsg),
|
SwitchToTime(usize),
|
||||||
Layer,
|
|
||||||
NewElement(Element),
|
NewElement(Element),
|
||||||
DeleteElement(ElementKey),
|
DeleteElement(ElementKey),
|
||||||
|
NewLayer(Layer),
|
||||||
}
|
}
|
||||||
pub type Buffer = Rc<RefCell<HashMap<String, BTreeMap<DateTime<Utc>, Option<RenderResult>>>>>;
|
pub type Buffer = Rc<RefCell<HashMap<String, BTreeMap<DateTime<Utc>, Option<RenderResult>>>>>;
|
||||||
type RcDispatcher = Rc<Dispatcher>;
|
type RcDispatcher = Rc<Dispatcher>;
|
||||||
@ -98,9 +85,6 @@ pub struct AppModel {
|
|||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
render: Controller<MonitorModel>,
|
render: Controller<MonitorModel>,
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
sidebar: Controller<SideBarModel>,
|
|
||||||
selected_layer: Vec<usize>,
|
|
||||||
#[do_not_track]
|
|
||||||
layers: Rc<RefCell<Vec<Layer>>>,
|
layers: Rc<RefCell<Vec<Layer>>>,
|
||||||
#[do_not_track]
|
#[do_not_track]
|
||||||
elements: Vec<Arc<Mutex<TimeSeriesElement>>>,
|
elements: Vec<Arc<Mutex<TimeSeriesElement>>>,
|
||||||
@ -174,21 +158,7 @@ impl Component for AppModel {
|
|||||||
adw::ToastOverlay{
|
adw::ToastOverlay{
|
||||||
set_hexpand: true,
|
set_hexpand: true,
|
||||||
set_vexpand: true,
|
set_vexpand: true,
|
||||||
DynamicCol {
|
model.render.widget(),
|
||||||
set_end_width: 300,
|
|
||||||
set_hexpand: true,
|
|
||||||
set_vexpand: true,
|
|
||||||
#[wrap(Some)]
|
|
||||||
#[name="paned"]
|
|
||||||
set_child_paned = >k::Paned{
|
|
||||||
#[local_ref]
|
|
||||||
#[wrap(Some)]
|
|
||||||
set_start_child=render->gtk::Frame{},
|
|
||||||
#[local_ref]
|
|
||||||
#[wrap(Some)]
|
|
||||||
set_end_child=sidebar->gtk::Box{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
home_stack_page = view_stack.add_titled(&home_page, Some("home"), "Home") -> adw::ViewStackPage{
|
home_stack_page = view_stack.add_titled(&home_page, Some("home"), "Home") -> adw::ViewStackPage{
|
||||||
@ -222,83 +192,61 @@ impl Component for AppModel {
|
|||||||
root: Self::Root,
|
root: Self::Root,
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
let layers = Rc::new(RefCell::new(vec![
|
let layers = Rc::new(RefCell::new(Vec::with_capacity(20)));
|
||||||
Layer::new(true, "Layer 1".to_string(), AssoElement::Test),
|
|
||||||
Layer::new(true, "Layer 2".to_string(), AssoElement::Test),
|
|
||||||
]));
|
|
||||||
let control = ControlPanelModel::builder().launch(layers.clone()).forward(
|
let control = ControlPanelModel::builder().launch(layers.clone()).forward(
|
||||||
sender.input_sender(),
|
sender.input_sender(),
|
||||||
|msg| match msg {
|
|msg| match msg {
|
||||||
ControlPanelOutputMsg::OpenFile((key, time)) => AppMsg::Close,
|
ControlPanelOutputMsg::OpenFile((key, time)) => AppMsg::Close,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let sidebar =
|
|
||||||
SideBarModel::builder()
|
|
||||||
.launch(layers.clone())
|
|
||||||
.forward(sender.input_sender(), |msg| {
|
|
||||||
AppMsg::LayerManager(match msg {
|
|
||||||
SideBarOutputMsg::SelectLayer(idx) => LayerMsg::Select(idx),
|
|
||||||
SideBarOutputMsg::NewLayer(layer) => LayerMsg::Add(layer),
|
|
||||||
SideBarOutputMsg::SwitchToTimeSeries(idx) => LayerMsg::SwitchToTime(idx),
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let render =
|
let render =
|
||||||
MonitorModel::builder()
|
MonitorModel::builder()
|
||||||
.launch(layers.clone())
|
.launch(layers.clone())
|
||||||
.forward(sender.input_sender(), |a| match a {
|
.forward(sender.input_sender(), |a| match a {
|
||||||
MonitorOutputMsg::LayerRenderFinished => AppMsg::Close,
|
MonitorOutputMsg::LayerRenderFinished => AppMsg::Close,
|
||||||
|
MonitorOutputMsg::LayerSwitchToTime(idx) => AppMsg::SwitchToTime(idx),
|
||||||
_ => AppMsg::Close,
|
_ => AppMsg::Close,
|
||||||
});
|
});
|
||||||
|
|
||||||
let setting = SettingModel::builder()
|
let setting = SettingModel::builder()
|
||||||
.launch(())
|
.launch(())
|
||||||
.forward(sender.input_sender(), |a| AppMsg::Close);
|
.forward(sender.input_sender(), |a| AppMsg::Close);
|
||||||
|
|
||||||
let mut dispatcher = Rc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1)));
|
let mut dispatcher = Rc::new(Dispatcher::new(5, 5, chrono::Duration::minutes(1)));
|
||||||
let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
let cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
||||||
|
let dialog_dispatcher = dispatcher.clone();
|
||||||
|
let dialog_render_sender = render.sender().clone();
|
||||||
|
let dialog = OpenDialog::builder()
|
||||||
|
.transient_for_native(&root)
|
||||||
|
.launch(OpenDialogSettings::default())
|
||||||
|
.forward(sender.input_sender(), move |response| match response {
|
||||||
|
OpenDialogResponse::Accept(path) => {
|
||||||
|
*FILE_PATH_ROOT.lock().unwrap() = path.clone();
|
||||||
|
let data = Self::open_file_only(path);
|
||||||
|
let meta: MetaInfo = (&data.meta).clone().into();
|
||||||
|
let (lat_start, lat_end) = meta.lat_range.unwrap();
|
||||||
|
let (lon_start, lon_end) = meta.lon_range.unwrap();
|
||||||
|
let element_impl = plugin_result_impl(&data);
|
||||||
|
let mut renderer = OffscreenRenderer::new(3000, 3000).unwrap();
|
||||||
|
let mut canvas = renderer.create_canvas();
|
||||||
|
let mut dialog_cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
||||||
|
let mut data_target = element_impl.render(&data, &mut canvas, &mut dialog_cms);
|
||||||
|
data_target.data = Some(Arc::new(data) as Arc<dyn Any + Send + Sync + 'static>);
|
||||||
|
|
||||||
let dialog = {
|
let element = Element::create_instant(
|
||||||
let dialog_dispatcher = dispatcher.clone();
|
InstantElementDrawerType::Prepared((data_target, Arc::new(element_impl))),
|
||||||
let dialog_sidebar_sender = sidebar.sender().clone();
|
dialog_dispatcher.clone(),
|
||||||
let dialog_render_sender = render.sender().clone();
|
"ET".to_string(),
|
||||||
OpenDialog::builder()
|
)
|
||||||
.transient_for_native(&root)
|
.get_instance();
|
||||||
.launch(OpenDialogSettings::default())
|
let layer =
|
||||||
.forward(sender.input_sender(), move |response| match response {
|
Layer::new(true, "New Layer".to_string(), AssoElement::Instant(element));
|
||||||
OpenDialogResponse::Accept(path) => {
|
dialog_render_sender.emit(MonitorInputMsg::AddMetaItem(meta.to_map()));
|
||||||
*FILE_PATH_ROOT.lock().unwrap() = path.clone();
|
dialog_render_sender.emit(MonitorInputMsg::SetRenderRange(
|
||||||
let data = Self::open_file_only(path);
|
lon_start, lon_end, lat_start, lat_end,
|
||||||
let meta: MetaInfo = (&data.meta).clone().into();
|
));
|
||||||
let (lat_start, lat_end) = meta.lat_range.unwrap();
|
AppMsg::NewLayer(layer)
|
||||||
let (lon_start, lon_end) = meta.lon_range.unwrap();
|
}
|
||||||
let element_impl = plugin_result_impl(&data);
|
_ => AppMsg::Close,
|
||||||
let mut renderer = OffscreenRenderer::new(3000, 3000).unwrap();
|
});
|
||||||
let mut canvas = renderer.create_canvas();
|
|
||||||
let mut dialog_cms = CMS::new(Mercator::default().into(), (3000.0, 3000.0));
|
|
||||||
let data_target = element_impl.render(&data, &mut canvas, &mut dialog_cms);
|
|
||||||
let data_target = DataTarget::new(Some(data), data_target);
|
|
||||||
let element = Element::create_instant(
|
|
||||||
InstantElementDrawerType::Prepared((data_target, element_impl)),
|
|
||||||
dialog_dispatcher.clone(),
|
|
||||||
"ET".to_string(),
|
|
||||||
)
|
|
||||||
.get_instance();
|
|
||||||
let layer = Layer::new(
|
|
||||||
true,
|
|
||||||
"New Layer".to_string(),
|
|
||||||
AssoElement::Instant(element),
|
|
||||||
);
|
|
||||||
dialog_sidebar_sender.emit(SideBarInputMsg::AddMetaItems(meta.to_map()));
|
|
||||||
dialog_render_sender.emit(MonitorInputMsg::SetRenderRange(
|
|
||||||
lon_start, lon_end, lat_start, lat_end,
|
|
||||||
));
|
|
||||||
|
|
||||||
AppMsg::LayerManager(LayerMsg::Add(layer))
|
|
||||||
}
|
|
||||||
_ => AppMsg::Close,
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let buffer: Buffer = Rc::new(RefCell::new(HashMap::new()));
|
let buffer: Buffer = Rc::new(RefCell::new(HashMap::new()));
|
||||||
let model = AppModel {
|
let model = AppModel {
|
||||||
@ -307,21 +255,15 @@ impl Component for AppModel {
|
|||||||
waiting_for: None,
|
waiting_for: None,
|
||||||
elements: Vec::with_capacity(20),
|
elements: Vec::with_capacity(20),
|
||||||
open_dialog: dialog,
|
open_dialog: dialog,
|
||||||
selected_layer: vec![],
|
|
||||||
sidebar,
|
|
||||||
control,
|
control,
|
||||||
render,
|
render,
|
||||||
layers,
|
layers,
|
||||||
setting,
|
setting,
|
||||||
tracker: 0,
|
tracker: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let render = model.render.widget();
|
|
||||||
let sidebar = model.sidebar.widget();
|
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
let mut group = RelmActionGroup::<FileActionGroup>::new();
|
let mut group = RelmActionGroup::<FileActionGroup>::new();
|
||||||
relm4::main_application().set_accelerators_for_action::<OpenAction>(&["<primary>O"]);
|
relm4::main_application().set_accelerators_for_action::<OpenAction>(&["<primary>O"]);
|
||||||
register_layer_actions(&widgets.main_window, sender.clone());
|
|
||||||
let action: RelmAction<OpenAction> = {
|
let action: RelmAction<OpenAction> = {
|
||||||
RelmAction::new_stateless(move |_| {
|
RelmAction::new_stateless(move |_| {
|
||||||
sender.input(AppMsg::OpenDialog);
|
sender.input(AppMsg::OpenDialog);
|
||||||
@ -329,6 +271,7 @@ impl Component for AppModel {
|
|||||||
};
|
};
|
||||||
group.add_action(action);
|
group.add_action(action);
|
||||||
group.register_for_widget(&widgets.main_window);
|
group.register_for_widget(&widgets.main_window);
|
||||||
|
|
||||||
ComponentParts { model, widgets }
|
ComponentParts { model, widgets }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,56 +284,31 @@ impl Component for AppModel {
|
|||||||
) {
|
) {
|
||||||
self.reset();
|
self.reset();
|
||||||
match msg {
|
match msg {
|
||||||
AppMsg::LayerManager(msg) => match msg {
|
AppMsg::NewLayer(layer) => {
|
||||||
LayerMsg::Add(layer) => {
|
(*self.layers).borrow_mut().push(layer);
|
||||||
(*self.layers).borrow_mut().push(layer);
|
self.render.sender().send(MonitorInputMsg::RefreshLayerList);
|
||||||
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
}
|
||||||
}
|
|
||||||
LayerMsg::SwitchToTime(idx) => {
|
|
||||||
let mut layer = (*self.layers).borrow_mut();
|
|
||||||
let switched_layer = layer.get_mut(idx).unwrap();
|
|
||||||
let asso_element = switched_layer.pop_associated_element();
|
|
||||||
|
|
||||||
if let AssoElement::Instant(e) = asso_element {
|
|
||||||
let dispatcher = self.dispatcher.clone();
|
|
||||||
let cms = self.cms.clone();
|
|
||||||
let (mut series, start_time) = e.to_time_series(dispatcher, cms);
|
|
||||||
switched_layer.set_time(start_time);
|
|
||||||
series.register(start_time).unwrap();
|
|
||||||
let element = Arc::new(Mutex::new(series));
|
|
||||||
switched_layer
|
|
||||||
.set_associated_element(AssoElement::TimeSeries(element.clone()));
|
|
||||||
self.elements.push(element);
|
|
||||||
}
|
|
||||||
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerMsg::Select(idx) => {
|
|
||||||
self.set_selected_layer(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerMsg::RemoveSelected => {
|
|
||||||
let mut layer = (*self.layers).borrow_mut();
|
|
||||||
let selected = self.selected_layer.clone();
|
|
||||||
for idx in selected {
|
|
||||||
layer.remove(idx);
|
|
||||||
}
|
|
||||||
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerMsg::Remove(idx) => {
|
|
||||||
let mut layers = (*self.layers).borrow_mut();
|
|
||||||
let mut layer = layers.remove(idx);
|
|
||||||
if let AssoElement::TimeSeries(e) = layer.pop_associated_element() {
|
|
||||||
let size = Arc::strong_count(&e);
|
|
||||||
}
|
|
||||||
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
AppMsg::CloseRequest => {
|
AppMsg::CloseRequest => {
|
||||||
relm4::main_application().quit();
|
relm4::main_application().quit();
|
||||||
}
|
}
|
||||||
AppMsg::Close => {}
|
AppMsg::Close => {}
|
||||||
|
AppMsg::SwitchToTime(idx) => {
|
||||||
|
let mut layer = (*self.layers).borrow_mut();
|
||||||
|
let switched_layer = layer.get_mut(idx).unwrap();
|
||||||
|
let asso_element = switched_layer.pop_associated_element();
|
||||||
|
|
||||||
|
if let AssoElement::Instant(e) = asso_element {
|
||||||
|
let dispatcher = self.dispatcher.clone();
|
||||||
|
let cms = self.cms.clone();
|
||||||
|
let (mut series, start_time) = e.to_time_series(dispatcher, cms);
|
||||||
|
switched_layer.set_time(start_time);
|
||||||
|
series.register(start_time).unwrap();
|
||||||
|
let element = Arc::new(Mutex::new(series));
|
||||||
|
switched_layer.set_associated_element(AssoElement::TimeSeries(element.clone()));
|
||||||
|
self.elements.push(element);
|
||||||
|
}
|
||||||
|
self.render.sender().send(MonitorInputMsg::RefreshLayerList);
|
||||||
|
}
|
||||||
AppMsg::OpenDialog => {
|
AppMsg::OpenDialog => {
|
||||||
self.open_dialog.emit(OpenDialogMsg::Open);
|
self.open_dialog.emit(OpenDialogMsg::Open);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use super::messages::*;
|
|||||||
use super::thumbnail::{ImgItem, TypedListView};
|
use super::thumbnail::{ImgItem, TypedListView};
|
||||||
use crate::data::{CoordType, Radar2d, RadarData2d};
|
use crate::data::{CoordType, Radar2d, RadarData2d};
|
||||||
use crate::plugin_system::init_plugin;
|
use crate::plugin_system::init_plugin;
|
||||||
use crate::predefined::color_mapper::BoundaryNorm;
|
use crate::widgets::render::predefined::color_mapper::BoundaryNorm;
|
||||||
use crate::widgets::render::Layer;
|
use crate::widgets::render::Layer;
|
||||||
use crate::widgets::timeline::{Selection, TimeLine};
|
use crate::widgets::timeline::{Selection, TimeLine};
|
||||||
use abi_stable::std_types::RStr;
|
use abi_stable::std_types::RStr;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
pub mod app;
|
pub mod app;
|
||||||
mod control_panel;
|
mod control_panel;
|
||||||
pub mod monitor;
|
mod monitor;
|
||||||
mod setting;
|
mod setting;
|
||||||
pub mod sidebar;
|
|
||||||
|
|
||||||
pub use control_panel::*;
|
pub use control_panel::*;
|
||||||
pub use monitor::*;
|
pub use monitor::*;
|
||||||
|
|||||||
@ -1,12 +1,20 @@
|
|||||||
use std::fmt::Debug;
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
|
|
||||||
use crate::components::monitor::widget::Widget;
|
use crate::{
|
||||||
|
components::app::ElementKey,
|
||||||
|
pipeline::element::ElementID,
|
||||||
|
widgets::{render::Layer, widget::Widget},
|
||||||
|
};
|
||||||
|
|
||||||
pub enum MonitorInputMsg {
|
pub enum MonitorInputMsg {
|
||||||
RefreshRender,
|
RefreshRender,
|
||||||
AddWidget(Box<dyn Widget>),
|
AddWidget(Box<dyn Widget>),
|
||||||
RemoveWidget,
|
RemoveWidget,
|
||||||
|
AddMetaItem(HashMap<String, String>),
|
||||||
|
ClearMetaItems,
|
||||||
|
UpdateMetaItem(HashMap<String, String>),
|
||||||
RefreshTiles,
|
RefreshTiles,
|
||||||
|
RefreshLayerList,
|
||||||
SetRenderRange(f64, f64, f64, f64),
|
SetRenderRange(f64, f64, f64, f64),
|
||||||
ChangeZoom(f64),
|
ChangeZoom(f64),
|
||||||
None,
|
None,
|
||||||
@ -21,15 +29,23 @@ impl Debug for MonitorInputMsg {
|
|||||||
MonitorInputMsg::SetRenderRange(_, _, _, _) => {
|
MonitorInputMsg::SetRenderRange(_, _, _, _) => {
|
||||||
write!(f, "MonitorInputMsg::SetRenderRange")
|
write!(f, "MonitorInputMsg::SetRenderRange")
|
||||||
}
|
}
|
||||||
|
MonitorInputMsg::RefreshLayerList => write!(f, "MonitorInputMsg::RefreshLayerList"),
|
||||||
MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"),
|
MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"),
|
||||||
MonitorInputMsg::AddWidget(_) => write!(f, "MonitorInputMsg::AddWidget"),
|
MonitorInputMsg::AddWidget(_) => write!(f, "MonitorInputMsg::AddWidget"),
|
||||||
MonitorInputMsg::RemoveWidget => write!(f, "MonitorInputMsg::RemoveWidget"),
|
MonitorInputMsg::RemoveWidget => write!(f, "MonitorInputMsg::RemoveWidget"),
|
||||||
|
MonitorInputMsg::AddMetaItem(_) => write!(f, "MonitorInputMsg::RemoveWidget"),
|
||||||
|
MonitorInputMsg::ClearMetaItems => write!(f, "MonitorInputMsg::ClearMetaItems"),
|
||||||
|
MonitorInputMsg::UpdateMetaItem(_) => write!(f, "MonitorInputMsg::UpdateMetaItem"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum MonitorOutputMsg {
|
pub enum MonitorOutputMsg {
|
||||||
|
LayerAdded(usize),
|
||||||
|
LayerRemoved(usize),
|
||||||
|
LayerUpdated(usize),
|
||||||
|
LayerSwitchToTime(usize),
|
||||||
LayerRenderFinished,
|
LayerRenderFinished,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
pub mod messages;
|
pub mod messages;
|
||||||
pub mod monitor;
|
pub mod monitor;
|
||||||
pub mod widget;
|
pub mod sidebar;
|
||||||
|
|
||||||
pub use monitor::*;
|
pub use monitor::*;
|
||||||
pub use widget::*;
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
use super::messages::{MonitorInputMsg, MonitorOutputMsg};
|
use super::messages::{MonitorInputMsg, MonitorOutputMsg};
|
||||||
use crate::components::monitor::widget::{Widget, WidgetType};
|
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::pipeline::offscreen_renderer::OffscreenRenderer;
|
use crate::pipeline::offscreen_renderer::OffscreenRenderer;
|
||||||
use crate::predefined::color_mapper::BoundaryNorm;
|
use crate::widgets::predefined::color_mapper::BoundaryNorm;
|
||||||
|
use crate::widgets::predefined::widgets::ColorBar;
|
||||||
use crate::widgets::render::RenderConfig;
|
use crate::widgets::render::RenderConfig;
|
||||||
|
use crate::widgets::widget::{Widget, WidgetType};
|
||||||
use crate::widgets::WidgetFrame;
|
use crate::widgets::WidgetFrame;
|
||||||
use crate::{
|
use crate::{
|
||||||
coords::{proj::Mercator, Mapper},
|
coords::{proj::Mercator, Mapper},
|
||||||
@ -18,7 +19,7 @@ use std::rc::Rc;
|
|||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
|
|
||||||
// use super::sidebar::{sidebar::SideBarModel, SideBarInputMsg, SideBarOutputMsg};
|
use super::sidebar::{sidebar::SideBarModel, SideBarInputMsg, SideBarOutputMsg};
|
||||||
use crate::coords::Range;
|
use crate::coords::Range;
|
||||||
use crate::map_tile::MapTile;
|
use crate::map_tile::MapTile;
|
||||||
use crate::map_tile_utils::lat_lon_to_zoom;
|
use crate::map_tile_utils::lat_lon_to_zoom;
|
||||||
@ -53,6 +54,8 @@ pub struct MonitorModel {
|
|||||||
widgets: Vec<WidgetFrame>,
|
widgets: Vec<WidgetFrame>,
|
||||||
#[no_eq]
|
#[no_eq]
|
||||||
layers: Rc<RefCell<Vec<Layer>>>,
|
layers: Rc<RefCell<Vec<Layer>>>,
|
||||||
|
#[no_eq]
|
||||||
|
sidebar: Controller<SideBarModel>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MonitorWidgets {
|
pub struct MonitorWidgets {
|
||||||
@ -68,50 +71,71 @@ impl Component for MonitorModel {
|
|||||||
|
|
||||||
view! {
|
view! {
|
||||||
#[root]
|
#[root]
|
||||||
gtk::Frame{
|
adw::BreakpointBin {
|
||||||
add_css_class: "rb",
|
set_hexpand: true,
|
||||||
set_margin_all: 5,
|
set_vexpand: true,
|
||||||
#[name="widget_layer"]
|
set_height_request: 500,
|
||||||
gtk::Overlay{
|
set_width_request: 700,
|
||||||
#[name = "renderer"]
|
#[wrap(Some)]
|
||||||
|
#[name="test"]
|
||||||
|
set_child = &DynamicCol{
|
||||||
|
set_end_width: 300,
|
||||||
|
set_hexpand: true,
|
||||||
|
set_vexpand: true,
|
||||||
|
#[wrap(Some)]
|
||||||
|
#[name="paned"]
|
||||||
|
set_child_paned=>k::Paned{
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
set_child = &Render{
|
#[name="render"]
|
||||||
#[track = "model.changed(MonitorModel::render_cfg())"]
|
set_start_child=>k::Frame{
|
||||||
set_cfg: model.render_cfg,
|
add_css_class: "rb",
|
||||||
#[track = "model.changed(MonitorModel::render_range())"]
|
set_margin_all: 5,
|
||||||
set_view: model.render_range,
|
#[name="widget_layer"]
|
||||||
set_tiles: model.map_tile_getter.clone(),
|
gtk::Overlay{
|
||||||
connect_render_status_notify[sender] => move |r| {
|
#[name = "renderer"]
|
||||||
sender.output(MonitorOutputMsg::LayerRenderFinished);
|
#[wrap(Some)]
|
||||||
|
set_child = &Render{
|
||||||
|
#[track = "model.changed(MonitorModel::render_cfg())"]
|
||||||
|
set_cfg: model.render_cfg,
|
||||||
|
#[track = "model.changed(MonitorModel::render_range())"]
|
||||||
|
set_view: model.render_range,
|
||||||
|
set_tiles: model.map_tile_getter.clone(),
|
||||||
|
connect_render_status_notify[sender] => move |r| {
|
||||||
|
sender.output(MonitorOutputMsg::LayerRenderFinished);
|
||||||
|
},
|
||||||
|
connect_range_changing_notify[sender] => move |r| {
|
||||||
|
sender.input(MonitorInputMsg::RefreshTiles);
|
||||||
|
},
|
||||||
|
connect_scale_notify[sender] => move |r| {
|
||||||
|
let scale = r.scale();
|
||||||
|
{
|
||||||
|
let initial = r.scale_rate();
|
||||||
|
let mut rate_start = initial_rate.lock().unwrap();
|
||||||
|
if rate_start.is_none() {
|
||||||
|
*rate_start = Some(scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debouncer.call(scale);
|
||||||
|
},
|
||||||
|
set_interior_layers: model.layers.clone(),
|
||||||
|
},
|
||||||
|
add_overlay=>k::Button{
|
||||||
|
set_label:"Add",
|
||||||
|
set_margin_all:10,
|
||||||
|
set_valign: gtk::Align::Start,
|
||||||
|
set_halign: gtk::Align::End,
|
||||||
|
},
|
||||||
|
#[track = "model.changed(MonitorModel::new_layer())"]
|
||||||
|
#[iterate]
|
||||||
|
add_overlay: &model.widgets
|
||||||
},
|
},
|
||||||
connect_range_changing_notify[sender] => move |r| {
|
|
||||||
sender.input(MonitorInputMsg::RefreshTiles);
|
|
||||||
},
|
|
||||||
connect_scale_notify[sender] => move |r| {
|
|
||||||
let scale = r.scale();
|
|
||||||
{
|
|
||||||
let initial = r.scale_rate();
|
|
||||||
let mut rate_start = initial_rate.lock().unwrap();
|
|
||||||
if rate_start.is_none() {
|
|
||||||
*rate_start = Some(scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
debouncer.call(scale);
|
|
||||||
},
|
|
||||||
set_interior_layers: model.layers.clone(),
|
|
||||||
},
|
|
||||||
add_overlay=>k::Button{
|
|
||||||
set_label:"Add",
|
|
||||||
set_margin_all:10,
|
|
||||||
set_valign: gtk::Align::Start,
|
|
||||||
set_halign: gtk::Align::End,
|
|
||||||
},
|
|
||||||
#[track = "model.changed(MonitorModel::new_layer())"]
|
|
||||||
#[iterate]
|
|
||||||
add_overlay: &model.widgets
|
|
||||||
},
|
|
||||||
|
|
||||||
|
},
|
||||||
|
#[wrap(Some)]
|
||||||
|
set_end_child=model.sidebar.widget(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_with_view(
|
fn update_with_view(
|
||||||
@ -126,13 +150,25 @@ impl Component for MonitorModel {
|
|||||||
MonitorInputMsg::RefreshRender => {
|
MonitorInputMsg::RefreshRender => {
|
||||||
widgets.renderer.queue_render();
|
widgets.renderer.queue_render();
|
||||||
}
|
}
|
||||||
|
MonitorInputMsg::RefreshLayerList => {
|
||||||
|
self.sidebar.sender().send(SideBarInputMsg::RefreshList);
|
||||||
|
sender.input(MonitorInputMsg::RefreshRender);
|
||||||
|
}
|
||||||
|
MonitorInputMsg::AddMetaItem(map) => {
|
||||||
|
self.sidebar.emit(SideBarInputMsg::AddMetaItems(map))
|
||||||
|
}
|
||||||
MonitorInputMsg::SetRenderRange(lon_start, lon_end, lat_start, lat_end) => {
|
MonitorInputMsg::SetRenderRange(lon_start, lon_end, lat_start, lat_end) => {
|
||||||
let current_rate = widgets.renderer.scale_rate();
|
let current_rate = widgets.renderer.scale_rate();
|
||||||
self.set_render_range((lat_start, lat_end, lon_start, lon_end));
|
self.set_render_range((lat_start, lat_end, lon_start, lon_end));
|
||||||
let new_rate = widgets.renderer.scale_rate();
|
let new_rate = widgets.renderer.scale_rate();
|
||||||
let zoom: f64 = (new_rate / current_rate).log2();
|
let zoom: f64 = (current_rate / new_rate).log2();
|
||||||
sender.input(MonitorInputMsg::ChangeZoom(zoom));
|
sender.input(MonitorInputMsg::ChangeZoom(zoom));
|
||||||
}
|
}
|
||||||
|
MonitorInputMsg::ClearMetaItems => self.sidebar.emit(SideBarInputMsg::ClearMetaItems),
|
||||||
|
MonitorInputMsg::UpdateMetaItem(map) => {
|
||||||
|
self.sidebar.emit(SideBarInputMsg::ClearMetaItems);
|
||||||
|
self.sidebar.emit(SideBarInputMsg::AddMetaItems(map))
|
||||||
|
}
|
||||||
MonitorInputMsg::RefreshTiles => {
|
MonitorInputMsg::RefreshTiles => {
|
||||||
let ((x1, x2), (y1, y2)) = widgets.renderer.render_range();
|
let ((x1, x2), (y1, y2)) = widgets.renderer.render_range();
|
||||||
self.load_tile(&sender, ((y1 as f32, y2 as f32), (x1 as f32, x2 as f32)));
|
self.load_tile(&sender, ((y1 as f32, y2 as f32), (x1 as f32, x2 as f32)));
|
||||||
@ -167,16 +203,16 @@ impl Component for MonitorModel {
|
|||||||
root: Self::Root,
|
root: Self::Root,
|
||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
// let sidebar_sender = sender.clone();
|
let sidebar_sender = sender.clone();
|
||||||
// let sidebar: Controller<SideBarModel> = SideBarModel::builder()
|
let sidebar: Controller<SideBarModel> = SideBarModel::builder()
|
||||||
// .launch(init.clone())
|
.launch(init.clone())
|
||||||
// .forward(sender.input_sender(), move |msg| match msg {
|
.forward(sender.input_sender(), move |msg| match msg {
|
||||||
// SideBarOutputMsg::SwitchToTimeSeries(layer) => {
|
SideBarOutputMsg::SwitchToTimeSeries(layer) => {
|
||||||
// sidebar_sender.output(MonitorOutputMsg::LayerSwitchToTime(layer));
|
sidebar_sender.output(MonitorOutputMsg::LayerSwitchToTime(layer));
|
||||||
// MonitorInputMsg::None
|
MonitorInputMsg::None
|
||||||
// }
|
}
|
||||||
// _ => MonitorInputMsg::None,
|
_ => MonitorInputMsg::None,
|
||||||
// });
|
});
|
||||||
|
|
||||||
let render_cfg = RenderConfig {
|
let render_cfg = RenderConfig {
|
||||||
padding: [0.0, 0.0, 0.0, 0.0],
|
padding: [0.0, 0.0, 0.0, 0.0],
|
||||||
@ -195,6 +231,7 @@ impl Component for MonitorModel {
|
|||||||
layers: init,
|
layers: init,
|
||||||
zoom: 4,
|
zoom: 4,
|
||||||
map_tile_getter: Rc::new(MapTile::default()),
|
map_tile_getter: Rc::new(MapTile::default()),
|
||||||
|
sidebar,
|
||||||
tracker: 0,
|
tracker: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
use crate::actions::*;
|
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
use relm4::{
|
use relm4::{
|
||||||
actions::traits::ActionablePlus, factory::FactoryView, gtk, prelude::*, FactorySender,
|
factory::FactoryView,
|
||||||
|
gtk,
|
||||||
|
prelude::{DynamicIndex, FactoryComponent},
|
||||||
|
FactorySender,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::SideBarInputMsg;
|
use super::SideBarInputMsg;
|
||||||
@ -38,9 +40,10 @@ impl FactoryComponent for BottomBarModel {
|
|||||||
|
|
||||||
view! {
|
view! {
|
||||||
#[root]
|
#[root]
|
||||||
gtk::Button{
|
gtk::Box{
|
||||||
set_icon_name=self.icon.as_str(),
|
gtk::Button{
|
||||||
ActionablePlus::set_stateless_action::<RemoveLayerAction>: &(),
|
set_icon_name=self.icon.as_str(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -9,7 +9,7 @@ use relm4::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub(in crate::components) struct MyListItem {
|
pub(super) struct MyListItem {
|
||||||
tag: String,
|
tag: String,
|
||||||
info: String,
|
info: String,
|
||||||
}
|
}
|
||||||
@ -20,7 +20,7 @@ impl MyListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::components) struct TagColumn;
|
pub(super) struct TagColumn;
|
||||||
|
|
||||||
impl LabelColumn for TagColumn {
|
impl LabelColumn for TagColumn {
|
||||||
type Item = MyListItem;
|
type Item = MyListItem;
|
||||||
@ -38,7 +38,7 @@ impl LabelColumn for TagColumn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::components) struct InfoColumn;
|
pub(super) struct InfoColumn;
|
||||||
|
|
||||||
impl RelmColumn for InfoColumn {
|
impl RelmColumn for InfoColumn {
|
||||||
type Root = gtk::Label;
|
type Root = gtk::Label;
|
||||||
@ -1,4 +1,3 @@
|
|||||||
use crate::actions::*;
|
|
||||||
use crate::widgets::AssoElement;
|
use crate::widgets::AssoElement;
|
||||||
use abi_stable::type_level::trait_marker::Hash;
|
use abi_stable::type_level::trait_marker::Hash;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
@ -21,7 +20,11 @@ use relm4::{
|
|||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
use crate::components::app::AppMsg;
|
use crate::components::app::AppMsg;
|
||||||
use crate::{chart::Chart, predefined::color_mapper::BoundaryNorm, widgets::render::Layer};
|
use crate::{
|
||||||
|
chart::Chart,
|
||||||
|
data::Npz,
|
||||||
|
widgets::render::{predefined::color_mapper::BoundaryNorm, Layer},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
bottom_bar::BottomBarModel,
|
bottom_bar::BottomBarModel,
|
||||||
@ -32,7 +35,7 @@ pub struct SideBarModel {
|
|||||||
layers: Rc<RefCell<Vec<Layer>>>,
|
layers: Rc<RefCell<Vec<Layer>>>,
|
||||||
selected_layer_idx: usize,
|
selected_layer_idx: usize,
|
||||||
counter: u8,
|
counter: u8,
|
||||||
list_view_wrapper: TypedListView<LayerItem, gtk::MultiSelection>,
|
list_view_wrapper: TypedListView<LayerItem, gtk::SingleSelection>,
|
||||||
bottom_bar_vec: FactoryVecDeque<BottomBarModel>,
|
bottom_bar_vec: FactoryVecDeque<BottomBarModel>,
|
||||||
meta_list_view: TypedColumnView<MyListItem, gtk::NoSelection>,
|
meta_list_view: TypedColumnView<MyListItem, gtk::NoSelection>,
|
||||||
}
|
}
|
||||||
@ -47,7 +50,6 @@ pub enum SideBarInputMsg {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SideBarOutputMsg {
|
pub enum SideBarOutputMsg {
|
||||||
SelectLayer(Vec<usize>),
|
|
||||||
NewLayer(Layer),
|
NewLayer(Layer),
|
||||||
SwitchToTimeSeries(usize),
|
SwitchToTimeSeries(usize),
|
||||||
}
|
}
|
||||||
@ -102,8 +104,7 @@ impl SimpleComponent for SideBarModel {
|
|||||||
.build() -> gtk::ScrolledWindow{
|
.build() -> gtk::ScrolledWindow{
|
||||||
#[wrap(Some)]
|
#[wrap(Some)]
|
||||||
#[local_ref]
|
#[local_ref]
|
||||||
set_child=my_view -> gtk::ListView{
|
set_child=my_view -> gtk::ListView{},
|
||||||
},
|
|
||||||
set_margin_horizontal:5,
|
set_margin_horizontal:5,
|
||||||
set_margin_vertical:3
|
set_margin_vertical:3
|
||||||
},
|
},
|
||||||
@ -131,19 +132,8 @@ impl SimpleComponent for SideBarModel {
|
|||||||
sender: ComponentSender<Self>,
|
sender: ComponentSender<Self>,
|
||||||
) -> ComponentParts<Self> {
|
) -> ComponentParts<Self> {
|
||||||
// Initialize the ListView wrapper
|
// Initialize the ListView wrapper
|
||||||
let mut list_view_wrapper: TypedListView<LayerItem, gtk::MultiSelection> =
|
let mut list_view_wrapper: TypedListView<LayerItem, gtk::SingleSelection> =
|
||||||
TypedListView::with_sorting();
|
TypedListView::with_sorting();
|
||||||
|
|
||||||
list_view_wrapper.selection_model.connect_selection_changed(
|
|
||||||
clone!(@strong sender => move |s,_, _| {
|
|
||||||
let selection = s.selection();
|
|
||||||
|
|
||||||
let (iter, first) = gtk::BitsetIter::init_first(&selection).unwrap();
|
|
||||||
let mut result = vec![first as usize];
|
|
||||||
result.extend(iter.map(|v| v as usize));
|
|
||||||
sender.output(SideBarOutputMsg::SelectLayer(result));
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
// let mut bottom_bar_vec = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
|
// let mut bottom_bar_vec = FactoryVecDeque::new(gtk::Box::default(), sender.input_sender());
|
||||||
|
|
||||||
let mut bottom_bar_vec =
|
let mut bottom_bar_vec =
|
||||||
@ -280,13 +270,11 @@ impl LayerItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Widgets {
|
struct Widgets {
|
||||||
label: gtk::EditableLabel,
|
label: gtk::Label,
|
||||||
screen_shot: gtk::Image,
|
screen_shot: gtk::Image,
|
||||||
status_icon: gtk::Image,
|
status: gtk::Label,
|
||||||
status_label: gtk::Label,
|
button: gtk::CheckButton,
|
||||||
visible: gtk::Button,
|
menu: gtk::PopoverMenu,
|
||||||
opacity: gtk::Label,
|
|
||||||
menu: gtk::Popover,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RelmListItem for LayerItem {
|
impl RelmListItem for LayerItem {
|
||||||
@ -294,22 +282,13 @@ impl RelmListItem for LayerItem {
|
|||||||
type Widgets = Widgets;
|
type Widgets = Widgets;
|
||||||
|
|
||||||
fn setup(_item: >k::ListItem) -> (gtk::Box, Widgets) {
|
fn setup(_item: >k::ListItem) -> (gtk::Box, Widgets) {
|
||||||
let position = _item.position() as u8;
|
|
||||||
|
|
||||||
relm4::menu! {
|
relm4::menu! {
|
||||||
main_menu: {
|
main_menu: {
|
||||||
custom: "MyWidget",
|
|
||||||
"Remove" => RemoveLayerAction,
|
|
||||||
section!{
|
|
||||||
"test" => RemoveLayerAction,
|
|
||||||
"select" => AddLayerAction
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
relm4::view! {
|
relm4::view! {
|
||||||
my_box = gtk::Box {
|
my_box = gtk::Box {
|
||||||
set_valign: gtk::Align::Center,
|
|
||||||
gtk::Frame{
|
gtk::Frame{
|
||||||
set_margin_end: 10,
|
set_margin_end: 10,
|
||||||
#[name = "screen_shot"]
|
#[name = "screen_shot"]
|
||||||
@ -317,46 +296,31 @@ impl RelmListItem for LayerItem {
|
|||||||
set_size_request: (65, 40),
|
set_size_request: (65, 40),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
gtk::Grid{
|
#[name = "label"]
|
||||||
set_row_homogeneous: true,
|
gtk::Label{
|
||||||
attach[0,0,1,1] = >k::Box{
|
set_halign: gtk::Align::Start,
|
||||||
#[name="status_icon"]
|
},
|
||||||
gtk::Image{
|
#[name = "status"]
|
||||||
inline_css: "-gtk-icon-transform: scale(0.8);",
|
gtk::Label{
|
||||||
},
|
set_halign: gtk::Align::Start
|
||||||
#[name="status_label"]
|
},
|
||||||
gtk::Label{
|
gtk::Label{
|
||||||
add_css_class:"tooltip",
|
set_hexpand: true,
|
||||||
set_halign: gtk::Align::Start,
|
},
|
||||||
}
|
#[name = "button"]
|
||||||
},
|
gtk::CheckButton{
|
||||||
#[name="label"]
|
set_halign: gtk::Align::End,
|
||||||
attach[0,1,1,1] = >k::EditableLabel{
|
|
||||||
set_hexpand: true,
|
|
||||||
},
|
|
||||||
#[name="opacity"]
|
|
||||||
attach[0,2,1,1] = >k::Label{
|
|
||||||
add_css_class:"tooltip",
|
|
||||||
set_halign: gtk::Align::Start
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
#[name="visible"]
|
|
||||||
gtk::Button{
|
|
||||||
set_vexpand: false,
|
|
||||||
set_hexpand: false,
|
|
||||||
},
|
|
||||||
#[name = "menu"]
|
#[name = "menu"]
|
||||||
gtk::Popover{}
|
gtk::PopoverMenu::from_model(Some(&main_menu)){}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let widgets = Widgets {
|
let widgets = Widgets {
|
||||||
screen_shot,
|
screen_shot,
|
||||||
label,
|
label,
|
||||||
status_icon,
|
status,
|
||||||
status_label,
|
button,
|
||||||
opacity,
|
|
||||||
visible,
|
|
||||||
menu,
|
menu,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -366,28 +330,24 @@ impl RelmListItem for LayerItem {
|
|||||||
fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
|
fn bind(&mut self, widgets: &mut Self::Widgets, _root: &mut Self::Root) {
|
||||||
let Widgets {
|
let Widgets {
|
||||||
label,
|
label,
|
||||||
visible,
|
button,
|
||||||
screen_shot,
|
screen_shot,
|
||||||
status_label,
|
status,
|
||||||
status_icon,
|
|
||||||
opacity,
|
|
||||||
menu,
|
menu,
|
||||||
} = widgets;
|
} = widgets;
|
||||||
|
|
||||||
status_label.set_label(&match self.status {
|
relm4::menu! {
|
||||||
|
main_menu: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menu.set_menu_model(Some(&main_menu));
|
||||||
|
|
||||||
|
status.set_label(&match self.status {
|
||||||
LayerStatus::BindToTime(t) => format!("Bind To Time: {}", t),
|
LayerStatus::BindToTime(t) => format!("Bind To Time: {}", t),
|
||||||
LayerStatus::Instance => "Instance".to_string(),
|
LayerStatus::Instance => "Instance".to_string(),
|
||||||
LayerStatus::BindToOtherLayer(idx) => format!("Bind To Layer: {}", idx),
|
LayerStatus::BindToOtherLayer(idx) => format!("Bind To Layer: {}", idx),
|
||||||
});
|
});
|
||||||
|
|
||||||
status_icon.set_icon_name(Some(match self.status {
|
|
||||||
LayerStatus::BindToTime(_) => "timer-filled",
|
|
||||||
LayerStatus::Instance => "timer-filled",
|
|
||||||
LayerStatus::BindToOtherLayer(_) => "timer-filled",
|
|
||||||
}));
|
|
||||||
|
|
||||||
opacity.set_markup(&format!("<b>Opacity:</b> 0.5"));
|
|
||||||
|
|
||||||
let gesture_click = gtk::GestureClick::new();
|
let gesture_click = gtk::GestureClick::new();
|
||||||
gesture_click.set_button(gtk::gdk::BUTTON_SECONDARY);
|
gesture_click.set_button(gtk::gdk::BUTTON_SECONDARY);
|
||||||
screen_shot.set_paintable(self.img.as_ref());
|
screen_shot.set_paintable(self.img.as_ref());
|
||||||
@ -398,10 +358,8 @@ impl RelmListItem for LayerItem {
|
|||||||
menu.popup();
|
menu.popup();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
visible.set_icon_name("eye-filled");
|
|
||||||
|
|
||||||
_root.add_controller(gesture_click);
|
_root.add_controller(gesture_click);
|
||||||
label.set_text(&self.layer_name);
|
label.set_label(&self.layer_name);
|
||||||
// button.set_active(self.visiable);
|
button.set_active(self.visiable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,8 +2,7 @@ use super::dispatcher_list::PathItem;
|
|||||||
use crate::{
|
use crate::{
|
||||||
config::PATH_FORMATS,
|
config::PATH_FORMATS,
|
||||||
data::{self, CoordType, Radar2d},
|
data::{self, CoordType, Radar2d},
|
||||||
predefined::color_mapper::BoundaryNorm,
|
widgets::render::{predefined::color_mapper::BoundaryNorm, Layer},
|
||||||
widgets::render::Layer,
|
|
||||||
CONFIG, PLUGIN_MANAGER,
|
CONFIG, PLUGIN_MANAGER,
|
||||||
};
|
};
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::coords::Mapper;
|
|
||||||
use geo_types::LineString;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
use geo_types::LineString;
|
||||||
|
use crate::coords::Mapper;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CMS {
|
pub struct CMS {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
use num_traits::AsPrimitive;
|
use num_traits::AsPrimitive;
|
||||||
use num_traits::Num;
|
use num_traits::Num;
|
||||||
pub mod cms;
|
|
||||||
pub mod mapper;
|
pub mod mapper;
|
||||||
pub mod proj;
|
pub mod proj;
|
||||||
pub mod wgs84;
|
pub mod wgs84;
|
||||||
|
pub mod cms;
|
||||||
|
|
||||||
pub use mapper::Mapper;
|
pub use mapper::Mapper;
|
||||||
// pub use wgs84::LatLonCoord;
|
// pub use wgs84::LatLonCoord;
|
||||||
|
|||||||
3
src/css/style.css
Normal file
3
src/css/style.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
button {
|
||||||
|
color: magenta;
|
||||||
|
}
|
||||||
570
src/data/mod.rs
570
src/data/mod.rs
@ -2,27 +2,18 @@ pub mod meta;
|
|||||||
use crate::errors::DataError;
|
use crate::errors::DataError;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
pub use meta::MetaInfo;
|
pub use meta::MetaInfo;
|
||||||
use ndarray::iter::Indices;
|
|
||||||
use ndarray::{
|
use ndarray::{
|
||||||
s, Array, Array1, Array2, Array3, ArrayBase, Axis, DataMut, Dimension, Ix1, Ix2, Ix3,
|
s, Array1, Array2, Array3, ArrayBase, DataMut, Dimension, Ix1, Ix2, OwnedRepr, RawDataClone,
|
||||||
OwnedRepr, RawDataClone, Slice, ViewRepr,
|
|
||||||
};
|
};
|
||||||
use npyz::{npz::NpzArchive, Deserialize};
|
use npyz::{npz::NpzArchive, Deserialize};
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, Num};
|
use num_traits::{AsPrimitive, FromPrimitive, Num};
|
||||||
|
use std::io::{Cursor, Seek};
|
||||||
use std::{self, f64::consts::PI, fmt::Debug, io::BufReader, path::Path};
|
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>, OwnedRepr<f64>, OwnedRepr<f64>>;
|
pub type Radar2d<T> = RadarData2d<T, OwnedRepr<T>>;
|
||||||
pub type Radar3d<T> = RadarData3d<T, OwnedRepr<T>, OwnedRepr<f64>, OwnedRepr<f64>, OwnedRepr<f64>>;
|
|
||||||
|
|
||||||
pub type Radar2dRef<'a, T> = RadarData2d<T, ViewRepr<&'a T>, ViewRepr<&'a f64>, ViewRepr<&'a f64>>;
|
|
||||||
pub type Radar3dRef<'a, T> =
|
|
||||||
RadarData3d<T, ViewRepr<&'a T>, ViewRepr<&'a f64>, ViewRepr<&'a f64>, ViewRepr<&'a f64>>;
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum CoordType {
|
|
||||||
Polar,
|
|
||||||
LatLon,
|
|
||||||
}
|
|
||||||
pub trait MultiDimensionData<T>
|
pub trait MultiDimensionData<T>
|
||||||
where
|
where
|
||||||
T: Num + Clone + PartialEq + PartialOrd,
|
T: Num + Clone + PartialEq + PartialOrd,
|
||||||
@ -33,84 +24,248 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RadarData2d<T, Raw, X, Y, I = Ix1>
|
pub struct RadarData2d<T, Raw, X = f64, Y = f64, I = Ix1>
|
||||||
where
|
where
|
||||||
T: Num + Clone + PartialEq + PartialOrd,
|
T: Num + Clone + PartialEq + PartialOrd,
|
||||||
Raw: ndarray::Data<Elem = T> + ndarray::RawDataClone,
|
Raw: ndarray::Data<Elem = T> + Clone + ndarray::RawDataClone,
|
||||||
X: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
X: Num,
|
||||||
Y: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
Y: Num,
|
||||||
{
|
{
|
||||||
pub dim1: ArrayBase<X, I>,
|
pub dim1: ArrayBase<OwnedRepr<X>, I>,
|
||||||
pub dim2: ArrayBase<Y, I>,
|
pub dim2: ArrayBase<OwnedRepr<Y>, I>,
|
||||||
pub data: ArrayBase<Raw, Ix2>,
|
pub data: ArrayBase<Raw, Ix2>,
|
||||||
pub fill_value: T,
|
pub fill_value: T,
|
||||||
pub coord_type: CoordType,
|
pub coord_type: CoordType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Radar2d<T>
|
impl<T, Raw, X, Y, I> Debug for RadarData2d<T, Raw, X, Y, I>
|
||||||
where
|
where
|
||||||
T: Num + Clone + PartialEq + PartialOrd,
|
T: Num + Clone + PartialEq + PartialOrd + Debug,
|
||||||
|
Raw: ndarray::Data<Elem = T> + Clone + ndarray::RawDataClone,
|
||||||
|
X: Num + Debug,
|
||||||
|
Y: Num + Debug,
|
||||||
|
I: Dimension,
|
||||||
{
|
{
|
||||||
pub fn as_ref<'a>(&'a self) -> Radar2dRef<'a, T> {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
RadarData2d {
|
f.debug_struct("RadarData2d")
|
||||||
dim1: self.dim1.view(),
|
.field("dim1", &self.dim1)
|
||||||
dim2: self.dim2.view(),
|
.field("dim2", &self.dim2)
|
||||||
data: self.data.view(),
|
.field("data", &self.data)
|
||||||
fill_value: self.fill_value.clone(),
|
.field("fill_value", &self.fill_value)
|
||||||
coord_type: self.coord_type.clone(),
|
.field("coord_type", &self.coord_type)
|
||||||
}
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
impl<T: Num + Clone + PartialEq + PartialOrd> Radar2d<T> {
|
||||||
pub struct RadarData3d<T, Raw, X, Y, Z, I = Ix1>
|
pub fn load(path: impl AsRef<Path>, meth: impl DataLoader<T, Self>) -> Result<Self, DataError> {
|
||||||
where
|
Ok(meth.load(path)?)
|
||||||
T: Num + Clone + PartialEq + PartialOrd,
|
}
|
||||||
Raw: ndarray::Data<Elem = T> + ndarray::RawDataClone,
|
|
||||||
X: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
|
||||||
Y: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
|
||||||
Z: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
|
||||||
{
|
|
||||||
pub dim1: ArrayBase<X, I>,
|
|
||||||
pub dim2: ArrayBase<Y, I>,
|
|
||||||
pub dim3: ArrayBase<Z, I>,
|
|
||||||
pub data: ArrayBase<Raw, Ix3>,
|
|
||||||
pub fill_value: T,
|
|
||||||
pub coord_type: CoordType,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Raw, X, Y, Z> RadarData3d<T, Raw, X, Y, Z>
|
pub struct RadarData3d<T, X = f64, Y = f64, Z = f64>
|
||||||
where
|
where
|
||||||
T: Num + Clone + PartialEq + PartialOrd,
|
T: Num,
|
||||||
X: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
X: Num,
|
||||||
Y: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
Y: Num,
|
||||||
Z: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
Z: Num,
|
||||||
Raw: ndarray::Data<Elem = T> + ndarray::RawDataClone,
|
|
||||||
{
|
{
|
||||||
pub fn index_axis(&self, axis: Axis, slice: usize) -> Radar2dRef<T> {
|
pub dim1: Array1<X>,
|
||||||
|
pub dim2: Array1<Y>,
|
||||||
|
pub dim3: Array1<Z>,
|
||||||
|
pub data: Array3<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, Raw> RadarData2d<T, Raw>
|
||||||
|
where
|
||||||
|
T: Num + AsPrimitive<f64> + FromPrimitive + Clone + Debug + PartialOrd + PartialEq,
|
||||||
|
Raw: ndarray::Data<Elem = T> + Clone + ndarray::RawDataClone,
|
||||||
|
{
|
||||||
|
pub fn downsample(&self, output_shape: (usize, usize), meth: DownSampleMeth) -> Radar2d<T> {
|
||||||
let shape = self.data.shape();
|
let shape = self.data.shape();
|
||||||
println!("shape: {:?}", shape);
|
assert!(shape[0] > output_shape.0 && shape[1] > output_shape.1);
|
||||||
let dim1 = self.dim1.view();
|
|
||||||
let dim2 = self.dim2.view();
|
if shape[0] == output_shape.0 && shape[1] == output_shape.1 {
|
||||||
let view = self.data.index_axis(axis, slice);
|
return Radar2d {
|
||||||
RadarData2d {
|
dim1: self.dim1.to_owned(),
|
||||||
|
dim2: self.dim2.to_owned(),
|
||||||
|
data: self.data.to_owned(),
|
||||||
|
fill_value: self.fill_value.clone(),
|
||||||
|
coord_type: self.coord_type.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let scale_x = shape[1] as f64 / output_shape.1 as f64;
|
||||||
|
let scale_y = shape[0] as f64 / output_shape.0 as f64;
|
||||||
|
|
||||||
|
let mut output: Array2<T> = Array2::zeros(output_shape);
|
||||||
|
|
||||||
|
let dim1 = Array1::linspace(
|
||||||
|
*self.dim1.first().unwrap(),
|
||||||
|
*self.dim1.last().unwrap(),
|
||||||
|
output_shape.1,
|
||||||
|
);
|
||||||
|
|
||||||
|
let dim2 = Array1::linspace(
|
||||||
|
*self.dim2.first().unwrap(),
|
||||||
|
*self.dim2.last().unwrap(),
|
||||||
|
output_shape.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
output.iter_mut().enumerate().for_each(|(s, vv)| {
|
||||||
|
let ri = s / output_shape.1;
|
||||||
|
let ci = s % output_shape.1;
|
||||||
|
let src_yf0 = scale_y * ri as f64;
|
||||||
|
let src_yf1 = src_yf0 + scale_y;
|
||||||
|
let src_y0 = src_yf0.floor() as usize;
|
||||||
|
let src_y1 = src_yf1.floor() as usize;
|
||||||
|
let src_xf0 = scale_x * ci as f64;
|
||||||
|
let src_xf1 = src_xf0 + scale_x;
|
||||||
|
let src_x0 = src_xf0.floor() as usize;
|
||||||
|
let src_x1 = src_xf1.floor() as usize;
|
||||||
|
|
||||||
|
match meth {
|
||||||
|
DownSampleMeth::MEAN => {}
|
||||||
|
DownSampleMeth::VAR | DownSampleMeth::STD => self.var(
|
||||||
|
src_yf0, src_yf1, src_xf0, src_xf1, src_y0, src_y1, src_x0, src_x1, vv,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let DownSampleMeth::STD = meth {
|
||||||
|
output = output.mapv(|x| T::from_f64(f64::sqrt(x.as_())).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Radar2d {
|
||||||
dim1,
|
dim1,
|
||||||
dim2,
|
dim2,
|
||||||
data: view,
|
|
||||||
fill_value: self.fill_value.clone(),
|
fill_value: self.fill_value.clone(),
|
||||||
|
data: output,
|
||||||
coord_type: self.coord_type.clone(),
|
coord_type: self.coord_type.clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn var(
|
||||||
|
&self,
|
||||||
|
src_yf0: f64,
|
||||||
|
src_yf1: f64,
|
||||||
|
src_xf0: f64,
|
||||||
|
src_xf1: f64,
|
||||||
|
src_y0: usize,
|
||||||
|
mut src_y1: usize,
|
||||||
|
src_x0: usize,
|
||||||
|
mut src_x1: usize,
|
||||||
|
row: &mut T,
|
||||||
|
) {
|
||||||
|
let wy0 = 1f64 - (src_yf0 - src_y0 as f64);
|
||||||
|
let mut wy1 = src_yf1 - src_y1 as f64;
|
||||||
|
let wx0 = 1f64 - (src_xf0 - src_x0 as f64);
|
||||||
|
let mut wx1 = src_xf1 - src_x1 as f64;
|
||||||
|
|
||||||
|
if wy1 < f64::EPSILON {
|
||||||
|
wy1 = 1f64;
|
||||||
|
if src_y1 > src_y0 {
|
||||||
|
src_y1 -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if wx1 < f64::EPSILON {
|
||||||
|
wx1 = 1f64;
|
||||||
|
if src_x1 > src_x0 {
|
||||||
|
src_x1 -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut v_sum: f64 = 0.0;
|
||||||
|
let mut w_sum = 0f64;
|
||||||
|
let mut wv_sum = 0f64;
|
||||||
|
let mut wvv_sum = 0f64;
|
||||||
|
|
||||||
|
for src_y in src_y0..=src_y1 {
|
||||||
|
let wy = if src_y == src_y0 {
|
||||||
|
wy0
|
||||||
|
} else {
|
||||||
|
if src_y == src_y1 {
|
||||||
|
wy1
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for src_x in src_x0..=src_x1 {
|
||||||
|
let wx = if src_x == src_x0 {
|
||||||
|
wx0
|
||||||
|
} else {
|
||||||
|
if src_x == src_x1 {
|
||||||
|
wx1
|
||||||
|
} else {
|
||||||
|
1.0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let v = self.data[[src_y, src_x]].as_();
|
||||||
|
let w = wx * wy;
|
||||||
|
|
||||||
|
v_sum += v;
|
||||||
|
w_sum += w;
|
||||||
|
wv_sum += w * v;
|
||||||
|
wvv_sum += w * v * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if w_sum < f64::EPSILON {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let v = ((wvv_sum * w_sum - wv_sum * wv_sum) / w_sum / w_sum).clamp(-125f64, 124f64);
|
||||||
|
*row = T::from_f64(v).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn split(&self) -> [RadarData2d<T, ndarray::ViewRepr<&T>>; 4] {
|
||||||
|
let middle_dim1 = self.dim1.len() / 2;
|
||||||
|
let middle_dim2 = self.dim2.len() / 2;
|
||||||
|
|
||||||
|
let lt = self.data.slice(s![..middle_dim1, ..middle_dim2]);
|
||||||
|
let rt = self.data.slice(s![middle_dim1.., ..middle_dim2]);
|
||||||
|
let lb = self.data.slice(s![..middle_dim1, middle_dim2..]);
|
||||||
|
let rb = self.data.slice(s![middle_dim1.., middle_dim2..]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
RadarData2d {
|
||||||
|
dim1: self.dim1.slice(s![..middle_dim1]).to_owned(),
|
||||||
|
dim2: self.dim2.slice(s![..middle_dim2]).to_owned(),
|
||||||
|
data: lt,
|
||||||
|
fill_value: self.fill_value.clone(),
|
||||||
|
coord_type: self.coord_type,
|
||||||
|
},
|
||||||
|
RadarData2d {
|
||||||
|
dim1: self.dim1.slice(s![middle_dim1..]).to_owned(),
|
||||||
|
dim2: self.dim2.slice(s![..middle_dim2]).to_owned(),
|
||||||
|
data: rt,
|
||||||
|
fill_value: self.fill_value.clone(),
|
||||||
|
coord_type: self.coord_type,
|
||||||
|
},
|
||||||
|
RadarData2d {
|
||||||
|
dim1: self.dim1.slice(s![..middle_dim1]).to_owned(),
|
||||||
|
dim2: self.dim2.slice(s![middle_dim2..]).to_owned(),
|
||||||
|
data: lb,
|
||||||
|
fill_value: self.fill_value.clone(),
|
||||||
|
coord_type: self.coord_type,
|
||||||
|
},
|
||||||
|
RadarData2d {
|
||||||
|
dim1: self.dim1.slice(s![middle_dim1..]).to_owned(),
|
||||||
|
dim2: self.dim2.slice(s![middle_dim2..]).to_owned(),
|
||||||
|
data: rb,
|
||||||
|
fill_value: self.fill_value.clone(),
|
||||||
|
coord_type: self.coord_type,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Raw, X, Y, Z> MultiDimensionData<T> for RadarData3d<T, Raw, X, Y, Z>
|
impl<T, Raw> MultiDimensionData<T> for RadarData2d<T, Raw>
|
||||||
where
|
where
|
||||||
T: Num + Clone,
|
T: Num + Clone,
|
||||||
T: PartialEq + PartialOrd,
|
T: PartialEq + PartialOrd,
|
||||||
X: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
Raw: ndarray::Data<Elem = T> + Clone + RawDataClone + DataMut,
|
||||||
Y: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
|
||||||
Z: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
|
||||||
Raw: ndarray::Data<Elem = T> + RawDataClone + DataMut,
|
|
||||||
{
|
{
|
||||||
fn map_by_fn<F>(&mut self, f: F)
|
fn map_by_fn<F>(&mut self, f: F)
|
||||||
where
|
where
|
||||||
@ -120,18 +275,285 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, Raw, X, Y> MultiDimensionData<T> for RadarData2d<T, Raw, X, Y>
|
pub trait DataLoader<V, T>
|
||||||
where
|
where
|
||||||
T: Num + Clone,
|
V: Num + Clone + PartialEq + PartialOrd,
|
||||||
T: PartialEq + PartialOrd,
|
T: MultiDimensionData<V>,
|
||||||
X: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
|
||||||
Y: ndarray::Data<Elem = f64> + ndarray::RawDataClone,
|
|
||||||
Raw: ndarray::Data<Elem = T> + RawDataClone + DataMut,
|
|
||||||
{
|
{
|
||||||
fn map_by_fn<F>(&mut self, f: F)
|
fn load<P: AsRef<Path>>(&self, path: P) -> Result<T, DataError>;
|
||||||
where
|
}
|
||||||
F: FnMut(&mut T),
|
|
||||||
{
|
#[async_trait]
|
||||||
self.data.map_inplace(f);
|
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, R: std::io::Read + Seek>(
|
||||||
|
&self,
|
||||||
|
data: &mut NpzArchive<R>,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<Array1<T>, DataError> {
|
||||||
|
// let mut data = npyz::npz::NpzArchive::open(path)?;
|
||||||
|
let a = data.by_name(name)?.unwrap();
|
||||||
|
let b: Vec<T> = a.into_vec().unwrap();
|
||||||
|
|
||||||
|
Ok(Array1::from_shape_vec(b.len(), b).unwrap())
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn load_2d<T: Num + Deserialize, R: std::io::Read + Seek>(
|
||||||
|
&self,
|
||||||
|
// path: &Path,
|
||||||
|
data: &mut NpzArchive<R>,
|
||||||
|
name: &str,
|
||||||
|
) -> Result<Array2<T>, DataError> {
|
||||||
|
// let mut data = npyz::npz::NpzArchive::open(path)?;
|
||||||
|
let a = data.by_name(name)?.unwrap();
|
||||||
|
|
||||||
|
let shape = a.shape().to_vec();
|
||||||
|
let b: Vec<T> = a.into_vec().unwrap();
|
||||||
|
|
||||||
|
Ok(Array2::from_shape_vec((shape[0] as usize, shape[1] as usize), b).unwrap())
|
||||||
|
}
|
||||||
|
fn load_3d(&self, data: &mut NpzArchive<BufReader<std::fs::File>>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> DataLoader<T, RadarData2d<T, OwnedRepr<T>>> for Npz
|
||||||
|
where
|
||||||
|
T: Num + Clone + Deserialize + FromPrimitive,
|
||||||
|
T: PartialEq + PartialOrd,
|
||||||
|
{
|
||||||
|
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, 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,
|
||||||
|
dim2: dim2,
|
||||||
|
fill_value: T::from_f64(-125.0).unwrap(),
|
||||||
|
data: value,
|
||||||
|
coord_type: CoordType::LatLon,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
|
use radarg_plugin_interface::{CoordType, PluginResult, PluginResultType};
|
||||||
use crate::pipeline::element::ElementImpl;
|
use crate::pipeline::element::ElementImpl;
|
||||||
use crate::pipeline::GridElementImpl;
|
use crate::pipeline::GridElementImpl;
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
use radarg_plugin_interface::{CoordType, DataShape, PluginResult, PluginResultType};
|
|
||||||
use std::sync::Arc;
|
|
||||||
macro_rules! data_to_grid {
|
macro_rules! data_to_grid {
|
||||||
($_type:ident,$(($branch:path ,$boundary_norm: expr)),+) => {
|
($_type:ident,$(($branch:path ,$boundary_norm: expr)),+) => {
|
||||||
match $_type {
|
match $_type {
|
||||||
$(
|
$(
|
||||||
$branch => {
|
$branch => {
|
||||||
let element_impl = GridElementImpl::new($boundary_norm);
|
let element_impl = GridElementImpl::new($boundary_norm);
|
||||||
Arc::new(element_impl)
|
Box::new(element_impl)
|
||||||
}
|
}
|
||||||
),+
|
),+
|
||||||
_ => panic!("Invalid type")
|
_ => panic!("Invalid type")
|
||||||
@ -17,8 +16,8 @@ macro_rules! data_to_grid {
|
|||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
pub fn plugin_result_impl(a: &PluginResult) -> Arc<dyn ElementImpl> {
|
pub fn plugin_result_impl(a: &PluginResult) -> Box<dyn ElementImpl> {
|
||||||
let block = a.blocks.first().unwrap();
|
let block= a.blocks.first().unwrap();
|
||||||
match block.coord_type {
|
match block.coord_type {
|
||||||
CoordType::Cartesian => {
|
CoordType::Cartesian => {
|
||||||
let _type = block.data_type;
|
let _type = block.data_type;
|
||||||
@ -42,3 +41,4 @@ pub fn plugin_result_impl(a: &PluginResult) -> Arc<dyn ElementImpl> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub enum PipelineError {
|
|||||||
source: ProjError,
|
source: ProjError,
|
||||||
},
|
},
|
||||||
#[error("data error")]
|
#[error("data error")]
|
||||||
DataError(String),
|
DataError(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
@ -50,6 +50,7 @@ pub enum PluginError {
|
|||||||
PluginError,
|
PluginError,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum PoolError {
|
pub enum PoolError {
|
||||||
#[error("")]
|
#[error("")]
|
||||||
@ -60,6 +61,7 @@ pub enum PoolError {
|
|||||||
PoolInitialized(&'static str),
|
PoolInitialized(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum RenderError {
|
pub enum RenderError {
|
||||||
#[error("")]
|
#[error("")]
|
||||||
@ -68,4 +70,5 @@ pub enum RenderError {
|
|||||||
None,
|
None,
|
||||||
#[error("Canceled")]
|
#[error("Canceled")]
|
||||||
Canceled,
|
Canceled,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/main.rs
14
src/main.rs
@ -12,7 +12,6 @@ use gtk::{
|
|||||||
use plugin_system::{init_plugin, PluginManager};
|
use plugin_system::{init_plugin, PluginManager};
|
||||||
use std::{ptr, sync::Mutex};
|
use std::{ptr, sync::Mutex};
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
mod actions;
|
|
||||||
mod chart;
|
mod chart;
|
||||||
mod components;
|
mod components;
|
||||||
mod config;
|
mod config;
|
||||||
@ -21,21 +20,17 @@ mod data;
|
|||||||
mod errors;
|
mod errors;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
mod plugin_system;
|
mod plugin_system;
|
||||||
use crate::components::app::AppMsg;
|
|
||||||
use components::app::AppModel;
|
use components::app::AppModel;
|
||||||
use once_cell::{sync::Lazy as SafeLazy, unsync::Lazy as UnsafeLazy};
|
use once_cell::{sync::Lazy as SafeLazy, unsync::Lazy as UnsafeLazy};
|
||||||
use relm4::RelmApp;
|
|
||||||
use surfman::declare_surfman;
|
use surfman::declare_surfman;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tracing_subscriber;
|
use tracing_subscriber;
|
||||||
|
|
||||||
mod data_utils;
|
mod data_utils;
|
||||||
mod map_tile;
|
mod map_tile;
|
||||||
mod map_tile_utils;
|
mod map_tile_utils;
|
||||||
mod predefined;
|
mod predefined;
|
||||||
mod widgets;
|
mod widgets;
|
||||||
|
|
||||||
#[cfg(target_env = "msvc")]
|
|
||||||
declare_surfman!();
|
declare_surfman!();
|
||||||
|
|
||||||
const APP_ID: &str = "org.tsuki.radar_g";
|
const APP_ID: &str = "org.tsuki.radar_g";
|
||||||
@ -62,19 +57,16 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
epoxy::load_with(|name| {
|
epoxy::load_with(|name| {
|
||||||
unsafe { library.get::<_>(name.as_bytes()) }
|
unsafe { library.get(name.as_bytes()) }
|
||||||
.map(|symbol| *symbol)
|
.map(|symbol| *symbol)
|
||||||
.unwrap_or(ptr::null())
|
.unwrap_or(ptr::null())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let relm = relm4::RelmApp::new(APP_ID);
|
||||||
let app = adw::Application::builder().application_id(APP_ID).build();
|
|
||||||
let relm: RelmApp<AppMsg> = relm4::RelmApp::from_app(app.clone());
|
|
||||||
relm4_icons::initialize_icons();
|
relm4_icons::initialize_icons();
|
||||||
|
initialize_custom_css();
|
||||||
info!("Init plugin system");
|
info!("Init plugin system");
|
||||||
let pluginmanager = PluginManager::new();
|
let pluginmanager = PluginManager::new();
|
||||||
initialize_custom_css();
|
|
||||||
|
|
||||||
relm.run::<AppModel>(());
|
relm.run::<AppModel>(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -144,7 +144,7 @@ impl MapTile {
|
|||||||
(origin.lon() as f64..rb.lon() as f64).into(),
|
(origin.lon() as f64..rb.lon() as f64).into(),
|
||||||
(origin.lat() as f64..rb.lat() as f64).into(),
|
(origin.lat() as f64..rb.lat() as f64).into(),
|
||||||
);
|
);
|
||||||
let result = Target::new(TargetType::Mem(result), 256.0, 256.0, bounds, None);
|
let result = Target::new(TargetType::Mem(result), 256.0, 256.0, bounds, None, None);
|
||||||
let cache = cache.lock().unwrap();
|
let cache = cache.lock().unwrap();
|
||||||
cache.insert(tile, Arc::new(std::sync::Mutex::new(result)));
|
cache.insert(tile, Arc::new(std::sync::Mutex::new(result)));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
pub fn lat_lon_to_zoom(lat_range: (f64, f64), lon_range: (f64, f64), w: f32, h: f32) -> u8 {
|
|
||||||
|
pub fn lat_lon_to_zoom(lat_range: (f64, f64), lon_range: (f64, f64), w: f32, h:f32 ) -> u8 {
|
||||||
let lat_diff = lat_range.1 - lat_range.0;
|
let lat_diff = lat_range.1 - lat_range.0;
|
||||||
let lon_diff = lon_range.1 - lon_range.0;
|
let lon_diff = lon_range.1 - lon_range.0;
|
||||||
let z1 = ((360.0 * w) as f64 / lon_diff / 256.0).log2();
|
let z1 = ( (360.0 * w) as f64 / lon_diff / 256.0).log2();
|
||||||
let z2 = ((180.0 * h) as f64 / lat_diff / 256.0).log2();
|
let z2 = ( (180.0 * h) as f64 / lat_diff / 256.0).log2();
|
||||||
let z = z1.min(z2);
|
let z = z1.min(z2);
|
||||||
z as u8
|
z as u8
|
||||||
}
|
}
|
||||||
@ -1,32 +1,36 @@
|
|||||||
use super::{offscreen_renderer::CanvasWrapper, Dispatcher, Pipeline};
|
use super::{offscreen_renderer::CanvasWrapper, Dispatcher, Pipeline};
|
||||||
use crate::components::Widget;
|
use crate::components::app::AppCommand;
|
||||||
|
use crate::components::ControlPanelInputMsg;
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::coords::Range;
|
|
||||||
use crate::data::MetaInfo;
|
use crate::data::MetaInfo;
|
||||||
use crate::errors::{PipelineError, RenderError};
|
use crate::errors::{PipelineError, RenderError};
|
||||||
use crate::predefined::color_mapper::ColorMapper;
|
|
||||||
use crate::widgets::Render;
|
use crate::widgets::Render;
|
||||||
use crate::RUNTIME;
|
use crate::RUNTIME;
|
||||||
|
use crate::{coords::Range, widgets::widget::Widget};
|
||||||
use chrono::{DateTime, TimeZone, Utc};
|
use chrono::{DateTime, TimeZone, Utc};
|
||||||
use femtovg::{ImageFlags, ImageId};
|
use core_extensions::SelfOps;
|
||||||
|
use femtovg::rgb::alt::GRAY8;
|
||||||
|
use femtovg::{renderer::OpenGl, Canvas, ImageFlags, ImageId, ImageInfo, PixelFormat};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, NumOps};
|
|
||||||
use radarg_plugin_interface::PluginResult;
|
use radarg_plugin_interface::PluginResult;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::fmt::Formatter;
|
use std::fmt::Formatter;
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::AtomicUsize;
|
use std::sync::atomic::AtomicUsize;
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::{Ref, RefCell},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
use tokio::sync::{
|
use tokio::sync::{
|
||||||
oneshot::{channel, Receiver},
|
oneshot::{channel, Receiver, Sender},
|
||||||
Notify,
|
Notify,
|
||||||
};
|
};
|
||||||
|
use tracing::Instrument;
|
||||||
|
|
||||||
pub type ElementID = usize;
|
pub type ElementID = usize;
|
||||||
static ELEMENT_ID: AtomicUsize = AtomicUsize::new(0);
|
static ELEMENT_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
@ -44,7 +48,7 @@ pub enum Element {
|
|||||||
|
|
||||||
impl Element {
|
impl Element {
|
||||||
pub fn create_time_series(
|
pub fn create_time_series(
|
||||||
imp: Arc<dyn ElementImpl>,
|
imp: Arc<Box<dyn ElementImpl>>,
|
||||||
dispatcher: Rc<Dispatcher>,
|
dispatcher: Rc<Dispatcher>,
|
||||||
key: String,
|
key: String,
|
||||||
cms: CMS,
|
cms: CMS,
|
||||||
@ -91,7 +95,7 @@ pub struct TimeSeriesElement {
|
|||||||
pub id: ElementID,
|
pub id: ElementID,
|
||||||
pub key: String,
|
pub key: String,
|
||||||
cms: CMS,
|
cms: CMS,
|
||||||
imp: Arc<dyn ElementImpl>,
|
imp: Arc<Box<dyn ElementImpl>>,
|
||||||
registers: Arc<Mutex<HashMap<DateTime<Utc>, Vec<Arc<Notify>>>>>,
|
registers: Arc<Mutex<HashMap<DateTime<Utc>, Vec<Arc<Notify>>>>>,
|
||||||
pipeline: Pipeline,
|
pipeline: Pipeline,
|
||||||
pub buffer: Buffer,
|
pub buffer: Buffer,
|
||||||
@ -101,7 +105,7 @@ pub struct TimeSeriesElement {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum InstantElementDrawerType {
|
pub enum InstantElementDrawerType {
|
||||||
Draw(DrawFunc),
|
Draw(DrawFunc),
|
||||||
Prepared((DataTarget, Arc<dyn ElementImpl>)),
|
Prepared((Target, Arc<Box<dyn ElementImpl>>)),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for InstantElementDrawerType {
|
impl Debug for InstantElementDrawerType {
|
||||||
@ -117,11 +121,6 @@ pub struct InstantElement {
|
|||||||
dispatcher: Rc<Dispatcher>,
|
dispatcher: Rc<Dispatcher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ElementImplMap {
|
|
||||||
ColorMap,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ElementImpl: Debug + Send + Sync + 'static {
|
pub trait ElementImpl: Debug + Send + Sync + 'static {
|
||||||
fn render(&self, data: &PluginResult, canvas: &mut CanvasWrapper, cms: &mut CMS) -> Target;
|
fn render(&self, data: &PluginResult, canvas: &mut CanvasWrapper, cms: &mut CMS) -> Target;
|
||||||
}
|
}
|
||||||
@ -142,24 +141,51 @@ impl InstantElement {
|
|||||||
func(render);
|
func(render);
|
||||||
}
|
}
|
||||||
InstantElementDrawerType::Prepared((ref mut target, _)) => {
|
InstantElementDrawerType::Prepared((ref mut target, _)) => {
|
||||||
render.draw_img(target);
|
let mut canvas = render.get_canvas();
|
||||||
|
let mut canvas = canvas.as_mut().unwrap();
|
||||||
|
let (ox, oy) = target.origin(render);
|
||||||
|
let (x, y) = target.size(render);
|
||||||
|
|
||||||
|
let result_id = match target.target {
|
||||||
|
TargetType::ImageId(id) => id,
|
||||||
|
TargetType::Mem(ref mem) => {
|
||||||
|
let gl_bind = render.get_context();
|
||||||
|
let gl = gl_bind.as_ref().unwrap();
|
||||||
|
let flags = ImageFlags::empty();
|
||||||
|
let texture = target.mem_to_native_texture(gl, flags);
|
||||||
|
let converted = canvas
|
||||||
|
.create_image_from_native_texture(
|
||||||
|
texture,
|
||||||
|
ImageInfo::new(flags, 3000, 3000, PixelFormat::Rgba8),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
target.set_target(TargetType::ImageId(converted));
|
||||||
|
converted
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let paint = femtovg::Paint::image(result_id, ox, oy, x, y, 0.0, 1.0);
|
||||||
|
let mut path = femtovg::Path::new();
|
||||||
|
path.rect(ox, oy, x, y);
|
||||||
|
canvas.fill_path(&path, &paint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imp(&self) -> &InstantElementDrawerType {
|
|
||||||
&self.draw_type
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_time_series(
|
pub fn to_time_series(
|
||||||
self,
|
self,
|
||||||
dispatcher: Rc<Dispatcher>,
|
dispatcher: Rc<Dispatcher>,
|
||||||
cms: CMS,
|
cms: CMS,
|
||||||
) -> (TimeSeriesElement, DateTime<Utc>) {
|
) -> (TimeSeriesElement, DateTime<Utc>) {
|
||||||
// let imp = Arc::new(InstantElementImpl::new(self));
|
// let imp = Arc::new(InstantElementImpl::new(self));
|
||||||
if let InstantElementDrawerType::Prepared((mut target, imp)) = self.draw_type {
|
if let InstantElementDrawerType::Prepared((target, imp)) = self.draw_type {
|
||||||
let mut time_series = TimeSeriesElement::new(imp, dispatcher, cms, self.key);
|
let mut time_series = TimeSeriesElement::new(imp, dispatcher, cms, self.key);
|
||||||
let data = target.take_data().unwrap();
|
let data = target
|
||||||
|
.data
|
||||||
|
.clone()
|
||||||
|
.unwrap()
|
||||||
|
.downcast::<PluginResult>()
|
||||||
|
.unwrap();
|
||||||
let time_stamp = data.blocks.first().unwrap().datetime;
|
let time_stamp = data.blocks.first().unwrap().datetime;
|
||||||
let meta_info: MetaInfo = data.meta.clone().into();
|
let meta_info: MetaInfo = data.meta.clone().into();
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
@ -176,7 +202,12 @@ impl InstantElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TimeSeriesElement {
|
impl TimeSeriesElement {
|
||||||
fn new(imp: Arc<dyn ElementImpl>, dispatcher: Rc<Dispatcher>, cms: CMS, key: String) -> Self {
|
fn new(
|
||||||
|
imp: Arc<Box<dyn ElementImpl>>,
|
||||||
|
dispatcher: Rc<Dispatcher>,
|
||||||
|
cms: CMS,
|
||||||
|
key: String,
|
||||||
|
) -> Self {
|
||||||
let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
let id = ELEMENT_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
let mut pipeline = Pipeline::new(20, key.clone());
|
let mut pipeline = Pipeline::new(20, key.clone());
|
||||||
pipeline.set_dispatcher(dispatcher.clone());
|
pipeline.set_dispatcher(dispatcher.clone());
|
||||||
@ -235,10 +266,6 @@ impl TimeSeriesElement {
|
|||||||
self.cms = cms;
|
self.cms = cms;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn imp(&self) -> &Arc<dyn ElementImpl> {
|
|
||||||
&self.imp
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_noti(&self, datetime: DateTime<Utc>, noti: Arc<Notify>) {
|
fn register_noti(&self, datetime: DateTime<Utc>, noti: Arc<Notify>) {
|
||||||
self.registers
|
self.registers
|
||||||
.lock()
|
.lock()
|
||||||
@ -302,12 +329,12 @@ impl TimeSeriesElement {
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RenderResult {
|
pub struct RenderResult {
|
||||||
target: DataTarget,
|
target: Target,
|
||||||
meta_info: MetaInfo,
|
meta_info: MetaInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderResult {
|
impl RenderResult {
|
||||||
pub fn new(target: DataTarget, meta_info: MetaInfo) -> Self {
|
pub fn new(target: Target, meta_info: MetaInfo) -> Self {
|
||||||
Self { target, meta_info }
|
Self { target, meta_info }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,14 +354,13 @@ pub struct Target {
|
|||||||
pub width: f32,
|
pub width: f32,
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
pub bounds: (Range, Range),
|
pub bounds: (Range, Range),
|
||||||
// pub data: Option<Arc<dyn Any + Send + Sync + 'static>>,
|
pub data: Option<Arc<dyn Any + Send + Sync + 'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
|
||||||
pub enum TargetType {
|
pub enum TargetType {
|
||||||
ImageId(ImageId),
|
ImageId(ImageId),
|
||||||
Mem(Vec<u8>),
|
Mem(Vec<u8>),
|
||||||
NativeBuffer(Vec<u8>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target {
|
impl Target {
|
||||||
@ -344,7 +370,7 @@ impl Target {
|
|||||||
height: f32,
|
height: f32,
|
||||||
bounds: (Range, Range),
|
bounds: (Range, Range),
|
||||||
thumbnail: Option<gtk::gdk::Texture>,
|
thumbnail: Option<gtk::gdk::Texture>,
|
||||||
// data: Option<Arc<dyn Any + Send + Sync + 'static>>,
|
data: Option<Arc<dyn Any + Send + Sync + 'static>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
target,
|
target,
|
||||||
@ -352,7 +378,7 @@ impl Target {
|
|||||||
height,
|
height,
|
||||||
bounds,
|
bounds,
|
||||||
thumbnail,
|
thumbnail,
|
||||||
// data,
|
data,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,12 +394,12 @@ impl Target {
|
|||||||
((x2 - x1).abs(), (y2 - y1).abs())
|
((x2 - x1).abs(), (y2 - y1).abs())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn native_buffer_to_native_texture(
|
pub fn mem_to_native_texture(
|
||||||
&self,
|
&self,
|
||||||
gl: &glow::Context,
|
gl: &glow::Context,
|
||||||
flags: ImageFlags,
|
flags: ImageFlags,
|
||||||
) -> glow::NativeTexture {
|
) -> glow::NativeTexture {
|
||||||
if let TargetType::NativeBuffer(ref mem) = self.target {
|
if let TargetType::Mem(ref mem) = self.target {
|
||||||
use glow::*;
|
use glow::*;
|
||||||
let texture = unsafe {
|
let texture = unsafe {
|
||||||
let id = gl.create_texture().unwrap();
|
let id = gl.create_texture().unwrap();
|
||||||
@ -523,41 +549,3 @@ impl Target {
|
|||||||
self.target = target;
|
self.target = target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct DataTarget {
|
|
||||||
data: Option<PluginResult>,
|
|
||||||
target: Target,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DataTarget {
|
|
||||||
pub fn new(data: Option<PluginResult>, target: Target) -> Self {
|
|
||||||
Self { data, target }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_data(&mut self) -> Option<PluginResult> {
|
|
||||||
self.data.take()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data(&self) -> Option<&PluginResult> {
|
|
||||||
self.data.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mut_data(&mut self) -> Option<&mut PluginResult> {
|
|
||||||
self.data.as_mut()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for DataTarget {
|
|
||||||
type Target = Target;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DerefMut for DataTarget {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.target
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
use super::predefined::GridFieldRenderer;
|
use super::predefined::GridFieldRenderer;
|
||||||
use super::renders::DataRenderer;
|
use super::renders::DataRenderer;
|
||||||
use crate::components::Widget;
|
use crate::data::Radar2d;
|
||||||
use crate::data::{Radar2d, Radar3d};
|
use crate::pipeline::element::{ElementImpl, Target};
|
||||||
use crate::pipeline::element::{ElementImpl, ElementImplMap, Target};
|
|
||||||
use crate::pipeline::offscreen_renderer::CanvasWrapper;
|
use crate::pipeline::offscreen_renderer::CanvasWrapper;
|
||||||
use crate::predefined::color_mapper::ColorMapper;
|
use crate::widgets::predefined::color_mapper::ColorMapper;
|
||||||
use crate::widgets::LayerImpl;
|
use crate::widgets::{LayerImpl};
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps};
|
use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps};
|
||||||
use radarg_plugin_interface::{DataShape, PluginResult};
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use radarg_plugin_interface::PluginResult;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GridElementImpl<CMAP, T>
|
pub struct GridElementImpl<CMAP, T>
|
||||||
@ -53,22 +52,8 @@ where
|
|||||||
cms: &mut crate::coords::cms::CMS,
|
cms: &mut crate::coords::cms::CMS,
|
||||||
) -> crate::pipeline::element::Target {
|
) -> crate::pipeline::element::Target {
|
||||||
let first_block = data.blocks.first().unwrap();
|
let first_block = data.blocks.first().unwrap();
|
||||||
match first_block.shape {
|
let data = first_block.clone().into();
|
||||||
DataShape::Vector => {
|
let result = self.renderer.render(canvas, cms, &data, (3000.0, 3000.0));
|
||||||
panic!("Vector data is not supported")
|
result
|
||||||
}
|
|
||||||
DataShape::Matrix => {
|
|
||||||
let data:Radar2d<T> = first_block.clone().into();
|
|
||||||
let data = data.as_ref();
|
|
||||||
let result = self.renderer.render(canvas, cms, &data, (3000.0, 3000.0));
|
|
||||||
result
|
|
||||||
}
|
|
||||||
DataShape::Cube => {
|
|
||||||
let data: Radar3d<T> = first_block.clone().into();
|
|
||||||
let data = data.index_axis(ndarray::Axis(0), 0);
|
|
||||||
let result = self.renderer.render(canvas, cms, &data, (3000.0, 3000.0));
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ mod renders;
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
pub use dispatcher::Dispatcher;
|
pub use dispatcher::Dispatcher;
|
||||||
pub use element::*;
|
pub use element::RenderResult;
|
||||||
pub use element_impl::*;
|
|
||||||
pub use new_pipeline::Pipeline;
|
pub use new_pipeline::Pipeline;
|
||||||
pub use offscreen_renderer::OffscreenRenderer;
|
pub use offscreen_renderer::OffscreenRenderer;
|
||||||
|
pub use element_impl::*;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use super::{
|
use super::{
|
||||||
dispatcher::Dispatcher,
|
dispatcher::Dispatcher,
|
||||||
element::{DataTarget, RenderResult},
|
element::RenderResult,
|
||||||
offscreen_renderer::{CanvasWrapper, OffscreenRenderer},
|
offscreen_renderer::{CanvasWrapper, OffscreenRenderer},
|
||||||
utils::data_to_element,
|
utils::data_to_element,
|
||||||
};
|
};
|
||||||
@ -16,7 +16,6 @@ use crate::{
|
|||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use femtovg::{renderer::OpenGl, Canvas, ImageId};
|
use femtovg::{renderer::OpenGl, Canvas, ImageId};
|
||||||
use futures::{future::BoxFuture, Future};
|
use futures::{future::BoxFuture, Future};
|
||||||
use radarg_plugin_interface::PluginResult;
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::{
|
use std::{
|
||||||
@ -24,6 +23,7 @@ use std::{
|
|||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
use radarg_plugin_interface::PluginResult;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::{mpsc, oneshot},
|
sync::{mpsc, oneshot},
|
||||||
task,
|
task,
|
||||||
@ -84,7 +84,7 @@ impl Pipeline {
|
|||||||
current_time: DateTime<Utc>,
|
current_time: DateTime<Utc>,
|
||||||
check_existed: bool,
|
check_existed: bool,
|
||||||
max_retry_time: usize,
|
max_retry_time: usize,
|
||||||
task: Arc<dyn Fn(&PluginResult, &mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>,
|
task: Arc<dyn Fn(&PluginResult ,&mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>,
|
||||||
cms: CMS,
|
cms: CMS,
|
||||||
) -> Option<Vec<DateTime<Utc>>> {
|
) -> Option<Vec<DateTime<Utc>>> {
|
||||||
let paths = {
|
let paths = {
|
||||||
@ -123,7 +123,7 @@ impl Pipeline {
|
|||||||
fn worker(
|
fn worker(
|
||||||
&self,
|
&self,
|
||||||
datetime: DateTime<Utc>,
|
datetime: DateTime<Utc>,
|
||||||
task: Arc<dyn Fn(&PluginResult, &mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>,
|
task: Arc<dyn Fn(&PluginResult ,&mut CanvasWrapper, &mut CMS) -> Target + Send + Sync>,
|
||||||
mut cms: CMS,
|
mut cms: CMS,
|
||||||
path: impl AsRef<str> + Send + 'static,
|
path: impl AsRef<str> + Send + 'static,
|
||||||
) -> BoxFuture<'static, RenderR> {
|
) -> BoxFuture<'static, RenderR> {
|
||||||
@ -135,8 +135,8 @@ impl Pipeline {
|
|||||||
let handle = task::spawn_blocking(move || {
|
let handle = task::spawn_blocking(move || {
|
||||||
let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap();
|
let mut offscreen_renderer = OffscreenRenderer::new(3000, 3000).unwrap();
|
||||||
let mut canvas_wrapper = offscreen_renderer.create_canvas();
|
let mut canvas_wrapper = offscreen_renderer.create_canvas();
|
||||||
let target = task(&loaded_data, &mut canvas_wrapper, &mut cms);
|
let target = task(&loaded_data,&mut canvas_wrapper, &mut cms);
|
||||||
DataTarget::new(Some(loaded_data), target)
|
target
|
||||||
});
|
});
|
||||||
|
|
||||||
let target = handle.await.unwrap();
|
let target = handle.await.unwrap();
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
use super::super::renders::DataRenderer;
|
use super::super::renders::DataRenderer;
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::data::{Radar2dRef, RadarData2d};
|
|
||||||
use crate::pipeline::element::{Target, TargetType};
|
use crate::pipeline::element::{Target, TargetType};
|
||||||
use crate::predefined::color_mapper::ColorMapper;
|
use crate::widgets::predefined::color_mapper::ColorMapper;
|
||||||
use crate::{data::Radar2d, utils::meshgrid};
|
use crate::{data::Radar2d, utils::meshgrid};
|
||||||
use femtovg::ImageInfo;
|
use femtovg::ImageInfo;
|
||||||
use femtovg::{
|
use femtovg::{
|
||||||
@ -10,11 +9,11 @@ use femtovg::{
|
|||||||
};
|
};
|
||||||
use geo_types::LineString;
|
use geo_types::LineString;
|
||||||
use gl::types::GLvoid;
|
use gl::types::GLvoid;
|
||||||
use gtk::ResponseType::No;
|
|
||||||
use image::{imageops::resize, ImageBuffer, Rgba};
|
use image::{imageops::resize, ImageBuffer, Rgba};
|
||||||
use ndarray::ArrayView2;
|
use ndarray::ArrayView2;
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps};
|
use num_traits::{AsPrimitive, FromPrimitive, Num, NumOps};
|
||||||
use std::{fmt::Debug, io::Cursor, marker::PhantomData};
|
use std::{fmt::Debug, io::Cursor, marker::PhantomData};
|
||||||
|
use gtk::ResponseType::No;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -23,7 +22,7 @@ where
|
|||||||
T: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64>,
|
T: NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64>,
|
||||||
CMAP: ColorMapper<T>,
|
CMAP: ColorMapper<T>,
|
||||||
{
|
{
|
||||||
pub cmap: CMAP,
|
cmap: CMAP,
|
||||||
value_phantom: PhantomData<T>,
|
value_phantom: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,6 +61,15 @@ impl<T: NumOps + PartialOrd + Copy + FromPrimitive + AsPrimitive<f64>, CMAP: Col
|
|||||||
|
|
||||||
let rt_lat = dim2[[r + 1, c + 1]];
|
let rt_lat = dim2[[r + 1, c + 1]];
|
||||||
let rt_lon = dim1[[r + 1, c + 1]];
|
let rt_lon = dim1[[r + 1, c + 1]];
|
||||||
|
// let cell: LineString = vec![
|
||||||
|
// (lb_lon, lb_lat),
|
||||||
|
// (rt_lon + 0.001, lb_lat),
|
||||||
|
// (rt_lon + 0.001, rt_lat),
|
||||||
|
// (lb_lon, rt_lat + 0.001),
|
||||||
|
// (lb_lon, lb_lat + 0.001),
|
||||||
|
// ]
|
||||||
|
// .into();
|
||||||
|
|
||||||
let v = &data[[r, c]];
|
let v = &data[[r, c]];
|
||||||
let mapped_color = self.cmap.map_value_to_color(*v, fill_value);
|
let mapped_color = self.cmap.map_value_to_color(*v, fill_value);
|
||||||
|
|
||||||
@ -69,23 +77,32 @@ impl<T: NumOps + PartialOrd + Copy + FromPrimitive + AsPrimitive<f64>, CMAP: Col
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (ox, oy) = cms.map((lb_lon, lb_lat)).unwrap();
|
// let mapped_ring = cms.ring_map(&cell).unwrap();
|
||||||
|
let (ox,oy) = cms.map((lb_lon, lb_lat)).unwrap();
|
||||||
let (rx, ry) = cms.map((rt_lon, rt_lat)).unwrap();
|
let (rx, ry) = cms.map((rt_lon, rt_lat)).unwrap();
|
||||||
|
|
||||||
let mut path = Path::new();
|
let mut path = Path::new();
|
||||||
|
// let mut points = mapped_ring.points();
|
||||||
|
// let first_point = points.next().unwrap();
|
||||||
|
// path.move_to(first_point.x(), first_point.y());
|
||||||
|
//
|
||||||
|
// for point in points {
|
||||||
|
// path.line_to(point.x(), point.y());
|
||||||
|
// }
|
||||||
path.rect(ox, oy, (rx - ox) * 1.5, (ry - oy) * 1.5);
|
path.rect(ox, oy, (rx - ox) * 1.5, (ry - oy) * 1.5);
|
||||||
|
// path.close();
|
||||||
canvas.fill_path(&path, &Paint::color(mapped_color.unwrap()));
|
canvas.fill_path(&path, &Paint::color(mapped_color.unwrap()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, CMAP> DataRenderer<'a> for GridFieldRenderer<CMAP, T>
|
impl<T, CMAP> DataRenderer for GridFieldRenderer<CMAP, T>
|
||||||
where
|
where
|
||||||
T: Num + NumOps + PartialOrd + Copy + Clone + FromPrimitive + AsPrimitive<f64>,
|
T: Num + NumOps + PartialOrd + Copy + Clone + FromPrimitive + AsPrimitive<f64>,
|
||||||
CMAP: ColorMapper<T>,
|
CMAP: ColorMapper<T>,
|
||||||
{
|
{
|
||||||
type Data = Radar2dRef<'a, T>;
|
type Data = Radar2d<T>;
|
||||||
|
|
||||||
fn render(
|
fn render(
|
||||||
&self,
|
&self,
|
||||||
@ -139,6 +156,25 @@ where
|
|||||||
debug_assert_eq!(gl::GetError(), gl::NO_ERROR);
|
debug_assert_eq!(gl::GetError(), gl::NO_ERROR);
|
||||||
}
|
}
|
||||||
info!("Time to read pixels: {:?}", start.elapsed());
|
info!("Time to read pixels: {:?}", start.elapsed());
|
||||||
|
|
||||||
|
// let img: ImageBuffer<Rgba<u8>, Vec<u8>> = ImageBuffer::from_raw(w as u32, h as u32, pixels)
|
||||||
|
// .expect("Failed to create ImageBuffer");
|
||||||
|
// let thumbnail = resize(&img, 500, 500, image::imageops::FilterType::Lanczos3);
|
||||||
|
// let mut thumb_buffer = Cursor::new(Vec::new());
|
||||||
|
// img.write_to(&mut thumb_buffer, image::ImageOutputFormat::Png)
|
||||||
|
// .expect("Failed to write PNG buffer");
|
||||||
|
// info!("Time to write PNG: {:?}", start.elapsed());
|
||||||
|
// let thumb_data = thumb_buffer.into_inner();
|
||||||
|
// let thumbnail_tex =
|
||||||
|
// gtk::gdk::Texture::from_bytes(>k::glib::Bytes::from(&thumb_data)).unwrap();
|
||||||
|
|
||||||
|
// 将 ImageBuffer 编码为 PNG
|
||||||
|
// let mut png_buffer = Cursor::new(Vec::new());
|
||||||
|
// img.write_to(&mut png_buffer, image::ImageOutputFormat::Bmp)
|
||||||
|
// .expect("Failed to write PNG buffer");
|
||||||
|
|
||||||
|
// let png_data = png_buffer.into_inner();
|
||||||
|
|
||||||
let d1_start = (data.dim1.view()).first().unwrap().clone();
|
let d1_start = (data.dim1.view()).first().unwrap().clone();
|
||||||
let d1_end = (data.dim1.view()).last().unwrap().clone();
|
let d1_end = (data.dim1.view()).last().unwrap().clone();
|
||||||
|
|
||||||
@ -147,11 +183,13 @@ where
|
|||||||
canvas.set_render_target(RenderTarget::Screen);
|
canvas.set_render_target(RenderTarget::Screen);
|
||||||
|
|
||||||
Target::new(
|
Target::new(
|
||||||
TargetType::NativeBuffer(pixels),
|
TargetType::Mem(pixels),
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
((d1_start, d1_end).into(), (d2_start, d2_end).into()),
|
((d1_start, d1_end).into(), (d2_start, d2_end).into()),
|
||||||
|
// Some(thumbnail_tex),
|
||||||
None,
|
None,
|
||||||
|
None
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use crate::coords::cms::CMS;
|
|||||||
use crate::pipeline::element::Target;
|
use crate::pipeline::element::Target;
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas};
|
||||||
|
|
||||||
pub trait DataRenderer<'a> {
|
pub trait DataRenderer {
|
||||||
type Data;
|
type Data;
|
||||||
fn render(
|
fn render(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
coords::cms::CMS, data::Radar2d, errors::RenderError, predefined::color_mapper::BoundaryNorm,
|
coords::cms::CMS, data::Radar2d, errors::RenderError,
|
||||||
|
widgets::predefined::color_mapper::BoundaryNorm,
|
||||||
};
|
};
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
use radarg_plugin_interface::*;
|
use radarg_plugin_interface::*;
|
||||||
@ -24,7 +25,7 @@ macro_rules! match_in_macro {
|
|||||||
match $block.data_type {
|
match $block.data_type {
|
||||||
$(
|
$(
|
||||||
$branch => {
|
$branch => {
|
||||||
let element = Element::create_time_series(Arc::new(GridElementImpl::new($color)), $dispatcher, $name.to_string(), $cms);
|
let element = Element::create_time_series(Arc::new(Box::new(GridElementImpl::new($color))), $dispatcher, $name.to_string(), $cms);
|
||||||
Some(element)
|
Some(element)
|
||||||
},
|
},
|
||||||
)+
|
)+
|
||||||
@ -35,7 +36,11 @@ macro_rules! match_in_macro {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data_to_element(block: &Block, dispatcher: Rc<Dispatcher>, cms: CMS) -> Option<Element> {
|
pub fn data_to_element(
|
||||||
|
block: &Block,
|
||||||
|
dispatcher: Rc<Dispatcher>,
|
||||||
|
cms: CMS,
|
||||||
|
) -> Option<Element> {
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
use radarg_plugin_interface::PluginResultType;
|
use radarg_plugin_interface::PluginResultType;
|
||||||
match block.shape {
|
match block.shape {
|
||||||
|
|||||||
@ -1,42 +1,8 @@
|
|||||||
use crate::data::{CoordType, Radar2d, Radar3d};
|
use crate::data::{CoordType, Radar2d};
|
||||||
use ndarray::{Array1, Array2, Array3, ShapeBuilder};
|
use ndarray::{Array1, Array2, Array3, ShapeBuilder};
|
||||||
use num_traits::{AsPrimitive, FromPrimitive, Num};
|
use num_traits::{AsPrimitive, FromPrimitive, Num};
|
||||||
use radarg_plugin_interface::{Block, DataShape, PluginResult, VecResult};
|
use radarg_plugin_interface::{Block, DataShape, PluginResult, VecResult};
|
||||||
|
|
||||||
macro_rules! match_in_macro_3d {
|
|
||||||
// ($(($branch:path, $t:ty)),+, $block:ident)
|
|
||||||
($block:tt, $(($branch:path, $t:path)),+) => {
|
|
||||||
{
|
|
||||||
let data = $block.data;
|
|
||||||
let dim3: Vec<_> = $block.dimension_values.remove(0).into();
|
|
||||||
let dim2: Vec<_> = $block.dimension_values.remove(0).into();
|
|
||||||
let dim1: Vec<_> = $block.dimension_values.remove(0).into();
|
|
||||||
let fill_value = $block.fill_value;
|
|
||||||
let data_shape: Vec<usize> = $block.size.into();
|
|
||||||
let coord_type = match $block.coord_type{
|
|
||||||
radarg_plugin_interface::CoordType::Cartesian => CoordType::LatLon,
|
|
||||||
radarg_plugin_interface::CoordType::Polar => CoordType::Polar,
|
|
||||||
_ => panic!("Unsupported coord type")
|
|
||||||
};
|
|
||||||
match data {
|
|
||||||
$(
|
|
||||||
$branch(x) => {
|
|
||||||
let shape = [data_shape[0], data_shape[1], data_shape[2]];
|
|
||||||
Radar3d {
|
|
||||||
fill_value: T::from_f64(fill_value).unwrap(),
|
|
||||||
data: Array3::from_shape_vec(shape, x.into_iter().map(|x| $t(x).unwrap()).collect::<Vec<T>>()).unwrap(),
|
|
||||||
dim1: Array1::from_vec(dim1),
|
|
||||||
dim2: Array1::from_vec(dim2),
|
|
||||||
dim3: Array1::from_vec(dim3),
|
|
||||||
coord_type: coord_type,
|
|
||||||
}},
|
|
||||||
)+
|
|
||||||
_ => panic!("Unsupported data type"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
macro_rules! match_in_macro {
|
macro_rules! match_in_macro {
|
||||||
// ($(($branch:path, $t:ty)),+, $block:ident)
|
// ($(($branch:path, $t:ty)),+, $block:ident)
|
||||||
($block:tt, $(($branch:path, $t:path)),+) => {
|
($block:tt, $(($branch:path, $t:path)),+) => {
|
||||||
@ -95,31 +61,3 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> From<Block> for Radar3d<T>
|
|
||||||
where
|
|
||||||
T: Num + Copy + PartialOrd + PartialEq,
|
|
||||||
T: FromPrimitive,
|
|
||||||
{
|
|
||||||
fn from(block: Block) -> Self {
|
|
||||||
let mut block = block;
|
|
||||||
let a = &block.dimension_values;
|
|
||||||
println!("{:?}", a);
|
|
||||||
if let DataShape::Cube = block.shape {
|
|
||||||
let result = match_in_macro_3d!(
|
|
||||||
block,
|
|
||||||
(VecResult::I8, T::from_i8),
|
|
||||||
(VecResult::I32, T::from_i32),
|
|
||||||
(VecResult::I64, T::from_i64),
|
|
||||||
(VecResult::U8, T::from_u8),
|
|
||||||
(VecResult::U32, T::from_u32),
|
|
||||||
(VecResult::U64, T::from_u64),
|
|
||||||
(VecResult::F32, T::from_f32),
|
|
||||||
(VecResult::F64, T::from_f64)
|
|
||||||
);
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
panic!("Expected matrix data shape");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,21 +1,16 @@
|
|||||||
use crate::map_tile_utils::*;
|
use crate::map_tile_utils::*;
|
||||||
use slippy_map_tiles::{merc_location_to_tile_coords, size_bbox_zoom_metatiles, BBox, Tile};
|
use slippy_map_tiles::{BBox, merc_location_to_tile_coords, size_bbox_zoom_metatiles, Tile};
|
||||||
|
|
||||||
pub fn map_tile_layer(lat_range: (f64, f64), lon_range: (f64, f64), w: f32, h: f32) {
|
pub fn map_tile_layer(lat_range: (f64, f64), lon_range: (f64, f64), w: f32, h: f32) {
|
||||||
let z = lat_lon_to_zoom(lat_range, lon_range, w, h);
|
let z = lat_lon_to_zoom(lat_range, lon_range, w, h);
|
||||||
let bbox = BBox::new(
|
let bbox = BBox::new(lat_range.0 as f32, lon_range.0 as f32, lat_range.1 as f32, lon_range.1 as f32).unwrap();
|
||||||
lat_range.0 as f32,
|
|
||||||
lon_range.0 as f32,
|
|
||||||
lat_range.1 as f32,
|
|
||||||
lon_range.1 as f32,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let size = size_bbox_zoom_metatiles(&bbox, z, 4);
|
let size = size_bbox_zoom_metatiles(&bbox, z, 4);
|
||||||
let t = Tile::new(10, 547, 380).unwrap();
|
let t = Tile::new(10, 547, 380).unwrap();
|
||||||
println!("size: {:?}", size);
|
println!("size: {:?}", size);
|
||||||
println!("tile: {:?}", t);
|
println!("tile: {:?}", t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -1,5 +1 @@
|
|||||||
pub mod map_tile;
|
pub mod map_tile;
|
||||||
// pub mod grid_field_renderer;
|
|
||||||
// pub mod layers;
|
|
||||||
pub mod color_mapper;
|
|
||||||
pub mod widgets;
|
|
||||||
|
|||||||
@ -1,100 +0,0 @@
|
|||||||
use crate::components::widget::{Widget, WidgetType};
|
|
||||||
use crate::predefined::color_mapper::ColorMapper;
|
|
||||||
use crate::widgets::{AssoElement, Layer};
|
|
||||||
use femtovg::{renderer::OpenGl, Canvas, Color, Paint, Path};
|
|
||||||
use num_traits::*;
|
|
||||||
use std::any::Any;
|
|
||||||
use topojson::Arc;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct ColorBar {
|
|
||||||
padding: [f32; 4],
|
|
||||||
width: f32,
|
|
||||||
height: f32,
|
|
||||||
margin: [i32; 4],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ColorBar {
|
|
||||||
pub fn new(padding: [f32; 4], size: (f32, f32), margin: [i32; 4]) -> Self {
|
|
||||||
Self {
|
|
||||||
padding,
|
|
||||||
width: size.0,
|
|
||||||
height: size.1,
|
|
||||||
margin,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Widget for ColorBar {
|
|
||||||
fn cairo_render(&self, layers: &Vec<Layer>, canvas: >k::cairo::Context, w: f32, h: f32) {
|
|
||||||
let bar_width = 10;
|
|
||||||
let bar_height = h - self.padding[0] - self.padding[2];
|
|
||||||
let (x, y) = (self.padding[3], self.padding[0]);
|
|
||||||
|
|
||||||
let length = layers.len();
|
|
||||||
|
|
||||||
if length == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let first = layers.first().unwrap();
|
|
||||||
|
|
||||||
match first.get_associated_element() {
|
|
||||||
AssoElement::Instant(i) => {
|
|
||||||
let imp = i.imp();
|
|
||||||
}
|
|
||||||
AssoElement::TimeSeries(t) => {
|
|
||||||
let c = t.lock().unwrap();
|
|
||||||
let imp = c.imp();
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for ((i, color), label) in self
|
|
||||||
// .color_list
|
|
||||||
// .iter()
|
|
||||||
// .enumerate()
|
|
||||||
// .zip(self.color_mapper.labels())
|
|
||||||
// {
|
|
||||||
// let y = y + i as f32 * b_h;
|
|
||||||
//
|
|
||||||
// canvas.set_source_rgba(
|
|
||||||
// color.r as f64,
|
|
||||||
// color.g as f64,
|
|
||||||
// color.b as f64,
|
|
||||||
// color.a as f64,
|
|
||||||
// );
|
|
||||||
// canvas.rectangle(x as f64, y as f64, bar_width as f64, b_h as f64);
|
|
||||||
// canvas.fill();
|
|
||||||
//
|
|
||||||
// let extents = canvas.text_extents(&label).unwrap();
|
|
||||||
//
|
|
||||||
// canvas.move_to(
|
|
||||||
// (x + bar_width as f32 + 5.0) as f64,
|
|
||||||
// y as f64 + extents.height() / 2.0 as f64,
|
|
||||||
// );
|
|
||||||
// canvas.set_source_rgba(1.0, 1.0, 1.0, 1.0);
|
|
||||||
// canvas.show_text(&label);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn location(&self) -> (gtk::Align, gtk::Align) {
|
|
||||||
(gtk::Align::End, gtk::Align::End)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> (f32, f32) {
|
|
||||||
(self.width, self.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn widget_type(&self) -> WidgetType {
|
|
||||||
WidgetType::Cairo
|
|
||||||
}
|
|
||||||
|
|
||||||
fn margin(&self) -> [i32; 4] {
|
|
||||||
self.margin
|
|
||||||
}
|
|
||||||
|
|
||||||
fn padding(&self) -> [i32; 4] {
|
|
||||||
[10, 10, 10, 10]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
43
src/utils.rs
43
src/utils.rs
@ -11,7 +11,7 @@ use surfman::{
|
|||||||
GLVersion, NativeConnection, NativeContext, SurfaceAccess, SurfaceType,
|
GLVersion, NativeConnection, NativeContext, SurfaceAccess, SurfaceType,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::predefined::color_mapper::BoundaryNorm;
|
use crate::widgets::render::predefined::color_mapper::BoundaryNorm;
|
||||||
use crate::RUNTIME;
|
use crate::RUNTIME;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -31,6 +31,47 @@ where
|
|||||||
(xx, yy)
|
(xx, yy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn creator() {
|
||||||
|
let connection = Connection::new().unwrap();
|
||||||
|
let adapter = connection.create_adapter().unwrap();
|
||||||
|
let mut device = connection.create_device(&adapter).unwrap();
|
||||||
|
let api = device.gl_api();
|
||||||
|
let descriptor = device
|
||||||
|
.create_context_descriptor(&ContextAttributes {
|
||||||
|
version: GLVersion::new(3, 3),
|
||||||
|
flags: ContextAttributeFlags::empty(),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut context = device.create_context(&descriptor, None).unwrap();
|
||||||
|
let mut surface = device
|
||||||
|
.create_surface(
|
||||||
|
&context,
|
||||||
|
SurfaceAccess::GPUOnly,
|
||||||
|
SurfaceType::Generic {
|
||||||
|
size: Size2D::new(500, 500),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let surface_info = device.surface_info(&surface);
|
||||||
|
device
|
||||||
|
.bind_surface_to_context(&mut context, surface)
|
||||||
|
.expect("Failed to bind surface to context");
|
||||||
|
device.make_context_current(&context).unwrap();
|
||||||
|
use femtovg::renderer::OpenGl;
|
||||||
|
static LOAD_FN: fn(&str) -> *const std::ffi::c_void = |s| epoxy::get_proc_addr(s) as *const _;
|
||||||
|
let (mut renderer, fbo) = unsafe {
|
||||||
|
let renderer = OpenGl::new_from_function(LOAD_FN).expect("Cannot create renderer");
|
||||||
|
let fbo =
|
||||||
|
glow::NativeFramebuffer(NonZeroU32::new(surface_info.framebuffer_object).unwrap());
|
||||||
|
(renderer, fbo)
|
||||||
|
};
|
||||||
|
|
||||||
|
renderer.set_screen_target(Some(fbo));
|
||||||
|
device.destroy_context(&mut context).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_dbz_boundarynorm() -> BoundaryNorm<i8> {
|
pub fn create_dbz_boundarynorm() -> BoundaryNorm<i8> {
|
||||||
BoundaryNorm::new(
|
BoundaryNorm::new(
|
||||||
vec![
|
vec![
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use crate::coords::Mapper;
|
|
||||||
use geo_types::LineString;
|
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
use geo_types::LineString;
|
||||||
|
use crate::coords::Mapper;
|
||||||
|
|
||||||
pub struct CMS {
|
pub struct CMS {
|
||||||
mapper: Mapper,
|
mapper: Mapper,
|
||||||
|
|||||||
@ -4,7 +4,8 @@ use gtk::subclass::prelude::*;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ExteriorWidget {}
|
pub struct ExteriorWidget {
|
||||||
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
impl ObjectSubclass for ExteriorWidget {
|
impl ObjectSubclass for ExteriorWidget {
|
||||||
@ -12,4 +13,4 @@ impl ObjectSubclass for ExteriorWidget {
|
|||||||
type Type = super::ExteriorWidget;
|
type Type = super::ExteriorWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl for ExteriorWidget {}
|
impl ObjectImpl for ExteriorWidget{}
|
||||||
|
|||||||
@ -98,7 +98,7 @@ impl ObjectImpl for Render {
|
|||||||
fn constructed(&self) {
|
fn constructed(&self) {
|
||||||
self.parent_constructed();
|
self.parent_constructed();
|
||||||
let area = self.obj();
|
let area = self.obj();
|
||||||
area.set_has_stencil_buffer(true);
|
// area.set_has_stencil_buffer(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn properties() -> &'static [glib::ParamSpec] {
|
fn properties() -> &'static [glib::ParamSpec] {
|
||||||
@ -114,16 +114,7 @@ impl ObjectImpl for Render {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WidgetImpl for Render {
|
impl WidgetImpl for Render {}
|
||||||
fn realize(&self) {
|
|
||||||
self.parent_realize();
|
|
||||||
}
|
|
||||||
fn unrealize(&self) {
|
|
||||||
self.obj().make_current();
|
|
||||||
self.canvas.replace(None);
|
|
||||||
self.parent_unrealize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GLAreaImpl for Render {
|
impl GLAreaImpl for Render {
|
||||||
fn resize(&self, width: i32, height: i32) {
|
fn resize(&self, width: i32, height: i32) {
|
||||||
@ -339,20 +330,6 @@ impl Render {
|
|||||||
target.set_target(TargetType::ImageId(converted));
|
target.set_target(TargetType::ImageId(converted));
|
||||||
converted
|
converted
|
||||||
}
|
}
|
||||||
TargetType::NativeBuffer(ref mem) => {
|
|
||||||
let gl_bind = self.glow_context.borrow();
|
|
||||||
let gl = gl_bind.as_ref().unwrap();
|
|
||||||
let flags = femtovg::ImageFlags::empty();
|
|
||||||
let texture = target.native_buffer_to_native_texture(gl, flags);
|
|
||||||
let converted = canvas
|
|
||||||
.create_image_from_native_texture(
|
|
||||||
texture,
|
|
||||||
femtovg::ImageInfo::new(flags, 3000, 3000, femtovg::PixelFormat::Rgba8),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
target.set_target(TargetType::ImageId(converted));
|
|
||||||
converted
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let painter = Paint::image(id, ox, oy, x, y, 0.0, 1.0);
|
let painter = Paint::image(id, ox, oy, x, y, 0.0, 1.0);
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
use super::super::WindowCoord;
|
use super::super::WindowCoord;
|
||||||
use super::layers::Layer;
|
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use gtk::subclass::prelude::*;
|
use gtk::subclass::prelude::*;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
use super::layers::Layer;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct InteriorWidget {
|
pub struct InteriorWidget {
|
||||||
|
|||||||
@ -1,14 +1,19 @@
|
|||||||
use super::super::Render;
|
use super::super::Render;
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::errors::PipelineError;
|
use crate::pipeline::element::{self, Element, ElementID, Target, TargetType};
|
||||||
use crate::pipeline::element::{self, Target};
|
|
||||||
use crate::pipeline::offscreen_renderer::CanvasWrapper;
|
use crate::pipeline::offscreen_renderer::CanvasWrapper;
|
||||||
|
use crate::{coords::Range, widgets::widget::Widget};
|
||||||
use chrono::{prelude::*, DateTime};
|
use chrono::{prelude::*, DateTime};
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas, ImageId};
|
||||||
use std::{
|
use std::{
|
||||||
|
cell::{Ref, RefCell},
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
|
future::Future,
|
||||||
|
pin::Pin,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
use core_extensions::SelfOps;
|
||||||
|
use crate::errors::PipelineError;
|
||||||
|
|
||||||
type PrepareFunc = Arc<
|
type PrepareFunc = Arc<
|
||||||
Mutex<
|
Mutex<
|
||||||
@ -24,7 +29,7 @@ pub type LayerImplSync = Arc<Mutex<Box<dyn LayerImpl + Send + Sync>>>;
|
|||||||
pub enum AssoElement {
|
pub enum AssoElement {
|
||||||
TimeSeries(Arc<Mutex<element::TimeSeriesElement>>),
|
TimeSeries(Arc<Mutex<element::TimeSeriesElement>>),
|
||||||
Instant(element::InstantElement),
|
Instant(element::InstantElement),
|
||||||
Test,
|
Test
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -65,7 +70,7 @@ impl Layer {
|
|||||||
|
|
||||||
pub fn draw(&mut self, render: &Render, window_size: (f32, f32)) -> Result<(), PipelineError> {
|
pub fn draw(&mut self, render: &Render, window_size: (f32, f32)) -> Result<(), PipelineError> {
|
||||||
if self.visiable {
|
if self.visiable {
|
||||||
match self.associated_element {
|
match self.associated_element{
|
||||||
AssoElement::Instant(ref mut e) => {
|
AssoElement::Instant(ref mut e) => {
|
||||||
e.render(render);
|
e.render(render);
|
||||||
}
|
}
|
||||||
@ -74,30 +79,34 @@ impl Layer {
|
|||||||
let mut buffer = e.buffer.lock().unwrap();
|
let mut buffer = e.buffer.lock().unwrap();
|
||||||
let mut result = buffer.get_mut(&self.time.unwrap()).map(|x| x.as_mut());
|
let mut result = buffer.get_mut(&self.time.unwrap()).map(|x| x.as_mut());
|
||||||
|
|
||||||
if result.is_none() {
|
if result.is_none(){
|
||||||
return Ok(());
|
return Ok(()) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(result) = result.unwrap() {
|
if let Some(result) = result.unwrap(){
|
||||||
let target = result.get_mut_target();
|
let target = result.get_mut_target();
|
||||||
|
|
||||||
// let mut canvas = render.get_canvas();
|
let mut canvas = render.get_canvas();
|
||||||
// let mut canvas = canvas.as_mut().unwrap();
|
let mut canvas = canvas.as_mut().unwrap();
|
||||||
// let (ox, oy) = target.origin(render);
|
let (ox, oy) = target.origin(render);
|
||||||
// let (x, y) = target.size(render);
|
let (x, y) = target.size(render);
|
||||||
|
|
||||||
render.draw_img(target);
|
let result_id = match target.target {
|
||||||
|
TargetType::ImageId(id) => id,
|
||||||
|
TargetType::Mem(ref mem) => {
|
||||||
|
let converted = canvas
|
||||||
|
.load_image_mem(mem, femtovg::ImageFlags::empty())
|
||||||
|
.unwrap();
|
||||||
|
target.set_target(TargetType::ImageId(converted));
|
||||||
|
converted
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let paint = femtovg::Paint::image(result_id, ox, oy, x, y, 0.0, self.alpha);
|
||||||
|
let mut path = femtovg::Path::new();
|
||||||
|
path.rect(ox, oy, x, y);
|
||||||
|
canvas.fill_path(&path, &paint);
|
||||||
|
|
||||||
// let result_id = match target.target {
|
|
||||||
// TargetType::ImageId(id) => id,
|
|
||||||
// TargetType::Mem(ref mem) => {
|
|
||||||
// let converted = canvas
|
|
||||||
// .load_image_mem(mem, femtovg::ImageFlags::empty())
|
|
||||||
// .unwrap();
|
|
||||||
// target.set_target(TargetType::ImageId(converted));
|
|
||||||
// converted
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -131,4 +140,5 @@ impl Layer {
|
|||||||
pub fn set_associated_element(&mut self, element: AssoElement) {
|
pub fn set_associated_element(&mut self, element: AssoElement) {
|
||||||
self.associated_element = element;
|
self.associated_element = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
|
use tracing::info;
|
||||||
mod cms;
|
mod cms;
|
||||||
mod exterior;
|
mod exterior;
|
||||||
mod imp;
|
mod imp;
|
||||||
mod interior;
|
mod interior;
|
||||||
pub mod predefined;
|
pub mod predefined;
|
||||||
pub mod renders;
|
pub mod renders;
|
||||||
|
pub mod widget;
|
||||||
pub use self::imp::{RenderConfig, RenderMotion, RenderStatus};
|
pub use self::imp::{RenderConfig, RenderMotion, RenderStatus};
|
||||||
|
use crate::components::messages::MonitorInputMsg;
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::coords::{Mapper, Range};
|
use crate::coords::{Mapper, Range};
|
||||||
use crate::errors::PipelineError;
|
use crate::errors::PipelineError;
|
||||||
@ -19,7 +21,9 @@ use gtk::prelude::*;
|
|||||||
use gtk::subclass::prelude::ObjectSubclassIsExt;
|
use gtk::subclass::prelude::ObjectSubclassIsExt;
|
||||||
use gtk::EventControllerScrollFlags;
|
use gtk::EventControllerScrollFlags;
|
||||||
pub use interior::*;
|
pub use interior::*;
|
||||||
|
use slippy_map_tiles::Tile;
|
||||||
use std::cell::{Ref, RefCell, RefMut};
|
use std::cell::{Ref, RefCell, RefMut};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@ -247,6 +251,7 @@ impl Render {
|
|||||||
height,
|
height,
|
||||||
bounds,
|
bounds,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,10 +263,6 @@ impl Render {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_img(&self, img: &mut Target) {
|
|
||||||
self.imp().draw_target(img);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale_rate(&self) -> f64 {
|
pub fn scale_rate(&self) -> f64 {
|
||||||
let status = self.imp().status.borrow();
|
let status = self.imp().status.borrow();
|
||||||
status.scale_rate.unwrap()
|
status.scale_rate.unwrap()
|
||||||
|
|||||||
@ -13,8 +13,8 @@ use std::{fmt::Debug, io::Cursor, marker::PhantomData};
|
|||||||
|
|
||||||
use super::super::renders::DataRenderer;
|
use super::super::renders::DataRenderer;
|
||||||
use super::super::{LayerImpl, Render};
|
use super::super::{LayerImpl, Render};
|
||||||
use crate::coords::cms::CMS;
|
|
||||||
use crate::{data::Radar2d, utils::meshgrid};
|
use crate::{data::Radar2d, utils::meshgrid};
|
||||||
|
use crate::coords::cms::CMS;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct GridFieldRenderer<CMAP, T>
|
pub struct GridFieldRenderer<CMAP, T>
|
||||||
@ -175,7 +175,7 @@ where
|
|||||||
let d2_end = data.dim2.view().last().unwrap().clone();
|
let d2_end = data.dim2.view().last().unwrap().clone();
|
||||||
|
|
||||||
Target::new(
|
Target::new(
|
||||||
TargetType::NativeBuffer(png_data),
|
TargetType::Mem(png_data),
|
||||||
w,
|
w,
|
||||||
h,
|
h,
|
||||||
((d1_start, d1_end).into(), (d2_start, d2_end).into()),
|
((d1_start, d1_end).into(), (d2_start, d2_end).into()),
|
||||||
|
|||||||
@ -1 +1,5 @@
|
|||||||
|
pub mod color_mapper;
|
||||||
pub mod gis;
|
pub mod gis;
|
||||||
|
// pub mod grid_field_renderer;
|
||||||
|
// pub mod layers;
|
||||||
|
pub mod widgets;
|
||||||
|
|||||||
103
src/widgets/render/predefined/widgets.rs
Normal file
103
src/widgets/render/predefined/widgets.rs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
use super::{
|
||||||
|
super::widget::{Widget as WidgetTrait, WidgetType},
|
||||||
|
super::Layer,
|
||||||
|
color_mapper::ColorMapper,
|
||||||
|
};
|
||||||
|
use femtovg::{renderer::OpenGl, Canvas, Color, Paint, Path};
|
||||||
|
use num_traits::*;
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ColorBar<V, T>
|
||||||
|
where
|
||||||
|
V: num_traits::NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64>,
|
||||||
|
T: ColorMapper<V>,
|
||||||
|
{
|
||||||
|
color_mapper: T,
|
||||||
|
padding: [f32; 4],
|
||||||
|
width: f32,
|
||||||
|
height: f32,
|
||||||
|
margin: [i32; 4],
|
||||||
|
color_list: Vec<femtovg::Color>,
|
||||||
|
phantom: std::marker::PhantomData<V>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, T> ColorBar<V, T>
|
||||||
|
where
|
||||||
|
V: num_traits::NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64>,
|
||||||
|
T: ColorMapper<V>,
|
||||||
|
{
|
||||||
|
pub fn new(color_mapper: T, padding: [f32; 4], size: (f32, f32), margin: [i32; 4]) -> Self {
|
||||||
|
let (l, ll) = color_mapper.min_max();
|
||||||
|
let invalid = color_mapper.invalid();
|
||||||
|
let colors = color_mapper.map_min_to_max();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
color_list: colors,
|
||||||
|
color_mapper,
|
||||||
|
padding,
|
||||||
|
width: size.0,
|
||||||
|
height: size.1,
|
||||||
|
margin,
|
||||||
|
phantom: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, T> WidgetTrait for ColorBar<V, T>
|
||||||
|
where
|
||||||
|
V: num_traits::NumOps + PartialOrd + FromPrimitive + AsPrimitive<f64> + Send + Sync,
|
||||||
|
T: ColorMapper<V> + 'static,
|
||||||
|
{
|
||||||
|
fn cairo_render(&self, canvas: >k::cairo::Context, w: f32, h: f32) {
|
||||||
|
let bar_width = 10;
|
||||||
|
let bar_height = h - self.padding[0] - self.padding[2];
|
||||||
|
let (x, y) = (self.padding[3], self.padding[0]);
|
||||||
|
let b_h = bar_height / self.color_list.len() as f32;
|
||||||
|
|
||||||
|
for ((i, color), label) in self
|
||||||
|
.color_list
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.zip(self.color_mapper.labels())
|
||||||
|
{
|
||||||
|
let y = y + i as f32 * b_h;
|
||||||
|
|
||||||
|
canvas.set_source_rgba(
|
||||||
|
color.r as f64,
|
||||||
|
color.g as f64,
|
||||||
|
color.b as f64,
|
||||||
|
color.a as f64,
|
||||||
|
);
|
||||||
|
canvas.rectangle(x as f64, y as f64, bar_width as f64, b_h as f64);
|
||||||
|
canvas.fill();
|
||||||
|
|
||||||
|
let extents = canvas.text_extents(&label).unwrap();
|
||||||
|
|
||||||
|
canvas.move_to(
|
||||||
|
(x + bar_width as f32 + 5.0) as f64,
|
||||||
|
y as f64 + extents.height() / 2.0 as f64,
|
||||||
|
);
|
||||||
|
canvas.set_source_rgba(1.0, 1.0, 1.0, 1.0);
|
||||||
|
canvas.show_text(&label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn location(&self) -> (gtk::Align, gtk::Align) {
|
||||||
|
(gtk::Align::End, gtk::Align::End)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> (f32, f32) {
|
||||||
|
(self.width, self.height)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn widget_type(&self) -> WidgetType {
|
||||||
|
WidgetType::Cairo
|
||||||
|
}
|
||||||
|
|
||||||
|
fn margin(&self) -> [i32; 4] {
|
||||||
|
self.margin
|
||||||
|
}
|
||||||
|
|
||||||
|
fn padding(&self) -> [i32; 4] {
|
||||||
|
[10, 10, 10, 10]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,7 @@
|
|||||||
use super::Render;
|
use super::Render;
|
||||||
use crate::coords::cms::CMS;
|
use crate::coords::cms::CMS;
|
||||||
use crate::pipeline::element::Target;
|
|
||||||
use femtovg::{renderer::OpenGl, Canvas};
|
use femtovg::{renderer::OpenGl, Canvas};
|
||||||
|
use crate::pipeline::element::Target;
|
||||||
|
|
||||||
pub trait DataRenderer {
|
pub trait DataRenderer {
|
||||||
type Data;
|
type Data;
|
||||||
|
|||||||
@ -11,8 +11,8 @@ pub enum WidgetType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Widget: 'static + Send + Sync {
|
pub trait Widget: 'static + Send + Sync {
|
||||||
fn opengl_render(&self, layers: &Vec<Layer>, canvas: &mut Canvas<OpenGl>, cms: CMS) {}
|
fn opengl_render(&self, canvas: &mut Canvas<OpenGl>, cms: CMS) {}
|
||||||
fn cairo_render(&self, layers: &Vec<Layer>, canvas: >k::cairo::Context, w: f32, h: f32) {}
|
fn cairo_render(&self, canvas: >k::cairo::Context, w: f32, h: f32) {}
|
||||||
fn widget_type(&self) -> WidgetType;
|
fn widget_type(&self) -> WidgetType;
|
||||||
|
|
||||||
fn size(&self) -> (f32, f32);
|
fn size(&self) -> (f32, f32);
|
||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::components::monitor::Widget;
|
use crate::widgets::widget::Widget;
|
||||||
use chrono::{prelude::*, Duration};
|
use chrono::{prelude::*, Duration};
|
||||||
use gtk::glib::{self, prelude::*, ParamSpec, Properties, Value};
|
use gtk::glib::{self, prelude::*, ParamSpec, Properties, Value};
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::components::monitor::Widget;
|
use self::widget::Widget;
|
||||||
|
|
||||||
pub use super::*;
|
pub use super::*;
|
||||||
mod imp;
|
mod imp;
|
||||||
@ -66,7 +66,7 @@ impl WidgetFrame {
|
|||||||
drawing_area.set_draw_func(clone!(@strong widget => move |_, canvas, x, y| {
|
drawing_area.set_draw_func(clone!(@strong widget => move |_, canvas, x, y| {
|
||||||
let widget = widget.borrow();
|
let widget = widget.borrow();
|
||||||
let widget = widget.as_ref().unwrap();
|
let widget = widget.as_ref().unwrap();
|
||||||
// widget.cairo_render(canvas,x as f32,y as f32);
|
widget.cairo_render(canvas,x as f32,y as f32);
|
||||||
}));
|
}));
|
||||||
drawing_area.queue_draw();
|
drawing_area.queue_draw();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user