- topology::brep_data_write / geometry_write: write B-reps and geometry to the SMLib
database format; topology::part_file: read part files.
- difftest units topology.part_file and corpus.parity (whole upstream TestFiles corpus,
Rust vs C++), with their shims and FFI, plus the corpus example.
- Fixes found by the corpus in line, ellipse, plane, offset-surface, B-spline and
surface code.
- WR-449: one sphere_diff fillet face integrates 0.6 too much area upstream; its area and
volume are exempted in corpus.parity, cause under investigation.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PJzQKZ9sjU1DhgS253e8J5
MakeAnalyticCornerSurface's SER / NER exits return TRUE without adding a
surface, so the MakeFaceBrep that follows sees m_vSurfaces unchanged (none in
the harness: it returns at once). The shim's pre-check treated every TRUE as a
surface added and refused the corners whose edge curve is NULL, although
upstream never copies those curves. Split P3A_TRUE into a surface exit and a
status exit; a planar corner's status exit after SetCurve(NULL) still refuses
when the corner already had one surface (MakeFaceBrep would copy the deleted
curve). Nine generated corner cases of blend.fillet_corner_p3 now compare
(rejected 28 -> 19), all passing.
Every remaining refused case was run natively with the pre-check bypassed:
each crashes in upstream (SIGSEGV), hangs in CreateExtendedSurface (HANG-9) or
calls a member through a null solver. Runner headers say so; the p2 header no
longer implies its rejections come from the find_concave refusal. HANG-9 gets
an addendum for the two side-face triggers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
The large-gap part of sm_RefineCCIToSurfaces (surf/surf/surf move, curve and
edge surface intersections, RefinePoint on both surface pairs and the bounded
recursion) now runs through refine_cci_to_surfaces_mut over ClassGeometryMut,
editing the classification curve, the edge and its UV trim curves. The
part-5 Access trait dispatches the refinement; curve_on_classify_mut inserts
edge solutions through a new intersect_edges_mut with the surface owner
cleared over the edge loop, as upstream.
Fixture route: topology.brep_p2 MergeSsi op (MergeCurvesOnSurface with UV
curves and pOptIntersectionSurface), the IntersectObject::FreeSurface handle
and p10 merge_curves_on_surface_through_surface. New fixture
refine_cci.json: CreatePlanarSectionCurves curves of Solids/nurb_fillet.smb
reaching parts 2a, 2b and 2d.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
Adds a MergeBreps runner op (shim op 35, SmBrep::MergeBrep) that puts both
operands in the primary B-rep as SmMerge does, and merged_* cases that run
SetEditing, EdgeFace and FaceFace on faces of that one B-rep.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
Adds a SetEditing script op (shim op 34, m_bEditingEnabled), a ChainFaces
marker that lets a FaceFace without input vertices follow a VertexFace or
EdgeFace (the FFI guard now allows exactly that), Vertexuse handles in the
runner's topology_entity, and crossing-plane fixtures. Existing cases are
unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
map_to_2d_on_curve evaluates the UV curve of a curve on this very surface
object (std::ptr::eq with the base surface) instead of returning Unported.
The surface_p9 analytic-surface stub was unreachable: the diagonal
SmCrvOnSurf already holds the analytic surface. Eight sphere and torus
diagonal cases (shim kinds 5 and 6) compare against C++.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
offset_executive_p2: tiny/far-translated boxes build as an empty B-rep and
merged/dropped-face sheets as a degenerate face; both are defined native
results (no crash, hang or UB) and are now built and compared on both sides.
Only a selection of the nonexistent face 0 stays rejected (nothing to run).
trans_sweep_geometry: a curve constructor failure status is compared with
Rust's instead of rejected; null curves are never passed to
CreateWireEdgeFromCurve.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
Add a full-only radius_end form for the actual native and Rust public linear-law fillet APIs. Keep the constant wire and API path, share complete output records, and reject unsupported prefix or thumbweight combinations before construction.
Co-Authored-By: OpenAI Codex <noreply@openai.com>
A runtime backtrace shows AdjustConcaveCornerTopology (SmFilletCorner.cpp:7185)
extending the side surface by 10 * dGapDist; with dGapDist == 0 the
CreateExtendedSurface halving loop (HANG-9) never ends. Add an addendum to HANG-9
and point the shim guard comment at it; the guard condition is unchanged.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
Generated patch and calc_geom corner cases give the model's fillet geometries a base solver
with a cross-section generator, identically in the Rust runner and the shim, so the
analytic-corner fits that read the solver run instead of being refused. The shim now
follows MakeAnalyticCornerSurface past the solver reads (chamfer re-intersection, the
constant radius conversion's generator checks); solver-less geometries stay refused.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
A new classification kind 5 puts the model's side edge use on the first loop of a
target face, so the side face (and its radial's face) exist and
AdjustConcaveCornerTopology reaches the surface extension. Rejected cases 19 -> 7.
The shim also refuses coincident rail points with a zero tolerance, where
CreateExtendedSurface (by 10 * 0) does not return.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011gJAwcLRBPQXYLmvXd3pWf
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
The shim no longer refuses a corner edge without a 3D curve: upstream
CreateCornerBlend returns SM_ERR below four curves and otherwise
SM_ERR_NULL_POINTER, without crashing. create_corner_patch now checks the
count before dereferencing curves, matching that order.
Co-Authored-By: Claude Sonnet 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