pantometry_shape/lib.rs
1//! Designed geometry as simulation input: a mesh read, measured, and turned into cells.
2//!
3//! Every domain in this workspace takes a **structured grid** — a box of cubes, `counts` and a cell
4//! size. Every 3D file a person designs is a **surface**: a bag of triangles, or a boundary
5//! representation that was tessellated into one. This crate is the bridge, and the bridge is where the
6//! physics gets decided.
7//!
8//! # The cell size decides three things at once, and only one of them is obvious
9//!
10//! A caller picking `cell_mm` is picking, in one number:
11//!
12//! - **how much of the shape survives.** A 0.5 mm rib voxelised at 2 mm is not a thin rib, it is *gone*,
13//! and the simulation runs perfectly well without it;
14//! - **the stability limit**, and therefore the step count, as `dx²`;
15//! - **the discretisation error** of whatever physics runs on it.
16//!
17//! The first is the one that has no symptom. A missing feature does not make a solver fail, produce a
18//! `NaN`, or trip the conservation audit — it produces a smooth, plausible answer about a different
19//! object. That is the failure this workspace is organised around not having, so this crate's job is not
20//! only to rasterise but to **say what the rasterisation lost**: see [`Loss`].
21//!
22//! # What this is not
23//!
24//! **Not a domain.** It depends on `pantometry-units` and nothing else in the workspace, and no domain
25//! depends on it. It produces a predicate; a domain's `fill` consumes one. That is the whole coupling,
26//! and it means adding geometry cost the ten domains nothing.
27//!
28//! **Not a mesh library.** No refinement, no repair, no boolean operations, no simplification. It reads
29//! what a CAD tool exported, measures it, and rasterises it.
30//!
31//! **STL only, and that is a dependency decision rather than a preference.** STEP needs a B-rep kernel
32//! and glTF needs a JSON and binary parser; both are external crates, and this workspace gates every one
33//! of its twelve through `deny.toml`. STL is the format every CAD tool exports and it can be read in two
34//! hundred lines with nothing added. When a second format earns its dependency it goes beside this one.
35//!
36//! # Where it sits
37//!
38//! ```text
39//! a designed file ──► Mesh ──► Voxels ──► `|i, j, k| voxels.contains(i, j, k)`
40//! │ │ │
41//! volume, Loss: Solid3D::fill
42//! closed? what the grid Block::fill
43//! could not hold Waves::fill
44//! ```
45//!
46//! The predicate on the right is exactly the signature those three already take, which is why this
47//! needed no change to any of them.
48
49#![deny(missing_docs)]
50
51mod mesh;
52mod voxels;
53
54pub use mesh::{Mesh, Triangle};
55pub use voxels::{Loss, Voxels};