diff --git a/Cargo.lock b/Cargo.lock index 6746b4e..69bd54c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -64,6 +64,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[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" @@ -271,6 +277,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.6", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -281,6 +301,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "combine" version = "4.6.7" @@ -340,6 +366,18 @@ dependencies = [ "libc", ] +[[package]] +name = "core-text" +version = "20.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" +dependencies = [ + "core-foundation", + "core-graphics", + "foreign-types", + "libc", +] + [[package]] name = "crc32fast" version = "1.4.2" @@ -361,6 +399,27 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -397,6 +456,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +[[package]] +name = "dwrote" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70182709525a3632b2ba96b6569225467b18ecb4a77f46d255f713a6bebf05fd" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -453,12 +524,43 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + [[package]] name = "foldhash" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +[[package]] +name = "font-kit" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64b34f4efd515f905952d91bc185039863705592c0c53ae6d979805dd154520" +dependencies = [ + "bitflags 2.6.0", + "byteorder", + "core-foundation", + "core-graphics", + "core-text", + "dirs", + "dwrote", + "float-ord", + "freetype-sys", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -486,6 +588,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +[[package]] +name = "freetype-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "futures-core" version = "0.3.31" @@ -513,6 +626,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -626,6 +749,43 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[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 = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "jpeg-decoder", + "num-traits", + "png", +] + [[package]] name = "image" version = "0.25.5" @@ -692,6 +852,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + [[package]] name = "js-sys" version = "0.3.76" @@ -719,6 +885,12 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.169" @@ -1138,6 +1310,12 @@ version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "orbclient" version = "0.3.48" @@ -1153,7 +1331,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec719bbf3b2a81c109a4e20b1f129b5566b7dce654bc3872f6a05abf82b2c4" dependencies = [ - "ttf-parser", + "ttf-parser 0.25.1", ] [[package]] @@ -1191,6 +1369,25 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf07ef4804cfa9aea3b04a7bbdd5a40031dbb6b4f2cbaf2b011666c80c5b4f2" +dependencies = [ + "rustc_version", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1229,6 +1426,52 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "chrono", + "font-kit", + "image 0.24.9", + "lazy_static", + "num-traits", + "pathfinder_geometry", + "plotters-backend", + "plotters-bitmap", + "plotters-svg", + "ttf-parser 0.20.0", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-bitmap" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ce181e3f6bf82d6c1dc569103ca7b1bd964c60ba03d7e6cdfbb3e3eb7f7405" +dependencies = [ + "gif", + "image 0.24.9", + "plotters-backend", +] + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + [[package]] name = "png" version = "0.17.16" @@ -1394,7 +1637,9 @@ dependencies = [ "async-channel", "bytemuck", "glam", - "image", + "image 0.24.9", + "image 0.25.5", + "plotters", "pollster", "rand", "rand_distr", @@ -1421,6 +1666,17 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + [[package]] name = "renderdoc-sys" version = "1.1.0" @@ -1433,6 +1689,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.38.42" @@ -1480,6 +1745,12 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "semver" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" + [[package]] name = "serde" version = "1.0.216" @@ -1689,6 +1960,12 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +[[package]] +name = "ttf-parser" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17f77d76d837a7830fe1d4f12b7b4ba4192c1888001c7164257e4bc6d21d96b4" + [[package]] name = "ttf-parser" version = "0.25.1" @@ -1937,6 +2214,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + [[package]] name = "wgpu" version = "23.0.1" @@ -2029,7 +2312,7 @@ dependencies = [ "web-sys", "wgpu-types", "windows", - "windows-core", + "windows-core 0.58.0", ] [[package]] @@ -2043,6 +2326,22 @@ dependencies = [ "web-sys", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -2052,13 +2351,28 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" dependencies = [ - "windows-core", + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[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.6", ] @@ -2125,6 +2439,15 @@ dependencies = [ "windows-targets 0.42.2", ] +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -2382,6 +2705,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-dl" version = "2.21.0" @@ -2445,6 +2777,17 @@ version = "0.8.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea8b391c9a790b496184c29f7f93b9ed5b16abb306c05415b68bcc16e4d06432" +[[package]] +name = "yeslogic-fontconfig-sys" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" +dependencies = [ + "dlib", + "once_cell", + "pkg-config", +] + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index 3fb1065..7987e4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,8 @@ async-channel = "2.3.1" bytemuck = { version = "1.21.0", features = ["derive"] } glam = { version = "0.29.2", features = ["bytemuck"] } image = { version = "0.25.5", default-features = false, features = ["png", "jpeg", "webp"] } +image24 = { version = "0.24", default-features = false, features = ["webp"], package = "image" } +plotters = "0.3.7" pollster = "0.4.0" rand = "0.8.5" rand_distr = { version = "0.4.3", features = ["std_math"] } diff --git a/src/bin/scatter.rs b/src/bin/scatter.rs new file mode 100644 index 0000000..c66c937 --- /dev/null +++ b/src/bin/scatter.rs @@ -0,0 +1,246 @@ +use std::f32::consts::PI; + +use glam::{vec2, Vec2}; +use plotters::{ + coord::{ranged1d::ValueFormatter, types::RangedCoordf32}, + prelude::*, +}; +use rand::Rng; +use rand_distr::{Bernoulli, Distribution, Uniform}; +use rand_pcg::Pcg32; + +const RANGE: f32 = 50.0; +const BIN_COUNT: usize = 500; +const BIN_SIZE: f32 = RANGE / BIN_COUNT as f32; +const N_PARTICLES: u32 = 100000; +const N_STEPS: u32 = 100; + +fn make_point_1(rng: &mut impl Rng) -> Vec2 { + let da = Uniform::new(0., 2. * PI); + (0..N_STEPS).map(|_| 0.66 * Vec2::from_angle(da.sample(rng))).sum() +} + +fn make_point_2(rng: &mut impl Rng) -> Vec2 { + let da = Uniform::new(0., 2. * PI); + let dr = Uniform::new(0., 1.); + (0..N_STEPS) + .map(|_| 1.14 * dr.sample(rng) * Vec2::from_angle(da.sample(rng))) + .sum() +} + +fn make_point_3(rng: &mut impl Rng) -> Vec2 { + let dx = Uniform::new(0., 1.); + (0..N_STEPS) + .map(|_| loop { + let ret = 2. * vec2(dx.sample(rng), dx.sample(rng)) - 1.; + if ret.length() < 1. { + break 0.95 * ret; + } + }) + .sum() +} + +fn make_point_4(rng: &mut impl Rng) -> Vec2 { + let da = Uniform::new(0., 2. * PI); + let db = Bernoulli::new(0.001).unwrap(); + let mut pt = Vec2::ZERO; + while !db.sample(rng) { + pt += Vec2::from_angle(da.sample(rng)); + } + 0.20 * pt +} + +fn make_point_5(rng: &mut impl Rng) -> Vec2 { + let da = Uniform::new(0., 2. * PI); + let dr = Uniform::new(0., 1.); + let db = Bernoulli::new(0.001).unwrap(); + let mut pt = Vec2::ZERO; + while !db.sample(rng) { + pt += dr.sample(rng) * Vec2::from_angle(da.sample(rng)); + } + 0.35 * pt +} + +fn make_point_6(rng: &mut impl Rng) -> Vec2 { + // let da = Uniform::new(0., 2. * PI); + // let dr = Uniform::new(0., 1.); + let dx = Uniform::new(0., 1.); + let mut pt = Vec2::ZERO; + loop { + // let r = dr.sample(rng); + // pt += r * Vec2::from_angle(da.sample(rng)); + let off = loop { + let ret = 2. * vec2(dx.sample(rng), dx.sample(rng)) - 1.; + if ret.length() < 1. { + break ret; + } + }; + pt += off; + let r = off.length(); + let db = Bernoulli::new((-0.003 * r).exp() as f64).unwrap(); + if !db.sample(rng) { + break 0.4 * pt; + } + } +} + +fn normal(v: f32) -> f32 { + (-0.5 * v * v).exp() +} + +fn bin_of(pt: Vec2) -> usize { + (pt.length() / BIN_SIZE) as usize +} + +fn bin_area(bin: usize) -> f32 { + 2. * bin as f32 + 1. +} + +fn graph_distrs(chart: &mut ChartContext>) { + let mut rng = Pcg32::new(42, 0); + let mut add_chart = |f: fn(&mut Pcg32) -> Vec2, color: RGBColor| { + let mut bins = vec![0; BIN_COUNT]; + for _ in 0..N_PARTICLES { + let bin = bin_of(f(&mut rng)); + if bin < BIN_COUNT { + bins[bin] += 1; + } + } + let bins: Vec<_> = bins + .into_iter() + .enumerate() + .map(|(bin, n)| n as f32 / bin_area(bin)) + .collect(); + let max = bins.iter().max_by(|a, b| a.total_cmp(b)).unwrap(); + chart + .draw_series(LineSeries::new( + bins.iter() + .enumerate() + .map(|(bin, count)| (bin as f32 * BIN_SIZE, count / max)), + color.mix(0.5).filled(), + )) + .unwrap(); + }; + add_chart(make_point_1, RED); + add_chart(make_point_2, GREEN); + add_chart(make_point_3, BLUE); + add_chart(make_point_4, CYAN); + add_chart(make_point_5, MAGENTA); + add_chart(make_point_6, RGBColor(255, 127, 0)); + + fn plot(f: &impl Fn(f32) -> f32) -> impl Iterator + '_ { + let xs = (0..BIN_COUNT).map(|bin| bin as f32 * BIN_SIZE); + xs.map(|x| (x, f(x))) + } + for s in [3.67, 4.67, 6.5] { + chart + .draw_series(LineSeries::new( + plot(&|x| normal(x / s)), + RGBColor(0, 0, 127).mix(0.5).filled(), + )) + .unwrap(); + } + + for s in [3., 3.5, 4.] { + chart + .draw_series(LineSeries::new( + plot(&|x| 1. / (1. + (x / s).powi(2))), + RGBColor(0, 127, 0).mix(0.5).filled(), + )) + .unwrap(); + } +} + +fn graph_cumul(chart: &mut ChartContext>>) { + let mut rng = Pcg32::new(42, 0); + let mut add_chart = |f: fn(&mut Pcg32) -> Vec2, color: RGBColor| { + let mut bins = vec![0; BIN_COUNT]; + for _ in 0..N_PARTICLES { + let bin = bin_of(f(&mut rng)); + if bin < BIN_COUNT { + bins[bin] += 1; + } + } + let bins: Vec<_> = bins + .into_iter() + .scan(0, |running_total, n| { + *running_total += n; + Some(*running_total) + }) + .collect(); + chart + .draw_series(LineSeries::new( + bins.iter() + .enumerate() + .map(|(bin, &n)| (bin as f32 * BIN_SIZE, n as f32 / N_PARTICLES as f32)), + color.mix(0.5).filled(), + )) + .unwrap(); + }; + add_chart(make_point_1, RED); + add_chart(make_point_2, GREEN); + add_chart(make_point_3, BLUE); + add_chart(make_point_4, CYAN); + add_chart(make_point_5, MAGENTA); + add_chart(make_point_6, RGBColor(255, 127, 0)); +} + +fn make_plot<'a, XT, YT, X, Y>( + coords: fn(cb: ChartBuilder<'_, '_, BitMapBackend<'a>>) -> ChartContext<'a, BitMapBackend<'a>, Cartesian2d>, + graph: for<'b> fn(chart: &'b mut ChartContext<'a, BitMapBackend<'a>, Cartesian2d>), + filename: &'a str, + title: &str, +) -> Result<(), Box> +where + X: Ranged + ValueFormatter, + Y: Ranged + ValueFormatter, +{ + let root = BitMapBackend::new(filename, (1920, 1080)).into_drawing_area(); + root.fill(&WHITE)?; + + let mut chart = ChartBuilder::on(&root); + chart + .caption(title, ("sans-serif", 50).into_font()) + .margin(5) + .x_label_area_size(30) + .y_label_area_size(30); + let mut chart = coords(chart); + + chart + .configure_mesh() + .bold_line_style(BLACK.mix(0.2)) + .light_line_style(BLACK.mix(0.1)) + .axis_desc_style(("sans-serif", 15)) + .draw()?; + + graph(&mut chart); + + chart + .configure_series_labels() + .background_style(&WHITE.mix(0.8)) + .border_style(&BLACK) + .draw()?; + + root.present()?; + + Ok(()) +} + +fn main() -> Result<(), Box> { + make_plot( + |mut c| c.build_cartesian_2d(0.0..RANGE, 0.0f32..1.0f32).unwrap(), + graph_distrs, + "scatter.webp", + "Scatter distance distribution", + )?; + make_plot( + |mut c| { + c.build_cartesian_2d(0.0..RANGE, (0.0f32..1.0f32).log_scale().zero_point(1.0)) + .unwrap() + }, + graph_cumul, + "cumul.webp", + "Cumulative light distribution", + )?; + Ok(()) +}