add layer button

This commit is contained in:
Tsuki 2024-01-13 21:54:39 +08:00
parent b70b86e71c
commit 79189212c2
30 changed files with 1136 additions and 632 deletions

459
Cargo.lock generated
View File

@ -37,6 +37,21 @@ dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "ansi_term"
version = "0.12.1"
@ -274,6 +289,20 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets 0.48.1",
]
[[package]]
name = "cinrad_g"
version = "0.1.0"
@ -298,6 +327,8 @@ dependencies = [
"ndarray",
"npyz",
"num-traits",
"plotters",
"plotters-backend",
"proj",
"proj-sys",
"proj5",
@ -308,6 +339,7 @@ dependencies = [
"shapefile",
"svg",
"thiserror",
"tokio",
"topojson",
]
@ -362,12 +394,70 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
[[package]]
name = "const-cstr"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed3d0b5ff30645a68f35ece8cea4556ca14ef8a1651455f789a099a0513532a6"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
[[package]]
name = "core-graphics"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-graphics-types",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics-types"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"libc",
]
[[package]]
name = "core-text"
version = "19.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"
dependencies = [
"core-foundation",
"core-graphics",
"foreign-types",
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.2.8"
@ -532,6 +622,48 @@ dependencies = [
"subtle",
]
[[package]]
name = "dirs-next"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [
"libc",
"redox_users",
"winapi",
]
[[package]]
name = "dlib"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
dependencies = [
"libloading 0.8.0",
]
[[package]]
name = "dwrote"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b"
dependencies = [
"lazy_static",
"libc",
"winapi",
"wio",
]
[[package]]
name = "earcutr"
version = "0.4.2"
@ -643,7 +775,7 @@ checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"redox_syscall 0.2.16",
"windows-sys",
]
@ -657,6 +789,12 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "float-ord"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bad48618fdb549078c333a7a8528acb57af271d0433bdecd523eb620628364e"
[[package]]
name = "float_next_after"
version = "1.0.0"
@ -682,12 +820,73 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "font-kit"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21fe28504d371085fae9ac7a3450f0b289ab71e07c8e57baa3fb68b9e57d6ce5"
dependencies = [
"bitflags 1.3.2",
"byteorder",
"core-foundation",
"core-graphics",
"core-text",
"dirs-next",
"dwrote",
"float-ord",
"freetype",
"lazy_static",
"libc",
"log",
"pathfinder_geometry",
"pathfinder_simd",
"walkdir",
"winapi",
"yeslogic-fontconfig-sys",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fragile"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
[[package]]
name = "freetype"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6"
dependencies = [
"freetype-sys",
"libc",
]
[[package]]
name = "freetype-sys"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a"
dependencies = [
"cmake",
"libc",
"pkg-config",
]
[[package]]
name = "futures"
version = "0.3.28"
@ -1278,6 +1477,29 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "iana-time-zone"
version = "0.1.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
@ -1459,6 +1681,17 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "libredox"
version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [
"bitflags 2.3.3",
"libc",
"redox_syscall 0.4.1",
]
[[package]]
name = "lock_api"
version = "0.4.10"
@ -1757,6 +1990,25 @@ dependencies = [
"proc-macro-hack",
]
[[package]]
name = "pathfinder_geometry"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3"
dependencies = [
"log",
"pathfinder_simd",
]
[[package]]
name = "pathfinder_simd"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0444332826c70dc47be74a7c6a5fc44e23a7905ad6858d4162b658320455ef93"
dependencies = [
"rustc_version",
]
[[package]]
name = "pbkdf2"
version = "0.11.0"
@ -1841,9 +2093,9 @@ dependencies = [
[[package]]
name = "pin-project-lite"
version = "0.2.10"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "pin-utils"
@ -1857,6 +2109,52 @@ version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "plotters"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45"
dependencies = [
"chrono",
"font-kit",
"image",
"lazy_static",
"num-traits",
"pathfinder_geometry",
"plotters-backend",
"plotters-bitmap",
"plotters-svg",
"ttf-parser 0.17.1",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609"
[[package]]
name = "plotters-bitmap"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cebbe1f70205299abc69e8b295035bb52a6a70ee35474ad10011f0a4efb8543"
dependencies = [
"gif",
"image",
"plotters-backend",
]
[[package]]
name = "plotters-svg"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab"
dependencies = [
"plotters-backend",
]
[[package]]
name = "png"
version = "0.17.9"
@ -2056,6 +2354,26 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "redox_users"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]]
name = "regex"
version = "1.8.4"
@ -2169,7 +2487,7 @@ dependencies = [
"bitflags 1.3.2",
"bytemuck",
"smallvec",
"ttf-parser",
"ttf-parser 0.18.1",
"unicode-bidi-mirroring",
"unicode-ccc",
"unicode-general-category",
@ -2182,6 +2500,15 @@ version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
@ -2488,11 +2815,10 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]]
name = "tokio"
version = "1.29.1"
version = "1.35.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da"
checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
dependencies = [
"autocfg",
"backtrace",
"num_cpus",
"pin-project-lite",
@ -2596,6 +2922,12 @@ dependencies = [
"syn 2.0.29",
]
[[package]]
name = "ttf-parser"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
[[package]]
name = "ttf-parser"
version = "0.18.1"
@ -2686,6 +3018,16 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
@ -2804,13 +3146,22 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.52.0",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
"windows-targets 0.48.1",
]
[[package]]
@ -2819,13 +3170,28 @@ version = "0.48.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
]
[[package]]
name = "windows-targets"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
dependencies = [
"windows_aarch64_gnullvm 0.52.0",
"windows_aarch64_msvc 0.52.0",
"windows_i686_gnu 0.52.0",
"windows_i686_msvc 0.52.0",
"windows_x86_64_gnu 0.52.0",
"windows_x86_64_gnullvm 0.52.0",
"windows_x86_64_msvc 0.52.0",
]
[[package]]
@ -2834,42 +3200,84 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_i686_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
[[package]]
name = "winnow"
version = "0.4.7"
@ -2879,6 +3287,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "wio"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
dependencies = [
"winapi",
]
[[package]]
name = "x11"
version = "2.21.0"
@ -2907,6 +3324,18 @@ dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "yeslogic-fontconfig-sys"
version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2bbd69036d397ebbff671b1b8e4d918610c181c5a16073b96f984a38d08c386"
dependencies = [
"const-cstr",
"dlib",
"once_cell",
"pkg-config",
]
[[package]]
name = "zip"
version = "0.6.6"

View File

