Skip to main content

Crate colino

Crate colino 

Source
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 the Limits you 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 a Mesh directly; its groups and group_names carry the faces’ names into the Hermite data.
  • Converting: convert with Options, 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: report counts 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:

FeatureDefaultGives
stlonreading STL
objonreading OBJ
threemfonreading 3MF, with its ZIP and XML parsing
serdeoffthe 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 vent

Given 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.5

It 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).