research-spectra.rs

4.2 kB · rust · 135 lines

1use mrlycore::errors::Result;2use mrlycore::Color;3use mrlyfig::board::{Board, Frame};4use mrlyfig::{hex, ink, save};5use mrlymath::six;6use mrlymath::six::Cell6d;7use mrlymath::three;89const BASE: usize = 5;10const LEVEL: usize = 2;11const SIDE: usize = 25;12const GRAIN: usize = 4;1314fn at(cell: &Cell6d, row: usize, col: usize) -> u8 {15    let offset = (cell.width() - hex::row_len(SIDE, row)) / 2;16    cell.cell.types().get(&[row, col + offset])17}1819fn source(row: usize, col: usize) -> usize {20    let size = GRAIN * SIDE;21    let k = (3 * (size - 1)) / 2;22    let z = 2 * row;23    let target = k - z;24    let min_x = target.saturating_sub(size - 1);25    let x = min_x + col;26    let y = target - x;27    x / GRAIN + y / GRAIN + z / GRAIN28}2930fn is_hexagon(row: usize, col: usize) -> bool {31    let size = GRAIN * SIDE;32    let k = (3 * (size - 1)) / 2;33    source(row, col) + 1 == k / GRAIN34}3536const RATIO: f64 = 0.866_025_403_784_438_6;3738fn shrink(pts: [(f64, f64); 3], gap: f64) -> [(f64, f64); 3] {39    let cx = (pts[0].0 + pts[1].0 + pts[2].0) / 3.0;40    let cy = (pts[0].1 + pts[1].1 + pts[2].1) / 3.0;41    let edge = ((pts[1].0 - pts[0].0).powi(2) + (pts[1].1 - pts[0].1).powi(2)).sqrt();42    let inradius = edge / (2.0 * 3f64.sqrt());43    let k = ((inradius - gap) / inradius).max(0.0);44    let pull = |p: (f64, f64)| (cx + (p.0 - cx) * k, cy + (p.1 - cy) * k);45    [pull(pts[0]), pull(pts[1]), pull(pts[2])]46}4748fn hexagon(49    board: &mut Board,50    frame: Frame,51    n: usize,52    gap: f64,53    ink: impl Fn(usize, usize) -> Option<Color>,54) {55    let edge = (frame.w / (2 * n) as f64).min(frame.h / (n as f64 * 2.0 * RATIO));56    let rise = edge * RATIO;57    let (cx, cy) = frame.center();58    let left = cx - edge * n as f64;59    let top = cy - rise * n as f64;60    for row in 0..2 * n {61        let reach = if row < n { row } else { 2 * n - 1 - row };62        let up = row < n;63        let (long, short) = (n + reach + 1, n + reach);64        let (top_len, bot_len) = if up { (short, long) } else { (long, short) };65        let tx = left + (2 * n - top_len) as f64 * edge / 2.0;66        let bx = left + (2 * n - bot_len) as f64 * edge / 2.0;67        let (y0, y1) = (top + row as f64 * rise, top + (row + 1) as f64 * rise);68        for col in 0..top_len + bot_len {69            let points = if (col % 2 == 0) == up {70                let j = (col / 2) as f64;71                [72                    (bx + j * edge, y1),73                    (bx + (j + 1.0) * edge, y1),74                    (bx + (j + 0.5) * edge, y0),75                ]76            } else {77                let i = (col / 2) as f64;78                [79                    (tx + i * edge, y0),80                    (tx + (i + 1.0) * edge, y0),81                    (tx + (i + 0.5) * edge, y1),82                ]83            };84            if let Some(color) = ink(row, col) {85                let small = shrink(points, gap);86                board.triangle(small[0], small[1], small[2], color);87            }88        }89    }90}9192fn main() -> Result<()> {93    let slice = six::cut(&three::carpet(BASE, LEVEL)?)?;94    assert_eq!(slice.height(), 2 * SIDE);95    let mut hexagons = 0usize;96    let mut triangles = 0usize;97    for row in 0..2 * SIDE {98        for col in 0..hex::row_len(SIDE, row) {99            if at(&slice, row, col) != six::FILL {100                continue;101            }102            if is_hexagon(row, col) {103                hexagons += 1;104            } else {105                triangles += 1;106            }107        }108    }109    assert_eq!(hexagons, 139 * 6);110    assert_eq!(triangles, 330);111    assert_eq!(hexagons + triangles, six::fills(&slice));112    assert_eq!(hex::count(SIDE), 3750);113114    let mut board = Board::square();115    let frame = board.frame(0.08);116    hexagon(&mut board, frame, SIDE, 0.0, |row, col| {117        if at(&slice, row, col) != six::FILL {118            return None;119        }120        if is_hexagon(row, col) {121            Some(ink::yellow())122        } else {123            None124        }125    });126    hexagon(&mut board, frame, SIDE, 1.2, |row, col| {127        if at(&slice, row, col) == six::FILL && !is_hexagon(row, col) {128            Some(ink::blue())129        } else {130            None131        }132    });133    save("research-spectra", &board)?;134    Ok(())135}