@ -38,6 +38,10 @@ rstar = "*"
geo = "0.26.0"
topojson = "0.5.1"
geojson = "0.24.1"
plotters = "0.3.5"
plotters-backend = "0.3.5"
tokio = "1.35.1"
# plotters-cairo = "0.5.0"

View File

@ -77,3 +77,11 @@
// RenderConfig { padding: [50.0;4] }
// )
// )
// Layer::grid_render_layer_with_path(
// "/users/tsuki/projects/radar-g/test2.npz",
// Npz,
// BoundaryNorm::default(),
// )

341
src/chart/backend.rs Normal file
View File

@ -0,0 +1,341 @@
use cairo::{Context as CairoContext, FontSlant, FontWeight};
use plotters_backend::text_anchor::{HPos, VPos};
#[allow(unused_imports)]
use plotters_backend::{
BackendColor, BackendCoord, BackendStyle, BackendTextStyle, DrawingBackend, DrawingErrorKind,
FontStyle, FontTransform,
};
/// The drawing backend that is backed with a Cairo context
pub struct CairoBackend<'a> {
context: &'a CairoContext,
width: u32,
height: u32,
init_flag: bool,
}
#[derive(Debug)]
pub struct CairoError;
impl std::fmt::Display for CairoError {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{:?}", self)
}
}
impl std::error::Error for CairoError {}
impl<'a> CairoBackend<'a> {
fn set_color(&self, color: &BackendColor) {
self.context.set_source_rgba(
f64::from(color.rgb.0) / 255.0,
f64::from(color.rgb.1) / 255.0,
f64::from(color.rgb.2) / 255.0,
color.alpha,
);
}
fn set_stroke_width(&self, width: u32) {
self.context.set_line_width(f64::from(width));
}
fn set_font<S: BackendTextStyle>(&self, font: &S) {
match font.style() {
FontStyle::Normal => self.context.select_font_face(
font.family().as_str(),
FontSlant::Normal,
FontWeight::Normal,
),
FontStyle::Bold => self.context.select_font_face(
font.family().as_str(),
FontSlant::Normal,
FontWeight::Bold,
),
FontStyle::Oblique => self.context.select_font_face(
font.family().as_str(),
FontSlant::Oblique,
FontWeight::Normal,
),
FontStyle::Italic => self.context.select_font_face(
font.family().as_str(),
FontSlant::Italic,
FontWeight::Normal,
),
};
self.context.set_font_size(font.size());
}
pub fn new(context: &'a CairoContext, (w, h): (u32, u32)) -> Result<Self, CairoError> {
Ok(Self {
context,
width: w,
height: h,
init_flag: false,
})
}
}
impl<'a> DrawingBackend for CairoBackend<'a> {
type ErrorType = cairo::Error;
fn get_size(&self) -> (u32, u32) {
(self.width, self.height)
}
fn ensure_prepared(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
if !self.init_flag {
let (x0, y0, x1, y1) = self
.context
.clip_extents()
.map_err(DrawingErrorKind::DrawingError)?;
self.context.scale(
(x1 - x0) / f64::from(self.width),
(y1 - y0) / f64::from(self.height),
);
self.init_flag = true;
}
Ok(())
}
fn present(&mut self) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
Ok(())
}
fn draw_pixel(
&mut self,
point: BackendCoord,
color: BackendColor,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
self.context
.rectangle(f64::from(point.0), f64::from(point.1), 1.0, 1.0);
self.context.set_source_rgba(
f64::from(color.rgb.0) / 255.0,
f64::from(color.rgb.1) / 255.0,
f64::from(color.rgb.2) / 255.0,
color.alpha,
);
self.context
.fill()
.map_err(DrawingErrorKind::DrawingError)?;
Ok(())
}
fn draw_line<S: BackendStyle>(
&mut self,
from: BackendCoord,
to: BackendCoord,
style: &S,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
self.set_color(&style.color());
self.set_stroke_width(style.stroke_width());
self.context.move_to(f64::from(from.0), f64::from(from.1));
self.context.line_to(f64::from(to.0), f64::from(to.1));
self.context
.stroke()
.map_err(DrawingErrorKind::DrawingError)?;
Ok(())
}
fn draw_rect<S: BackendStyle>(
&mut self,
upper_left: BackendCoord,
bottom_right: BackendCoord,
style: &S,
fill: bool,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
self.set_color(&style.color());
self.set_stroke_width(style.stroke_width());
self.context.rectangle(
f64::from(upper_left.0),
f64::from(upper_left.1),
f64::from(bottom_right.0 - upper_left.0),
f64::from(bottom_right.1 - upper_left.1),
);
if fill {
self.context
.fill()
.map_err(DrawingErrorKind::DrawingError)?;
} else {
self.context
.stroke()
.map_err(DrawingErrorKind::DrawingError)?;
}
Ok(())
}
fn draw_path<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
&mut self,
path: I,
style: &S,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
self.set_color(&style.color());
self.set_stroke_width(style.stroke_width());
let mut path = path.into_iter();
if let Some((x, y)) = path.next() {
self.context.move_to(f64::from(x), f64::from(y));
}
for (x, y) in path {
self.context.line_to(f64::from(x), f64::from(y));
}
self.context
.stroke()
.map_err(DrawingErrorKind::DrawingError)?;
Ok(())
}
fn fill_polygon<S: BackendStyle, I: IntoIterator<Item = BackendCoord>>(
&mut self,
path: I,
style: &S,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
self.set_color(&style.color());
self.set_stroke_width(style.stroke_width());
let mut path = path.into_iter();
if let Some((x, y)) = path.next() {
self.context.move_to(f64::from(x), f64::from(y));
for (x, y) in path {
self.context.line_to(f64::from(x), f64::from(y));
}
self.context.close_path();
self.context
.fill()
.map_err(DrawingErrorKind::DrawingError)?;
}
Ok(())
}
fn draw_circle<S: BackendStyle>(
&mut self,
center: BackendCoord,
radius: u32,
style: &S,
fill: bool,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
self.set_color(&style.color());
self.set_stroke_width(style.stroke_width());
self.context.new_sub_path();
self.context.arc(
f64::from(center.0),
f64::from(center.1),
f64::from(radius),
0.0,
std::f64::consts::PI * 2.0,
);
if fill {
self.context
.fill()
.map_err(DrawingErrorKind::DrawingError)?;
} else {
self.context
.stroke()
.map_err(DrawingErrorKind::DrawingError)?;
}
Ok(())
}
fn estimate_text_size<S: BackendTextStyle>(
&self,
text: &str,
font: &S,
) -> Result<(u32, u32), DrawingErrorKind<Self::ErrorType>> {
self.set_font(font);
let extents = self
.context
.text_extents(text)
.map_err(DrawingErrorKind::DrawingError)?;
Ok((extents.width() as u32, extents.height() as u32))
}
fn draw_text<S: BackendTextStyle>(
&mut self,
text: &str,
style: &S,
pos: BackendCoord,
) -> Result<(), DrawingErrorKind<Self::ErrorType>> {
let color = style.color();
let (mut x, mut y) = (pos.0, pos.1);
let degree = match style.transform() {
FontTransform::None => 0.0,
FontTransform::Rotate90 => 90.0,
FontTransform::Rotate180 => 180.0,
FontTransform::Rotate270 => 270.0,
//FontTransform::RotateAngle(angle) => angle as f64,
} / 180.0
* std::f64::consts::PI;
if degree != 0.0 {
self.context
.save()
.map_err(DrawingErrorKind::DrawingError)?;
self.context.translate(f64::from(x), f64::from(y));
self.context.rotate(degree);
x = 0;
y = 0;
}
self.set_font(style);
self.set_color(&color);
let extents = self
.context
.text_extents(text)
.map_err(DrawingErrorKind::DrawingError)?;
let dx = match style.anchor().h_pos {
HPos::Left => 0.0,
HPos::Right => -extents.width(),
HPos::Center => -extents.width() / 2.0,
};
let dy = match style.anchor().v_pos {
VPos::Top => extents.height(),
VPos::Center => extents.height() / 2.0,
VPos::Bottom => 0.0,
};
self.context.move_to(
f64::from(x) + dx - extents.x_bearing(),
f64::from(y) + dy - extents.y_bearing() - extents.height(),
);
self.context
.show_text(text)
.map_err(DrawingErrorKind::DrawingError)?;
if degree != 0.0 {
self.context
.restore()
.map_err(DrawingErrorKind::DrawingError)?;
}
Ok(())
}
}

