cadcore_math/lib.rs
1//! # cadcore-math
2//!
3//! Fundamental numeric primitives for the **cadcore** CAD kernel.
4//!
5//! This crate has **zero external dependencies** — everything is built on
6//! `std` and const-generic arithmetic.
7//!
8//! ## Design rules
9//!
10//! * All lengths are in **millimetres** unless noted otherwise.
11//! * All angles are in **radians** unless noted otherwise.
12//! * [`Point3`] and [`Vec3`] are distinct types — the compiler will not let
13//! you confuse a location with a direction.
14//! * Every function is pure; no global mutable state.
15//!
16//! ## Types at a glance
17//!
18//! | Type | Description |
19//! |---|---|
20//! | [`Point3`] | A location in 3-D space |
21//! | [`Vec3`] | A free vector (direction + magnitude) |
22//! | [`UnitVec3`] | A `Vec3` guaranteed to have length 1 |
23//! | [`Mat3`] | Column-major 3×3 matrix (rotations, linear maps) |
24//! | [`Frame3`] | Right-handed orthonormal frame (origin + 3 axes) |
25//! | [`Transform3`] | Rigid-body transform: rotation + translation |
26//! | [`Interval`] | Closed real interval `[lo, hi]` |
27//!
28//! ## Quick example
29//!
30//! ```rust
31//! use cadcore_math::{Point3, Vec3, UnitVec3, Frame3};
32//!
33//! let origin = Point3::new(1.0, 2.0, 3.0);
34//! let dir = UnitVec3::try_from_vec(Vec3::new(0.0, 0.0, 1.0)).unwrap();
35//! let frame = Frame3::from_origin_z(origin, dir);
36//!
37//! let world_pt = Point3::new(4.0, 5.0, 6.0);
38//! let local_pt = frame.to_local_point(world_pt);
39//! let back = frame.to_world_point(local_pt);
40//! assert!((world_pt - back).length() < 1e-10);
41//! ```
42
43#![warn(missing_docs)]
44#![warn(clippy::pedantic)]
45#![allow(clippy::module_name_repetitions)]
46
47mod interval;
48mod mat3;
49mod point3;
50mod transform;
51mod unitvec;
52mod vec3;
53mod frame;
54
55pub use interval::Interval;
56pub use mat3::Mat3;
57pub use point3::Point3;
58pub use transform::Transform3;
59pub use unitvec::UnitVec3;
60pub use vec3::Vec3;
61pub use frame::Frame3;
62
63/// Machine epsilon for `f64` comparisons.
64pub const EPS: f64 = 1e-10;
65/// π
66pub const PI: f64 = std::f64::consts::PI;
67/// 2π
68pub const TAU: f64 = std::f64::consts::TAU;
69
70/// Return `true` when two `f64` values are within [`EPS`] of each other.
71#[inline]
72pub fn approx_eq(a: f64, b: f64) -> bool { (a - b).abs() < EPS }
73
74/// Clamp `v` into `[lo, hi]`.
75#[inline]
76pub fn clamp(v: f64, lo: f64, hi: f64) -> f64 { v.max(lo).min(hi) }
77
78/// Linearly interpolate: `(1-t)*a + t*b`.
79#[inline]
80pub fn lerp(a: f64, b: f64, t: f64) -> f64 { a + t * (b - a) }