amosaic 1.0.0

This library provides tools for generating and working with aperiodic tilings and mosaics, based on the hat monotile discovered by David Smith and inspired by the work of Craig S. Kaplan.
Documentation
//! # Amosaic
//!
//! `Amosaic` is a Rust library for generating **aperiodic tilings and mosaics** based on the [hat monotile](https://en.wikipedia.org/wiki/Aperiodic_monotile).
//!
//! It transforms input images into mosaic patterns using geometric tiling techniques, leveraging the **Smith–Myers–Biggs–Kaplan** hat tile for non-periodic arrangements.
//!
//! ## 📦 Installation
//!
//! Add this to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! amosaic = "1.0.0"
//! ```
//!
//! ## ✨ Features
//!
//! - Generates aperiodic tilings using the **hat monotile**.
//! - Supports **image-based color sampling** for realistic mosaic patterns.
//! - Uses `nalgebra` for geometric transforms and `image` crate for pixel processing.
//!
mod hat;

use anyhow::Result;
use hat::tiles::{collect_hats, DrawContext, MetaTile, Tile};
use hat::{AMosaic, ImageDrawContext};
use image::{open, ImageBuffer, Rgb};

#[cfg(test)]
mod tests {

  use image::RgbImage;
  use std::fs;

  use super::*;
  #[test]
  fn test_generate_mosaic_from_input() -> Result<()> {
    // load & decode the PNG
    let input_img = image::open("input.png")?.into_rgb8();
    let (width, height) = input_img.dimensions();
    let buffer = input_img.clone().into_raw();

    let amosaic = AMosaic::new(width, height, buffer);
    let mut mosaic_img = RgbImage::from_pixel(width, height, Rgb([255, 255, 255]));
    amosaic.draw(/*scale=*/ 30.0, &mut mosaic_img)?;
    mosaic_img.save("output.png")?;

    let pixel_sum: u64 = mosaic_img
      .pixels()
      .map(|p| (p[0] as u64 + p[1] as u64 + p[2] as u64))
      .sum();
    assert!(
      pixel_sum > 0,
      "Output image is entirely dark (all pixels black)"
    );
    Ok(())
  }

  #[test]
  fn test_generate_mosaic_as_svg() -> Result<(), Box<dyn std::error::Error>> {
    // 1) Load & decode the PNG input
    let input_img = image::open("input.png")?.into_rgb8();
    let (width, height) = input_img.dimensions();
    let buffer = input_img.clone().into_raw();

    // 2) Build AMosaic and produce the SVG string
    let amosaic = AMosaic::new(width, height, buffer);
    let svg_output = amosaic.to_svg(/* scale */ 100.0);

    // 3) Write it out
    fs::write("output.svg", &svg_output)?;

    // 4) Basic sanity check: file exists and has an <svg> tag
    let contents = fs::read_to_string("output.svg")?;
    assert!(
      contents.starts_with("<?xml") || contents.contains("<svg"),
      "SVG output missing expected header or <svg> element"
    );

    Ok(())
  }
}