19
src/chart/imp.rs Normal file
View File

@ -0,0 +1,19 @@
use gtk::subclass::prelude::*;
use gtk::{glib, prelude::WidgetExtManual};
use std::cell::{Cell, RefCell};
#[derive(Default)]
pub struct Chart {}
#[glib::object_subclass]
impl ObjectSubclass for Chart {
const NAME: &'static str = "Chart";
type Type = super::Chart;
type ParentType = gtk::DrawingArea;
}
impl ObjectImpl for Chart {}
impl WidgetImpl for Chart {}
impl DrawingAreaImpl for Chart {}

110
src/chart/mod.rs Normal file
View File

@ -0,0 +1,110 @@
mod backend;
mod imp;
use self::backend::CairoBackend;
use crate::render::{Render, RenderConfig, RenderMotion};
use glib::{clone, ObjectExt};
use gtk::prelude::*;
use gtk::{glib, AspectFrame};
use plotters::prelude::*;
glib::wrapper! {
pub struct Chart(ObjectSubclass<imp::Chart>)
@extends gtk::DrawingArea, gtk::Widget;
}
impl Chart {
pub fn new() -> Self {
let this: Self = glib::Object::new();
this.set_hexpand(true);
this.set_vexpand(true);
this.set_draw_func(|_s, context, w, h| {
let root_area = CairoBackend::new(context, (w as u32, h as u32))
.expect("Can't create backend")
.into_drawing_area();
root_area.fill(&BLACK).unwrap();
let root_area = root_area.titled("Image Title", ("sans-serif", 60)).unwrap();
let (upper, lower) = root_area.split_vertically(512);
let x_axis = (-3.4f32..3.4).step(0.1);
let mut cc = ChartBuilder::on(&upper)
.margin(5)
.set_all_label_area_size(50)
.caption("Sine and Cosine", ("sans-serif", 40))
.build_cartesian_2d(-3.4f32..3.4, -1.2f32..1.2f32).unwrap();
cc.configure_mesh()
.x_labels(20)
.y_labels(10)
.disable_mesh()
.x_label_formatter(&|v| format!("{:.1}", v))
.y_label_formatter(&|v| format!("{:.1}", v))
.draw().unwrap();
cc.draw_series(LineSeries::new(x_axis.values().map(|x| (x, x.sin())), &RED)).unwrap()
.label("Sine")
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], RED));
cc.draw_series(LineSeries::new(
x_axis.values().map(|x| (x, x.cos())),
&BLUE,
)).unwrap()
.label("Cosine")
.legend(|(x, y)| PathElement::new(vec![(x, y), (x + 20, y)], BLUE));
cc.configure_series_labels().border_style(WHITE).draw().unwrap();
/*
// It's possible to use a existing pointing element
cc.draw_series(PointSeries::<_, _, Circle<_>>::new(
(-3.0f32..2.1f32).step(1.0).values().map(|x| (x, x.sin())),
5,
Into::<ShapeStyle>::into(&RGBColor(255,0,0)).filled(),
)).unwrap();*/
// Otherwise you can use a function to construct your pointing element yourself
cc.draw_series(PointSeries::of_element(
(-3.0f32..2.1f32).step(1.0).values().map(|x| (x, x.sin())),
5,
ShapeStyle::from(&RED).filled(),
&|coord, size, style| {
EmptyElement::at(coord)
+ Circle::new((0, 0), size, style)
+ Text::new(format!("{:.?}", coord), (0, 15), ("sans-serif", 15))
},
)).unwrap();
let drawing_areas = lower.split_evenly((1, 2));
for (drawing_area, idx) in drawing_areas.iter().zip(1..) {
let mut cc = ChartBuilder::on(drawing_area)
.x_label_area_size(30)
.y_label_area_size(30)
.margin_right(20)
.caption(format!("y = x^{}", 1 + 2 * idx), ("sans-serif", 40))
.build_cartesian_2d(-1f32..1f32, -1f32..1f32).unwrap();
cc.configure_mesh()
.x_labels(5)
.y_labels(3)
.max_light_lines(4)
.draw().unwrap();
cc.draw_series(LineSeries::new(
(-1f32..1f32)
.step(0.01)
.values()
.map(|x| (x, x.powf(idx as f32 * 2.0 + 1.0))),
&BLUE,
)).unwrap();
}
// To avoid the IO failure being ignored silently, we manually call the present function
root_area.present().expect("Unable to write result to file, please make sure 'plotters-doc-data' dir exists under current dir");
});
this
}
}

View File

