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}