wiki-minkowski-content.rs
3.9 kB · rust · 120 lines
1use figures::{ink, plot, save, Board, Frame};2use mrlyrs::core::error::Result;34const ROWS: usize = 7;5const WIDEST: f64 = 0.1;6const THREAD: usize = 5;7const FROM: f64 = 2.0;8const TO: f64 = 6.0;9const SAMPLES: usize = 4000;10const LOW: f64 = 2.494975716;1112fn main() -> Result<()> {13 let dimension = 2f64.ln() / 3f64.ln();14 let mut board = Board::square();15 let frame = board.frame(0.08);16 let upper = Frame::new(frame.x, frame.y, frame.w, frame.h * 0.58);17 let lower = Frame::new(frame.x, frame.y + frame.h * 0.66, frame.w, frame.h * 0.34);1819 let span = 1.0 + 2.0 * WIDEST;20 let px = |u: f64| upper.x + upper.w * (u + WIDEST) / span;21 let pitch = upper.h / ROWS as f64;22 let thick = pitch * 0.62;23 let fine = pitch * 0.16;24 let thread = intervals(THREAD);25 for row in 0..ROWS {26 let eps = WIDEST * 3f64.powf(-(row as f64) / 2.0);27 let top = upper.y + row as f64 * pitch + (pitch - thick) / 2.0;28 let tube = tube(eps);29 let length: f64 = tube.iter().map(|(a, b)| b - a).sum();30 assert!((length - volume(eps)).abs() < 1e-12);31 for (a, b) in tube {32 board.rect(px(a), top, px(b) - px(a), thick, ink::blue());33 }34 let mid = top + (thick - fine) / 2.0;35 for &(a, b) in &thread {36 board.rect(px(a), mid, px(b) - px(a), fine, ink::yellow());37 }38 }3940 let xs: Vec<f64> = (0..=SAMPLES)41 .map(|i| FROM + (TO - FROM) * i as f64 / SAMPLES as f64)42 .collect();43 let ys: Vec<f64> = xs44 .iter()45 .map(|&x| reading(3f64.powf(-x), dimension))46 .collect();47 let high = 2f64.powf(2.0 - dimension);48 let lo = ys.iter().copied().fold(f64::MAX, f64::min);49 let hi = ys.iter().copied().fold(f64::MIN, f64::max);50 assert!((lo - LOW).abs() < 1e-5);51 assert!(hi <= high + 1e-9);52 assert!((reading(1.0 / 18.0, dimension) - high).abs() < 1e-9);53 for k in 2..=6 {54 assert!((reading(3f64.powi(-k), dimension) - 2.5).abs() < 1e-9);55 }56 for &x in xs.iter().step_by(97) {57 let eps = 3f64.powf(-x);58 assert!((reading(eps / 3.0, dimension) - reading(eps, dimension)).abs() < 1e-9);59 }60 let pad = (high - LOW) * 0.12;61 let (bottom, ceiling) = (LOW - pad, high + pad);62 let hair = (lower.h / 256.0).max(1.0);63 for k in (FROM as usize + 1)..(TO as usize) {64 let x = lower.x + lower.w * (k as f64 - FROM) / (TO - FROM);65 board.segment((x, lower.y), (x, lower.y + lower.h), hair, ink::dim());66 }67 let pts: Vec<(f64, f64)> = xs68 .iter()69 .zip(&ys)70 .map(|(&x, &y)| {71 (72 lower.x + lower.w * (x - FROM) / (TO - FROM),73 lower.y + lower.h * (1.0 - (y - bottom) / (ceiling - bottom)),74 )75 })76 .collect();77 board.polyline(&pts, (lower.h / 64.0).max(2.0), ink::yellow());78 plot::axis(&mut board, lower, ink::line());79 save("wiki-minkowski-content", &board)?;80 Ok(())81}8283fn intervals(level: usize) -> Vec<(f64, f64)> {84 let side = 3f64.powi(-(level as i32));85 (0..1usize << level)86 .map(|i| {87 let a: f64 = (0..level)88 .filter(|&l| (i >> (level - 1 - l)) & 1 == 1)89 .map(|l| 2.0 * 3f64.powi(-(l as i32 + 1)))90 .sum();91 (a, a + side)92 })93 .collect()94}9596fn tube(eps: f64) -> Vec<(f64, f64)> {97 let level = (0..40)98 .find(|&k| 3f64.powi(-(k as i32 + 1)) <= 2.0 * eps)99 .unwrap_or(40);100 let mut out: Vec<(f64, f64)> = Vec::new();101 for (a, b) in intervals(level) {102 let (a, b) = (a - eps, b + eps);103 match out.last_mut() {104 Some(last) if a <= last.1 => last.1 = last.1.max(b),105 _ => out.push((a, b)),106 }107 }108 out109}110111fn volume(eps: f64) -> f64 {112 2.0 * eps113 + (1..80)114 .map(|k| 2f64.powi(k - 1) * 3f64.powi(-k).min(2.0 * eps))115 .sum::<f64>()116}117118fn reading(eps: f64, dimension: f64) -> f64 {119 eps.powf(dimension - 1.0) * volume(eps)120}