@ -1,12 +1,34 @@
use std::fmt::Debug;
use crate::render::Layer;
pub enum MonitorInputMsg {
AddLayer(Layer),
RemoveLayer(usize),
UpdateLayer((usize, Box<dyn Fn(&mut Layer) + 'static>)),
None,
}
impl Debug for MonitorInputMsg {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MonitorInputMsg::AddLayer(_) => write!(f, "MonitorInputMsg::AddLayer"),
MonitorInputMsg::RemoveLayer(_) => write!(f, "MonitorInputMsg::RemoveLayer"),
MonitorInputMsg::UpdateLayer(_) => write!(f, "MonitorInputMsg::UpdateLayer"),
MonitorInputMsg::None => write!(f, "MonitorInputMsg::None"),
}
}
}
#[derive(Debug)]
pub enum MonitorOutputMsg {
LayerAdded(usize),
LayerRemoved(usize),
LayerUpdated(usize),
}
#[derive(Debug)]
pub enum RenderInputMsg {
AddLayer(Layer),
RemoveLayer(usize),
MoveLayer(usize, usize),
SetLayerVisibility(usize, bool),
EditLayer(usize),
Monitor(MonitorInputMsg),
}

View File

@ -1,4 +1,4 @@
pub mod monitor;
pub mod sidebar;
pub mod render;
pub mod sidebar;
pub use monitor::MonitorModel;

View File

@ -1,23 +1,46 @@
use super::{render::render::RenderModel, sidebar::sidebar::SideBarModel};
use crate::{
components::render_panel::messages::{MonitorInputMsg, MonitorOutputMsg},
render::{Layer, Render},
};
use super::{render::render::RenderModel, sidebar::{sidebar::SideBarModel, SideBarOutputMsg}};
use adw::prelude::*;
use relm4::*;
pub struct MonitorModel {
render: Controller<RenderModel>,
sidebar_open: bool,
sidebar_width: i32,
layers: Vec<Layer>,
sidebar: Controller<SideBarModel>,
}
pub struct MonitorWidgets {
paned: gtk::Paned,
}
#[relm4::component(pub)]
impl SimpleComponent for MonitorModel {
type Init = ();
type Output = ();
type Input = ();
type Output = MonitorOutputMsg;
type Input = MonitorInputMsg;
view! {
adw::OverlaySplitView {
set_sidebar_position:gtk::PackType::End,
adw::BreakpointBin {
set_hexpand: true,
set_vexpand: true,
set_height_request: 500,
set_width_request: 700,
#[wrap(Some)]
set_sidebar = &adw::NavigationPage::builder().title("sidebar").child(model.sidebar.widget()).build(),
set_child=&gtk::Paned{
set_position: 1000,
#[wrap(Some)]
set_content = &adw::NavigationPage::builder().title("content").child(model.render.widget()).build(),
#[name="render"]
set_start_child=&Render{
#[watch]
set_interior_layers: model.layers.clone(),
},
#[wrap(Some)]
set_end_child=model.sidebar.widget(),
}
}
}
@ -28,19 +51,45 @@ impl SimpleComponent for MonitorModel {
) -> relm4::ComponentParts<Self> {
let sidebar: Controller<SideBarModel> = SideBarModel::builder()
.launch(())
.forward(sender.input_sender(), |msg| {});
let render: Controller<RenderModel> = RenderModel::builder()
.launch((None, None))
.forward(sender.input_sender(), |msg| {});
let model = MonitorModel { render, sidebar };
let widgets = view_output!();
.forward(sender.input_sender(), |msg| match msg {
SideBarOutputMsg::NewLayer(layer) => MonitorInputMsg::AddLayer(layer),
});
let model = MonitorModel {
sidebar_open: true,
sidebar_width: 400,
layers: vec![],
sidebar,
};
let widgets = view_output! {};
ComponentParts { model, widgets }
}
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {}
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>) {
match msg {
MonitorInputMsg::AddLayer(layer) => {
self.layers.push(layer);
_sender
.output_sender()
.send(MonitorOutputMsg::LayerAdded(0))
.unwrap();
}
MonitorInputMsg::RemoveLayer(index) => {
self.layers.remove(index);
_sender
.output_sender()
.send(MonitorOutputMsg::LayerRemoved(0))
.unwrap();
}
MonitorInputMsg::UpdateLayer((idx, f)) => {
f(&mut self.layers[idx]);
_sender
.output_sender()
.send(MonitorOutputMsg::LayerUpdated(0))
.unwrap();
}
MonitorInputMsg::None => {}
}
}
}

View File

