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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
//! Measured tolerance for offset constructions — the deviation OBSERVED
//! between a built entity and the geometry it was built to reproduce.
//!
//! # What this module is
//!
//! [`crate::MeasuredTolerance`] is the vocabulary; this is the offset family's
//! measurement. Two quantities, one per construction kind:
//!
//! * [`measure_edge_against_pcurve_image`] — for a rim/trim edge built by
//! sampling a pcurve through a surface and interpolating the images:
//! `max_t ‖C_3d(t) − S(p(t))‖`. This is the number that makes the offset
//! family's tolerance measured rather than predicted — the size-derived band
//! stays the acceptance bar the caller gates on, and this observed deviation
//! is what gets recorded — and the analogue of OCCT's
//! `BRepOffset_SimpleOffset::FillEdgeData`
//! (`BRepOffset_SimpleOffset.cxx:296-310`), which sets the edge tolerance to
//! exactly this distance measured with `BRepLib_ValidateEdge`.
//! * [`measure_surface_fit_against_pointwise_offset`] — for a carrier built by
//! collocation: `max_{u,v} ‖S_fit(u,v) − offset(u,v)‖`. Nothing in this tree
//! has ever measured our Greville fit against the pointwise offset it
//! interpolates; this does.
//!
//! Plus [`vertex_endpoint_gap`], the endpoint half of the edge → vertex
//! propagation whose rule (and whose verdict on OCCT's 1.001 factor) lives on
//! [`crate::vertex_tolerance_from_edges`].
//!
//! # Why the edge measurement is `adaptive_coedge_error` PLUS a span pass
//!
//! `brep/topology/validate.rs:453` already computes `max_s ‖S(q(s)) − c(t(s))‖`
//! over an adaptive subdivision, seam-aware through `evaluate_extended`, and it
//! is what [`crate::BrepSolid::validate`] itself runs on every coedge. Writing a
//! second sampler from scratch would produce a second answer to one question —
//! the failure the offset-unification audit spent five slices removing — so it
//! is kept as the general backstop and its band-driven refinement is passed
//! through exactly as validate passes `pcurve_limit`.
//!
//! **But it is not sufficient here, and this was measured, not assumed.** Its
//! sample set is 32 uniform intervals bisected to depth 3, i.e. the DYADIC grid
//! of multiples of 1/256. Every 3D curve `offset_face_carrier` built when this
//! was written came from `mapped_pcurve_polyline`, whose adaptive subdivision
//! bisects the same interval and therefore places its interpolation nodes on
//! the dyadic grid too (up to 1024 of them at its depth cap,
//! `offset/offset.rs:560`). Once the polyline is finer than 1/256, **every one
//! of the sampler's points is an interpolation node**, where a degree-1
//! interpolant is exact by construction. (Since 2026-09-06 the carrier builds
//! its edges through the `image_curve` ladder and reaches that polyline only
//! as the ladder's fallback — `offset.rs::carrier_edge_curve` — but the
//! fallback, and any degree-1 curve a caller transfers, is measured here the
//! same way.)
//! Measured on a 1200-long cylinder's cap rim: `adaptive_coedge_error` answers
//! `8.0e-14`; a dense scan of the same comparison answers `2.356e-3`. Ten orders
//! of magnitude, and the aliasing gets WORSE the finer the curve. (The same
//! blind spot is in `BrepSolid::validate`, which runs the same sampler over the
//! same curves — recorded in the study doc, not fixed here.)
//!
//! So the measurement adds [`span_midpoint_error`]: one sample at the MIDPOINT
//! of each of the curve's own knot spans. For a degree-1 interpolant — the
//! construction's fallback curve — the deviation from the smooth image is
//! zero at the nodes and extremal inside the span, so a midpoint per span is not
//! a heuristic, it is the right estimator for this construction class. The
//! recorded deviation is the maximum of the two passes: a general backstop that
//! can see between spans, and a span pass that cannot be aliased away.
//!
//! A caller transferring a HIGHER-degree curve (the general pcurve → 3D image
//! curve the `image_curve` ladder interpolates as a cubic once neither its
//! affine nor its iso tier applies) needs both for the opposite reason: a
//! cubic's worst point is not generally the span midpoint, so the adaptive pass
//! carries that case and the span pass only floors it.
//!
//! Cost is bounded by the curve's own span count plus one validate pass — a
//! ceiling this kernel already pays on every offset result.
//!
//! # The direction rule
//!
//! Everything here RECORDS. Nothing here widens a band. See
//! [`crate::MeasuredTolerance`]'s "direction rule".
use crate;
use crate::;
/// The grid used by [`measure_surface_fit_against_pointwise_offset`], and the
/// two fractional offsets that keep its samples off the knot lines a
/// collocation fit interpolates exactly.
///
/// Both are copied deliberately from the free-form push's dense residual gate
/// (`edit/direct_edit/face_offset_freeform.rs:72-76`): 15x15 with `+0.31` /
/// `+0.43` cell offsets. Sampling the Greville parameters themselves would
/// report `0.0` by construction — the fit interpolates there — so the whole
/// value of this measurement is in sampling BETWEEN them.
const FIT_SAMPLES: usize = 15;
const FIT_OFFSET_U: f64 = 0.31;
const FIT_OFFSET_V: f64 = 0.43;
/// `max_t ‖C_3d(t) − S(p(t))‖` — how far the edge's own 3D curve sits from the
/// locus its pcurve traces on `surface`, recorded against `band`.
///
/// This is the measurement that makes a general pcurve → 3D transfer
/// trustworthy: the transfer's whole claim is that the interpolated 3D curve
/// reproduces the composed image, and this is that claim, measured rather than
/// assumed. It is equally what an iso SHORTCUT owes: `rim_welds.rs` accepts an
/// iso on a structural degree/knot match, and this is the geometric check that
/// would replace it.
///
/// `forward` follows the coedge's own sense, as in `BrepSolid::validate`.
/// The same comparison as [`measure_edge_against_pcurve_image`], sampled once at
/// the midpoint of every knot span of the edge's own 3D curve.
///
/// This is the anti-aliasing half described in the module doc: it samples where
/// the curve is furthest from what it interpolates, by construction, and its
/// sample set is derived from the curve's own knots rather than from a fixed
/// grid that a dyadically-subdivided curve can hide behind.
///
/// Exposed so the general pcurve → 3D image-curve transfer can floor its own
/// self-verification with it without re-deriving the span walk.
/// `max_{u,v} ‖S_fit(u,v) − offset(u,v)‖` — how far a fitted offset carrier
/// sits from the pointwise offset it was fitted to, recorded against `band`.
///
/// `distance` and `same_sense` are `offset_surface`'s, and the evaluator is
/// constructed with the same convention that produced the fit's samples
/// ([`OffsetNormal::FaceStable`], with the same single negation), so this
/// measures the FIT and nothing else — not a sign disagreement, and not a
/// second opinion about which way "outward" points.
///
/// Only meaningful when the carrier really is a pointwise fit over the same
/// parameterisation. `offset_surface`'s planar/ruled extension and its
/// apex-cone pinch retrim both move the sample grid off the pointwise offset on
/// purpose; measuring one of those against a pointwise offset reports a
/// designed divergence, not an error. `offset_surface_measured` decides that
/// and does not call this in those cases.
/// `|p_V − c_E(t_end)|` — how far a curve end sits from the vertex point the
/// topology says it meets.
///
/// The endpoint half of the edge → vertex propagation. On a freshly built
/// carrier this is exactly zero for the edge that CLAIMED the vertex (the
/// vertex was placed at that curve's end) and non-zero for every later edge
/// that reuses it — which is the whole reason it is worth measuring.
// BREP private tests: c329615ce4176843