models.rs

3.0 kB · rust · 102 lines

1use super::{Orientation, Projection, FILL, VOID};2use crate::two::Cell2d;3use mrlycore::errors::Result;4use mrlycore::tensor::Tensor;56/// The projected cell: a triangle grid with its projection, orientation and start parity.7#[derive(Clone, Debug, PartialEq, Eq)]8pub struct Cell6d {9    /// The triangle grid of type codes.10    pub cell: Cell2d,11    /// The projection that made the grid.12    pub projection: Projection,13    /// The way the hexagon points.14    pub orientation: Orientation,15    /// The parity of the first triangle.16    pub start: u8,17}1819impl Cell6d {20    /// Builds a cell from its four parts.21    pub fn new(22        cell: Cell2d,23        projection: Projection,24        orientation: Orientation,25        start: u8,26    ) -> Cell6d {27        Cell6d {28            cell,29            projection,30            orientation,31            start,32        }33    }34    /// Returns the grid width in triangles.35    pub fn width(&self) -> usize {36        self.cell.width()37    }38    /// Returns the grid height in triangles.39    pub fn height(&self) -> usize {40        self.cell.height()41    }42    /// Swaps every fill triangle for a void and back.43    pub fn anti(mut self) -> Cell6d {44        for v in self.cell.cell.types.bytes_mut().iter_mut() {45            if *v == FILL {46                *v = VOID;47            } else if *v == VOID {48                *v = FILL;49            }50        }51        self52    }53    /// Maps each triangle to one at or above the threshold, zero below.54    pub fn binarize(self, threshold: u8) -> Cell6d {55        Cell6d {56            cell: self.cell.binarize(threshold),57            ..self58        }59    }60    /// Binarizes the triangles at the threshold Otsu's method picks.61    pub fn binarize_otsu(self) -> Cell6d {62        Cell6d {63            cell: self.cell.binarize_otsu(),64            ..self65        }66    }67    /// Rounds each triangle to the mean of its masked neighborhood, wrapping on request.68    pub fn blur(self, mask: &Tensor, wrap: bool) -> Result<Cell6d> {69        Ok(Cell6d {70            cell: self.cell.blur(mask, wrap)?,71            ..self72        })73    }74    /// Writes the value wherever the tiled mask is nonzero.75    pub fn perforate(self, mask: &Tensor, value: u8) -> Result<Cell6d> {76        Ok(Cell6d {77            cell: self.cell.perforate(mask, value)?,78            ..self79        })80    }81}8283#[cfg(test)]84mod tests {85    use super::*;86    use crate::six::designs::iso_design;87    #[test]88    fn binarize_wrapper_keeps_projection_metadata() {89        let hex = iso_design(23, 3, 1, 2).unwrap();90        let binarized = hex.clone().binarize(1);91        assert_eq!(binarized.projection, hex.projection);92        assert_eq!(binarized.orientation, hex.orientation);93        assert_eq!(binarized.start, hex.start);94    }95    #[test]96    fn perforate_wrapper_zero_mask_is_identity_6d() {97        let hex = iso_design(23, 3, 1, 2).unwrap();98        let mask = Tensor::new(hex.cell.types().shape.clone());99        let perforated = hex.clone().perforate(&mask, 5).unwrap();100        assert_eq!(perforated.cell.types(), hex.cell.types());101    }102}