@ -1,3 +1,4 @@
use glib::clone;
use gtk::prelude::*;
use relm4::{
binding::{Binding, U8Binding},
@ -5,6 +6,8 @@ use relm4::{
typed_list_view::{RelmListItem, TypedListView},
RelmObjectExt,
};
use crate::{chart::Chart, render::{Layer, predefined::color_mapper::BoundaryNorm}, data::Npz};
pub struct SideBarModel {
counter: u8,
list_view_wrapper: TypedListView<MyListItem, gtk::SingleSelection>,
@ -17,10 +20,15 @@ pub enum Msg {
OnlyShowEven(bool),
}
#[derive(Debug)]
pub enum SideBarOutputMsg {
NewLayer(Layer),
}
#[relm4::component(pub)]
impl SimpleComponent for SideBarModel {
type Init = ();
type Output = ();
type Output = SideBarOutputMsg;
type Input = Msg;
view! {
@ -33,17 +41,21 @@ impl SimpleComponent for SideBarModel {
append_page:(&page_1, Some(&label)),
},
gtk::Button {
set_label: "Append 10 items",
connect_clicked => Msg::Append,
set_label: "Add Layer",
connect_clicked[sender] => move |_| {
sender.output(
SideBarOutputMsg::NewLayer(
Layer::grid_render_layer_with_path(
"/users/tsuki/projects/radar-g/test2.npz",
Npz,
BoundaryNorm::default(),
)
)
).unwrap()
},
gtk::Button {
set_label: "Remove second item",
connect_clicked => Msg::Remove,
},
gtk::ScrolledWindow {
set_vexpand: true,
#[local_ref]
my_view -> gtk::ListView {}
}
@ -69,7 +81,19 @@ impl SimpleComponent for SideBarModel {
};
let my_view = &model.list_view_wrapper.view;
let page_1 = gtk::Box::new(gtk::Orientation::Vertical, 5);
let page_1 = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.vexpand(true)
.hexpand(true)
.build();
let chart = Chart::new();
chart.connect_resize(clone!(@weak chart as my_view => move |_, w,h|{
my_view.set_height_request((w as f32 / 16.0 * 3.0) as i32);
}));
page_1.append(&chart);
let label = gtk::Label::new(Some("Page 1"));
let widgets = view_output!();

View File

1
src/dealers/mod.rs Normal file
View File

@ -0,0 +1 @@
mod layer_handler;

View File

@ -1,24 +1,19 @@
use coords::proj::Mercator;
use coords::Mapper;
use data::{Npz, Radar2d};
use femtovg::{Color, Paint};
mod utils;
use gtk::prelude::*;
use gtk::{gio, glib, Application, ApplicationWindow};
use relm4::menu;
use relm4::RelmApp;
use std::ptr;
mod chart;
mod components;
mod coords;
mod data;
mod dealers;
mod errors;
mod monitor;
mod pipeline;
mod render;
mod window;
use components::app::{AppMode, AppModel};
use monitor::Monitor;
use render::{BackgroundConfig, BackgroundWidget, ForegroundConfig, ForegroundWidget, Render};
const APP_ID: &str = "org.gtk_rs.HelloWorld2";

View File

@ -1,29 +0,0 @@
use crate::render::Render;
use glib::subclass::InitializingObject;
use gtk::subclass::prelude::*;
use gtk::CompositeTemplate;
use gtk::{glib, prelude::WidgetExtManual};
use std::cell::{Cell, RefCell};
#[derive(Default)]
pub struct Monitor {
pub(super) renderer: RefCell<Render>,
}
#[glib::object_subclass]
impl ObjectSubclass for Monitor {
const NAME: &'static str = "Monitor";
type Type = super::Monitor;
type ParentType = gtk::Box;
}
impl ObjectImpl for Monitor {}
impl WidgetImpl for Monitor {
fn size_allocate(&self, width: i32, height: i32, baseline: i32) {
println!("new width {}", width);
self.parent_size_allocate(width, height, baseline)
}
}
impl BoxImpl for Monitor {}

View File

@ -1,92 +0,0 @@
mod imp;
use crate::render::{Render, RenderMotion, RenderConfig};
use adw::prelude::{ButtonExt, GLAreaExt, GestureDragExt};
use glib::subclass::prelude::*;
use glib::{clone, ObjectExt};
use gtk::traits::WidgetExt;
use gtk::{glib, AspectFrame};
use gtk::{EventControllerScrollFlags, Inhibit};
glib::wrapper! {
pub struct Monitor(ObjectSubclass<imp::Monitor>)
@extends gtk::Box,gtk::Widget;
}
impl Monitor {
pub fn new(config:RenderConfig) -> Self {
let this: Self = glib::Object::new();
let pointer_location_detecture = gtk::EventControllerMotion::new();
let render = Render::new(None, config);
pointer_location_detecture.connect_motion(
clone!(@weak this as s, @weak render as r => move |_context, x, y| {
r.update_status(|s| {
let dpi = r.scale_factor();
let (_,h) = s.window_size;
s.pointer_location = (x as f32 * dpi as f32, h as f32 - y as f32 * dpi as f32);
});
}
),
);
let scale_detecture = gtk::EventControllerScroll::new(EventControllerScrollFlags::VERTICAL);
scale_detecture.connect_scroll(clone!(
@weak this as s, @weak render as r => @default-panic,move |_context, _x, y| {
r.update_status(|status|{
status.scale = y as f32;
status.motion = RenderMotion::Scale;
});
r.queue_render();
Inhibit(false)
}
));
let drag_detecture = gtk::GestureDrag::new();
drag_detecture.connect_drag_update(clone!(
@weak render as r => move |this, _, _| {
let (ox, oy) = this.offset().unwrap_or((0.0,0.0));
r.update_status(|s| {
s.translate = Some((-ox as f32 * 1.35, oy as f32 * 1.35));
s.motion = RenderMotion::Translate;
});
r.queue_render();
}));
drag_detecture.connect_drag_end(clone!(
@weak render as r => move |_,_,_|{
r.update_status(|cfg| {
cfg.translate = None;
cfg.motion = RenderMotion::Translate;
})
}
r.queue_render();
));
let split_view = adw::OverlaySplitView::new();
let sidebar = adw::NavigationPage::builder().title("sidebar").child(&gtk::ListView::builder().build()).build();
let content = adw::NavigationPage::builder().title("content").child(&render).build();
split_view.set_sidebar_position(gtk::PackType::End);
split_view.set_sidebar(Some(&sidebar));
split_view.set_content(Some(&content));
render.add_controller(pointer_location_detecture);
render.add_controller(scale_detecture);
render.add_controller(drag_detecture);
// render.set_hexpand(true);
// render.set_vexpand(true);
split_view.set_parent(&this);
split_view.set_hexpand(true);
split_view.set_vexpand(true);
// paned.set_parent(&this);
// render.set_parent(&this);
// aspect_frame.set_hexpand(true);
// aspect_frame.set_vexpand(true);
// aspect_frame.set_parent(&this);
this.imp().renderer.replace(render);
this
}
}

View File

@ -1,13 +1,12 @@
use super::layer::foreground::exterior::ExteriorWidget;
use super::layer::foreground::interior::InteriorWidget;
use super::WindowCoord;
use super::exterior::ExteriorWidget;
use super::interior::InteriorWidget;
use super::{Layer, WindowCoord};
use crate::coords::proj::Mercator;
use crate::coords::Mapper;
use femtovg::{Color, FontId, Paint, Path, Transform2D};
use femtovg::{Canvas, Color, FontId};
use gtk::glib;
use gtk::subclass::prelude::*;
use gtk::traits::{GLAreaExt, WidgetExt};
use ndarray::Array2;
use std::cell::RefCell;
use std::num::NonZeroU32;
@ -29,16 +28,16 @@ impl Default for RenderMotion {
}
}
#[derive(Debug, Default, Clone)]
#[derive(Default)]
pub struct RenderStatus {
pub window_size: (i32, i32),
pub(super) window_size: (i32, i32),
pub(super) scale_rate: Option<f64>,
pub(super) pointer_location: WindowCoord,
pub(super) motion: RenderMotion,
pub(super) scale: f32,
pub(super) translate: Option<(f32, f32)>,
translation: Option<(f64, f64)>,
init_translation: (f64, f64),
pub pointer_location: WindowCoord,
pub motion: RenderMotion,
pub scale: f32,
pub translate: Option<(f32, f32)>,
}
struct Fonts {
@ -50,10 +49,11 @@ struct Fonts {
pub struct Render {
pub(super) exterior: RefCell<ExteriorWidget>,
pub(super) interior: RefCell<InteriorWidget>,
pub(super) canvas: RefCell<Option<femtovg::Canvas<femtovg::renderer::OpenGl>>>,
pub config: RefCell<RenderConfig>,
pub status: RefCell<RenderStatus>,
pub mapper: RefCell<Mapper>,
pub(super) canvas: RefCell<Option<femtovg::Canvas<femtovg::renderer::OpenGl>>>,
pub(super) interior_layers: RefCell<Vec<Layer>>,
}
impl Default for Render {
@ -61,6 +61,7 @@ impl Default for Render {
Self {
exterior: RefCell::new(ExteriorWidget::default()),
interior: RefCell::new(InteriorWidget::default()),
interior_layers: RefCell::new(Vec::new()),
config: RefCell::new(RenderConfig::default()),
status: RefCell::new(RenderStatus::default()),
mapper: RefCell::new(Mercator::default().into()),
@ -169,11 +170,19 @@ impl GLAreaImpl for Render {
}
}
self.interior
.borrow()
.draw(canvas, &self.obj(), self.status.borrow(), configs);
let c = &(*self.interior_layers.borrow());
self.interior.borrow().draw(
c,
canvas,
&self.obj(),
self.status.borrow(),
configs,
);
self.exterior.borrow().draw(canvas, &self.obj());
canvas.flush();
true
}
@ -232,7 +241,10 @@ impl Render {
status.translation.and_then(|(tx, ty)| {
status.scale_rate.and_then(|scale| {
let (x1, y1) = (tx + padding[3] as f64, ty + padding[2] as f64);
let (x2, y2) = (tx + w * scale + padding[3] as f64, ty + h * scale + padding[2] as f64);
let (x2, y2) = (
tx + w * scale + padding[3] as f64,
ty + h * scale + padding[2] as f64,
);
let (x1, y1) = mapper.inverse_map((x1, y1)).unwrap();
let (x2, y2) = mapper.inverse_map((x2, y2)).unwrap();
Some(((x1, x2), (y1, y2)))
@ -242,7 +254,6 @@ impl Render {
pub(super) fn inverse_map(&self, loc: (f32, f32)) -> Option<(f64, f64)> {
let (x, y) = loc;
// let (_, h) = self.window_size().unwrap();
let status = self.status.borrow();
status.translation.and_then(|(tx, ty)| {
status.scale_rate.and_then(|scale| {
@ -257,9 +268,6 @@ impl Render {
}
pub(super) fn map(&self, loc: (f64, f64)) -> Option<(f32, f32)> {
// let padding = self.padding();
// let left_padding = padding[3];
// let bottom_padding = padding[2];
let (x, y) = loc;
let (_, h) = self.window_size().unwrap();
let status = self.status.borrow();

View File

@ -1,7 +1,4 @@
use crate::render::layer::background::BackgroundWidget;
use crate::render::layer::foreground::ForegroundWidget;
use crate::render::{imp, WindowCoord};
use femtovg::RenderTarget;
use crate::render::WindowCoord;
use gtk::glib;
use gtk::subclass::prelude::*;
use std::cell::RefCell;
@ -10,11 +7,8 @@ use super::layers::Layer;
#[derive(Default)]
pub struct InteriorWidget {
pub(super) background: RefCell<BackgroundWidget>,
pub(super) foreground: RefCell<ForegroundWidget>,
pub(super) trans: RefCell<WindowCoord>,
pub(super) update_trans: RefCell<WindowCoord>,
pub(super) layers: RefCell<Vec<Layer>>,
}
#[glib::object_subclass]

View File

@ -1,23 +1,19 @@
use geojson::GeoJson;
use std::{
any::Any,
cell::{Ref, RefCell}, fmt::Debug,
};
use topojson::TopoJson;
use crate::{
coords::{Coord, Mapper, Range},
render::{renders::DataRenderer, Render},
};
use crate::{coords::Range, render::Render};
use femtovg::{renderer::OpenGl, Canvas, ImageId};
use std::{
cell::{Ref, RefCell},
fmt::Debug, sync::Arc,
};
#[derive(Clone)]
pub struct Layer {
pub visiable: bool,
target: RefCell<Option<Target>>,
imp: RefCell<Option<Box<dyn LayerImpl>>>,
draw: Box<dyn Fn(&Self, &mut Canvas<OpenGl>, &Render, (f32, f32))>,
imp: RefCell<Option<Arc<dyn LayerImpl>>>,
draw: Arc<dyn Fn(&Self, &mut Canvas<OpenGl>, &Render, (f32, f32))>,
}
impl Debug for Layer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Layer")
@ -28,7 +24,7 @@ impl Debug for Layer {
}
}
pub trait LayerImpl:Debug {
pub trait LayerImpl: Debug {
fn draw(&self, canvas: &mut Canvas<OpenGl>, render: &Render) -> Option<Target>;
}
@ -44,8 +40,8 @@ impl Layer {
Layer {
visiable,
target: RefCell::new(None),
draw: Box::new(draw),
imp: RefCell::new(imp.map(|x| Box::new(x) as Box<dyn LayerImpl>)),
draw: Arc::new(draw),
imp: RefCell::new(imp.map(|x| Arc::new(x) as Arc<dyn LayerImpl>)),
}
}
@ -63,7 +59,7 @@ impl Layer {
self.target.borrow().clone()
}
pub fn get_imp(&self) -> Ref<Option<Box<dyn LayerImpl>>> {
pub fn get_imp(&self) -> Ref<Option<Arc<dyn LayerImpl>>> {
let im = self.imp.borrow();
im
}

View File

@ -1,18 +1,9 @@
mod imp;
mod layers;
use crate::coords::{Mapper, Range};
use crate::data::Npz;
use crate::data::{DataLoader, RadarData2d};
use crate::render::predefined::color_mapper::BoundaryNorm;
use crate::render::predefined::gis::MapRender;
use crate::render::renders::DataRenderer;
use crate::render::Render;
use femtovg::{renderer::OpenGl, Canvas, Color, Paint, Path};
use glib::subclass::types::ObjectSubclassIsExt;
use femtovg::{renderer::OpenGl, Canvas};
pub use layers::{Layer, LayerImpl, Target};
use ndarray::OwnedRepr;
use std::cell::Ref;
use std::ops::Deref;
use crate::render::imp::{RenderConfig, RenderStatus};
@ -29,27 +20,21 @@ impl Default for InteriorWidget {
impl InteriorWidget {
pub fn new() -> Self {
let this: Self = glib::Object::new();
this.imp().layers.replace(vec![
// Layer::grid_render_layer_with_path(
// "/users/tsuki/projects/radar-g/test2.npz",
// Npz,
// BoundaryNorm::default(),
// )
]);
this
}
pub fn draw(
&self,
layers: &Vec<Layer>,
canvas: &mut Canvas<OpenGl>,
render: &Render,
status: Ref<'_, RenderStatus>,
_c: Ref<'_, RenderConfig>,
) {
let mut layers = self.imp().layers.borrow_mut();
let (x, y) = (canvas.width(), canvas.height());
for layer in layers.iter_mut().filter(|x| x.visiable) {
for layer in layers.iter().filter(|x| x.visiable) {
layer.draw(canvas, &render, (x, y));
}
}

View File

@ -1,36 +0,0 @@
use crate::render::{imp, WindowCoord};
use femtovg::Paint;
use geo_macros::Prj;
use geo_types::MultiPolygon;
use gtk::glib;
use gtk::subclass::prelude::*;
use std::cell::RefCell;
#[derive(Prj, Default)]
pub struct BackgroundConfig {
pub show_lat_lines: bool,
pub show_lon_lines: bool,
pub lat_lines: Vec<f64>,
pub lon_lines: Vec<f64>,
pub painter: Paint,
}
impl BackgroundConfig {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Default)]
pub struct BackgroundWidget {
pub(super) config: RefCell<BackgroundConfig>,
pub(super) shp: RefCell<Option<Vec<MultiPolygon>>>
}
#[glib::object_subclass]
impl ObjectSubclass for BackgroundWidget {
const NAME: &'static str = "BackgroundWidget";
type Type = super::BackgroundWidget;
}
impl ObjectImpl for BackgroundWidget {}

View File

@ -1,238 +0,0 @@
mod imp;
use crate::coords::{Mapper, Range};
use femtovg::{renderer::OpenGl, Canvas, Color, Paint, Path};
use geo_types::{line_string, LineString, Point};
use glib::subclass::types::ObjectSubclassIsExt;
use shapefile;
use std::cell::Ref;
pub use self::imp::BackgroundConfig;
glib::wrapper! {
pub struct BackgroundWidget(ObjectSubclass<imp::BackgroundWidget>);
}
impl Default for BackgroundWidget {
fn default() -> Self {
Self::new(BackgroundConfig::default())
}
}
impl BackgroundWidget {
pub fn new(config: BackgroundConfig) -> Self {
let this: Self = glib::Object::new();
let imp = this.imp();
let polygons = shapefile::read_as::<_, shapefile::Polygon, shapefile::dbase::Record>(
"shp/ne_110m_admin_0_countries.shp",
)
.unwrap();
let polys: Vec<geo_types::MultiPolygon<f64>> = polygons
.into_iter()
.map(|(polygon, _)| polygon.into())
.collect();
imp.shp.replace(Some(polys));
imp.config.replace(config);
this
}
fn draw_lines<V: IntoIterator<Item = LineString<f32>>>(
&self,
canvas: &mut Canvas<OpenGl>,
line_painter: &Paint,
p: V,
) {
p.into_iter().for_each(|line| {
let mut path = Path::new();
let points: Vec<Point<f32>> = line.points().collect();
path.move_to(points[0].x() as f32, points[0].y() as f32);
points[1..].into_iter().for_each(|p| {
path.line_to(p.x() as f32, p.y() as f32);
});
canvas.stroke_path(&mut path, line_painter);
});
}
fn mesh_lines(
&self,
canvas: &mut Canvas<OpenGl>,
scale: f32,
translate: (f32, f32),
canvas_width: f32,
canvas_height: f32,
mapper: &Ref<'_, Mapper>,
bound: (Range, Range),
) {
let imp = self.imp();
let line_painter = &imp.config.borrow().painter;
let (left, right) = (bound.0 .0, bound.0 .1);
let (bottom, top) = (bound.1 .0, bound.1 .1);
let config = imp.config.borrow();
if config.show_lat_lines {
let r = config.lat_lines.iter().map(|lat| {
let line = LineString::new(vec![(left, *lat).into(), (right, *lat).into()]);
let result = mapper.map_line(&line).unwrap();
LineString::new(
result
.points()
.map(|p| {
(
p.x() as f32 * canvas_width * scale - translate.0,
p.y() as f32 * canvas_height * scale - translate.1,
)
.into()
})
.collect(),
)
});
self.draw_lines(canvas, line_painter, r);
}
if config.show_lat_lines {
config.lat_lines.iter().for_each(|lat| {
let mut paint = Paint::color(Color::white());
paint.set_font_size(25.0);
paint.set_line_width(1.0);
let (x, y) = self.map_to_screen(
mapper,
scale,
translate,
canvas_height,
canvas_width,
(left, *lat),
);
let _ = canvas.stroke_text(x, y, format!("{:.2} N", lat), &paint);
});
}
if config.show_lon_lines {
config.lon_lines.iter().for_each(|lon| {
let mut paint = Paint::color(Color::white());
paint.set_font_size(25.0);
paint.set_line_width(1.0);
let (x, y) = self.map_to_screen(
mapper,
scale,
translate,
canvas_height,
canvas_width,
(*lon + 0.5, bottom + 0.1),
);
let _ = canvas.stroke_text(x, y, format!("{:.2}", lon), &paint);
});
}
if imp.config.borrow().show_lon_lines {
let r = config.lon_lines.iter().map(|lon| {
let line = LineString::new(vec![(*lon, bottom).into(), (*lon, top).into()]);
let result = mapper.map_line(&line).unwrap();
LineString::new(
result
.points()
.map(|p| {
(
p.x() as f32 * canvas_width * scale - translate.0,
p.y() as f32 * canvas_height * scale - translate.1,
)
.into()
})
.collect(),
)
});
self.draw_lines(canvas, line_painter, r);
}
}
pub fn draw(
&self,
canvas: &mut Canvas<OpenGl>,
scale: f32,
dpi: i32,
width: f32,
hdight: f32,
translate: (f32, f32),
mapper: Ref<'_, Mapper>,
bound: (Range, Range),
) {
let config = self.imp().config.borrow();
self.mesh_lines(canvas, scale, translate, width, hdight, &mapper, bound);
self.shp(mapper, canvas, translate, scale, width, hdight);
}
fn shp(
&self,
mapper: Ref<'_, Mapper>,
canvas: &mut Canvas<OpenGl>,
translate: (f32, f32),
scale: f32,
canvas_width: f32,
canvas_height: f32,
) {
if let Some(s) = self.imp().shp.borrow().as_ref() {
for p in s.iter() {
for poly in p.iter() {
let mut points = poly.exterior().points();
let first_point = points.next().unwrap();
let mut path = Path::new();
let first = self.map_to_screen(
&mapper,
scale,
translate,
canvas_height,
canvas_width,
(first_point.x(), first_point.y()),
);
path.move_to(first.0, first.1);
for p in points {
let (nx, ny) = self.map_to_screen(
&mapper,
scale,
translate,
canvas_height,
canvas_width,
(p.x(), p.y()),
);
path.line_to(nx, ny);
}
canvas.stroke_path(&path, &Paint::color(Color::white()));
}
}
}
}
#[inline]
fn map_to_screen(
&self,
mapper: &Ref<'_, Mapper>,
scale: f32,
translate: (f32, f32),
canvas_height: f32,
canvas_width: f32,
point: (f64, f64),
) -> (f32, f32) {
let (x, y) = mapper.map(point).unwrap();
(
x as f32 * canvas_width * scale - translate.0,
y as f32 * canvas_height * scale - translate.1,
)
}
pub fn set_lat_lines(&self, lat_lines: Vec<f64>) {
let imp = self.imp();
imp.config.borrow_mut().lat_lines = lat_lines;
}
pub fn set_lon_lines(&self, lon_lines: Vec<f64>) {
let imp = self.imp();
imp.config.borrow_mut().lon_lines = lon_lines;
}
}

View File

@ -1,42 +0,0 @@
use crate::render::{imp, WindowCoord};
use femtovg::{Color, ImageId, Paint, RenderTarget};
use geo_macros::Prj;
use geo_types::LineString;
use gtk::glib;
use gtk::subclass::prelude::*;
use ndarray::Array2;
use std::cell::RefCell;
use std::collections::HashMap;
#[derive(Prj, Default)]
pub struct ForegroundConfig {
pub show_lat_lines: bool,
pub show_lon_lines: bool,
pub lat_lines: Vec<Vec<WindowCoord>>,
pub lon_lines: Vec<Vec<WindowCoord>>,
pub painter: Paint,
}
impl ForegroundConfig {
pub fn new() -> Self {
Self::default()
}
}
#[derive(Default)]
pub struct ForegroundWidget {
pub(super) config: RefCell<ForegroundConfig>,
pub(super) dim1: RefCell<Option<Array2<f64>>>,
pub(super) dim2: RefCell<Option<Array2<f64>>>,
pub(super) image: RefCell<Option<ImageId>>,
pub(super) data: RefCell<Option<Array2<LineString>>>,
pub(super) color: RefCell<Option<Array2<Option<Color>>>>,
}
#[glib::object_subclass]
impl ObjectSubclass for ForegroundWidget {
const NAME: &'static str = "ForegroundWidget";
type Type = super::ForegroundWidget;
}
impl ObjectImpl for ForegroundWidget {}

View File

@ -1,34 +0,0 @@
pub mod exterior;
mod imp;
pub mod interior;
use crate::coords::Mapper;
use femtovg::{renderer::OpenGl, Canvas, Path};
use glib::subclass::types::ObjectSubclassIsExt;
use gtk::glib;
use std::cell::Ref;
pub use self::imp::ForegroundConfig;
glib::wrapper! {
pub struct ForegroundWidget(ObjectSubclass<imp::ForegroundWidget>);
}
impl Default for ForegroundWidget {
fn default() -> Self {
Self::new(ForegroundConfig::default())
}
}
impl ForegroundWidget {
pub fn new(config: ForegroundConfig) -> Self {
let this: Self = glib::Object::new();
let imp = this.imp();
imp.config.replace(config);
this
}
pub fn draw(&self, canvas: &mut Canvas<OpenGl>, scale: f32, dpi: i32, mapper: Ref<'_, Mapper>) {
let config = self.imp().config.borrow();
}
}

View File

@ -1,2 +0,0 @@
pub mod background;
pub mod foreground;

View File

@ -1,22 +1,20 @@
mod cms;
mod imp;
mod layer;
mod predefined;
mod exterior;
mod interior;
pub mod predefined;
mod renders;
use self::cms::CMS;
pub use self::imp::{RenderConfig, RenderMotion, RenderStatus};
pub use self::layer::background::{BackgroundConfig, BackgroundWidget};
pub use self::layer::foreground::{ForegroundConfig, ForegroundWidget};
use crate::coords::Mapper;
use adw::prelude::{GLAreaExt, GestureDragExt};
use geo_types::LineString;
use glib::clone;
pub use glib::subclass::prelude::*;
use gtk::traits::WidgetExt;
use gtk::{EventControllerScrollFlags, Inhibit};
pub use layer::foreground::interior::Layer;
use std::cell::Ref;
use gtk::prelude::*;
pub use glib::subclass::prelude::*;
pub use interior::{Layer, LayerImpl, Target};
pub(super) type WindowCoord = (f32, f32);
@ -122,13 +120,12 @@ impl Render {
self.imp().mapper.replace(mapper);
}
pub fn set_interior_layers(&self, layers: Vec<Layer>) {
self.imp().interior_layers.replace(layers);
self.queue_render();
}
pub fn map(&self, loc: (f64, f64)) -> Option<(f32, f32)> {
// let (x, y) = loc;
// let (x_range, y_range) = self.imp().window_range().unwrap();
// if x >= x_range.0 && x <= x_range.1 && y >= y_range.0 && y <= y_range.1 {
// }
let foremapped = self.get_mapper().map(loc).unwrap();
return self.imp().map(foremapped);
}
@ -170,9 +167,6 @@ impl Render {
let mut mapper = self.get_mapper().clone();
mapper.set_lat_range(lat1..lat2);
mapper.set_lon_range(lon1..lon2);
println!("new_mapper: {:?}", mapper.get_bounds());
println!("old_mapper: {:?}", self.get_mapper().get_bounds());
let cms = CMS::new(mapper, window_size);
f(&cms);
}

View File

@ -1,5 +1,4 @@
use super::color_mapper::{BoundaryNorm, ColorMapper};
use crate::render::layer::foreground::interior::LayerImpl;
use femtovg::{ImageFlags, Paint, Path, PixelFormat::Rgba8, RenderTarget};
use geo_types::LineString;
use ndarray::ArrayView2;
@ -9,8 +8,7 @@ use std::{marker::PhantomData, fmt::Debug};
use super::super::renders::DataRenderer;
use crate::{
data::Radar2d,
render::{layer::foreground::interior::Target, Render},
utils::meshgrid,
utils::meshgrid, render::{Render, Target, LayerImpl},
};
#[derive(Debug)]
@ -39,6 +37,7 @@ impl<T: NumOps + PartialOrd + Copy, CMAP: ColorMapper<T>> GridFieldRenderer<CMAP
window_size: (f32, f32),
fill_value: T,
) {
let shape = data.shape();
let (rows, cols) = (shape[0], shape[1]);
let (dim1, dim2) = dims;

View File

@ -4,7 +4,7 @@ use std::path::Path;
use crate::{
data::{DataLoader, Radar2d},
render::layer::foreground::interior::Layer,
render::Layer
};
use super::{

View File

@ -1,6 +1,5 @@
use femtovg::{renderer::OpenGl, Canvas};
use crate::render::layer::foreground::interior::Target;
use crate::coords::Mapper;
use super::Target;
use super::Render;
pub trait DataRenderer {