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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
//! §4.3.2 — every zero along an edge, not just the first.
//!
//! This is the half of subgrid Marching Tetrahedra that
//! [`surface`](super::surface) is defined against. Baktash, Gillespie & Crane,
//! `10.48550/arXiv.2606.00454` §1:
//!
//! > We replace 0-dimensional sampling (evaluate `f` at each grid node), with
//! > 1-dimensional root finding (find all zeros of `f` along each grid edge).
//!
//! A sign test asks one question per edge and gets one bit back. This asks *how
//! many times* and *where*, which is what lets a feature thinner than a cell
//! survive — M-67 measured the cost of the other approach: a sign test cannot
//! distinguish **95.6%** of the configurations a tetrahedron can be in.
//!
//! # Sampling is the primary path, not a fallback
//!
//! The 1D search below samples and refines rather than solving analytically, and
//! that is a deliberate single path rather than a degraded one. §1.3 prices it:
//!
//! > 1D marching can of course miss intersections, \[but\] we are no worse off
//! > than classic marching.
//!
//! An analytic root solver would need each field to expose its polynomial form,
//! which [`Sdf`] deliberately does not — the trait's whole point is
//! that a field is a black box. Offering both would mean two root finders and
//! two sets of results for one input, which is exactly what `CLAUDE.md`'s
//! one-path rule exists to prevent. **What sampling loses is bounded and
//! stated**: a pair of roots closer together than the sample spacing is invisible,
//! exactly as a pair closer than the *grid* spacing is invisible to classic
//! marching.
//!
//! # The sign convention, and why zero is not a root
//!
//! Inside is `f < 0`, and a sample of exactly zero counts as **outside** — the
//! same convention as [`marching_cubes`](crate::marching_cubes) and
//! [`marching_tetrahedra`](crate::marching_tetrahedra), stated here because a
//! root finder is precisely where an inconsistency would show up as a mesh that
//! is subtly not the field's. A crossing is a change in `f < 0` between two
//! samples, so a field that merely touches zero without passing through it
//! contributes no root, and neither does one that sits at zero along a stretch
//! of edge.
use Vec;
use crateReal;
use crateSdf;
/// How many refinement steps a bracketed root gets before it is accepted.
///
/// The bisection stops early once the midpoint stops differing from an endpoint,
/// which is machine precision for whichever [`Real`] is in use — 24 bits of
/// mantissa for `f32`, 53 for `f64`. This is the backstop that guarantees
/// termination regardless, and 80 is comfortably past `f64`'s worst case of 53.
const REFINEMENTS: u32 = 80;
/// The point at parameter `t` along the edge `from → to`.
///
/// The one expression every sample along an edge is positioned by. The extractor
/// reads the field here, and
/// [`mark_edit_subgrid`](crate::chunk::dirty::mark_edit_subgrid) asks what an
/// edit changed *at the points the extractor reads*, so the two share this
/// function rather than agree by algebra: M-32 is the reminder that two
/// expressions equal on paper are not equal in IEEE.
pub
/// The spacing of the sample parameters on an edge cut into `samples` intervals.
///
/// `samples` must be at least 1.
pub
/// The parameter of sample point `i` on an edge cut into `samples` intervals,
/// for `i` in `1..=samples` (point `0` is parameter zero).
///
/// The last point is exactly `1`, which an accumulating sum would only
/// approximate. `step` is [`edge_step`] for the same `samples`, passed in so a
/// loop pays for the division once.
pub
/// Every crossing along one edge, as parameters in `[0, 1]` from `from`.
///
/// `samples` is the 1D marching resolution: the edge is divided into that many
/// intervals, and each interval carrying a sign change yields one root. It must
/// be at least 1.
///
/// Results are appended to `out` in **ascending order**, which is
/// [`TetCrossings`](super::surface::TetCrossings)' contract. Two roots can never
/// coincide, because each comes from a distinct bracketing interval.
///
/// # Determinism
///
/// The parameters are computed as `i / samples` and refined by bisection on
/// those, so a given `(from, to, sdf, samples)` always produces bit-identical
/// output. That matters more here than anywhere else in the crate: two
/// tetrahedra sharing an edge call this independently and must agree exactly, or
/// the conformity §3.1 guarantees combinatorially is lost geometrically.
///
/// **The caller is responsible for calling this with identical endpoints** from
/// both sides. M-32 is the precedent: `origin + h·i` and `(origin + h·c·n) + h·i`
/// are equal by algebra and not by IEEE.
/// Bisect a bracketed sign change down to machine precision.
///
/// The bracket always contains a sign change on entry, and every step preserves
/// that, so the returned parameter is strictly inside the original interval —
/// which is what keeps roots from different intervals from colliding.