Expand description
§brepkit-math
Vectors, matrices, NURBS, analytic curves and surfaces, and exact geometric predicates. Layer L0 of the brepkit CAD kernel, with no workspace dependencies.
§What is here
| Area | Modules |
|---|---|
| Linear algebra | vec, mat, plane, frame |
| NURBS | nurbs (evaluation, knot operations, fitting, projection, intersection) |
| Analytic curves | curves, curves2d |
| Analytic surfaces | surfaces, analytic_intersection |
| Robustness | tolerance, predicates, filtered |
| Spatial structures | aabb, obb, bvh, cdt, convex_hull |
| 2D polygons | polygon2d, polygon_offset |
§Points are not vectors
Point3 (a position) and Vec3 (a direction)
are separate types rather than one three-float struct. Subtracting two
points gives a vector; adding a vector to a point gives a point; adding two
points is not defined. The distinction is load-bearing under transforms: a
Mat4 translates a point but must not translate a direction,
and conflating the two is a classic source of silently wrong normals.
§The tolerance model
Floating-point coordinates never compare equal in the way geometry needs.
A wire that closes to within a billionth of a millimetre has closed, and a
kernel that insists on bit equality will reject every real model. So
measured comparisons, distances, angles, and coordinates go through
Tolerance, which bundles three thresholds.
Orientation decisions are the deliberate exception, covered below.
| Field | Default | Meaning |
|---|---|---|
linear | 1e-7 | Distance below which two points are the same point |
angular | 1e-12 rad | Angle below which two directions are parallel |
relative | 1e-10 | Fraction of the larger operand, for scale-aware comparison |
Three presets are provided. Tolerance::new
is the CAD default above. loose
(1e-4/1e-8/1e-6) suits visualization and rough checks.
tight (1e-10/1e-15/1e-14) suits
high-precision work, at the cost of rejecting geometry that a looser
setting would accept.
§Scale-aware by default
approx_eq is not a plain epsilon
compare. It returns true when
|a - b| <= max(linear, relative * max(|a|, |b|))The relative term is what keeps the comparison meaningful at any
magnitude. Two coordinates near 1e6 differ by more than 1e-7 purely
from rounding, and an absolute-only test would call them distinct forever.
That scaling is wrong for quantities that are not coordinates. A dot
product, a determinant, or anything already normalized should use
approx_eq_abs, which compares
against linear alone. Reaching for approx_eq on a near-zero dot product
works, because the relative term vanishes, but on a large one it silently
widens the threshold.
§When exactness is required
Some decisions cannot be tolerance-based at all. Whether a point is left
of a line, or above a plane, has to be consistent across every call or the
algorithm built on it will contradict itself and produce a non-manifold
result. The predicates module provides filtered exact orientation
tests (orient2d,
orient3d) that compute in floating point, check
whether the error bound admits the answer, and fall back to exact
arithmetic only when it does not. They are fast in the common case and
never wrong in the degenerate one.
§When tolerance bites
Two situations account for most tolerance trouble:
- Geometry far from the origin. Doubles carry roughly 15 significant
digits. Near a coordinate of
1e7the gap between representable values is about1.9e-9, so a1e-7linear tolerance sits only some 50 times above the noise floor. Booleans on far-flung parts lose precision well before they lose correctness. Translate the part near the origin, operate, and translate back. - Units much smaller than a millimetre. The defaults assume millimetre
scale. Modelling in micrometres makes
1e-7of your unit a distance the kernel cannot resolve, and distinct points start merging. Model in millimetres and scale at export.
As a rule, keep coordinates roughly within 1e0 to 1e4 in your chosen
units and the defaults take care of themselves.
§Analytic first, NURBS as the general case
Curves and surfaces are enums, not one universal representation.
Circle3D is a circle, not a rational B-spline that
happens to be circular. Analytic types get closed-form intersections where
a pair admits one (see analytic_intersection), which is both faster and
exact. NURBS is what everything can convert into and what free-form
geometry uses: the fallback, not the default.
§Example
use brepkit_math::curves::Circle3D;
use brepkit_math::tolerance::Tolerance;
use brepkit_math::vec::{Point3, Vec3};
let center = Point3::new(0.0, 0.0, 0.0);
let circle = Circle3D::new(center, Vec3::new(0.0, 0.0, 1.0), 2.0)?;
let tol = Tolerance::new();
let start = circle.evaluate(0.0);
let quarter = circle.evaluate(std::f64::consts::FRAC_PI_2);
// Every point sits one radius from the center, in the plane the normal
// defines, and a quarter turn is a right angle.
assert!(tol.approx_eq((quarter - center).length(), 2.0));
assert!(tol.approx_eq_abs(quarter.z(), 0.0));
assert!(tol.approx_eq_abs((start - center).dot(quarter - center), 0.0));
// Which direction `evaluate(0.0)` points is set by the frame derived from
// the normal. Use `Circle3D::new_with_ref` when the seam position matters.§See also
brepkit_topology: the B-Rep structures these types give shape to.brepkit_operations: the modeling operations most projects call instead of this crate directly.- brepjs.dev: the same tolerance model from the TypeScript side, with guidance on when to heal.
Modules§
- aabb
- Axis-aligned bounding boxes for spatial queries.
- analytic_
intersection - Closed-form and semi-analytic intersections of analytic surfaces with planes.
- bvh
- Flat-array AABB tree for broad-phase spatial queries.
- cdt
- Constrained Delaunay Triangulation (CDT).
- chord
- Chord deviation computation for circular arc discretization.
- convex_
hull - 3D convex hull via incremental Quickhull algorithm.
- curves
- Analytic 3D curve types: lines, circles, and ellipses.
- curves2d
- 2D analytic curve types for parametric curves on surfaces (pcurves).
- det_
hash - Deterministic hashing primitives.
- filtered
- Filtered exact arithmetic for geometric predicates.
- frame
- Orthonormal reference frame in 3D space.
- mat
- Matrix types for geometric transforms.
- nurbs
- NURBS curve and surface representations.
- obb
- Oriented bounding box (OBB) for tighter spatial filtering.
- plane
- Plane intersection utilities.
- polygon2d
- 2D polygon operations: clipping, filleting, chamfering, and segment detection.
- polygon_
boolean - Robust 2D boolean operations on simple polygons (union, intersection, difference).
- polygon_
offset - 2D polygon offset via parallel edge translation and miter joins.
- predicates
- Exact geometric predicates backed by the
robustcrate. - quadrature
- Gauss-Legendre quadrature for numerical integration.
- ray_
triangle - Watertight ray-triangle intersection (Woop, Benthin, Wald 2013).
- simd
- SIMD-friendly batch math operations.
- surfaces
- Analytic surface types for exact geometric computations.
- tolerance
- Tolerance model for geometric comparisons.
- traits
- Parametric geometry traits for unified curve and surface evaluation.
- vec
- Vector and point types for geometric computation.
Enums§
- Math
Error - Errors from math operations.