layer.rs

2.4 kB · rust · 82 lines

1use super::sample::{axes, membership};2use super::{Lattice, Spec};3use mrlycore::errors::{value_error, Result};45/// The recipe for one moire layer.6#[derive(Clone, Debug)]7pub struct Layer {8    /// The design to sample.9    pub spec: Spec,10    /// The side number of the residue grid.11    pub number: usize,12    /// The fractal depth.13    pub level: usize,14    /// The sampling lattice.15    pub lattice: Lattice,16    /// The output side in pixels.17    pub size: usize,18    /// The 0..1 positions fixing the axes beyond the first two.19    pub slices: Vec<f64>,20}2122impl Layer {23    /// Builds a layer at level 1 on a 512-pixel square lattice.24    pub fn new(spec: Spec, number: usize) -> Layer {25        Layer {26            spec,27            number,28            level: 1,29            lattice: Lattice::Square,30            size: 512,31            slices: Vec::new(),32        }33    }34}3536/// Samples a design over the pixel grid into a boolean mask, or an error below dimension 2.37pub fn layer(params: &Layer) -> Result<Vec<bool>> {38    let Spec {39        code,40        base: q,41        dimension: d,42    } = params.spec;43    if d < 2 {44        return value_error("moire needs dimension >= 2.");45    }46    let size = params.size;47    let n = params.number;48    let table = membership(code, q, d)?;49    let extra = d - 2;50    let mut mask = vec![true; size * size];51    for k in 0..params.level.max(1) {52        let s = (n * q.pow(k as u32)) as f64;53        let mut fixed = Vec::with_capacity(extra);54        for e in 0..extra {55            let pos = params.slices.get(e).copied().unwrap_or(0.0);56            let r = ((s * pos).floor() as i64).rem_euclid(q as i64) as usize;57            fixed.push(r);58        }59        for row in 0..size {60            let (a, b) = axes(size, params.lattice, row);61            let base_idx = row * size;62            for col in 0..size {63                let cell = base_idx + col;64                if !mask[cell] {65                    continue;66                }67                let ia = (s * a[col]).floor() as i64;68                let ib = (s * b[col]).floor() as i64;69                let ra = ia.rem_euclid(q as i64) as usize;70                let rb = ib.rem_euclid(q as i64) as usize;71                let mut idx = ra * q + rb;72                for &f in &fixed {73                    idx = idx * q + f;74                }75                if !table[idx] {76                    mask[cell] = false;77                }78            }79        }80    }81    Ok(mask)82}