diff --git a/.idea/wxbox.iml b/.idea/wxbox.iml index 125c7cc..74ddee0 100644 --- a/.idea/wxbox.iml +++ b/.idea/wxbox.iml @@ -4,6 +4,8 @@ + + diff --git a/Cargo.lock b/Cargo.lock index a9fd1dd..8deaf0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 0ac0f55..cb9a13e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = [ "wxbox-pal","wxbox-tiler"] +members = ["wxbox-pal","wxbox-tiler"] [profile.release] codegen-units = 1 diff --git a/wxbox-pal/src/lib.rs b/wxbox-pal/src/lib.rs index f0b2b19..ce44f0c 100644 --- a/wxbox-pal/src/lib.rs +++ b/wxbox-pal/src/lib.rs @@ -1,10 +1,19 @@ use std::collections::BTreeMap; use ordered_float::OrderedFloat; -pub struct Palette { - pub colors: BTreeMap, 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, 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 = None; @@ -37,4 +48,41 @@ impl Palette { best_v.expect("color_for() on empty 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)); + } } \ No newline at end of file diff --git a/wxbox-tiler/Cargo.toml b/wxbox-tiler/Cargo.toml index ef3bc42..028f10f 100644 --- a/wxbox-tiler/Cargo.toml +++ b/wxbox-tiler/Cargo.toml @@ -16,4 +16,6 @@ flate2 = "1" tokio = "1" wxbox-pal = { version = "0.1", path = "../wxbox-pal" } png = "0.17" -mime = "0.3.17" \ No newline at end of file +mime = "0.3.17" +eccodes = { version = "0.12", features = ["message_ndarray"] } +ndarray = "0.16" \ No newline at end of file diff --git a/wxbox-tiler/src/grib2.rs b/wxbox-tiler/src/grib2.rs index 8f66157..2262fd2 100644 --- a/wxbox-tiler/src/grib2.rs +++ b/wxbox-tiler/src/grib2.rs @@ -70,9 +70,9 @@ pub enum GribMapError { IoError(#[from] std::io::Error) } -pub type GriddedLookupTable = BTreeMap, BTreeMap, f64>>; +pub type LookupTable2D = BTreeMap, BTreeMap, f64>>; -pub async fn map_grib2(i: Response) -> Result { +pub async fn map_grib2(i: Response) -> Result { let b = Cursor::new(i.bytes().await?.to_vec()); let mut decoder = GzDecoder::new(b); diff --git a/wxbox-tiler/src/main.rs b/wxbox-tiler/src/main.rs index b300cd7..ec50ff9 100644 --- a/wxbox-tiler/src/main.rs +++ b/wxbox-tiler/src/main.rs @@ -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>, + lut_cache: RwLock>, lut_cache_timestamps: RwLock> } #[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 + } diff --git a/wxbox-tiler/src/sources/noaa/mod.rs b/wxbox-tiler/src/sources/noaa/mod.rs index b792978..9855eb8 100644 --- a/wxbox-tiler/src/sources/noaa/mod.rs +++ b/wxbox-tiler/src/sources/noaa/mod.rs @@ -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) -> HttpResponse { @@ -46,25 +45,58 @@ async fn mrms_cref(path: web::Path<(i32, i32, i32)>, data: Data) -> Ht } drop(lct_reader); - + if needs_reload { 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) -> 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) -> 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 = vec![]; // borrow checker insanity { diff --git a/wxbox-web/src/routes/+page.svelte b/wxbox-web/src/routes/+page.svelte index 89814b6..1ed3882 100644 --- a/wxbox-web/src/routes/+page.svelte +++ b/wxbox-web/src/routes/+page.svelte @@ -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