demo-universe.rs

3.5 kB · rust · 116 lines

1use mrlycore::colors::{shades, INDIGO};2use mrlycore::errors::Result;3use mrlyfig::{ink, iso, save, Board, Color};4use mrlymath::bang::bang;5use mrlymath::three::designs;6use mrlymath::three::faces::quads;7use mrlymath::three::Cell3d;89const NUMBER: usize = 3;10const ROWS: [usize; 5] = [4, 5, 4, 5, 4];11const HALF: f64 = 1.5;1213fn cage(board: &mut Board, cx: f64, cy: f64, s: f64) {14    let corner = |i: usize| {15        let bit = |b: usize| ((i >> b) & 1) as f64 * 2.0 - 1.0;16        let p = iso::project(bit(0) * HALF, bit(1) * HALF, bit(2) * HALF);17        (cx + p.0 * s, cy + p.1 * s)18    };19    for a in 0usize..8 {20        for b in (a + 1)..8 {21            if (a ^ b).count_ones() == 1 {22                board.segment(23                    corner(a),24                    corner(b),25                    s / 24.0,26                    ink::mix(ink::line(), ink::dim(), 0.3),27                );28            }29        }30    }31}3233fn stamp(board: &mut Board, cell: &Cell3d, cx: f64, cy: f64, s: f64, shade: [Color; 3]) {34    let mut faces = Vec::new();35    for quad in quads(cell) {36        let n = (37            quad.normal.x as f64,38            quad.normal.y as f64,39            quad.normal.z as f64,40        );41        if n.0 + n.1 + n.2 <= 0.0 {42            continue;43        }44        let tone = if n.2 > 0.0 {45            046        } else if n.1 > 0.0 {47            148        } else {49            250        };51        let pts: Vec<(f64, f64)> = quad52            .verts53            .iter()54            .map(|v| {55                let p = iso::project(v.x as f64 - HALF, v.y as f64 - HALF, v.z as f64 - HALF);56                (cx + p.0 * s, cy + p.1 * s)57            })58            .collect();59        let depth = quad60            .verts61            .iter()62            .map(|v| (v.x + v.y + v.z) as f64)63            .sum::<f64>();64        faces.push((depth, tone, pts));65    }66    faces.sort_by(|a, b| a.0.total_cmp(&b.0));67    for (_, tone, pts) in &faces {68        board.polygon(pts, shade[*tone]);69        let mut ring = pts.clone();70        ring.push(pts[0]);71        board.polyline(&ring, s / 18.0, ink::ground());72    }73}7475fn weight(corner: &[u8]) -> u64 {76    corner77        .iter()78        .map(|bit| if *bit == 0 { 2 } else { 1 })79        .product()80}8182fn main() -> Result<()> {83    let mut board = Board::square();84    let frame = board.frame(0.08);85    let gallery = bang(3).canonical();86    assert_eq!(gallery.len(), 22);87    assert_eq!(ROWS.iter().sum::<usize>(), gallery.len());88    let shade = shades(INDIGO);89    let (mx, _) = frame.center();90    let pitch = (frame.w / 5.0, frame.h / 5.0);91    let s = (pitch.0 * 0.46 / (3.0 * 0.866_025_403_784_438_6)).min(pitch.1 * 0.46 / 3.0);92    let mut taken = 0usize;93    for (r, count) in ROWS.iter().enumerate() {94        let cy = frame.y + (r as f64 + 0.5) * pitch.1;95        for j in 0..*count {96            let design = &gallery[taken];97            let cx = mx + (j as f64 - (*count as f64 - 1.0) / 2.0) * pitch.0;98            let solid = designs::create(design.i, NUMBER, 1, 2)?;99            assert_eq!((solid.width(), solid.height(), solid.depth()), (3, 3, 3));100            assert_eq!(101                solid.types().sum(),102                design103                    .rule()104                    .iter()105                    .map(|c| weight(c.as_slice()))106                    .sum::<u64>()107            );108            cage(&mut board, cx, cy, s);109            stamp(&mut board, &solid, cx, cy, s, shade);110            taken += 1;111        }112    }113    assert_eq!(taken, 22);114    save("demo-universe", &board)?;115    Ok(())116}