APPROX_VERTICES / APPROX_EDGES for CalculateBoundingBox's approximation
shortcut and MIN_SHIFT_CENTER_LENGTH_SQ for SmTemporaryBrepTransform.
The FFI module derives its record and output lengths from named layouts,
passes the op and kind codes as #[repr(i32)] discriminants, routes both
fixture-B-rep entry points through one validated call, and owns the
sentinel box (SEED_BOX), which it now hands to the shim instead of both
sides repeating it. The runner names its status, no-entity and object
kind codes. Outputs are unchanged (report identical).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Real calls replace the UNPORTED(query.brep) stubs of SmBrep::
CalculateBoundingBox (topology.brep_p1/p9/p10, heal.stitch_p1/p2,
blend.hcr, mass.integrator, query.api_queries incl. the tight box),
SmLockBrepBox (topology.brep_p1, and topology.brep_p5's SqueezeFace whose
stubs named topology.brep_p1) and SmTemporaryBrepTransform
(boolean.merge_p1: boxes before any transform, as upstream, then
TemporaryBrepShift::apply). Kernels are threaded where a caller had none;
ignored statuses stay ignored. topology.brep_p6 stops after its real box
at an OMITTED marker for its own remainder (SmBrep.cpp:27966-28583).
Callers that cannot reach a ported function keep returning Unported
under a DISPATCH GAP comment naming it: Point3DClassify (merge_p1/p4/p5,
proto_topology_p3, api_queries), the ShellRayWorld defaults, p9 RayFire,
p10 MergeCurvesOnSurface and geom.object's SmShape over B-rep keys.
Runner fixes for the newly reached paths, from bherbruck's #332:
geom.a_object attaches a built cache (SetCacheObj), boolean.merge_p4 owns
imported geometry as its adapter keys it, boolean.topology_intersector_p1
keys its cache by its notification keys, mass.integrator builds the
shim's wire-edge B-rep. topology.brep_p2 builds its RayFire cache.
Fixture coverage, also prompted by #332: a shared B-rep kind with up to
600 vertices and 150 wire segments at given tolerances (reaches the
500-vertex/100-edge approximation shortcut and non-default tolerance
expansion); attribute ids and sort indices carried as exact 32-bit
halves (full ULONG width); the classification guard accepts any finite
point and tolerance (negative and huge tolerances, 1e100 points).
difftest: PARTIAL query.brep cases=1170 passed=923 failed=0 deferred=247;
perturb 923/923. 0 failed in every touched unit; geom.a_object PASS
2040/2040 (was 1909); more passes in merge_p1 (+11), merge_p4 (+50),
topology_intersector_p1/p2 (+6/+5), stitch_p1/p2 (+3/+31),
offset_executive_p1 (+1), api_queries (+126), topology.brep_p1 (+71).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
point_3d_classify takes the B-rep cache and identities as
topology::brep::p2::ray_fire does: the boundary solve (BrepPointSolve,
INTERSECT, SINGLE) first when asked, the single-region shortcut, then ray
fires along +x/-x, +y/-y, +z/-z with upstream's retry structure. It
returns the classification: every upstream caller builds a fresh one and
drops it on failure.
Back-edges wired here because the classification needs them:
- topology::brep_cache::build_trees: SmBrep::CalculateBoundingBox.
- topology::brep::p2: the same box for RayFire and SetTolerance (whose
status upstream ignores: a failure keeps the initialised box).
p2::cache_entity becomes pub(crate) for the solve's objects.
Harness:
- The shared B-rep fixture gains kind 7, the closed box solid of
SmApiCreateBox (SmPrimitiveCreation::CreateBox), so a multi-region
B-rep with exact geometry reaches the ray fires. No generator of other
units produces it; topology.edgeuse_p1/p2 re-run with 0 failed.
- topology.brep_p2's RayFire op now builds the B-rep cache
(make_brep_cache) and owns the imported geometry as a native B-rep
does (util::own_arena_geometry); it passed an empty cache, which the
query.brep stub had hidden.
difftest: PARTIAL query.brep cases=1128 passed=879 failed=0 deferred=249
(geom.tol 72, analytic export 20, surface.cone_p1 47, surface.sphere 18,
surface.surf_of_extrusion_p2 45, topology.face_p2 47); perturb 879/879.
PASS topology.brep_cache 663/663 (was partial, 1 query.brep deferral).
PARTIAL topology.brep_p2 1492 passed (was 1437), 0 failed, no query.brep
deferrals.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SmBrep::CalculateBoundingBox (options struct with upstream's defaults),
CalculateTightBoundingBox, LockBoundingBox and UnLockBoundingBox, over
topology.brep_p1's vertex/edge/face lists in list order. The locked box
is a new Brep field. Upstream builds with SM_USE_OLDTOL, so expansions
use the entities' GetTolerance().
CalculateTightBoundingBox ignores the edge and face statuses and keeps
what a failed call leaves (rFaceBBox persists across faces), so
query.face_p3 gains calculate_tight_bounding_box_into, writing the
caller's box at the same two points as SmFace::CalculateTightBoundingBox;
calculate_tight_bounding_box wraps it unchanged.
The shim runs a program of box/tight/lock/unlock steps on a real SmBrep
from the shared topology fixture; the Rust side reuses query.face_p1's
import and its analytic-geometry deferral (made pub(crate)).
difftest: PARTIAL query.brep cases=849 passed=715 failed=0 deferred=134
(analytic export 10, surface.cone_p1 29, surface.sphere 7,
surface.surf_of_extrusion_p2 35, topology.face_p2 53); perturb 715/715.
query.face_p3 and query.face_p1 re-run: reports unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SmDecimateVertexAttr, SmQuadricVertexAttr and SmQuadricEdgeAttr become
AttributeValue variants (as query.tess did for its attributes) built by
query::brep::{decimate_vertex,quadric_vertex,quadric_edge}_attribute;
their MakeCopy overrides are Attribute::make_copy arms (sort indices
restart at 0). The quadric edge constructor's uninitialised sort index
is None. The shim reads the protected data through peek classes and
compares the constructed attribute and its copy.
geom.attribute's runner gains the new variants in its exhaustive
matches (reported as plain attributes, as it never builds them); its
report is unchanged.
difftest: PASS query.brep cases=715 passed=715 failed=0 deferred=0;
perturb 715/715. PASS geom.attribute cases=2029 passed=2029.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SmApiEvaluateSurfacePoint, SmApiEvaluateSurfaceNormal and
SmApiEvaluateSurfaceDerivatives as query::brep::evaluate_surface_*, with
the shim calling the public API, its FFI guard and the difftest runner.
Fixtures re-express TestSmCreateSurfaceFromCornerPoints (NaN, outside and
NULL inputs) and evaluate the upstream .sms surfaces; generated cases
cover planes, B-splines and curve-bounded surfaces at interior, boundary,
just-outside and non-finite parameters. The shim pre-fills the outputs
with sentinels so the comparison also checks that a failed call leaves
them untouched.
difftest: PASS query.brep cases=681 passed=681 failed=0 deferred=0
max_rel_err=0; perturb 681/681 detected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>