- kernel_adapter: main's adopt_namespace_owners (#1626) replaces ours
- boolean.api_brep: 'checked' moves to op 20 (#1649's attributed list took 19)
- edgeuse_p1: no owner value for imported .smb cases on either side (owners
compared only where the Rust input is built in Rust)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main took boolean.api_brep op 19 for AttributedList; the attributed sweeps
move to ops 20 / 21. attribute_row counts the users that are topology
objects, within the caller's B-rep scope when one is given.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNXLXj2sJf943y2dDF36Vy
- adopt_namespace_owners re-owns merge-namespace UV trims, as it does surfaces and curves
- set_member_uv_trim_curve sets the owner (SmEdgeuse::SetMemberUVTrimCurve)
- boolean.api_brep op 19 'checked' compares the capi check of a boolean result; edgeuse_p1 compares real UV owners
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
boolean.api_brep's attributed call takes optional SmApiBooleanWithOptions
flags and an SmApiBrepCopy of the first operand (102 split/imprint cases).
topology.brep_local_operation op 3 and heal.stitch_p1's tagged ops tag every
face and edge first and compare the attribute ids each face and edge
carries afterwards (sc_attribute_tags.h; 18 and 218 cases).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNXLXj2sJf943y2dDF36Vy
PrimitiveModel keeps one attribute store for all its B-reps, keyed per
B-rep, and every edit (single and two-B-rep edits, the HCR scene copy,
merge stages, the sweep stitch, RemoveFaces / RemoveAllTopology) renames
the touched B-reps' lists in place to the identities it notifies, so the
non-manifold sweeps carry a B-rep's attributes as upstream's
notifications do, reference sharing included. SM_AI_TAG tags of a
tagging sweep live there too and stay on the result. SweepStore moves
an inserted or adopted body's attributes into its shared store and
hands a taken body its lists back.
Difftest: attributed non-manifold sweeps in boolean.api_brep and
attributed curve sweeps from faces / edges in sweep.api_brep; the shims
count only topology users of an attribute (the port keeps none on
geometry). Regression test: tests/issue_1462_sweep_attributes.rs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNXLXj2sJf943y2dDF36Vy
- boolean.api_brep: TessellateBoundaries moves to op 18 (main's attribute store took 17)
- primitive::api_curves: keep both create_curve_approx_points (#1543) and remove_curve_knots
- topology.api_files: primitive write cases name faces and edges by their geometry owners
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Part of #1462 (P2). DependencyMerge::carrying_attributes seeds and restores the
operands' own attributes around every merge it runs (merge_breps, boolean_trees,
the boolean_lists merge and the two-B-rep entry points). boolean_lists lends each
list B-rep's attributes to its operand copies and the component copies under
distinct source identities. api_brep_copy lends the source's attributes to the
copy. kernel_named_edit (with_kernel_callbacks) and the ArenaNotifyState plain
entry points (brep_p5, heal glue) lend the B-rep's store to the edit and hand
back the lists of the objects it still has; an unlinked face, edge or vertex
counts as deleted. Attributed difftest modes for the list calls and the copy.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNXLXj2sJf943y2dDF36Vy
Which of two coplanar faces the C++ cleanup keeps (and so whose attributes
lead its list) depends on the C++ process's earlier heap use; the set of
attributes does not. Both sides now sort each row's attributes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNXLXj2sJf943y2dDF36Vy
topology::Brep owns an AttributeStore keyed by the B-rep-local notify_ref
identity, with add/attach/find/entity/remove/clear attribute methods; a
clone copies it. The two-B-rep boolean entry points seed the merge engine's
store from both operands and write the surviving attributes back to the
result and a kept other B-rep, so SMLib's Split/Copy/Merge handlers carry
operand face and edge attributes to the result. The boolean cleanup's
DeleteEdge/DeleteVertex/DeleteTopologicalVertex now notify on the merge's
records, attributes and names (coplanar faces merged by the cleanup keep
both origins, as upstream). SmApiEdgeComputeLength passes the edge's zone
tolerance to the curve length.
Difftest: boolean.api_brep 'attributed' op (shim tags operands with
SmLongAttribute, both sides compare per face/edge attribute rows) and a
cylinder operand kind; 44 fixture cases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MNXLXj2sJf943y2dDF36Vy
The runner, shim and FFI build a capped skin from given section curves
(degree, control points, knots as the NURB stores them), so both sides
start from bit-identical operands. Six fixture cases run union,
intersection and difference of #1036's two skins whose sides coincide over
sections 2..4, with and without mass measurements; an ignored test
regenerates the fixture.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJzQKZ9sjU1DhgS253e8J5
`BrepIn::Moved`: an operand moved by SmApiRotate / SmApiTranslate steps,
built the same way on both sides. Used by two new fixtures:
crossing_creases.json (4 unions, crease offsets 3e-6..1e-4) and
issue_1059_grazing_bar.json (2 unions, alpha -1.0 / -0.1, beta 30).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJzQKZ9sjU1DhgS253e8J5
Surface::convert_uv_from_step_to_nurbs / convert_uv_from_nurbs_to_step had no Torus arm,
so a torus took the base identity. Upstream SmTorus overrides both (SmTorus.h:184/:190);
the ported overrides (surface/torus.rs) were never dispatched. In BooleanPostProcess the
merge of two torus faces then united a NURBS domain with a STEP-degree domain and
re-trimmed the merged face in it: box ∩ tangent torus lost volume (seed 86: 23.57 against
C++ 104.84).
Difftest: boolean.api_brep gains a torus operand kind and a measured call (volume and face
areas), 8 issue383 cases and 12 torus_guard cases (radius boundaries, horn, huge scale).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJzQKZ9sjU1DhgS253e8J5
boolean.api_brep now records, per region in GetRegions order, IsVoid,
IsInfiniteRegion and the shell count, and per shell its faceuse count and
the region behind its first faceuse's mate, so region and shell order are
compared against SMLib.
That exposed three merges of inverted spheres (gen0001, gen0033, gen0118)
whose region list differed from SMLib's. The B-rep region list was modelled
as the region arena rotated to its head, which is only SMLib's circular list
while the head is the oldest region. Once the head moves to a later region
(the inverted sphere's infinite region), SmOwningTopology::PostInsert
appends before the head, but the arena model put new regions after the
newest one. The Brep now records the link order whenever the head moves or a
region is pre/post-inserted or removed; regions appended since follow in
arena order, as PostInsert.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
Follows #1077: a result-changing fix of an upstream defect is an opt-in
`Kernel::fixes` field and the default is pinned SMLib behaviour.
- WR-214 (#480): the Boolean's topology intersector sets
`split_self_loops_on_vertices` from `proto_edge_self_loop_on_vertex_degenerate`
instead of forcing it off.
- WR-254 (#528): the slice side rule for coincident faces needs
`slice_coincident_faces_sheet_side`; by default the slice takes upstream's
difference rule.
- WR-265 (#388): `put_outer_shells_first` (shell order and the nested-solid
void-flag rewrite) needs `boolean_outer_shell_first`.
The boolean.api_brep runner can now build sheets (SmApiCreatePlane) and operands
that are an SmApiBoolean result, and it gains the C++-confirmed WR-254 and WR-265
repros as fixture cases that pass at the default. Each fix has an issue test with
the field on and a test that pins the default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
125 shims carried private copies of the same small helpers (put_vec, st,
nl_status, Rd, dump_crv, read_nurb, ...). Move the most common, byte-identical
form of each into three headers grouped by the upstream API they need, and have
those shims pull them in with `using sc::<name>;`. Shims with a different
variant keep their own copy; files touched by open PRs are left alone.
`the_context()` stays per shim (its function-local SmContext must not be shared).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FBLgPenT24P1dunqnZR1Dj
SmApiBrep.cpp boolean entry points: SmApiBoolean, SmApiBooleanUnion/
Difference/Intersection/Merge, SmApiMergeBreps, SmApiBooleanWithOptions,
SmApiBooleanLists, SmApiBooleanTrees and their static validators. Input
validation is compared against the C++; everything past it reaches SmMerge
and is deferred (boolean.merge_p2, boolean.merge_p3). Co-ports
SmMergeOptions into boolean::merge::p1.
difftest: cases=284 passed=142 failed=0 deferred=142
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BY8UpXKuMci15rAWGXsbsm