feat: sample precipitation at POIs, add download script
This commit is contained in:
parent
60ea19f2c4
commit
e977380817
|
@ -1,4 +1,5 @@
|
|||
/target
|
||||
|
||||
input
|
||||
rv.png
|
||||
*.png
|
||||
config.toml
|
||||
data/
|
||||
|
|
|
@ -8,6 +8,15 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
|
@ -32,6 +41,12 @@ version = "1.23.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder-lite"
|
||||
version = "0.1.0"
|
||||
|
@ -71,6 +86,12 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.12"
|
||||
|
@ -112,6 +133,119 @@ dependencies = [
|
|||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float_next_after"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
|
||||
|
||||
[[package]]
|
||||
name = "geo"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4416397671d8997e9a3e7ad99714f4f00a22e9eaa9b966a5985d2194fc9e02e1"
|
||||
dependencies = [
|
||||
"float_next_after",
|
||||
"geo-types",
|
||||
"geographiclib-rs",
|
||||
"i_overlay",
|
||||
"log",
|
||||
"num-traits",
|
||||
"proj",
|
||||
"robust",
|
||||
"rstar",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "geo-types"
|
||||
version = "0.7.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62ddb1950450d67efee2bbc5e429c68d052a822de3aad010d28b351fbb705224"
|
||||
dependencies = [
|
||||
"approx",
|
||||
"num-traits",
|
||||
"rstar",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "geographiclib-rs"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f611040a2bb37eaa29a78a128d1e92a378a03e0b6e66ae27398d42b1ba9a7841"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hash32"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad"
|
||||
dependencies = [
|
||||
"hash32",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i_float"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85df3a416829bb955fdc2416c7b73680c8dcea8d731f2c7aa23e1042fe1b8343"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i_key_sort"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "347c253b4748a1a28baf94c9ce133b6b166f08573157e05afe718812bc599fcd"
|
||||
|
||||
[[package]]
|
||||
name = "i_overlay"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0542dfef184afdd42174a03dcc0625b6147fb73e1b974b1a08a2a42ac35cee49"
|
||||
dependencies = [
|
||||
"i_float",
|
||||
"i_key_sort",
|
||||
"i_shape",
|
||||
"i_tree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i_shape"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a38f5a42678726718ff924f6d4a0e79b129776aeed298f71de4ceedbd091bce"
|
||||
dependencies = [
|
||||
"i_float",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "i_tree"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "155181bc97d770181cf9477da51218a19ee92a8e5be642e796661aee2b601139"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.6"
|
||||
|
@ -124,12 +258,28 @@ dependencies = [
|
|||
"png",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.3"
|
||||
|
@ -143,9 +293,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.32.0"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbb8270bb4060bd76c6e96f20c52d80620f1d82a3470885694e41e0f81ef6fe7"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
|
@ -166,6 +316,18 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
|
@ -183,6 +345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -215,10 +378,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proj"
|
||||
version = "0.30.0"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58e0c01de214d7ea50ee6519969be9efdc6f0dc5ce6c64fbd4f054ea26d43ca4"
|
||||
checksum = "3939f58cd2f8e5f3bba7fb76b3854956d39b1b76cec4fe5f65481d18f9c92d22"
|
||||
dependencies = [
|
||||
"geo-types",
|
||||
"libc",
|
||||
"num-traits",
|
||||
"proj-sys",
|
||||
|
@ -227,9 +391,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proj-sys"
|
||||
version = "0.26.0"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a208129995443a4c475464c33308274be1578993b0ad266c9139188ed0dc7e91"
|
||||
checksum = "533a4ed2ab59f7605ecea26db7ed76572d30aed9d2a6a90738bc7f7e7b5a11d8"
|
||||
dependencies = [
|
||||
"cmake",
|
||||
"flate2",
|
||||
|
@ -257,6 +421,23 @@ dependencies = [
|
|||
"bitflags 2.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "robust"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839"
|
||||
|
||||
[[package]]
|
||||
name = "rstar"
|
||||
version = "0.12.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "421400d13ccfd26dfa5858199c30a5d76f9c54e0dba7575273025b43c5175dbb"
|
||||
dependencies = [
|
||||
"heapless",
|
||||
"num-traits",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.7"
|
||||
|
@ -270,6 +451,35 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
|
@ -282,6 +492,18 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
|
@ -324,6 +546,47 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_write",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
|
@ -340,8 +603,11 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
|||
name = "wetter"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"geo",
|
||||
"image",
|
||||
"proj",
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -417,6 +683,15 @@ version = "0.52.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xattr"
|
||||
version = "1.5.0"
|
||||
|
|
|
@ -4,5 +4,8 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
geo = { version = "0.30.0", default-features = false, features = ["use-proj", "use-serde"] }
|
||||
image = { version = "0.25.6", default-features = false, features = ["png"] }
|
||||
proj = { version = "0.30.0", default-features = false }
|
||||
proj = "0.29.0"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
toml = "0.8.22"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
use geo::Point;
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use toml::de::Error;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Config {
|
||||
pois: HashMap<String, Point>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn from_toml(s: &str) -> Result<Self, Error> {
|
||||
toml::from_str(s)
|
||||
}
|
||||
|
||||
pub fn pois(&self) -> &HashMap<String, Point> {
|
||||
&self.pois
|
||||
}
|
||||
}
|
|
@ -2,3 +2,4 @@ mod parser;
|
|||
mod rv;
|
||||
|
||||
pub use rv::Rv;
|
||||
pub use rv::DATA_LEN as RV_DATA_LEN;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use std::fmt::{self, Display, Formatter};
|
||||
use std::io::{Error as IoError, Read, Seek};
|
||||
use std::num::ParseIntError;
|
||||
use std::slice;
|
||||
use std::str::{self, FromStr, Utf8Error};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum ParseError {
|
||||
IoError(IoError),
|
||||
|
@ -12,6 +12,19 @@ pub enum ParseError {
|
|||
Utf8Error(Utf8Error),
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ParseError::IoError(err) => err.fmt(fmt),
|
||||
ParseError::ParseIntError(err) => err.fmt(fmt),
|
||||
ParseError::Unexpected(actual, expected) => {
|
||||
fmt.write_fmt(format_args!("Expected '{}', got '{}'", expected, actual))
|
||||
}
|
||||
ParseError::Utf8Error(err) => err.fmt(fmt),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Parser<R: Read + Seek> {
|
||||
r: R,
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ compile_error!("Only little-endian architectures are supported.");
|
|||
|
||||
use crate::data::parser::{ParseError, Parser};
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::io::{Read, Seek};
|
||||
|
||||
const DATA_LEN: usize = 1100 * 1200;
|
||||
pub const DATA_LEN: usize = 1100 * 1200;
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct VersionMismatch {
|
||||
|
@ -13,7 +15,16 @@ pub struct VersionMismatch {
|
|||
pub expected: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
impl Display for VersionMismatch {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
fmt.write_fmt(format_args!(
|
||||
"Expected data version {}, got {}",
|
||||
self.expected, self.actual
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Datetime {
|
||||
pub year: u16,
|
||||
pub month: u8,
|
||||
|
@ -27,6 +38,7 @@ pub struct Rv {
|
|||
timestamp: Datetime,
|
||||
version: u8,
|
||||
precision: i8,
|
||||
interval: u16,
|
||||
forecast: u16,
|
||||
data: Vec<u16>,
|
||||
}
|
||||
|
@ -68,7 +80,7 @@ impl Rv {
|
|||
|
||||
parser.expect("INT")?;
|
||||
|
||||
let _interval = parser.parse_int::<u16, 4>()?;
|
||||
let interval = parser.parse_int::<_, 4>()?;
|
||||
|
||||
parser.expect("GP")?;
|
||||
|
||||
|
@ -102,6 +114,7 @@ impl Rv {
|
|||
},
|
||||
version,
|
||||
precision,
|
||||
interval,
|
||||
forecast,
|
||||
data,
|
||||
})
|
||||
|
@ -122,6 +135,10 @@ impl Rv {
|
|||
10_f64.powi(self.precision as i32)
|
||||
}
|
||||
|
||||
pub fn interval(&self) -> u16 {
|
||||
self.interval
|
||||
}
|
||||
|
||||
pub fn instant(&self) -> (Datetime, u16) {
|
||||
(self.timestamp, self.forecast)
|
||||
}
|
||||
|
@ -130,3 +147,25 @@ impl Rv {
|
|||
&self.data[..]
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Rv {}
|
||||
|
||||
impl Ord for Rv {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.timestamp
|
||||
.cmp(&other.timestamp)
|
||||
.then(self.forecast.cmp(&other.forecast))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Rv {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.timestamp == other.timestamp && self.forecast == other.forecast
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Rv {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
|
117
src/main.rs
117
src/main.rs
|
@ -1,14 +1,21 @@
|
|||
mod config;
|
||||
mod data;
|
||||
|
||||
use data::Rv;
|
||||
use config::Config;
|
||||
|
||||
use data::{Rv, RV_DATA_LEN};
|
||||
|
||||
use image::imageops;
|
||||
use image::RgbaImage;
|
||||
|
||||
use proj::Proj;
|
||||
|
||||
use std::fs::File;
|
||||
use std::cmp::Reverse;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::BufReader;
|
||||
use std::str;
|
||||
|
||||
const PROJ_WGS84_DE1200: &'static str = "+proj=stere +lat_0=90 +lat_ts=60 +lon_0=10 +a=6378137 +b=6356752.3142451802 +no_defs +x_0=543196.83521776402 +y_0=3622588.8619310018";
|
||||
|
||||
|
@ -21,17 +28,13 @@ enum Intensity {
|
|||
Unknown = 0xd0d0d080,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let rv = Rv::parse(BufReader::new(File::open("input").unwrap())).unwrap();
|
||||
rv.expect_version(5).unwrap();
|
||||
|
||||
let mut data = Vec::with_capacity(1100 * 1200 * 4);
|
||||
|
||||
for v in rv.data() {
|
||||
let intensity = if *v == 0x29c4 {
|
||||
impl Intensity {
|
||||
fn from_rv_value(v: u16, scale: f64, interval: u16) -> Self {
|
||||
if v == 0x29c4 {
|
||||
Intensity::Unknown
|
||||
} else {
|
||||
let mm_per_h = *v as f64 * rv.scale() * 12.0; // 12 * 5 min intervals per hour
|
||||
let mm_per_h = v as f64 * scale * (60.0 / interval as f64);
|
||||
|
||||
if mm_per_h < 0.1 {
|
||||
Intensity::None
|
||||
} else if mm_per_h < 5.0 {
|
||||
|
@ -41,23 +44,85 @@ fn main() {
|
|||
} else {
|
||||
Intensity::Heavy
|
||||
}
|
||||
};
|
||||
|
||||
data.extend_from_slice(&(intensity as u32).to_be_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut img = RgbaImage::from_raw(1100, 1200, data).unwrap();
|
||||
imageops::flip_vertical_in_place(&mut img);
|
||||
img.save("rv.png").unwrap();
|
||||
fn main() -> Result<(), String> {
|
||||
let config =
|
||||
Config::from_toml(&fs::read_to_string("config.toml").map_err(|err| err.to_string())?)
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
let wgs84_to_de1200 = Proj::new(PROJ_WGS84_DE1200).unwrap();
|
||||
println!(
|
||||
"{:#?}",
|
||||
wgs84_to_de1200
|
||||
.project(
|
||||
(1.463301510_f64.to_radians(), 55.86208711_f64.to_radians()),
|
||||
false
|
||||
)
|
||||
.unwrap()
|
||||
let mut heap = BinaryHeap::new();
|
||||
|
||||
for path in env::args().skip(1) {
|
||||
let rv = Rv::parse(BufReader::new(
|
||||
File::open(&path).map_err(|err| err.to_string())?,
|
||||
))
|
||||
.map_err(|err| err.to_string())?;
|
||||
rv.expect_version(5).map_err(|err| err.to_string())?;
|
||||
|
||||
heap.push(Reverse(rv));
|
||||
}
|
||||
|
||||
let Reverse(current) = heap.pop().ok_or("At least one file must be given")?;
|
||||
|
||||
let (timestamp, offset) = current.instant();
|
||||
|
||||
if offset != 0 {
|
||||
eprintln!(
|
||||
"First file is expected to contain current situation, got forecast for +{} minutes",
|
||||
offset
|
||||
);
|
||||
}
|
||||
|
||||
let mut img_data = Vec::with_capacity(RV_DATA_LEN * 4);
|
||||
|
||||
for v in current.data() {
|
||||
let intensity = Intensity::from_rv_value(*v, current.scale(), current.interval());
|
||||
|
||||
img_data.extend_from_slice(&(intensity as u32).to_be_bytes());
|
||||
}
|
||||
|
||||
let mut img = RgbaImage::from_raw(1100, 1200, img_data).unwrap();
|
||||
imageops::flip_vertical_in_place(&mut img);
|
||||
img.save(format!(
|
||||
"rv_{}-{}-{}_{}:{}.png",
|
||||
timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.minute
|
||||
))
|
||||
.map_err(|err| err.to_string())?;
|
||||
|
||||
let mut data = Vec::with_capacity(RV_DATA_LEN * heap.len());
|
||||
|
||||
while heap.len() > 0 {
|
||||
let Reverse(forecast) = heap.pop().unwrap();
|
||||
data.extend_from_slice(forecast.data());
|
||||
}
|
||||
|
||||
let wgs84_to_de1200 = Proj::new(PROJ_WGS84_DE1200).map_err(|err| err.to_string())?;
|
||||
|
||||
for (name, poi) in config.pois() {
|
||||
let (x, y) = (wgs84_to_de1200
|
||||
.project(poi.to_radians(), false)
|
||||
.map_err(|err| err.to_string())?
|
||||
/ 1000.0)
|
||||
.x_y();
|
||||
|
||||
let (x, y) = (x.round() as usize, (1200 + y.round() as i64) as usize);
|
||||
if !(0..1100).contains(&x) || !(0..1200).contains(&y) {
|
||||
eprintln!("POI \"{}\" is out of range", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
let v = current.data()[y * 1100 + x];
|
||||
if v == 0x29c4 {
|
||||
eprintln!("No value for POI \"{}\"", name);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mm_per_h = v as f64 * current.scale() * (60.0 / current.interval() as f64);
|
||||
println!("intensity{{poi=\"{}\"}} {}", name, mm_per_h);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import subprocess
|
||||
import tarfile
|
||||
from datetime import UTC, datetime, timedelta
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
from sys import exit, stderr, stdout
|
||||
|
||||
import requests
|
||||
|
||||
DATA_DIR = Path.cwd() / "data"
|
||||
DATA_DIR.mkdir(exist_ok=True)
|
||||
|
||||
DOWNLOAD_URL = (
|
||||
"https://opendata.dwd.de/weather/radar/composite/rv/DE1200_RV%y%m%d%H%M.tar.bz2"
|
||||
)
|
||||
|
||||
now = datetime.now(UTC)
|
||||
now = now.replace(minute=now.minute // 5 * 5, second=0, microsecond=0)
|
||||
|
||||
for dt in (now, now - timedelta(minutes=5)):
|
||||
url = dt.strftime(DOWNLOAD_URL)
|
||||
print(f"Attempting to download {url}", file=stderr)
|
||||
|
||||
try:
|
||||
r = requests.get(url)
|
||||
r.raise_for_status()
|
||||
break
|
||||
except requests.HTTPError:
|
||||
print(f"Not Found: {url}")
|
||||
else:
|
||||
exit()
|
||||
|
||||
with tarfile.open(fileobj=BytesIO(r.content)) as tar:
|
||||
tar.extractall(DATA_DIR, filter="data")
|
||||
files = list(map(lambda n: DATA_DIR / n, tar.getnames()))
|
||||
|
||||
subprocess.run(
|
||||
[str(Path(__name__).resolve().parent / "target/release/wetter")] + files,
|
||||
stdout=stdout,
|
||||
stderr=stderr,
|
||||
check=True,
|
||||
)
|
Loading…
Reference in New Issue