aaaaaaaaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
This commit is contained in:
parent
2dd910e919
commit
3633c01142
|
@ -4,6 +4,8 @@
|
|||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/wxbox-pal/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/wxbox-tiler/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/wxbox-eccodes-sys/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/wxbox-web/wxbox-eccodes-sys/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
|
|
|
@ -285,6 +285,29 @@ version = "0.22.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.69.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
|
@ -365,6 +388,15 @@ dependencies = [
|
|||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
|
@ -385,6 +417,17 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "convert_case"
|
||||
version = "0.4.0"
|
||||
|
@ -499,6 +542,40 @@ dependencies = [
|
|||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eccodes"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7851e2dfed8264270ebee69af9ab16ffc6d0981f7829d4c8379359b97f5abeed"
|
||||
dependencies = [
|
||||
"eccodes-sys",
|
||||
"errno",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"libc",
|
||||
"log",
|
||||
"ndarray",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "eccodes-sys"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d2bdc129e03da6393abb9fea441903fb6a5e88f1fd15da111c17be03017fd59"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.34"
|
||||
|
@ -524,6 +601,18 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.1"
|
||||
|
@ -645,6 +734,12 @@ version = "0.31.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
|
||||
[[package]]
|
||||
name = "grib"
|
||||
version = "0.10.2"
|
||||
|
@ -717,6 +812,15 @@ version = "0.3.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "home"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
|
||||
dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.12"
|
||||
|
@ -901,6 +1005,15 @@ version = "2.10.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
|
@ -931,12 +1044,34 @@ version = "0.3.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.159"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
|
@ -976,6 +1111,16 @@ version = "0.4.22"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "matrixmultiply"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"rawpointer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
|
@ -988,6 +1133,12 @@ version = "0.3.17"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.0"
|
||||
|
@ -1028,6 +1179,31 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndarray"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
|
||||
dependencies = [
|
||||
"matrixmultiply",
|
||||
"num-complex",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"rawpointer",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.4.3"
|
||||
|
@ -1067,6 +1243,17 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
|
@ -1272,6 +1459,21 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90a7d5beecc52a491b54d6dd05c7a45ba1801666a5baad9fdbfc6fef8d2d206c"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
|
@ -1287,6 +1489,16 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "904afd36257cdb6ce0bee88b7981847bd7b955e5e216bb32f466b302923ad446"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "3.2.0"
|
||||
|
@ -1344,6 +1556,12 @@ dependencies = [
|
|||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rawpointer"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.7"
|
||||
|
@ -1452,6 +1670,12 @@ version = "0.1.24"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
|
@ -1678,9 +1902,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.79"
|
||||
version = "2.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
|
||||
checksum = "e6e185e337f816bc8da115b8afcb3324006ccc82eeaddf35113888d3bd8e44ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2064,6 +2288,18 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
|
||||
dependencies = [
|
||||
"either",
|
||||
"home",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
|
@ -2207,9 +2443,11 @@ name = "wxbox-tiler"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"eccodes",
|
||||
"flate2",
|
||||
"grib",
|
||||
"mime",
|
||||
"ndarray",
|
||||
"ordered-float",
|
||||
"png",
|
||||
"reqwest",
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
use std::collections::BTreeMap;
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
pub struct Palette {
|
||||
pub colors: BTreeMap<OrderedFloat<f64>, Color>
|
||||
#[macro_export]
|
||||
macro_rules! color {
|
||||
($v:expr,$r:expr,$g:expr,$b:expr) => { (OrderedFloat(f64::from($v)), Color { red: $r, green: $g, blue: $b, alpha: 255 }) };
|
||||
($v:expr,$r:expr,$g:expr,$b:expr,$a:expr) => { (OrderedFloat(f64::from($v)), Color { red: $r, green: $g, blue: $b, alpha: $a }) };
|
||||
(rgb: $r:expr,$g:expr,$b:expr) => { Color { red: $r, green: $g, blue: $b, alpha: 255 }};
|
||||
(rgba: $r:expr,$g:expr,$b:expr,$a:expr) => { Color { red: $r, green: $g, blue: $b, alpha: $a }};
|
||||
}
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
|
||||
pub struct Palette {
|
||||
pub colors: BTreeMap<OrderedFloat<f64>, Color>,
|
||||
pub clear_value: f64
|
||||
}
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct Color {
|
||||
pub red: u8,
|
||||
pub green: u8,
|
||||
|
@ -25,7 +34,9 @@ impl Color {
|
|||
|
||||
impl Palette {
|
||||
pub fn color_for(&self, val: f64) -> Color {
|
||||
if self.colors.is_empty() {
|
||||
if val <= self.clear_value {
|
||||
Color { red: 0, green: 0, blue: 0, alpha: 0 }
|
||||
} else if self.colors.is_empty() {
|
||||
panic!("color_for() on empty palette");
|
||||
} else {
|
||||
let mut best_v: Option<Color> = None;
|
||||
|
@ -38,3 +49,40 @@ impl Palette {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::BTreeMap;
|
||||
use crate::Palette;
|
||||
use crate::Color;
|
||||
use ordered_float::OrderedFloat;
|
||||
|
||||
#[test]
|
||||
fn basic_palette_test() {
|
||||
let pal = Palette {
|
||||
colors: BTreeMap::from([
|
||||
color!(-30, 165, 165, 165),
|
||||
color!(10, 0, 165, 255),
|
||||
color!(20, 16, 255, 8),
|
||||
color!(35, 251, 238, 0),
|
||||
color!(50, 255, 0, 0),
|
||||
color!(65, 247, 1, 249),
|
||||
color!(75, 255, 255, 255),
|
||||
color!(85, 184, 184, 184),
|
||||
color!(95, 184, 184, 184)
|
||||
]),
|
||||
clear_value: -99.0
|
||||
};
|
||||
|
||||
|
||||
|
||||
assert_eq!(pal.color_for(-999.0), color!(rgba: 0, 0, 0, 0));
|
||||
assert_eq!(pal.color_for(-99.0), color!(rgba: 0, 0, 0, 0));
|
||||
|
||||
assert_eq!(pal.color_for(-30.0), color!(rgb: 165, 165, 165));
|
||||
assert_eq!(pal.color_for(-25.0), color!(rgb: 165, 165, 165));
|
||||
|
||||
assert_eq!(pal.color_for(10.0), color!(rgb: 0, 165, 255));
|
||||
assert_eq!(pal.color_for(15.0), color!(rgb: 0, 165, 255));
|
||||
}
|
||||
}
|
|
@ -17,3 +17,5 @@ tokio = "1"
|
|||
wxbox-pal = { version = "0.1", path = "../wxbox-pal" }
|
||||
png = "0.17"
|
||||
mime = "0.3.17"
|
||||
eccodes = { version = "0.12", features = ["message_ndarray"] }
|
||||
ndarray = "0.16"
|
|
@ -70,9 +70,9 @@ pub enum GribMapError {
|
|||
IoError(#[from] std::io::Error)
|
||||
}
|
||||
|
||||
pub type GriddedLookupTable = BTreeMap<OrderedFloat<f64>, BTreeMap<OrderedFloat<f64>, f64>>;
|
||||
pub type LookupTable2D = BTreeMap<OrderedFloat<f64>, BTreeMap<OrderedFloat<f64>, f64>>;
|
||||
|
||||
pub async fn map_grib2(i: Response) -> Result<GriddedLookupTable, GribMapError> {
|
||||
pub async fn map_grib2(i: Response) -> Result<LookupTable2D, GribMapError> {
|
||||
let b = Cursor::new(i.bytes().await?.to_vec());
|
||||
let mut decoder = GzDecoder::new(b);
|
||||
|
||||
|
|
|
@ -6,16 +6,22 @@ mod pixmap;
|
|||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::env::args;
|
||||
use std::ffi::c_void;
|
||||
use std::fmt::Debug;
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::io::{BufReader, Cursor, Read};
|
||||
use std::ptr::{null, null_mut};
|
||||
use tokio::sync::RwLock;
|
||||
use std::time::SystemTime;
|
||||
use actix_web::{App, get, HttpServer};
|
||||
use actix_web::web::Data;
|
||||
use eccodes::{CodesHandle, FallibleStreamingIterator, KeyedMessage, KeyRead, ProductKind};
|
||||
use eccodes::codes_handle::CodesFile;
|
||||
use flate2::read::GzDecoder;
|
||||
use grib::codetables::{CodeTable1_4, CodeTable4_2, CodeTable4_3, Lookup};
|
||||
use grib::{GribError, SectionBody};
|
||||
use ordered_float::OrderedFloat;
|
||||
use crate::grib2::GriddedLookupTable;
|
||||
use crate::grib2::{LookupTable2D, lookup};
|
||||
use crate::sources::noaa::mrms_cref;
|
||||
|
||||
#[global_allocator]
|
||||
|
@ -28,12 +34,16 @@ pub enum LutKey {
|
|||
}
|
||||
|
||||
pub struct AppState {
|
||||
lut_cache: RwLock<BTreeMap<LutKey, GriddedLookupTable>>,
|
||||
lut_cache: RwLock<BTreeMap<LutKey, LookupTable2D>>,
|
||||
lut_cache_timestamps: RwLock<BTreeMap<LutKey, SystemTime>>
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
let f = reqwest::get("https://mrms.ncep.noaa.gov/data/2D/ReflectivityAtLowestAltitude/MRMS_ReflectivityAtLowestAltitude.latest.grib2.gz").await.unwrap();
|
||||
|
||||
|
||||
|
||||
let data = Data::new(AppState {
|
||||
lut_cache: RwLock::new(BTreeMap::new()),
|
||||
lut_cache_timestamps: RwLock::new(BTreeMap::new())
|
||||
|
@ -43,8 +53,9 @@ async fn main() -> std::io::Result<()> {
|
|||
.service(mrms_cref)
|
||||
.app_data(data.clone())
|
||||
})
|
||||
.bind(("127.0.0.1", 8080))?
|
||||
.bind(("::", 8080))?
|
||||
.run()
|
||||
.await
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::f64::consts::PI;
|
||||
use std::io::{BufReader, BufWriter, Cursor, Read};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use actix_web::{get, HttpResponse, web};
|
||||
use actix_web::http::header::{CONTENT_TYPE, HeaderValue};
|
||||
use actix_web::http::{header, StatusCode};
|
||||
use actix_web::web::Data;
|
||||
use eccodes::{CodesHandle, FallibleStreamingIterator, ProductKind};
|
||||
use flate2::read::GzDecoder;
|
||||
use grib::{GribError, SectionBody};
|
||||
use grib::codetables::{CodeTable4_2, CodeTable4_3, Lookup};
|
||||
use ndarray::{Order, Zip};
|
||||
use ordered_float::OrderedFloat;
|
||||
use png::{BitDepth, ColorType, Encoder};
|
||||
use wxbox_pal::{Color, Palette};
|
||||
use crate::{AppState, LutKey};
|
||||
use crate::coords::bounds;
|
||||
use crate::grib2::{closest_key, lookup, map_grib2};
|
||||
use crate::coords::{bounds, ul};
|
||||
use crate::grib2::{closest_key, LookupTable2D, lookup, map_grib2};
|
||||
use crate::pixmap::Pixmap;
|
||||
|
||||
macro_rules! color {
|
||||
($v:expr,$r:expr,$g:expr,$b:expr) => { (OrderedFloat(f64::from($v)), Color { red: $r, green: $g, blue: $b, alpha: 255 }) };
|
||||
($v:expr,$r:expr,$g:expr,$b:expr,$a:expr) => { (OrderedFloat(f64::from($v)), Color { red: $r, green: $g, blue: $b, alpha: $a }) };
|
||||
}
|
||||
use wxbox_pal::color;
|
||||
|
||||
#[get("/mrms_cref/{z}/{x}/{y}.png")]
|
||||
async fn mrms_cref(path: web::Path<(i32, i32, i32)>, data: Data<AppState>) -> HttpResponse {
|
||||
|
@ -51,20 +50,53 @@ async fn mrms_cref(path: web::Path<(i32, i32, i32)>, data: Data<AppState>) -> Ht
|
|||
let mut lct_writer = data.lut_cache_timestamps.write().await;
|
||||
let mut lc_writer = data.lut_cache.write().await;
|
||||
let f = reqwest::get("https://mrms.ncep.noaa.gov/data/2D/ReflectivityAtLowestAltitude/MRMS_ReflectivityAtLowestAltitude.latest.grib2.gz").await.unwrap();
|
||||
let map = map_grib2(f).await.unwrap();
|
||||
let data = f.bytes().await.unwrap().to_vec();
|
||||
let b = Cursor::new(data);
|
||||
let mut decoder = GzDecoder::new(b);
|
||||
|
||||
let mut data = vec![];
|
||||
decoder.read_to_end(&mut data).expect("decoding failure");
|
||||
|
||||
let product_kind = ProductKind::GRIB;
|
||||
|
||||
let mut handle = CodesHandle::new_from_memory(data.clone(), product_kind).unwrap();
|
||||
let msg = handle.next().expect("empty grib2 file").expect("empty grib2 file").try_clone().unwrap();
|
||||
|
||||
let mut map = LookupTable2D::new();
|
||||
|
||||
let mut arr = msg.to_lons_lats_values().unwrap();
|
||||
|
||||
Zip::from(&arr.latitudes)
|
||||
.and(&arr.longitudes)
|
||||
.and(&arr.values)
|
||||
.for_each(|&lat, &long, &value| {
|
||||
let lat = OrderedFloat(lat);
|
||||
|
||||
let mut long = long;
|
||||
if long > 180.0 {
|
||||
long -= 360.0;
|
||||
}
|
||||
|
||||
let long = OrderedFloat(long);
|
||||
|
||||
if value != -99.0 && value != -999.0 {
|
||||
println!("{}, {} => {}", lat, long, value);
|
||||
}
|
||||
|
||||
if let Some(row) = map.get_mut(&lat) {
|
||||
row.insert(long, value);
|
||||
} else {
|
||||
map.insert(lat, BTreeMap::from([
|
||||
(long, value)
|
||||
]));
|
||||
}
|
||||
});
|
||||
|
||||
lc_writer.insert(LutKey::NoaaMrmsCref, map);
|
||||
lct_writer.insert(LutKey::NoaaMrmsCref, SystemTime::now());
|
||||
}
|
||||
|
||||
if let Some(map) = data.lut_cache.read().await.get(&LutKey::NoaaMrmsCref) {
|
||||
let closest_south = match closest_key(&map, bbox.south) {
|
||||
Some(c) => c,
|
||||
None => { eprintln!("gridded LUT is empty?"); return HttpResponse::new(StatusCode::NOT_FOUND); }
|
||||
};
|
||||
let closest_north = match closest_key(&map, bbox.north) {
|
||||
Some(c) => c,
|
||||
None => { eprintln!("gridded LUT is empty?"); return HttpResponse::new(StatusCode::NOT_FOUND); }
|
||||
};
|
||||
|
||||
let pal = Palette {
|
||||
colors: BTreeMap::from([
|
||||
|
@ -78,10 +110,48 @@ async fn mrms_cref(path: web::Path<(i32, i32, i32)>, data: Data<AppState>) -> Ht
|
|||
color!(85, 184, 184, 184),
|
||||
color!(95, 184, 184, 184)
|
||||
]),
|
||||
clear_value: -99.0
|
||||
};
|
||||
|
||||
let mut image: Pixmap = Pixmap::new();
|
||||
|
||||
let tile_size = 360.0 / 2.0_f64.powi(z);
|
||||
let degrees_per_px = tile_size / 256.0;
|
||||
|
||||
let upper_left = ul(tile);
|
||||
|
||||
for x in 0..256 {
|
||||
for y in 0..256 {
|
||||
let lon = upper_left.lng + degrees_per_px * x as f64;
|
||||
let lat = upper_left.lat + degrees_per_px * y as f64;
|
||||
|
||||
let closest_lat_in_map = &closest_key(&map, lat).unwrap();
|
||||
let row = map.get(closest_lat_in_map).unwrap();
|
||||
let closest_long_in_row = closest_key(&row, lon).unwrap();
|
||||
|
||||
let value = row.get(&closest_long_in_row).unwrap();
|
||||
|
||||
let color = match value {
|
||||
-999.0 | -99.0 => Color { red: 0, green: 0, blue: 0, alpha: 5 },
|
||||
value_at_pos => {
|
||||
match *value_at_pos {
|
||||
..=-30.0 => color!(rgb: 165, 165, 165),
|
||||
-30.0..=10.0 => color!(rgb: 0, 165, 255),
|
||||
10.0..=20.0 => color!(rgb: 16, 255, 8),
|
||||
20.0..=35.0 => color!(rgb: 251, 238, 0),
|
||||
35.0..=50.0 => color!(rgb: 255, 0, 0),
|
||||
50.0..=65.0 => color!(rgb: 247, 1, 249),
|
||||
65.0..=75.0 => color!(rgb: 255, 255, 255),
|
||||
75.0.. => color!(rgb: 184, 184, 184),
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
};
|
||||
image.set(x, y, color);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
for (lat, row) in map.range(closest_south..=closest_north) {
|
||||
let closest_west = match closest_key(&row, bbox.west) {
|
||||
Some(c) => c,
|
||||
|
@ -94,32 +164,40 @@ async fn mrms_cref(path: web::Path<(i32, i32, i32)>, data: Data<AppState>) -> Ht
|
|||
for (long, gridpoint) in row.range(closest_west..=closest_east) {
|
||||
let epsg_lon = **long;
|
||||
let epsg_lat = **lat;
|
||||
|
||||
let wm_x = epsg_lon;
|
||||
let wm_y = epsg_lat.tan().asinh();
|
||||
|
||||
let x = 0.5 + wm_x / 360.0;
|
||||
let y = 0.5 - wm_y / (2.0 * std::f64::consts::PI);
|
||||
|
||||
let zoom = z;
|
||||
let n = 2.0_f64.powi(zoom);
|
||||
|
||||
let x_tile = n * x;
|
||||
let y_tile = n * y;
|
||||
|
||||
let x_pixel = x_tile.fract() * 256.0;
|
||||
let y_pixel = y_tile.fract() * 256.0;
|
||||
|
||||
let x = x_pixel.trunc() as usize;
|
||||
let y = y_pixel.trunc() as usize;
|
||||
let xf = x_pixel.trunc() as usize;
|
||||
let yf = y_pixel.trunc() as usize;
|
||||
|
||||
println!("@{} -> {}: {} -> {} -> {} -> {} -> {} => {}\n{} -> {} -> {} -> {} -> {} => {}", z, n, epsg_lon, wm_x, x, x_tile, x_pixel, xf, epsg_lat, wm_y, y, y_tile, y_pixel, yf);
|
||||
|
||||
let mut color = pal.color_for(*gridpoint);
|
||||
|
||||
let existing = image.get(x, y);
|
||||
let existing = image.get(xf, yf);
|
||||
if existing != (Color { red: 0, green: 0, blue: 0, alpha: 0 }) {
|
||||
color = color.average(existing);
|
||||
}
|
||||
|
||||
image.set(x, y, color);
|
||||
image.set(xf, yf, color);
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
let mut buf: Vec<u8> = vec![];
|
||||
// borrow checker insanity
|
||||
{
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
}
|
||||
).addTo(m);
|
||||
L.tileLayer(
|
||||
'http://localhost:8080/mrms_cref/{z}/{x}/{y}.png',
|
||||
'http://100.64.0.1:8080/mrms_cref/{z}/{x}/{y}.png',
|
||||
{
|
||||
attribution: '© NOAA',
|
||||
maxZoom: 19
|
||||
|
|
Loading…
Reference in New Issue