Skip to main content

axiolid_mesh_compile/
deviation.rs

1//! How far the exact geometry may lie from a compiled mesh (#232).
2//!
3//! [`ReferenceMeshCompiler::compile_mesh_with_deviation`] returns, next to
4//! the mesh, a [`DeviationReport`]: a certified upper bound on the distance
5//! from any point of the exact surface the graph describes to the nearest
6//! mesh triangle, which paths contributed to it, and whether it is within
7//! the chord budget the caller asked for. This is the quantity #231 proves
8//! for revolutions, spheres, tori and sweeps along one arc; for the paths
9//! that have no proof by construction it is computed for the mesh at hand.
10//!
11//! # A bound, never an estimate
12//!
13//! Every number in a report is an upper bound: either a construction's
14//! proof ([`DeviationBound::Proven`]) or a computation that only uses
15//! certified derivative bounds and exact distances
16//! ([`DeviationBound::Certified`]). Where neither exists the path is named
17//! [`DeviationBound::Unbounded`] with its reason, and the report's overall
18//! bound is `None`; nothing is filled in with a sampled or heuristic value.
19//! The bounds are one-sided, exact surface to mesh: the bound limits how far
20//! the exact surface lies from the mesh; it does not detect extra material
21//! in the mesh (a cap the exact solid does not have) and does not change
22//! with it. A measured all-planar boolean is the exception (#329): it also
23//! reports how far its mesh lies from the exact result, under
24//! [`MESH_TO_EXACT`].
25//!
26//! # How each path is bounded
27//!
28//! - Authored meshes are their own exact surface: `0`. An authored polygon
29//!   face within the linear tolerance of its plane counts as planar and
30//!   adds nothing. A face warped beyond it has no unique surface (#254):
31//!   it is triangulated in its fit plane and reported
32//!   [`DeviationBound::Certified`] under the detail
33//!   `"non-planar authored face"`, never `Proven`. The value is the width
34//!   of the slab the face's corners (holes included) span about that fit
35//!   plane, largest minus smallest signed distance (#261): every reading
36//!   of the face that lies in that slab (either diagonal triangulation,
37//!   the face flattened onto the plane, a bilinear patch) is within it of
38//!   the mesh wherever it lies over the face, and the mesh within it of
39//!   each reading that covers the face (`crate::planar` gives the
40//!   argument); the worst face of the mesh is reported.
41//! - Profiles ([`axiolid_construct::profile::profile_deviation`]): the
42//!   chord budget for every family the flattener certifies (lines, arcs,
43//!   circles, ellipses, B-splines), plus any merged near-duplicate point,
44//!   scaled by a derived profile's stretch. An extrusion's walls and caps
45//!   are within that of the exact solid.
46//! - Revolutions: the profile's bound plus the half budget the turn gets
47//!   (#231). Tapered revolutions only between straight-edged profiles,
48//!   whose rings correspond exactly; tapered extrusions are unbounded
49//!   (their twisted walls are not measured).
50//! - Swept disks: along lines, polylines (filleted, open or closed) and
51//!   chains of segments and arcs by `axiolid_construct::pipe`'s proof
52//!   (#232, #245, #248: a loop's closing twist is part of it), along one
53//!   circular arc by #231's; a corner mitred beside an arc (#248) is
54//!   certified by the branch and bound below, over the bend's band of
55//!   torus up to the mitre plane and the planar face between the two
56//!   tubes' sections (each trimmed by certain inequalities on its cells),
57//!   and reported [`DeviationBound::Certified`] under the detail
58//!   [`MITRE_BESIDE_AN_ARC`]; along an ellipse, a B-spline, or an
59//!   elevated or banked curve without a grade break (#252, its derivative
60//!   bounds in plan distance from `axiolid_reference::elevated`), certified
61//!   against the exact tube (walls, bore and square end caps) by branch and
62//!   bound, below, its centre over an intrinsic plan read from a certified
63//!   position table whose error the bound carries (#393); an elevated curve
64//!   whose grade breaks, or over a chain plan, or under an intrinsic
65//!   profile, is unbounded by name. A straight plan under a constant grade
66//!   is a segment.
67//!   Fixed-reference sweeps along a segment, or along a circle whose plane
68//!   the reference is normal to, by #231; other frame laws, polyline and
69//!   composite directrices are unbounded here.
70//! - Primitives: spheres and tori by #231, cylinders and cones by #232
71//!   (`axiolid_reference::primitive`), flat-faced ones exactly.
72//! - B-rep faces: planar faces with straight edges exactly; a face that
73//!   declares no surface and whose corners lie off their fit plane beyond
74//!   the linear tolerance (#257) as a warped authored face is, by its
75//!   slab width, [`DeviationBound::Certified`] under the detail
76//!   `"non-planar face without a surface"`; curved faces
77//!   per triangle from the surface's second derivatives over the
78//!   triangle, plus the trim lens of each pcurve chord (the B-rep
79//!   tessellator's module notes give the argument).
80//!
81//! # Branch and bound against an exact parameterisation
82//!
83//! Where the mesh's vertices sit at no known surface parameters (a tube's
84//! stations stand on frames read off its sampled path, a boolean's cut
85//! curve wherever the mesh boolean put it), the exact surface
86//! `T` is covered by parameter cells. A cell with centre `x_c` and
87//! half-widths `h` maps into `T(x_c) + DT(x_c) [-h, h]` grown by
88//! `e2 = 1/2 (A h_x^2 + 2 B h_x h_y + C h_y^2)`, with `A, B, C` certified
89//! bounds on `T`'s second partials over the cell (for a tube, from the
90//! directrix's derivative bounds through its normalised frame). Distance
91//! to one triangle is convex, so over a piece of that parallelogram it is
92//! at most the largest of the piece's corners'; the best triangle per piece
93//! and the worst piece, plus `e2`, bound the cell. Cells are split worst
94//! first until the worst bound is within 10% of the largest exact distance
95//! sampled at a cell centre, or a work cap is reached; the reported value
96//! is always the worst bound over all cells. A tube (#252) settles once
97//! within the budget, joins its slightly twisted quads as flat regions up
98//! to a twentieth of the budget thick (that thickness is part of the
99//! bound), and cuts each cell the way that lowers its halves more, so a
100//! long tube's long, thin quads do not force every cell down to the width
101//! of their diagonals.
102//! - Surfaces trimmed by a parameter rectangle (#311): a uniform grid of
103//!   cells whose corners are exact surface points, each cell within
104//!   `1/8 ((A + B) h_u^2 + (C + B) h_v^2)` of its two triangles from the
105//!   surface's certified interpolation bounds over the cell
106//!   (`crate::trimmed`), [`DeviationBound::Certified`]; a cell a B-spline
107//!   knot line of full multiplicity crosses is
108//!   [`DeviationBound::Unbounded`] by name.
109//! - Instances scale the bound by an upper bound on their transform's
110//!   largest stretch (`stretch`): the largest column length grown by
111//!   `1 + 96 eps` when the columns are orthogonal, else the Frobenius
112//!   norm. The margin keeps it above one even for an identity or a
113//!   rotation, since an `f64` rotation is orthonormal only to rounding;
114//!   the source is meshed to the budget shrunk by that factor, down to the
115//!   largest value whose rounded product with it is within the budget
116//!   (`shrunk_budget`, as #255 shrinks a curve-bounded plane's), so a
117//!   rigid or scaled instance of a body meshed to exactly its budget
118//!   reports at most the requested budget, nested instances included
119//!   (#258). Uniform, non-uniform and sheared instances grow the bound by
120//!   their full stretch and stay sound. The rounding of moving each vertex
121//!   is added on top (#295, "Placement rounding" below). The rounding of
122//!   computing a construction's own vertices is not part of any bound.
123//!   Collections take the worst member.
124//! - Runs of sections at stations (#247): stationed spines and sectioned
125//!   surfaces are bounded cell by cell as they are sampled
126//!   (`crate::station`'s `bound` module): the vertex paths' chord bound
127//!   from certified derivative bounds of the frame law, breakpoints at
128//!   seams inside a cell, and the wall quad's
129//!   `axiolid_construct::loft::quad_deviation`, plus a spine's profile
130//!   flattening, [`DeviationBound::Certified`], a frame read by quadrature
131//!   (an ellipse, a B-spline, an offset of a curve in closed form) bounded
132//!   against its exact law (#316); a frame on an intrinsic curve, a chain or
133//!   an offset beside one, a cell beside a mitre on a curved piece or with
134//!   a changing section, and different curved profiles are
135//!   [`DeviationBound::Unbounded`] by name.
136//! - Instances at stations (#264) move their source rigidly: on a line
137//!   basis the frame is exact and the source's bound stands. On any other
138//!   the frame is the exact curve's at a distance read by an estimate (the
139//!   arc-length inverse, quadrature), and `crate::station::placement_accuracy`
140//!   states how far the placement lies from the exact one (#405): on a
141//!   circle, a polyline, an elevated or banked curve over a line or a
142//!   circle, an intrinsic plan alone or under a closed-form profile and
143//!   composites of them, a [`DeviationBound::Certified`] error `F` of any
144//!   point of the source (`point_error + axis_error R`, `R` the largest
145//!   sum `|x| + |y| + |z|` over the source mesh's vertices) that every contribution
146//!   grows by as it grows by the placement's rounding, and that is named
147//!   once under the path [`DeviationPath::StationPlacement`]; the source is
148//!   re-meshed with room for the rounding and `F` when they would carry it
149//!   over the budget. Any other basis (a frame read by quadrature, a chain,
150//!   a basis itself placed inexactly, a station beside a seam it is not
151//!   read on) is [`DeviationBound::Unbounded`] under that path, with the
152//!   reason named.
153//! - Booleans (#235): cutting two meshes moves the intersection curve, and
154//!   a one-sided bound on each operand does not bound it, so nothing is
155//!   derived from the operands. Where `ReferenceExactCompiler` builds the
156//!   exact result of the same node (booleans of placed extrusions and
157//!   revolutions, #228, #376, #378, and half-space clips, #234; for the report also booleans with
158//!   a mesh operand, any operator, below), the mesh is certified against that
159//!   exact B-rep by the branch and bound above, over each face's trimmed
160//!   parameter domain; a boolean it refuses is unbounded with the
161//!   refusal's name. The bound is relative to the exact compiler's result,
162//!   the exact boolean of operands moved by at most the tolerance (#228),
163//!   not to the boolean of the unperturbed operands. It runs only for a
164//!   report, and only for the booleans whose result is emitted, not for
165//!   the inner booleans of a chain; the search stops once within the
166//!   requested budget. When the exact result is all planar the other
167//!   direction is measured too (#329): how far any point of the mesh lies
168//!   from the exact result, against a witness mesh built on the exact
169//!   faces, a separate [`DeviationPath::Boolean`] contribution under the
170//!   detail [`MESH_TO_EXACT`], so material the mesh has and the exact
171//!   result lacks (a strip of a clipped wall the mesh kept) shows in the
172//!   report's bound. Both directions are carried through instances like
173//!   any other contribution.
174//! - Operands snapped together (#276, #291): before the mesh boolean,
175//!   operand coordinates a rounding residue (16 `f64::EPSILON` of the
176//!   operands' largest coordinate) from the other operand's axis-aligned
177//!   faces are set onto them exactly (`crate::snap`), so a skin that thin
178//!   is not cut as one; a thicker skin is kept. The largest move is a
179//!   [`DeviationBound::Certified`] contribution of
180//!   [`DeviationPath::Boolean`] under the detail [`SNAPPED_OPERANDS`],
181//!   carried through instances and enclosing booleans, the measured ones
182//!   included; it never exceeds the tolerance. A boolean whose snapped
183//!   operands are refused is cut as given and reports no snap.
184//! - Warped operands (#266): an operand that is an authored mesh, or a
185//!   B-rep whose faces are all planes with straight edges or warped faces
186//!   without a surface, is measured as the exact polyhedron of its
187//!   triangle mesh: a warped face flattened to its triangles, within its
188//!   slab width `w` of every reading of the face (`crate::planar`), both
189//!   ways. That is how an operand's certified bound composes into a
190//!   boolean's: not as a one-sided bound (above), but as a two-sided
191//!   perturbation of the operand. The boolean's mesh is measured against
192//!   the exact boolean of the flattened operands (ADR 0080: the exact
193//!   boolean of operands perturbed within the reported deviation), by `d`,
194//!   and its contribution is [`DeviationBound::Certified`] `d + w`, `w`
195//!   the largest slab width of any operand flattened beneath it, under
196//!   the detail "measured against the exact boolean of operands flattened
197//!   within their slab width, plus it". The search settles within the
198//!   budget less `w`, so a boolean whose slab widths fit the budget
199//!   reports within it, and `meets_requested` follows. Each warped
200//!   operand's own contribution ("non-planar authored face", "non-planar
201//!   face without a surface") is carried as the snap is, so the report
202//!   names it. Transversal to the cut, the boolean of the unflattened operands
203//!   is within `d + w` of the mesh too; near tangency the guarantee is
204//!   ADR 0080's, relative to the flattened operands. Where the exact
205//!   boolean cannot take the flattened operand (a mesh that is not a
206//!   closed two-manifold, a B-rep with a curved face, a tool that is
207//!   itself a boolean, a configuration the general boolean refuses) the
208//!   boolean is [`DeviationBound::Unbounded`] with that refusal's name,
209//!   and the warp is still named. An unwarped mesh operand (`w = 0`) is
210//!   measured like any exact operand, against the exact boolean of the
211//!   operands as given when no decision within tolerance fired.
212//! - Operand faces read as one surface (#324): where the general boolean
213//!   reads a face of one operand on a face of the other within tolerance
214//!   (a niche flush with a curved wall's inner face, or a unit in the last
215//!   place inside it), the furthest the reading moved an operand is a
216//!   [`DeviationBound::Certified`] contribution of
217//!   [`DeviationPath::Boolean`] under the detail [`COINCIDENT_OPERANDS`],
218//!   next to the boolean's measured one. Like a snap's move, it names the
219//!   perturbation the exact result stands for; it is not carried through
220//!   enclosing booleans, whose exact result merges the reading's report.
221//! - Every reading within tolerance (#421): the furthest any kind of reading
222//!   (merged points, contact, an incident point, coincident supports, ...)
223//!   moved a feature is a [`DeviationBound::Certified`] contribution of
224//!   [`DeviationPath::Boolean`] under [`TOLERANCE_READINGS`], and the
225//!   report's rounding floor under [`BOOLEAN_ROUNDING_FLOOR`]. The
226//!   boolean's own contribution is widened by their sum: the bound covers
227//!   the boolean of the operands as read, each moved by at most the named
228//!   readings, so they add to the measured distance rather than being the
229//!   worst of it and them. A reading may change the topology against the
230//!   operands as given; the named readings are what say so.
231//!
232//! # Placement rounding
233//!
234//! An `Instance` or an `InstanceAtStation` moves its source's vertices by
235//! applying its transform in `f64`, which rounds each coordinate by a few
236//! ulps of its magnitude: an *absolute* error, about `1e-9` at
237//! georeferenced coordinates of `6e6`, that no relative factor covers
238//! (#295). Every reported bound therefore carries, for each transform
239//! applied, the term `r = 4 eps M` ([`PLACEMENT_EPSILONS`],
240//! `placement_rounding`): `M` is the largest magnitude a placed coordinate
241//! sums, `sum_j |a_ij| |p_j| + |t_i|` over the source's vertices `p`
242//! (the coordinate's own magnitude where nothing cancels), and the
243//! constant covers `sqrt 3 gamma_4 < 3.47 eps`: four rounded operations
244//! per coordinate, three coordinates per point. A source bound `d` placed
245//! with stretch `s` reports `s d + r`, its kind kept; a nested instance
246//! grows the inner `r` by the outer stretch and adds its own. The term is
247//! named under [`DeviationPath::Placement`] / [`PLACEMENT_ROUNDING`]. A
248//! row that copies a coordinate (one coefficient `+-1`, no translation)
249//! rounds nothing, so an identity or a mirror adds nothing.
250//!
251//! The source's budget leaves room for it: the source is meshed to the
252//! budget less a room, shrunk by the stretch, so `s b + room` rounds to
253//! within the budget (`shrunk_budget_within`). The room starts at the
254//! floor `r` reaches at the translation's scale (the term at the origin)
255//! plus a `2^-20` share of what is left, for the source's own
256//! coordinates; where the source's mesh then rounds by more than that and
257//! its bound would carry the instance over the budget, it is meshed once
258//! more with room for an eighth more than it showed. A budget at or below
259//! the floor at the translation's scale, or below the rounding of the
260//! placed vertices themselves, is refused with
261//! [`BUDGET_BELOW_PLACEMENT_ROUNDING`] rather than reported as met.
262//!
263//! [`ReferenceMeshCompiler::compile_mesh_with_deviation`]: crate::ReferenceMeshCompiler::compile_mesh_with_deviation
264
265use axiolid_core::{Point3, Scalar, Transform3};
266
267mod boolean;
268mod mitre;
269mod paths;
270pub(crate) use boolean::{
271    emitted_booleans, extra_shells, geometric_components, of_boolean, with_readings,
272};
273pub(crate) use paths::{
274    of_curve_bounded, of_primitive, of_sectioned_surface, of_solid, stationed_spine,
275};
276
277/// The [`DeviationContribution::detail`] of authored polygon faces warped
278/// beyond the linear tolerance (#254).
279pub(crate) const WARPED_AUTHORED_FACE: &str = "non-planar authored face";
280
281/// The [`DeviationContribution::detail`] of a keyhole face, authored or a
282/// B-rep's, whose Steiner points lie off an axis plane (#283): a face
283/// takes them so that its seam is no triangle edge, each a chain of
284/// midpoints of its corners, so within rounding of the face. The bound is
285/// the slab width of [`crate::planar::steiner_offset`]. A face in an axis
286/// plane holds its Steiner points exactly and reports nothing.
287pub(crate) const KEYHOLE_STEINER_POINT: &str =
288    "point added inside a keyhole face, off an axis plane";
289
290/// The [`DeviationContribution::detail`] of the corners a swept disk mitres
291/// beside an arc (#248): the bend's band and the planar face between the
292/// two tubes' sections, certified against the mesh by branch and bound;
293/// the rest of the pipe stays proven under its own detail.
294pub const MITRE_BESIDE_AN_ARC: &str = "mitre beside an arc";
295
296/// The [`DeviationContribution::detail`] of a node placed at a station
297/// whose frame is read at a numerically resolved distance (#264): the
298/// frame's certified error (#405), or why it has none.
299pub(crate) const NUMERICAL_STATION_FRAME: &str = "frame at a numerically resolved station";
300
301/// The [`DeviationContribution::detail`] of B-rep faces that declare no
302/// surface and are warped beyond the linear tolerance (#257).
303pub(crate) const WARPED_BREP_FACE: &str = "non-planar face without a surface";
304
305/// The [`DeviationContribution::detail`] of a boolean whose operands were
306/// moved onto each other's faces by a rounding residue, within the linear
307/// tolerance, before the mesh boolean cut them (#276, #291): its bound is
308/// the largest distance any operand vertex moved, so the mesh is the
309/// boolean of operands perturbed by at most that much. It travels with the boolean's result through
310/// instances (scaled, plus the placement's rounding, #295) and enclosing booleans, also where an enclosing
311/// boolean is measured against its exact result.
312pub const SNAPPED_OPERANDS: &str = "operands snapped onto each other within tolerance";
313
314/// The [`DeviationContribution::detail`] of a boolean measured against an
315/// exact result in which faces of the two operands were read as one
316/// surface within tolerance (#324: a niche's inner cylinder a unit in the
317/// last place off a curved wall's inner face): its bound is the furthest
318/// that reading moved an operand, so the exact result the mesh is measured
319/// against is the boolean of operands perturbed by at most that much
320/// (ADR 0080). It names the perturbation, as [`SNAPPED_OPERANDS`] does;
321/// the boolean's own contribution bounds the mesh's distance to that
322/// result.
323pub const COINCIDENT_OPERANDS: &str = "operand faces read as one surface within tolerance";
324
325/// The [`DeviationContribution::detail`] of a boolean measured against an
326/// exact result whose report holds readings within tolerance (#421): its
327/// bound is the largest distance any kind of reading moved a feature
328/// (`BooleanReport::linear`: merged points, an incident point, coincident
329/// supports, ..., or an angle turned, as a distance over the operands'
330/// extent), so the exact result the mesh is measured against is the boolean
331/// of operands perturbed by at most that much (a reading may change the
332/// topology against the operands as given: this contribution is what says
333/// so). The boolean's own bound is widened by it. [`COINCIDENT_OPERANDS`] names the coincident supports'
334/// share.
335pub const TOLERANCE_READINGS: &str = "operands moved by readings within tolerance";
336
337/// The [`DeviationContribution::detail`] of a boolean measured against an
338/// exact result: the rounding floor of its report (#244, #421), within
339/// which constructed points were read as one without a decision. Present
340/// whenever the floor is not zero, exact result or not. The boolean's own
341/// bound is widened by it.
342pub const BOOLEAN_ROUNDING_FLOOR: &str = "constructed points read as one within the rounding floor";
343
344/// The [`DeviationContribution::detail`] of a measured boolean's other
345/// direction (#329): a certified bound on how far any point of the mesh
346/// lies from the exact compiler's result (the same result as the boolean's
347/// own contribution), widened like it by the flattening, the readings and
348/// the rounding floor. Only for an all-planar exact result.
349pub const MESH_TO_EXACT: &str =
350    "mesh to the exact compiler's result: how far any point of the mesh lies from it";
351
352/// The [`DeviationContribution::detail`] of a boolean whose exact result is
353/// empty and whose mesh is too (#326): nothing is left in either, so the
354/// distance between them is certified `0`, widened like any bound by the
355/// readings and the rounding floor of the exact result's report. The
356/// bound is unbounded by name when the empty result is that of operands
357/// flattened within a warped slab width. The exact compiler holds the
358/// empty result internally and refuses it only as a root, so the report
359/// cannot be measured against a B-rep; an empty exact result against a
360/// mesh with triangles, or the reverse, is unbounded by name.
361pub const EMPTY_RESULT: &str = "the exact compiler's result is empty, and so is the mesh";
362
363/// The [`DeviationContribution::detail`] of a union the mesh cut could not
364/// settle and the exact compiler decided (#391, ADR 0098): the mesh is
365/// the exact compiler's union tessellated, and the exact union is that of
366/// operands read as in contact within the tolerance
367/// ([`COINCIDENT_OPERANDS`] names how far). The bound is the
368/// tessellation's: how far the exact union's surface lies from the mesh.
369pub const REFEREED_UNION: &str =
370    "tessellated from the exact compiler's union, operands within tolerance";
371
372/// [`REFEREED_UNION`] when no decision within the tolerance fired: the mesh
373/// is the tessellation of the exact union of the operands as given.
374pub const REFEREED_UNION_EXACT: &str =
375    "tessellated from the exact compiler's union, the exact union of the given operands";
376
377/// [`REFEREED_UNION`] for a difference whose mesh held a void the exact
378/// result lacks, bounded by skins within rounding where the cutter met its
379/// host, and which the exact compiler decided (#423, ADR 0098). A
380/// difference with no extra shell, or whose faces the exact compiler read
381/// further than rounding, is never refereed: a skin or void thinner than
382/// the tolerance stays as authored (ADR 0096, D7).
383pub const REFEREED_DIFFERENCE: &str =
384    "tessellated from the exact compiler's difference, operands within tolerance";
385
386/// [`REFEREED_DIFFERENCE`] when no decision within the tolerance fired.
387pub const REFEREED_DIFFERENCE_EXACT: &str =
388    "tessellated from the exact compiler's difference, the exact difference of the given operands";
389
390/// [`REFEREED_DIFFERENCE`] for an intersection, on the same trigger: its
391/// mesh held a shell the exact result lacks (#423, ADR 0098).
392pub const REFEREED_INTERSECTION: &str =
393    "tessellated from the exact compiler's intersection, operands within tolerance";
394
395/// [`REFEREED_INTERSECTION`] when no decision within the tolerance fired.
396pub const REFEREED_INTERSECTION_EXACT: &str =
397    "tessellated from the exact compiler's intersection, the exact intersection of the given operands";
398
399/// The [`DeviationContribution::detail`] of [`DeviationPath::Placement`]:
400/// the rounding of applying an instance's transform to its source's
401/// vertices in `f64` (#295), [`PLACEMENT_EPSILONS`] `f64::EPSILON` of the
402/// largest coordinate magnitude the placement sums (see the module's
403/// "Placement rounding"). Every other contribution of the instance is
404/// grown by it too.
405pub const PLACEMENT_ROUNDING: &str = "rounding of applying the transform in f64";
406
407/// The input family a compilation is refused with when its chord budget,
408/// in an instance's frame, is at or below the rounding of placing the
409/// instance's vertices (#295): at the translation's scale before the
410/// source is meshed, at the placed vertices' scale after. No mesh placed
411/// in `f64` there is within the budget, so none is reported as meeting it.
412pub const BUDGET_BELOW_PLACEMENT_ROUNDING: &str =
413    "chord budget at or below the rounding of placing an instance's vertices in f64";
414
415/// The construction path a part of the mesh came from.
416#[non_exhaustive]
417#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
418pub enum DeviationPath {
419    /// An authored triangle or polygon mesh.
420    AuthoredMesh,
421    /// A linear extrusion of a profile.
422    Extrusion,
423    /// A revolution of a profile.
424    Revolution,
425    /// An extrusion between two profiles.
426    TaperedExtrusion,
427    /// A revolution between two profiles.
428    TaperedRevolution,
429    /// A disk swept along a directrix.
430    SweptDisk,
431    /// A profile swept with a fixed reference direction.
432    FixedReferenceSweep,
433    /// A profile swept along a curve on a surface.
434    SurfaceCurveSweep,
435    /// Sections placed along a spine.
436    SectionedSpine,
437    /// A half-space bounded by a polygon or a profile.
438    BoundedHalfSpace,
439    /// A CSG primitive.
440    Primitive,
441    /// A face of a B-rep.
442    BRepFace,
443    /// A plane trimmed by boundary curves.
444    CurveBoundedPlane,
445    /// A boolean of two meshes, measured against its exact result (#235).
446    ///
447    /// An operand's own bound does not compose into it as a one-sided
448    /// bound: a boolean is measured, not derived. A warped operand (#266)
449    /// enters as a two-sided perturbation: the exact result is the boolean
450    /// of the operands flattened to their triangles, each within its slab
451    /// width `w` of every reading, and the contribution is the measured
452    /// distance plus the largest `w` (see the module's "Warped operands").
453    ///
454    /// A measured boolean whose exact result is all planar has two
455    /// contributions under this path (#329): the exact result to the mesh,
456    /// and the mesh to the exact result ([`MESH_TO_EXACT`]), so extra
457    /// material in the mesh is reported.
458    Boolean,
459    /// A path that does not report its deviation.
460    Unreported,
461    /// Sections standing at stations along a directrix (#241).
462    StationedSpine,
463    /// Open sections at stations joined by tag (#241).
464    SectionedSurface,
465    /// A node placed in the frame of a curve station (#264), on a basis
466    /// whose frame is not exact: [`DeviationBound::Certified`] by how far
467    /// the placement may lie from the exact one (#405), or
468    /// [`DeviationBound::Unbounded`] by name.
469    StationPlacement,
470    /// A surface trimmed by a parameter rectangle (#311).
471    TrimmedSurface,
472    /// The rounding of moving an instance's vertices with its `f64`
473    /// transform (#295), an `Instance` or an `InstanceAtStation`: an
474    /// absolute term every other contribution of the instance also
475    /// carries, named under [`PLACEMENT_ROUNDING`] so the report shows it.
476    Placement,
477    /// A surface ruled between two sides (#402).
478    RuledSurface,
479}
480
481/// A bound on how far the exact surface may lie from the mesh.
482#[non_exhaustive]
483#[derive(Debug, Clone, Copy, PartialEq)]
484pub enum DeviationBound {
485    /// Guaranteed by the construction's own proof, without inspecting the
486    /// mesh (#231): typically the chord budget itself.
487    Proven(Scalar),
488    /// Computed for this mesh from certified derivative bounds and exact
489    /// distances (#232).
490    Certified(Scalar),
491    /// No certified bound exists for this path; the reason names it.
492    Unbounded(&'static str),
493}
494
495impl DeviationBound {
496    /// The bound's value, `None` when unbounded.
497    #[must_use]
498    pub const fn value(self) -> Option<Scalar> {
499        match self {
500            Self::Proven(value) | Self::Certified(value) => Some(value),
501            Self::Unbounded(_) => None,
502        }
503    }
504
505    /// The worse of two bounds: unbounded wins, else the larger value
506    /// (keeping its kind).
507    #[must_use]
508    pub fn worst(self, other: Self) -> Self {
509        match (self.value(), other.value()) {
510            (None, _) => self,
511            (_, None) => other,
512            (Some(a), Some(b)) => {
513                if b > a {
514                    other
515                } else {
516                    self
517                }
518            }
519        }
520    }
521
522    /// The bound after a placement: grown by the stretch `factor`, plus the
523    /// placement's absolute `rounding` ([`grown`]), keeping its kind.
524    fn placed(self, factor: Scalar, rounding: Scalar) -> Self {
525        match self {
526            Self::Proven(value) => Self::Proven(grown(value, factor, rounding)),
527            Self::Certified(value) => Self::Certified(grown(value, factor, rounding)),
528            unbounded => unbounded,
529        }
530    }
531}
532
533/// One path's share of a report.
534#[non_exhaustive]
535#[derive(Debug, Clone, Copy, PartialEq)]
536pub struct DeviationContribution {
537    /// The construction path.
538    pub path: DeviationPath,
539    /// What within the path: a surface family, a directrix family, a
540    /// primitive kind. Empty when the path says it all.
541    pub detail: &'static str,
542    /// The worst bound over every part of the mesh this path made.
543    pub bound: DeviationBound,
544}
545
546/// A certified bound on the distance from the exact surface to a compiled
547/// mesh (#232).
548///
549/// The bound is one-sided: it limits how far the exact surface lies from
550/// the mesh, and does not detect extra material in the mesh. Only a
551/// measured all-planar boolean also bounds the mesh's distance to the exact
552/// result ([`MESH_TO_EXACT`], #329).
553#[non_exhaustive]
554#[derive(Debug, Clone, PartialEq)]
555pub struct DeviationReport {
556    /// The chord budget the compilation was asked for, in world units:
557    /// `ExecutionOptions::chord_error`, else the linear tolerance.
558    pub requested: Scalar,
559    /// An upper bound on the distance from every point of the exact
560    /// surface to the mesh's triangles, in world units; `None` when any
561    /// contribution is unbounded. It does not bound material the mesh has
562    /// beyond the exact surface, except for a measured all-planar
563    /// boolean's ([`MESH_TO_EXACT`]).
564    pub bound: Option<Scalar>,
565    /// Each path that contributed, with the worst bound it reached, in
566    /// first-seen order.
567    pub contributions: Vec<DeviationContribution>,
568}
569
570impl DeviationReport {
571    /// Whether the mesh is certified within the requested chord budget.
572    ///
573    /// `false` means "not certified", not "missed": an unbounded path, or a
574    /// bound above the budget whose true deviation may still be below it.
575    /// `true` is about the exact surface's distance to the mesh: a mesh
576    /// with extra material can still meet the request, except where a
577    /// measured all-planar boolean bounds that too ([`MESH_TO_EXACT`]).
578    #[must_use]
579    pub fn meets_requested(&self) -> bool {
580        self.bound.is_some_and(|bound| bound <= self.requested)
581    }
582
583    /// The contributions with no certified bound.
584    pub fn unbounded(&self) -> impl Iterator<Item = &DeviationContribution> {
585        self.contributions
586            .iter()
587            .filter(|c| matches!(c.bound, DeviationBound::Unbounded(_)))
588    }
589}
590
591/// A node's deviation while the graph is compiled: its contributions,
592/// merged by path and detail.
593#[derive(Debug, Clone, PartialEq)]
594pub(crate) struct Deviation(Vec<DeviationContribution>);
595
596impl Default for Deviation {
597    /// Unreported: a path that never states its deviation must not read as
598    /// exact.
599    fn default() -> Self {
600        Self::one(
601            DeviationPath::Unreported,
602            "",
603            DeviationBound::Unbounded("this path does not report its deviation"),
604        )
605    }
606}
607
608impl Deviation {
609    pub(crate) fn one(path: DeviationPath, detail: &'static str, bound: DeviationBound) -> Self {
610        Self(vec![DeviationContribution {
611            path,
612            detail,
613            bound,
614        }])
615    }
616
617    /// No contribution yet; [`Self::add`] fills it.
618    pub(crate) const fn empty() -> Self {
619        Self(Vec::new())
620    }
621
622    /// Fold one contribution in, keeping the worst per path and detail.
623    pub(crate) fn add(&mut self, path: DeviationPath, detail: &'static str, bound: DeviationBound) {
624        match self
625            .0
626            .iter_mut()
627            .find(|c| c.path == path && c.detail == detail)
628        {
629            Some(existing) => existing.bound = existing.bound.worst(bound),
630            None => self.0.push(DeviationContribution {
631                path,
632                detail,
633                bound,
634            }),
635        }
636    }
637
638    /// Fold another node's contributions in.
639    pub(crate) fn absorb(&mut self, other: &Self) {
640        for c in &other.0 {
641            self.add(c.path, c.detail, c.bound);
642        }
643    }
644
645    /// Fold in `other`'s operand perturbations: its [`SNAPPED_OPERANDS`]
646    /// contributions (#276) and its warped faces' slab widths
647    /// ([`WARPED_AUTHORED_FACE`], [`WARPED_BREP_FACE`], #266), and the slab
648    /// widths of keyhole faces' Steiner points off an axis plane
649    /// ([`KEYHOLE_STEINER_POINT`], #283). They stay
650    /// reported when a boolean replaces the rest of an operand's
651    /// deviation, so the report names every operand that was moved or
652    /// flattened, through any chain of booleans.
653    pub(crate) fn carry_perturbations(&mut self, other: &Self) {
654        for c in &other.0 {
655            let carried = matches!(
656                (c.path, c.detail),
657                (DeviationPath::Boolean, SNAPPED_OPERANDS)
658                    | (DeviationPath::AuthoredMesh, WARPED_AUTHORED_FACE)
659                    | (DeviationPath::BRepFace, WARPED_BREP_FACE)
660                    | (DeviationPath::AuthoredMesh, KEYHOLE_STEINER_POINT)
661                    | (DeviationPath::BRepFace, KEYHOLE_STEINER_POINT)
662            );
663            if carried {
664                self.add(c.path, c.detail, c.bound);
665            }
666        }
667    }
668
669    /// The largest slab width of a B-rep's warped faces when its mesh is
670    /// the polyhedron it describes up to them (#266): every contribution
671    /// an exact plane with straight edges, a warped face without a
672    /// surface, or a keyhole face's Steiner points off an axis plane,
673    /// whose bound is a slab width too (#283). `None` when any face is
674    /// curved, chorded or off its plane.
675    pub(crate) fn polyhedral_warp(&self) -> Option<Scalar> {
676        self.0
677            .iter()
678            .try_fold(0.0, |widest: Scalar, c| match (c.path, c.detail, c.bound) {
679                (DeviationPath::BRepFace, "plane", DeviationBound::Proven(0.0)) => Some(widest),
680                (
681                    DeviationPath::BRepFace,
682                    WARPED_BREP_FACE | KEYHOLE_STEINER_POINT,
683                    DeviationBound::Certified(width),
684                ) => Some(widest.max(width)),
685                _ => None,
686            })
687    }
688
689    /// The same contributions after a transform whose application rounded
690    /// each vertex by at most `rounding` ([`placement_rounding`], #295):
691    /// lengths grow by at most its largest stretch, and every bound by the
692    /// rounding on top, which is also named under [`PLACEMENT_ROUNDING`]
693    /// when it is not zero.
694    pub(crate) fn transformed(&self, transform: Transform3, rounding: Scalar) -> Self {
695        self.moved(transform, rounding, 0.0)
696    }
697
698    /// [`Self::transformed`] for a transform that places the source at a
699    /// station whose frame lies within `frame` of the exact one over the
700    /// whole source (#405): every contribution grows by it as it grows by
701    /// the rounding, and it is named once under
702    /// [`DeviationPath::StationPlacement`].
703    pub(crate) fn transformed_within(
704        &self,
705        transform: Transform3,
706        rounding: Scalar,
707        frame: Scalar,
708    ) -> Self {
709        let mut placed = self.moved(transform, rounding, frame);
710        placed.add(
711            DeviationPath::StationPlacement,
712            NUMERICAL_STATION_FRAME,
713            DeviationBound::Certified(frame),
714        );
715        placed
716    }
717
718    /// Every contribution after the transform: grown by its stretch, and
719    /// by `rounding + frame` on top; the rounding named under
720    /// [`PLACEMENT_ROUNDING`] when it is not zero.
721    fn moved(&self, transform: Transform3, rounding: Scalar, frame: Scalar) -> Self {
722        let factor = stretch(transform);
723        let mut placed = Self(
724            self.0
725                .iter()
726                .map(|c| DeviationContribution {
727                    bound: c.bound.placed(factor, rounding + frame),
728                    ..*c
729                })
730                .collect(),
731        );
732        if rounding > 0.0 {
733            placed.add(
734                DeviationPath::Placement,
735                PLACEMENT_ROUNDING,
736                DeviationBound::Certified(rounding),
737            );
738        }
739        placed
740    }
741
742    /// The worst contribution's bound ([`DeviationBound::worst`]): unbounded
743    /// wins, so a reason is never dropped. Unbounded when there is none.
744    pub(crate) fn worst_bound(&self) -> DeviationBound {
745        self.0
746            .iter()
747            .map(|c| c.bound)
748            .reduce(DeviationBound::worst)
749            .unwrap_or(DeviationBound::Unbounded(
750                "this path does not report its deviation",
751            ))
752    }
753
754    /// The worst bound over every contribution, `None` when any is
755    /// unbounded or there is none.
756    pub(crate) fn bound(&self) -> Option<Scalar> {
757        if self.0.is_empty() {
758            return None;
759        }
760        self.0.iter().try_fold(0.0, |worst: Scalar, c| {
761            c.bound.value().map(|value| worst.max(value))
762        })
763    }
764
765    /// The worst certified bound above `budget`, if any: what a mesh
766    /// rebuilt finer could still bring within it. A proven bound is the
767    /// construction's own and does not move with a finer mesh.
768    pub(crate) fn certified_over(&self, budget: Scalar) -> Option<Scalar> {
769        self.0
770            .iter()
771            .filter_map(|c| match c.bound {
772                DeviationBound::Certified(value) if value > budget => Some(value),
773                _ => None,
774            })
775            .reduce(Scalar::max)
776    }
777
778    pub(crate) fn report(&self, requested: Scalar) -> DeviationReport {
779        DeviationReport {
780            requested,
781            bound: self.bound(),
782            contributions: self.0.clone(),
783        }
784    }
785}
786
787/// An upper bound on the largest factor a transform's linear part stretches
788/// a length by: the largest column length when the columns are orthogonal,
789/// else the Frobenius norm. The same factor the compiler shrinks a chord
790/// budget by into an instance's local space ([`shrunk_budget`]).
791///
792/// The `1 + 96 eps` margin on the orthogonal branch covers what the column
793/// lengths do not: columns orthogonal only to `32 eps` (an `f64` rotation
794/// matrix is never exactly orthonormal) raise the largest singular value
795/// above the largest column length by at most about `32 eps` of it, and
796/// each computed length is itself rounded. It is why a rigid transform's
797/// factor is a hair above one, never exactly one: no `f64` rotation can be
798/// shown to stretch nothing, so none is read as stretch 1 (#258). The
799/// instance's source is instead meshed to a budget shrunk by this factor,
800/// so the grown bound still fits the request.
801pub(crate) fn stretch(transform: Transform3) -> Scalar {
802    let m = transform.matrix3;
803    let (sx, sy, sz) = (m.x_axis.length(), m.y_axis.length(), m.z_axis.length());
804    let eps = 32.0 * f64::EPSILON;
805    let orthogonal = m.x_axis.dot(m.y_axis).abs() <= eps * sx * sy
806        && m.x_axis.dot(m.z_axis).abs() <= eps * sx * sz
807        && m.y_axis.dot(m.z_axis).abs() <= eps * sy * sz;
808    if orthogonal {
809        sx.max(sy).max(sz) * (1.0 + 3.0 * eps)
810    } else {
811        (sx * sx + sy * sy + sz * sz).sqrt()
812    }
813}
814
815/// A bound `value` after a placement that stretches by at most `factor`
816/// and rounds each vertex by at most `rounding` (#295), rounded as
817/// [`Deviation::transformed`] rounds it: every point of a source triangle
818/// moves with its corners' barycentric combination, so a vertex rounding
819/// of `r` moves no point of the mesh further than `r`.
820pub(crate) fn grown(value: Scalar, factor: Scalar, rounding: Scalar) -> Scalar {
821    value * factor + rounding
822}
823
824/// How many `f64::EPSILON` of the largest summed coordinate magnitude
825/// bound the rounding of applying a transform to a point (#295): a
826/// coordinate sums four terms, each rounded at most four times, so it is
827/// off by at most `gamma_4 < 2.000_001 eps` of its summed magnitude, and a
828/// point by `sqrt 3` of that, below `3.47 eps`; `4` also covers computing
829/// the magnitude itself in `f64` (see the module's "Placement rounding").
830pub const PLACEMENT_EPSILONS: Scalar = 4.0;
831
832/// An upper bound on how far applying `transform` to `positions` in `f64`
833/// moves any of them from its exact image (#295), the absolute term
834/// [`Deviation::transformed`] adds to an instance's bounds.
835///
836/// Each image coordinate `q_i = a_i1 p_1 + a_i2 p_2 + a_i3 p_3 + t_i` is
837/// four terms, each rounded at most four times (one product, at most three
838/// sums, in any order, with or without a fused multiply-add), so it is off
839/// by at most `gamma_4 S_i`, `S_i = sum_j |a_ij| |p_j| + |t_i|` and
840/// `gamma_4 = 4u / (1 - 4u) < 2.000_001 eps` (`u = eps / 2`). Over three
841/// coordinates the point is off by at most `sqrt 3 gamma_4 max S_i <
842/// 3.47 eps max S_i`, and `S_i` computed in `f64` is low by at most a
843/// factor `1 + gamma_4`, so [`PLACEMENT_EPSILONS`] `eps M`, `M` the
844/// largest computed `S_i` over every position, covers it with room (and
845/// multiplying by `4 eps`, a power of two, is exact). `S_i` is the
846/// coordinate's own magnitude where nothing cancels, so the term is
847/// `4 eps max|coordinate|`: about `5.3e-9` at `6e6`. A row that copies one
848/// coordinate (a single coefficient `+-1` and no translation) moves
849/// nothing and adds nothing, so an identity or a mirror is exact.
850///
851/// At the origin (`positions = [0]`) it is the floor every placement by
852/// `transform` reaches at least: `4 eps` times its largest translation
853/// component in a row that rounds.
854pub(crate) fn placement_rounding(positions: &[Point3], transform: Transform3) -> Scalar {
855    let m = transform.matrix3;
856    let t = transform.translation;
857    let rows = [
858        ([m.x_axis.x, m.y_axis.x, m.z_axis.x], t.x),
859        ([m.x_axis.y, m.y_axis.y, m.z_axis.y], t.y),
860        ([m.x_axis.z, m.y_axis.z, m.z_axis.z], t.z),
861    ];
862    let mut largest: Scalar = 0.0;
863    for (coefficients, offset) in rows {
864        let nonzero = coefficients.iter().filter(|&&a| a != 0.0).count();
865        let copies = offset == 0.0
866            && nonzero <= 1
867            && coefficients.iter().all(|&a| a == 0.0 || a.abs() == 1.0);
868        if copies {
869            continue;
870        }
871        let a = coefficients.map(Scalar::abs);
872        for p in positions {
873            let sum = a[0] * p.x.abs() + a[1] * p.y.abs() + a[2] * p.z.abs() + offset.abs();
874            if sum.is_nan() {
875                return Scalar::INFINITY;
876            }
877            largest = largest.max(sum);
878        }
879    }
880    PLACEMENT_EPSILONS * Scalar::EPSILON * largest
881}
882
883/// The largest budget `b` from `budget / stretch` down whose product with
884/// `stretch`, rounded as [`Deviation::transformed`] rounds it, is within
885/// `budget` (#255, #258).
886///
887/// `budget / stretch` alone is not enough: at some factors (a scale of
888/// 0.33 or 1.19 at a budget of `1e-4`) the quotient multiplied back
889/// rounds one ulp above `budget`, and a source meshed to exactly its local
890/// budget would report just over the request. Rounded multiplication is
891/// monotone, so any source bound `d <= b` then reports `d * stretch <=
892/// budget`, and nested instances keep that through every level.
893/// `budget` itself when `stretch` is not a positive finite factor (the
894/// callers refuse those first), and the plain quotient when no positive
895/// value fits (a quotient in the subnormal range, which no mesh reaches).
896pub(crate) fn shrunk_budget(budget: Scalar, stretch: Scalar) -> Scalar {
897    shrunk_budget_within(budget, stretch, 0.0)
898}
899
900/// [`shrunk_budget`] leaving `room` for a placement's rounding (#295): the
901/// largest `b` from `(budget - room) / stretch` down with
902/// [`grown`]`(b, stretch, room) <= budget`, so a source bound `d <= b`
903/// placed with a rounding `r <= room` reports within `budget` (rounded
904/// addition and multiplication are monotone). The callers refuse a `room`
905/// at or above `budget` first ([`BUDGET_BELOW_PLACEMENT_ROUNDING`]).
906pub(crate) fn shrunk_budget_within(budget: Scalar, stretch: Scalar, room: Scalar) -> Scalar {
907    if !(stretch.is_finite() && stretch > 0.0) {
908        return budget;
909    }
910    let mut shrunk = (budget - room) / stretch;
911    while shrunk > 0.0 && grown(shrunk, stretch, room) > budget {
912        shrunk = shrunk.next_down();
913    }
914    if shrunk > 0.0 {
915        shrunk
916    } else {
917        (budget - room) / stretch
918    }
919}
920
921#[cfg(test)]
922mod tests {
923    use axiolid_core::{Mat3, Vec3};
924
925    use super::*;
926
927    /// Columns orthogonal only to `30 eps` pass as orthogonal, and the
928    /// largest singular value then exceeds the largest column length: the
929    /// margin must cover it (#258).
930    #[test]
931    fn the_stretch_covers_columns_orthogonal_only_to_rounding() {
932        let skew = 30.0 * f64::EPSILON;
933        let m = Mat3::from_cols(Vec3::X, Vec3::new(skew, 1.0, 0.0), Vec3::Z);
934        // Both columns have length one in f64; the largest singular value
935        // of [[1, skew], [0, 1]] is above 1 + skew / 2.
936        assert_eq!(m.y_axis.length(), 1.0);
937        let factor = stretch(Transform3::from_mat3(m));
938        assert!(factor >= 1.0 + 0.5 * skew, "{factor}");
939        assert!(factor < 1.0 + 200.0 * f64::EPSILON, "{factor}");
940        assert!(stretch(Transform3::IDENTITY) > 1.0);
941    }
942
943    /// The placement's rounding is `4 eps` of the largest summed magnitude
944    /// of a row that rounds, nothing for a row that copies a coordinate,
945    /// and covers the rounding `transform_point3` actually makes (#295),
946    /// measured against an error-free evaluation of the same sums.
947    #[test]
948    fn the_placement_rounding_covers_applying_the_transform() {
949        let eps = Scalar::EPSILON;
950        let site = Transform3::from_translation(Vec3::new(6e6, -6e6, 100.0));
951        assert_eq!(placement_rounding(&[Point3::ZERO], site), 4.0 * eps * 6e6);
952        let p = Point3::new(0.25, -0.5, 2.0);
953        assert_eq!(placement_rounding(&[p], site), 4.0 * eps * (6e6 + 0.5));
954        let mirror = Transform3::from_scale(Vec3::new(-1.0, 1.0, 1.0));
955        assert_eq!(placement_rounding(&[p], Transform3::IDENTITY), 0.0);
956        assert_eq!(placement_rounding(&[p], mirror), 0.0);
957        // A turn about z rounds x and y, not z.
958        let turn = Transform3::from_rotation_z(0.3);
959        let (c, s) = (0.3_f64.cos().abs(), 0.3_f64.sin().abs());
960        let sums = [c * 0.25 + s * 0.5, s * 0.25 + c * 0.5];
961        let largest = sums[0].max(sums[1]);
962        let r = placement_rounding(&[p], turn);
963        assert!((r - 4.0 * eps * largest).abs() <= 4.0 * eps * largest * 4.0 * eps);
964
965        // The actual rounding, from exact products (fused) and exact sums.
966        let exact = |t: Transform3, p: Point3| -> [Scalar; 3] {
967            let m = t.matrix3;
968            let rows = [
969                ([m.x_axis.x, m.y_axis.x, m.z_axis.x], t.translation.x),
970                ([m.x_axis.y, m.y_axis.y, m.z_axis.y], t.translation.y),
971                ([m.x_axis.z, m.y_axis.z, m.z_axis.z], t.translation.z),
972            ];
973            rows.map(|(a, offset)| {
974                // Each term as a high and a low part, summed from the
975                // smallest magnitude up in a running double-double.
976                let mut parts = Vec::new();
977                for (coefficient, x) in a.into_iter().zip([p.x, p.y, p.z]) {
978                    let high = coefficient * x;
979                    parts.push(high);
980                    parts.push(coefficient.mul_add(x, -high));
981                }
982                parts.push(offset);
983                parts.sort_by(|u, v| u.abs().total_cmp(&v.abs()));
984                let (mut high, mut low) = (0.0, 0.0);
985                for part in parts {
986                    let sum = high + part;
987                    let bb = sum - high;
988                    low += (high - (sum - bb)) + (part - bb);
989                    high = sum;
990                }
991                high + low
992            })
993        };
994        let placements = [
995            site,
996            Transform3::from_translation(Vec3::new(5.61e6, 3.3e5, -71.25))
997                * Transform3::from_rotation_z(1.1),
998            Transform3::from_axis_angle(Vec3::new(1.0, 2.0, 3.0).normalize(), 0.7)
999                * Transform3::from_scale(Vec3::new(1.5, 0.75, 2.0)),
1000        ];
1001        for t in placements {
1002            let points: Vec<Point3> = (0..200)
1003                .map(|i| {
1004                    let k = i as Scalar;
1005                    Point3::new((k * 0.37).sin() * 3e3, (k * 0.91).cos() * 7.0, k * 1.3e-3)
1006                })
1007                .collect();
1008            let bound = placement_rounding(&points, t);
1009            for &p in &points {
1010                let placed = t.transform_point3(p);
1011                let truth = exact(t, p);
1012                let error = Vec3::new(
1013                    placed.x - truth[0],
1014                    placed.y - truth[1],
1015                    placed.z - truth[2],
1016                );
1017                assert!(error.length() <= bound, "{error:?} over {bound:e}");
1018            }
1019        }
1020    }
1021
1022    /// The shrunk budget times the stretch is within the budget, and the
1023    /// next value up would not be (unless the quotient already fit).
1024    #[test]
1025    fn the_shrunk_budget_fits_after_rounding() {
1026        for budget in [1e-4, 1e-3, 3.7e-5, 0.125] {
1027            for factor in [0.33, 1.0, 1.19, 2.38, 2.510_038_280_268_978, 1e6] {
1028                let s = factor * (1.0 + 96.0 * f64::EPSILON);
1029                let b = shrunk_budget(budget, s);
1030                assert!(b * s <= budget, "{budget} {factor}");
1031                assert!(b <= budget / s);
1032                assert!(b == budget / s || b.next_up() * s > budget);
1033            }
1034        }
1035        // With room for a placement's rounding (#295): the grown bound fits.
1036        for room in [5.3e-9, 1e-5, 9.9e-5] {
1037            for factor in [0.33, 1.0, 1.19, 2.38] {
1038                let s = factor * (1.0 + 96.0 * f64::EPSILON);
1039                let b = shrunk_budget_within(1e-4, s, room);
1040                assert!(b > 0.0 && grown(b, s, room) <= 1e-4, "{room} {factor}");
1041                assert!(grown(b.next_up(), s, room) > 1e-4 || b == (1e-4 - room) / s);
1042            }
1043        }
1044        // The quotient alone rounds over at this factor.
1045        let s = 0.33 * (1.0 + 96.0 * f64::EPSILON);
1046        assert!((1e-4 / s) * s > 1e-4);
1047        assert!(shrunk_budget(1e-4, s) < 1e-4 / s);
1048    }
1049}