Skip to main content

Crate brepkit_math

Crate brepkit_math 

Source
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

AreaModules
Linear algebravec, mat, plane, frame
NURBSnurbs (evaluation, knot operations, fitting, projection, intersection)
Analytic curvescurves, curves2d
Analytic surfacessurfaces, analytic_intersection
Robustnesstolerance, predicates, filtered
Spatial structuresaabb, obb, bvh, cdt, convex_hull
2D polygonspolygon2d, 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.

FieldDefaultMeaning
linear1e-7Distance below which two points are the same point
angular1e-12 radAngle below which two directions are parallel
relative1e-10Fraction 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 1e7 the gap between representable values is about 1.9e-9, so a 1e-7 linear 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-7 of 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 robust crate.
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§

MathError
Errors from math operations.