layer.rs

2.5 kB · rust · 87 lines

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