//! Draw concentric spheres that are rendered together
//!
//! >>> cargo run --example concentric
//!
//! Writes to `target/test_renderings/concentric.*`
use crater::{
    bounding::BoundingBox,
    csg::{
        algebra::CSGAlgebra,
        marching_cubes::{marching_cubes, MarchingCubesParams},
        regions::Region,
        surfaces::{IntoSurface, Surface3D},
    },
    mesh::MeshCollection,
    serde::vtk::evaluations::{GeometryEvaluator, MeshCollectionEvaluator, MeshColoring},
    utils::Parallel,
};

fn make_concentric() -> Vec<Region<3>> {
    (0..10)
        .map(|i| {
            let r = 0.5 * (i as f64 + 1.0);
            -Surface3D::Sphere { r }.into_surface()
        })
        .collect()
}

fn main() {
    // Generate the spheres
    let spheres = make_concentric();
    // Marching Cubes over each of them
    let resolution = 30;
    let bound = 10.0;
    let meshes: MeshCollection = spheres
        .into_iter()
        .map(|region| {
            let params = MarchingCubesParams {
                region,
                bounds: BoundingBox {
                    min: [-bound, -bound, -bound],
                    max: [bound, bound, bound],
                },
                resolution: (resolution, resolution, resolution),
                algebra: CSGAlgebra::default(),
            };
            marching_cubes::<Parallel>(&params)
        })
        .into();

    let mut path_buf = std::path::PathBuf::from("./target/test_renderings/");
    path_buf.push("concentric");
    path_buf.set_extension("stl");
    std::fs::create_dir_all(path_buf.parent().expect("Failed to get parent directory"))
        .expect("Failed to create directory");

    // Write the mesh to VTK:
    // STL
    meshes
        .write_stl(path_buf.to_str().unwrap())
        .expect("Failed to write csg.stl");

    // VTK
    let algebra = CSGAlgebra::default();
    let spheres = make_concentric();
    let evaluators: Vec<Box<dyn MeshCollectionEvaluator>> = vec![
        Box::new(GeometryEvaluator::Gradients(&spheres, &algebra)),
        Box::new(GeometryEvaluator::Normals(&spheres, &algebra)),
        Box::new(MeshColoring),
    ];

    meshes
        .to_vtk(Some(evaluators.as_slice()))
        .export_be(path_buf.with_extension("vtk").to_str().unwrap())
        .unwrap();
}