moire-local-limit.rs

4.2 kB · rust · 132 lines

1use figures::board::{Board, Frame};2use figures::ink::Ramp;3use figures::{field, ink, save};4use mrlyrs::core::error::Result;5use mrlyrs::math::two::{carpet, Cell2d};67const LOW: usize = 21;8const HIGH: usize = 23;9const PANEL: usize = 410;10const EDGE: f64 = 82.0;11const STEPS: usize = 400;1213fn inked(cell: &Cell2d) -> Result<Vec<Vec<bool>>> {14    let n = cell.width();15    let mut rows = vec![vec![false; n]; n];16    for (i, row) in rows.iter_mut().enumerate() {17        for (j, slot) in row.iter_mut().enumerate() {18            *slot = cell.types().get(&[i, j])? != 0;19        }20    }21    Ok(rows)22}2324fn pieces(lo: f64, hi: f64) -> Vec<(f64, usize, usize)> {25    let mut cuts = vec![lo, hi];26    for n in [LOW, HIGH] {27        for k in 1..n {28            let x = k as f64 / n as f64;29            if x > lo && x < hi {30                cuts.push(x);31            }32        }33    }34    cuts.sort_by(|a, b| a.total_cmp(b));35    cuts.windows(2)36        .filter(|w| w[1] > w[0])37        .map(|w| {38            let mid = 0.5 * (w[0] + w[1]);39            let a = ((mid * LOW as f64) as usize).min(LOW - 1);40            let b = ((mid * HIGH as f64) as usize).min(HIGH - 1);41            (w[1] - w[0], a, b)42        })43        .collect()44}4546fn overlay(low: &[Vec<bool>], high: &[Vec<bool>]) -> Vec<f64> {47    let side = PANEL as f64;48    let spans: Vec<Vec<(f64, usize, usize)>> = (0..PANEL)49        .map(|k| pieces(k as f64 / side, (k + 1) as f64 / side))50        .collect();51    let mut values = Vec::with_capacity(PANEL * PANEL);52    for rows in &spans {53        for cols in &spans {54            let mut area = 0.0;55            for &(ly, ra, rb) in rows {56                for &(lx, ca, cb) in cols {57                    if low[ra][ca] != high[rb][cb] {58                        area += lx * ly;59                    }60                }61            }62            values.push(area * side * side);63        }64    }65    values66}6768fn limit(u: f64, v: f64) -> f64 {69    0.5 * (1.0 - (1.0 - 2.0 * u).abs() * (1.0 - 2.0 * v).abs())70}7172fn fill(n: usize) -> f64 {73    let q = (n - 1) as f64 / (2 * n) as f64;74    1.0 - q * q75}7677fn arcs(board: &mut Board, frame: Frame, kappa: f64, thick: f64, chords: bool) {78    for (sx, sy) in [(1.0, 1.0), (1.0, -1.0), (-1.0, 1.0), (-1.0, -1.0)] {79        if chords {80            let a = frame.at(0.5 * (1.0 - sx), 0.5 * (1.0 - sy * kappa));81            let b = frame.at(0.5 * (1.0 - sx * kappa), 0.5 * (1.0 - sy));82            board.segment(a, b, 2.0, ink::dim());83        }84        let arc: Vec<(f64, f64)> = (0..=STEPS)85            .map(|k| {86                let x = kappa + (1.0 - kappa) * k as f64 / STEPS as f64;87                frame.at(0.5 * (1.0 - sx * x), 0.5 * (1.0 - sy * kappa / x))88            })89            .collect();90        board.polyline(&arc, thick, ink::orange());91    }92}9394fn main() -> Result<()> {95    let low = inked(&carpet(LOW, 1)?)?;96    let high = inked(&carpet(HIGH, 1)?)?;97    assert_eq!(low.iter().flatten().filter(|&&on| on).count(), 341);98    assert_eq!(high.iter().flatten().filter(|&&on| on).count(), 408);99100    let raw = overlay(&low, &high);101    let mean = raw.iter().sum::<f64>() / raw.len() as f64;102    let (a, b) = (fill(LOW), fill(HIGH));103    assert!((mean - (a + b - 2.0 * a * b)).abs() < 1e-9);104105    let side = PANEL as f64;106    let smooth: Vec<f64> = (0..PANEL * PANEL)107        .map(|k| {108            limit(109                ((k % PANEL) as f64 + 0.5) / side,110                ((k / PANEL) as f64 + 0.5) / side,111            )112        })113        .collect();114    let smean = smooth.iter().sum::<f64>() / smooth.len() as f64;115    assert!((smean - 0.375).abs() < 1e-12);116117    let kappa = 2f64.sqrt() - 1.0;118    assert!((2.0 * kappa - 2f64.sqrt() * (1.0 - kappa)).abs() < 1e-12);119120    let ramp = Ramp::tone(ink::panel(), ink::blue());121    let mut board = Board::square();122    let first = Frame::new(EDGE, EDGE, side, side);123    let far = board.width as f64 - EDGE - side;124    let second = Frame::new(far, far, side, side);125    field::draw_range(&mut board, first, PANEL, PANEL, &raw, (0.0, 1.0), &ramp);126    field::draw_range(&mut board, second, PANEL, PANEL, &smooth, (0.0, 0.5), &ramp);127128    arcs(&mut board, second, kappa, 4.0, true);129    arcs(&mut board, first, kappa, 3.0, false);130    save("moire-local-limit", &board)?;131    Ok(())132}