lib/geometry/src/tolerance.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 //! Every tolerance the package compares against, in one place.
2 //!
3 //! Primitive queries are exact computations in strict float mode that reject
4 //! only degenerate input through the floors below. Tree queries add
5 //! one relative slack to their box tests so a node box never culls a triangle
6 //! that the primitive test would accept.
7 const std = @import("std");
8
9 /// Two directions whose angle has a sine at or below this are parallel. A
10 /// cross or triple product this small next to its factors' lengths is mostly
11 /// rounding, which is about 2^-22 of those lengths in f32, so every answer
12 /// built on one would be noise. The test is relative, so it reads the same at
13 /// every coordinate scale.
14 pub const sine_floor: f32 = 0x1p-16;
15
16 /// A squared length at or below this has no direction, so a segment this
17 /// short is a point.
18 pub const length_sq_floor: f32 = 1e-20;
19
20 /// A ray direction component at or below this magnitude is parallel to the
21 /// matching slab, so its reciprocal is never formed.
22 pub const direction_component_floor: f32 = 1e-30;
23
24 /// Whether a product of squared magnitude `product_sq` is parallel noise next
25 /// to `factors_sq`, the product of its factors' squared lengths. A triangle
26 /// is degenerate when its area normal is parallel noise next to its two
27 /// edges, and a ray grazes a triangle when their determinant is parallel
28 /// noise next to the ray and both edges.
29 pub fn isParallel(product_sq: f32, factors_sq: f32) bool {
30 return product_sq <= sine_floor * sine_floor * factors_sq;
31 }
32
33 /// A closing speed squared at or below this cannot reach a feature within the
34 /// sweep, so the feature contributes no contact.
35 pub const closing_sq_floor: f32 = 1e-24;
36
37 /// The margin tree box tests add on every side, for coordinates no larger than
38 /// `magnitude` in absolute value. Sixteen units in the last place of the
39 /// largest coordinate bound the rounding of a slab or closest-point test.
40 pub fn boxSlack(magnitude: f32) f32 {
41 std.debug.assert(magnitude >= 0);
42 return 16 * std.math.floatEps(f32) * magnitude;
43 }
44
45 test "parallel noise is judged relative to the factors" {
46 try std.testing.expect(isParallel(0, 0));
47 try std.testing.expect(isParallel(1, 1e12));
48 try std.testing.expect(!isParallel(1e-6, 1));
49 try std.testing.expect(!isParallel(1e6, 1e12));
50 }
51
52 test "box slack scales with the coordinate magnitude" {
53 try std.testing.expectEqual(@as(f32, 0), boxSlack(0));
54 try std.testing.expect(boxSlack(1000) > boxSlack(1));
55 try std.testing.expect(boxSlack(1) < 1e-5);
56 }