diff --git a/Cargo.lock b/Cargo.lock index 1169b32..a60d311 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 3c8cf83..1c881fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/back.txt b/back.txt index 0bca492..772c9b3 100644 --- a/back.txt +++ b/back.txt @@ -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(), + // ) diff --git a/src/chart/backend.rs b/src/chart/backend.rs new file mode 100644 index 0000000..c019477 --- /dev/null +++ b/src/chart/backend.rs @@ -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(&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 { + 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> { + 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> { + Ok(()) + } + + fn draw_pixel( + &mut self, + point: BackendCoord, + color: BackendColor, + ) -> Result<(), DrawingErrorKind> { + 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( + &mut self, + from: BackendCoord, + to: BackendCoord, + style: &S, + ) -> Result<(), DrawingErrorKind> { + 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( + &mut self, + upper_left: BackendCoord, + bottom_right: BackendCoord, + style: &S, + fill: bool, + ) -> Result<(), DrawingErrorKind> { + 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>( + &mut self, + path: I, + style: &S, + ) -> Result<(), DrawingErrorKind> { + 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>( + &mut self, + path: I, + style: &S, + ) -> Result<(), DrawingErrorKind> { + 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( + &mut self, + center: BackendCoord, + radius: u32, + style: &S, + fill: bool, + ) -> Result<(), DrawingErrorKind> { + 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( + &self, + text: &str, + font: &S, + ) -> Result<(u32, u32), DrawingErrorKind> { + 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( + &mut self, + text: &str, + style: &S, + pos: BackendCoord, + ) -> Result<(), DrawingErrorKind> { + 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(()) + } +} diff --git a/src/chart/imp.rs b/src/chart/imp.rs new file mode 100644 index 0000000..caf42bb --- /dev/null +++ b/src/chart/imp.rs @@ -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 {} diff --git a/src/chart/mod.rs b/src/chart/mod.rs new file mode 100644 index 0000000..735ee91 --- /dev/null +++ b/src/chart/mod.rs @@ -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) + @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::::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 + } +} diff --git a/src/components/render_panel/messages.rs b/src/components/render_panel/messages.rs index aa7c6cf..b735513 100644 --- a/src/components/render_panel/messages.rs +++ b/src/components/render_panel/messages.rs @@ -1,12 +1,34 @@ +use std::fmt::Debug; + use crate::render::Layer; +pub enum MonitorInputMsg { + AddLayer(Layer), + RemoveLayer(usize), + UpdateLayer((usize, Box)), + 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), } diff --git a/src/components/render_panel/monitor/mod.rs b/src/components/render_panel/monitor/mod.rs index 3f559f0..c41e0b7 100644 --- a/src/components/render_panel/monitor/mod.rs +++ b/src/components/render_panel/monitor/mod.rs @@ -1,4 +1,4 @@ pub mod monitor; -pub mod sidebar; pub mod render; +pub mod sidebar; pub use monitor::MonitorModel; diff --git a/src/components/render_panel/monitor/monitor.rs b/src/components/render_panel/monitor/monitor.rs index d2f968d..182fa0e 100644 --- a/src/components/render_panel/monitor/monitor.rs +++ b/src/components/render_panel/monitor/monitor.rs @@ -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, + sidebar_open: bool, + sidebar_width: i32, + layers: Vec, sidebar: Controller, } +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(), - #[wrap(Some)] - set_content = &adw::NavigationPage::builder().title("content").child(model.render.widget()).build(), + set_child=>k::Paned{ + set_position: 1000, + #[wrap(Some)] + #[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 { let sidebar: Controller = SideBarModel::builder() .launch(()) - .forward(sender.input_sender(), |msg| {}); - let render: Controller = 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) {} + fn update(&mut self, msg: Self::Input, _sender: ComponentSender) { + 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 => {} + } + } + } diff --git a/src/components/render_panel/monitor/sidebar/sidebar.rs b/src/components/render_panel/monitor/sidebar/sidebar.rs index 50b1386..e5fc836 100644 --- a/src/components/render_panel/monitor/sidebar/sidebar.rs +++ b/src/components/render_panel/monitor/sidebar/sidebar.rs @@ -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, @@ -17,38 +20,47 @@ 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! { - gtk::Box { - set_orientation: gtk::Orientation::Vertical, - set_spacing: 5, - set_margin_all: 5, - gtk::Notebook { - set_vexpand: true, - append_page:(&page_1, Some(&label)), - }, - gtk::Button { - set_label: "Append 10 items", - connect_clicked => Msg::Append, - }, - - gtk::Button { - set_label: "Remove second item", - connect_clicked => Msg::Remove, - }, - gtk::ScrolledWindow { - set_vexpand: true, - - #[local_ref] - my_view -> gtk::ListView {} + gtk::Box { + set_orientation: gtk::Orientation::Vertical, + set_spacing: 5, + set_margin_all: 5, + gtk::Notebook { + set_vexpand: true, + append_page:(&page_1, Some(&label)), + }, + gtk::Button { + 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::ScrolledWindow { + set_vexpand: true, + #[local_ref] + my_view -> gtk::ListView {} + } + } } - } - } fn init( init: Self::Init, @@ -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!(); diff --git a/src/dealers/layer_handler.rs b/src/dealers/layer_handler.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/dealers/mod.rs b/src/dealers/mod.rs new file mode 100644 index 0000000..f1b1cec --- /dev/null +++ b/src/dealers/mod.rs @@ -0,0 +1 @@ +mod layer_handler; diff --git a/src/main.rs b/src/main.rs index f530ad0..d5c140c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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"; diff --git a/src/monitor/imp.rs b/src/monitor/imp.rs deleted file mode 100644 index eaa6025..0000000 --- a/src/monitor/imp.rs +++ /dev/null @@ -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, -} - -#[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 {} diff --git a/src/monitor/mod.rs b/src/monitor/mod.rs deleted file mode 100644 index 8771119..0000000 --- a/src/monitor/mod.rs +++ /dev/null @@ -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) - @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(>k::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 - } -} diff --git a/src/render/layer/foreground/exterior/imp.rs b/src/render/exterior/imp.rs similarity index 100% rename from src/render/layer/foreground/exterior/imp.rs rename to src/render/exterior/imp.rs diff --git a/src/render/layer/foreground/exterior/mod.rs b/src/render/exterior/mod.rs similarity index 100% rename from src/render/layer/foreground/exterior/mod.rs rename to src/render/exterior/mod.rs diff --git a/src/render/imp.rs b/src/render/imp.rs index 8e4ce9e..b8291e4 100644 --- a/src/render/imp.rs +++ b/src/render/imp.rs @@ -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, + 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, pub(super) interior: RefCell, + pub(super) canvas: RefCell>>, pub config: RefCell, pub status: RefCell, pub mapper: RefCell, - pub(super) canvas: RefCell>>, + pub(super) interior_layers: RefCell>, } 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(); diff --git a/src/render/layer/foreground/interior/imp.rs b/src/render/interior/imp.rs similarity index 57% rename from src/render/layer/foreground/interior/imp.rs rename to src/render/interior/imp.rs index 2577ecd..1580c38 100644 --- a/src/render/layer/foreground/interior/imp.rs +++ b/src/render/interior/imp.rs @@ -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, - pub(super) foreground: RefCell, pub(super) trans: RefCell, pub(super) update_trans: RefCell, - pub(super) layers: RefCell>, } #[glib::object_subclass] diff --git a/src/render/layer/foreground/interior/layers.rs b/src/render/interior/layers.rs similarity index 81% rename from src/render/layer/foreground/interior/layers.rs rename to src/render/interior/layers.rs index 8810c0a..d156ad3 100644 --- a/src/render/layer/foreground/interior/layers.rs +++ b/src/render/interior/layers.rs @@ -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>, - imp: RefCell>>, - draw: Box, &Render, (f32, f32))>, + imp: RefCell>>, + draw: Arc, &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, render: &Render) -> Option; } @@ -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)), + draw: Arc::new(draw), + imp: RefCell::new(imp.map(|x| Arc::new(x) as Arc)), } } @@ -63,7 +59,7 @@ impl Layer { self.target.borrow().clone() } - pub fn get_imp(&self) -> Ref>> { + pub fn get_imp(&self) -> Ref>> { let im = self.imp.borrow(); im } diff --git a/src/render/layer/foreground/interior/mod.rs b/src/render/interior/mod.rs similarity index 50% rename from src/render/layer/foreground/interior/mod.rs rename to src/render/interior/mod.rs index 947d1bc..7c1492a 100644 --- a/src/render/layer/foreground/interior/mod.rs +++ b/src/render/interior/mod.rs @@ -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, canvas: &mut Canvas, 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)); } } diff --git a/src/render/layer/background/imp.rs b/src/render/layer/background/imp.rs deleted file mode 100644 index b3287d4..0000000 --- a/src/render/layer/background/imp.rs +++ /dev/null @@ -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, - pub lon_lines: Vec, - pub painter: Paint, -} - -impl BackgroundConfig { - pub fn new() -> Self { - Self::default() - } -} - -#[derive(Default)] -pub struct BackgroundWidget { - pub(super) config: RefCell, - pub(super) shp: RefCell>> -} - -#[glib::object_subclass] -impl ObjectSubclass for BackgroundWidget { - const NAME: &'static str = "BackgroundWidget"; - type Type = super::BackgroundWidget; -} - -impl ObjectImpl for BackgroundWidget {} diff --git a/src/render/layer/background/mod.rs b/src/render/layer/background/mod.rs deleted file mode 100644 index 6d26269..0000000 --- a/src/render/layer/background/mod.rs +++ /dev/null @@ -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); -} - -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> = polygons - .into_iter() - .map(|(polygon, _)| polygon.into()) - .collect(); - - imp.shp.replace(Some(polys)); - imp.config.replace(config); - this - } - - fn draw_lines>>( - &self, - canvas: &mut Canvas, - line_painter: &Paint, - p: V, - ) { - p.into_iter().for_each(|line| { - let mut path = Path::new(); - let points: Vec> = 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, - 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, - 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, - 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) { - let imp = self.imp(); - imp.config.borrow_mut().lat_lines = lat_lines; - } - - pub fn set_lon_lines(&self, lon_lines: Vec) { - let imp = self.imp(); - imp.config.borrow_mut().lon_lines = lon_lines; - } -} diff --git a/src/render/layer/foreground/imp.rs b/src/render/layer/foreground/imp.rs deleted file mode 100644 index 3950cf4..0000000 --- a/src/render/layer/foreground/imp.rs +++ /dev/null @@ -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>, - pub lon_lines: Vec>, - pub painter: Paint, -} - -impl ForegroundConfig { - pub fn new() -> Self { - Self::default() - } -} - -#[derive(Default)] -pub struct ForegroundWidget { - pub(super) config: RefCell, - pub(super) dim1: RefCell>>, - pub(super) dim2: RefCell>>, - pub(super) image: RefCell>, - pub(super) data: RefCell>>, - pub(super) color: RefCell>>>, -} - -#[glib::object_subclass] -impl ObjectSubclass for ForegroundWidget { - const NAME: &'static str = "ForegroundWidget"; - type Type = super::ForegroundWidget; -} - -impl ObjectImpl for ForegroundWidget {} diff --git a/src/render/layer/foreground/mod.rs b/src/render/layer/foreground/mod.rs deleted file mode 100644 index 1b0f7c4..0000000 --- a/src/render/layer/foreground/mod.rs +++ /dev/null @@ -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); -} - -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, scale: f32, dpi: i32, mapper: Ref<'_, Mapper>) { - let config = self.imp().config.borrow(); - } - -} diff --git a/src/render/layer/mod.rs b/src/render/layer/mod.rs deleted file mode 100644 index 82610d3..0000000 --- a/src/render/layer/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod background; -pub mod foreground; diff --git a/src/render/mod.rs b/src/render/mod.rs index 1659c5a..aa43ced 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -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) { + 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); } diff --git a/src/render/predefined/grid_field_renderer.rs b/src/render/predefined/grid_field_renderer.rs index f30f1ff..69ad322 100644 --- a/src/render/predefined/grid_field_renderer.rs +++ b/src/render/predefined/grid_field_renderer.rs @@ -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> GridFieldRenderer