1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
use Aabb;
use orient3d;
use ;
use Tri;
// --- ray parity: sound far endpoint + exact inside test -------------------
/// EXACT segment–triangle intersection via `orient3d` (no epsilon): the segment
/// `q1→q2` crosses triangle `t` iff its endpoints straddle `t`'s plane AND the
/// line passes the same side of all three edges. A grazing hit (`orient3d == 0`)
/// is rejected — the fixed generic ray direction makes those vanishingly rare.
pub
/// Ray-cast "far" distance: just past the operand's actual extent. Critically NOT
/// a huge constant (1e7) — that blows the orient3d float-filter error bound so
/// EVERY predicate escalates to BigRational (≈5000× slower). Sized to the operand,
/// the float filter resolves the common case and only true grazing escalates.
pub
/// The fixed generic ray direction for parity casts. No two components
/// near-equal and no pairwise ratio near a simple architectural slope (1:1
/// roofs, axis planes). The previous direction had x≈y and dz/dx≈1 — nearly
/// PARALLEL to 45° roof slopes/ridge edges, so a roof-clipped wall's ray grazed
/// the roof and edge-crossings (rejected, not counted) miscounted parity → the
/// sub-ridge gable triangle was wrongly judged inside the cutter and removed
/// (the "missing wall" over-clip). Shared by [`point_inside`] and the
/// per-component AABB ray prefilter so they can never disagree.
pub
/// The parity segment's far endpoint, placed strictly outside `[lo, hi]` (the
/// AABB of the mesh being tested) - the soundness condition the parity argument
/// needs, and the one the pre-fix code did not have.
///
/// PRECONDITION: `far_l` must be commensurate with the box, which every caller
/// satisfies by passing `operand_extent` of the SAME mesh (that bounds
/// `esc / far_l` at about 3.3). Hand a `far_l` far smaller than the box and
/// `esc + far_l` is absorbed by f64 rounding, putting the endpoint back inside:
/// measured 33425 of 200000 at box scale 1e10 to 1e18 with `far_l` in [1, 10].
/// The assert below pins that, since the property is otherwise silent.
///
/// `far_l` is `operand_extent(other)`, sized from the coordinates of the OTHER
/// operand. But `p` is a centroid of THIS operand, and can sit outside that
/// envelope along `dir`. Then `p + dir*far_l` lands strictly INSIDE the other
/// solid: the segment counts the ENTRY crossing and never reaches the EXIT, odd
/// parity calls an outside point inside, and in a Difference the triangle is
/// dropped - deleting a whole face of the host and leaving an open shell. That
/// is issue #3341, where two boxes that merely TOUCH lose a face of the host,
/// and a purely DISJOINT pair does the same. The bug is the segment LENGTH; it
/// has nothing to do with touching or coplanarity.
///
/// When the default endpoint falls inside the AABB, walk out along `dir` to the
/// first face of the box it can escape through and add a `far_l` margin. Both
/// endpoints then lie outside the mesh, so both parities are valid; what the
/// extension buys is that the NEW one is reliably so.
///
/// Note what this does NOT claim. Extension fires whenever the old endpoint was
/// inside the AABB, which on a non-convex operand includes points inside the
/// bounding box but outside the solid, where the old parity was already correct.
/// Those queries do get a different, longer segment. The justification is not
/// that they are untouched, it is that both endpoints are outside the solid and
/// so both answers agree. Queries whose endpoint was ALREADY outside the AABB
/// keep a byte-identical segment, because the early return below is literally
/// the pre-fix expression.
///
/// The escape face is chosen per axis by `dir`'s sign, so this holds for any
/// direction and not only the all-positive [`ray_dir`]; pinned by
/// `classify_tests::the_extended_endpoint_clears_the_box_for_any_direction_sign`,
/// which also records why that generality is load-bearing.
///
/// FMA-free f64 throughout, so native and wasm stay bit-identical.
pub
/// Is point `p` inside the closed mesh `tris`? Exact ray-cast parity to a far
/// point (`far_l` past the extent, lengthened by [`sound_far`] whenever that
/// endpoint would land inside the mesh) along a fixed generic direction; each
/// crossing tested by the exact predicate above.
///
/// `aabb` must CONTAIN `tris`'s true box; every caller already holds one, so this
/// takes it rather than rescanning per query. A superset is verdict-identical:
/// [`sound_far`] only uses it to lengthen the far endpoint, and extending past the
/// real AABB crosses no further triangles, so parity is unchanged.
pub