Expand description
§colino
Converts triangle meshes into narrow-band signed distance fields on brodo’s sparse volumes, and reports how the conversion may have changed the shape: a hole closed, a cavity opened, a wall too thin or a gap too narrow for the voxel size. ARCHITECTURE.md §5 says what a conversion gives and what each part of the report finds.
- Reading: binary and ASCII STL, Wavefront OBJ and 3MF, each into a
Mesh, under theLimitsyou set on triangles, vertices and bytes, so that an untrusted file cannot exhaust memory. A mesh from elsewhere, a CAD kernel’s triangulation say, is built as aMeshdirectly; itsgroupsandgroup_namescarry the faces’ names into the Hermite data. - Converting:
convertwithOptions, chiefly the voxel size in the mesh’s unit and the band’s half-width in voxels (with_band). It gives the topology, the distances (negative inside, in the mesh’s unit) and the grid’s metadata. Inside and outside are told by the generalised winding number, which holds where parts pass into each other or walls are doubled, approximate by default or exact (with_accuracy); or, for a mesh whose triangles face either way at random, by counting crossings (with_sign(Sign::Parity)). - Reporting:
reportcounts the components, tunnels and cavities of the solid and of the space around it; compares the Euler characteristic with the input’s when the input is closed and manifold; says which component each point you name lies in; and lists the places thinner, or gaps narrower, than two voxels. - Hermite data: where the mesh crosses each voxel edge, with its normal and the
triangle’s group, beside the signs at the corners, in brodo’s format
(
colino::hermite).
Features, each a part a user may leave out or opt into:
| Feature | Default | Gives |
|---|---|---|
stl | on | reading STL |
obj | on | reading OBJ |
threemf | on | reading 3MF, with its ZIP and XML parsing |
serde | off | the report serialisable with serde |
§Example
An octahedron read from OBJ text, converted, and its report checked:
use colino::convert::{Options, convert};
use colino::mesh::Limits;
use colino::report::{Place, report};
// An octahedron, its faces turned outward, as OBJ text.
let obj = b"v 10 0 0\nv -10 0 0\nv 0 10 0\nv 0 -10 0\nv 0 0 10\nv 0 0 -10\n\
f 1 3 5\nf 3 2 5\nf 2 4 5\nf 4 1 5\nf 3 1 6\nf 2 3 6\nf 4 2 6\nf 1 4 6\n";
// At most 2²⁰ triangles, 2²⁰ vertices and 64 MiB read.
let limits = Limits::new(1 << 20, 1 << 20, 1 << 26);
let mesh = colino::obj::from_bytes(obj, limits)?;
// Voxels of 0.5 in the mesh's unit; OBJ states none, so the grid is told its own.
let options = Options::new(0.5).with_unit(Some("millimeter".into()));
let converted = convert(&mesh, &options)?;
let points = [("centre".to_string(), [0.1, 0.2, 0.3]), ("far".to_string(), [30.0, 0.0, 0.0])];
// One solid piece with no tunnel or cavity, its Euler characteristic as the mesh's, and
// the first point inside it.
let r = report(&mesh, &converted, &points)?;
assert_eq!((r.solid.components, r.solid.tunnels, r.solid.cavities), (1, 0, 0));
assert_eq!(r.euler_change, Some(0));
assert_eq!(r.regions[0].place, Place::Solid);The examples convert a torus, checked against its exact distance, and a vented box whose
vent closes at a coarser voxel size. Each writes a slice as PNG and its report to
out/examples/colino/:
cargo run -p colino --example torus
cargo run -p colino --example ventGiven a mesh file of your own and a voxel size in its unit, the torus example converts that file instead:
cargo run -p colino --example torus -- part.stl 0.5It is written by a human, its owner, together with AI coding agents, chiefly Claude Code and Antigravity in support: the owner decides and approves, the agents write under the repository’s rules, and every change passes the same checks and tests (the repository’s README says more).
Issues are welcome at https://github.com/akahmys/brodo/issues, a bug with the steps that show it or a request. Pull requests are not accepted: code written elsewhere cannot be shown free of copyleft sources, so fixes are written here from issues.
Licensed under either of MIT or Apache-2.0, at your option.
The design is in the repository’s ARCHITECTURE.md §5.
Modules§
- bvh
- A tree of axis-aligned boxes over a mesh’s triangles (ARCHITECTURE.md §5.1, ADR-0027), for the triangle nearest a point. A node’s triangles are split in two at the median of their centres along the box’s longest side, down to a few a leaf; building and walking use an explicit stack. Of triangles at one distance, the lowest-numbered is nearest, so that the answer does not depend on the walk; for the triangle nearest a segment, ARCHITECTURE.md §5.1 says which is taken.
- convert
- A mesh converted into a narrow-band signed distance field on brodo’s tree (ARCHITECTURE.md §5.1, ADR-0027).
- distance
- The point of a triangle nearest a point (ARCHITECTURE.md §5.1, ADR-0027), by the textbook method that tells which of the triangle’s seven regions, three corners, three edges and the face, the point projects to. A triangle with no area, its corners on one line or one point, has no face: its nearest point is its edges’.
- error
- The crate’s error types.
- hermite
- Hermite data from a mesh, in brodo’s format (ARCHITECTURE.md §5.1, ADR-0030, ADR-0032): signs on the corners of a conversion’s voxels, and on each edge whose ends differ, where the mesh crosses it, its normal and its group.
- intersect
- Segments against triangles (ARCHITECTURE.md §5.1, ADR-0030): where a segment crosses a triangle, by Woop, Benthin and Wald’s watertight test (JCGT 2(1), 2013), and the point of a segment nearest a triangle.
- mesh
- A triangle mesh as read from a file (ARCHITECTURE.md §5.1): vertices and the triangles that index them, as given. Nothing is repaired; badly oriented, holed and degenerate meshes are kept as they are (ADR-0017).
- obj
- Wavefront OBJ (ARCHITECTURE.md §5.1, ADR-0026), after the Wavefront specification as
published at paulbourke.net/dataformats/obj/. This module parses untrusted bytes: it is
listed in
UNTRUSTED_INPUT, indexes nothing (CODING.md Rule 3), and is fuzzed (TESTING.md T6). - report
- The topology report’s three layers (ARCHITECTURE.md §5.2, ADR-0028).
- stl
- STL, binary and ASCII (ARCHITECTURE.md §5.1), after the Library of Congress’s format
descriptions fdd000505 and fdd000506. This module parses untrusted bytes: it is listed
in
UNTRUSTED_INPUT, indexes nothing (CODING.md Rule 3), and is fuzzed (TESTING.md T6). - surface
- A mesh’s surface as the topology report’s reference (ARCHITECTURE.md §5.2, ADR-0028):
its vertices, edges and faces, and whether it is a closed 2-manifold, every edge shared
by exactly two triangles in opposite directions, every vertex’s triangles one fan, no
triangle with a repeated corner. Only then is V − E + F the surface’s Euler
characteristic and half of it the solid’s. Weld a mesh that lists triangles’ corners
apart first (
Mesh::welded). - threemf
- 3MF (ARCHITECTURE.md §5.1, ADR-0026), after the 3MF Core Specification 1.4.0. This
module parses untrusted bytes: it is listed in
UNTRUSTED_INPUT, indexes nothing (CODING.md Rule 3), and is fuzzed (TESTING.md T6). - winding
- The generalised winding number of a mesh at a point (ARCHITECTURE.md §5.1, ADR-0027): the sum of its triangles’ signed solid angles over 4π, after Jacobson, Kavan and Sorkine-Hornung (2013); 1 inside a closed, outward-facing surface, 0 outside, and in between where the surface is open or overlaps itself. A triangle’s solid angle is van Oosterom and Strackee’s (their equation 6).