feat: sample precipitation at POIs, add download script
This commit is contained in:
parent
60ea19f2c4
commit
e977380817
|
@ -1,4 +1,5 @@
|
||||||
/target
|
/target
|
||||||
|
|
||||||
input
|
*.png
|
||||||
rv.png
|
config.toml
|
||||||
|
data/
|
||||||
|
|
|
@ -8,6 +8,15 @@ version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
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]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -32,6 +41,12 @@ version = "1.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder-lite"
|
name = "byteorder-lite"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -71,6 +86,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.12"
|
version = "0.3.12"
|
||||||
|
@ -112,6 +133,119 @@ dependencies = [
|
||||||
"miniz_oxide",
|
"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]]
|
[[package]]
|
||||||
name = "image"
|
name = "image"
|
||||||
version = "0.25.6"
|
version = "0.25.6"
|
||||||
|
@ -124,12 +258,28 @@ dependencies = [
|
||||||
"png",
|
"png",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.172"
|
version = "0.2.172"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libm"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
@ -143,9 +293,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.32.0"
|
version = "0.30.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbb8270bb4060bd76c6e96f20c52d80620f1d82a3470885694e41e0f81ef6fe7"
|
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
|
@ -166,6 +316,18 @@ version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
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]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.8"
|
version = "0.8.8"
|
||||||
|
@ -183,6 +345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
|
"libm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -215,10 +378,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proj"
|
name = "proj"
|
||||||
version = "0.30.0"
|
version = "0.29.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "58e0c01de214d7ea50ee6519969be9efdc6f0dc5ce6c64fbd4f054ea26d43ca4"
|
checksum = "3939f58cd2f8e5f3bba7fb76b3854956d39b1b76cec4fe5f65481d18f9c92d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"geo-types",
|
||||||
"libc",
|
"libc",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"proj-sys",
|
"proj-sys",
|
||||||
|
@ -227,9 +391,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proj-sys"
|
name = "proj-sys"
|
||||||
version = "0.26.0"
|
version = "0.25.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a208129995443a4c475464c33308274be1578993b0ad266c9139188ed0dc7e91"
|
checksum = "533a4ed2ab59f7605ecea26db7ed76572d30aed9d2a6a90738bc7f7e7b5a11d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cmake",
|
"cmake",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
@ -257,6 +421,23 @@ dependencies = [
|
||||||
"bitflags 2.9.1",
|
"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]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
@ -270,6 +451,35 @@ dependencies = [
|
||||||
"windows-sys",
|
"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]]
|
[[package]]
|
||||||
name = "shlex"
|
name = "shlex"
|
||||||
version = "1.3.0"
|
version = "1.3.0"
|
||||||
|
@ -282,6 +492,18 @@ version = "0.3.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
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]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.101"
|
version = "2.0.101"
|
||||||
|
@ -324,6 +546,47 @@ dependencies = [
|
||||||
"syn",
|
"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]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
@ -340,8 +603,11 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
name = "wetter"
|
name = "wetter"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"geo",
|
||||||
"image",
|
"image",
|
||||||
"proj",
|
"proj",
|
||||||
|
"serde",
|
||||||
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -417,6 +683,15 @@ version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.7.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xattr"
|
name = "xattr"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
|
|
|
@ -4,5 +4,8 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
geo = { version = "0.30.0", default-features = false, features = ["use-proj", "use-serde"] }
|
||||||
image = { version = "0.25.6", default-features = false, features = ["png"] }
|
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;
|
mod rv;
|
||||||
|
|
||||||
pub use rv::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::io::{Error as IoError, Read, Seek};
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::str::{self, FromStr, Utf8Error};
|
use std::str::{self, FromStr, Utf8Error};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ParseError {
|
pub enum ParseError {
|
||||||
IoError(IoError),
|
IoError(IoError),
|
||||||
|
@ -12,6 +12,19 @@ pub enum ParseError {
|
||||||
Utf8Error(Utf8Error),
|
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> {
|
pub struct Parser<R: Read + Seek> {
|
||||||
r: R,
|
r: R,
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,11 @@ compile_error!("Only little-endian architectures are supported.");
|
||||||
|
|
||||||
use crate::data::parser::{ParseError, Parser};
|
use crate::data::parser::{ParseError, Parser};
|
||||||
|
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
use std::io::{Read, Seek};
|
use std::io::{Read, Seek};
|
||||||
|
|
||||||
const DATA_LEN: usize = 1100 * 1200;
|
pub const DATA_LEN: usize = 1100 * 1200;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct VersionMismatch {
|
pub struct VersionMismatch {
|
||||||
|
@ -13,7 +15,16 @@ pub struct VersionMismatch {
|
||||||
pub expected: u8,
|
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 struct Datetime {
|
||||||
pub year: u16,
|
pub year: u16,
|
||||||
pub month: u8,
|
pub month: u8,
|
||||||
|
@ -27,6 +38,7 @@ pub struct Rv {
|
||||||
timestamp: Datetime,
|
timestamp: Datetime,
|
||||||
version: u8,
|
version: u8,
|
||||||
precision: i8,
|
precision: i8,
|
||||||
|
interval: u16,
|
||||||
forecast: u16,
|
forecast: u16,
|
||||||
data: Vec<u16>,
|
data: Vec<u16>,
|
||||||
}
|
}
|
||||||
|
@ -68,7 +80,7 @@ impl Rv {
|
||||||
|
|
||||||
parser.expect("INT")?;
|
parser.expect("INT")?;
|
||||||
|
|
||||||
let _interval = parser.parse_int::<u16, 4>()?;
|
let interval = parser.parse_int::<_, 4>()?;
|
||||||
|
|
||||||
parser.expect("GP")?;
|
parser.expect("GP")?;
|
||||||
|
|
||||||
|
@ -102,6 +114,7 @@ impl Rv {
|
||||||
},
|
},
|
||||||
version,
|
version,
|
||||||
precision,
|
precision,
|
||||||
|
interval,
|
||||||
forecast,
|
forecast,
|
||||||
data,
|
data,
|
||||||
})
|
})
|
||||||
|
@ -122,6 +135,10 @@ impl Rv {
|
||||||
10_f64.powi(self.precision as i32)
|
10_f64.powi(self.precision as i32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn interval(&self) -> u16 {
|
||||||
|
self.interval
|
||||||
|
}
|
||||||
|
|
||||||
pub fn instant(&self) -> (Datetime, u16) {
|
pub fn instant(&self) -> (Datetime, u16) {
|
||||||
(self.timestamp, self.forecast)
|
(self.timestamp, self.forecast)
|
||||||
}
|
}
|
||||||
|
@ -130,3 +147,25 @@ impl Rv {
|
||||||
&self.data[..]
|
&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;
|
mod data;
|
||||||
|
|
||||||
use data::Rv;
|
use config::Config;
|
||||||
|
|
||||||
|
use data::{Rv, RV_DATA_LEN};
|
||||||
|
|
||||||
use image::imageops;
|
use image::imageops;
|
||||||
use image::RgbaImage;
|
use image::RgbaImage;
|
||||||
|
|
||||||
use proj::Proj;
|
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::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";
|
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,
|
Unknown = 0xd0d0d080,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
impl Intensity {
|
||||||
let rv = Rv::parse(BufReader::new(File::open("input").unwrap())).unwrap();
|
fn from_rv_value(v: u16, scale: f64, interval: u16) -> Self {
|
||||||
rv.expect_version(5).unwrap();
|
if v == 0x29c4 {
|
||||||
|
|
||||||
let mut data = Vec::with_capacity(1100 * 1200 * 4);
|
|
||||||
|
|
||||||
for v in rv.data() {
|
|
||||||
let intensity = if *v == 0x29c4 {
|
|
||||||
Intensity::Unknown
|
Intensity::Unknown
|
||||||
} else {
|
} 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 {
|
if mm_per_h < 0.1 {
|
||||||
Intensity::None
|
Intensity::None
|
||||||
} else if mm_per_h < 5.0 {
|
} else if mm_per_h < 5.0 {
|
||||||
|
@ -41,23 +44,85 @@ fn main() {
|
||||||
} else {
|
} else {
|
||||||
Intensity::Heavy
|
Intensity::Heavy
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data.extend_from_slice(&(intensity as u32).to_be_bytes());
|
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 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 mut img = RgbaImage::from_raw(1100, 1200, data).unwrap();
|
let Reverse(current) = heap.pop().ok_or("At least one file must be given")?;
|
||||||
imageops::flip_vertical_in_place(&mut img);
|
|
||||||
img.save("rv.png").unwrap();
|
|
||||||
|
|
||||||
let wgs84_to_de1200 = Proj::new(PROJ_WGS84_DE1200).unwrap();
|
let (timestamp, offset) = current.instant();
|
||||||
println!(
|
|
||||||
"{:#?}",
|
if offset != 0 {
|
||||||
wgs84_to_de1200
|
eprintln!(
|
||||||
.project(
|
"First file is expected to contain current situation, got forecast for +{} minutes",
|
||||||
(1.463301510_f64.to_radians(), 55.86208711_f64.to_radians()),
|
offset
|
||||||
false
|
);
|
||||||
)
|
}
|
||||||
.unwrap()
|
|
||||||
);
|
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