Conflicts resolved in favour of main where main superseded this branch's
code, combined where both added; main's new kernel argument threaded
through the offset point solves, the fillet solver's LocalPointSolve and
copy_and_add_analytics callers; OffsetSurface arms added to main's new
SurfaceKind matches (evaluation copy, drop curve, CrvOnSurf dispatch gap,
loop UV gap test).
With surface_point_solve_p3 landed, the 213 cases that deferred on
LocalPointSolve_1 now run, and 5 disagreed: Rust found a pole solution C++
rejects. Cause: upstream's owning offset does m_pSurface->SetOwner(this),
so LocalPointSolve_1 on the base takes GetZoneTol3d(GetOwner()) as its
loose tolerance instead of 0.01. Ported that ownership: an owning offset
gives its base the BASE_OWNER surface owner wherever upstream calls
SetOwner(this) (constructor, Copy, ReadFromDB), and hands down the face
its own owner chain reaches, so Surface::face of a base follows the chain
as GetFace does. This replaces the face_owned flag the box code passed
down (review item 2 keeps its Unported(topology.face_p2) result). The
approximation-tolerance and surface-cache zone checks that asked "any
owner" now ask GetFace(), as SmTol::GetZoneTol3d(const SmObject*) does.
The six cases (three generated, base owned and shared) are fixtures.
surface.offset_surface: 3072 cases, 3072 passed, 0 failed, 0 deferred.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace the GCC/Clang-only weak symbol with a plain flag the shim defines
(at namespace scope, external linkage) and the worker's main() sets when it
is linked with its NLib --wrap wrappers. Verified the non-Linux branch by
forcing it on Linux: the worker builds without __wrap_ symbols and refuses
every extension step; the regression now asserts that per platform.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
FFI guards now refuse only what C++ cannot handle, each probed against the
isolated worker:
- drop the 1e6 coordinate cap, the 1e-3 transform-scale floor, the 1e3
extension-distance cap and the 1e-6 revolution generator minimum (offset
callers only; surf_of_revolution_p1's in-process calls keep it);
- orders: cap 64 (caller array bound; upstream refuses >3 before writing);
UB-116 moves into the worker on the actual compound distance, so zero
offsets are compared;
- box guard follows CalculateBoundingBox level by level against each
offset's own m_pSurface instead of only the innermost base.
Remaining refusals are UB-107 and HANG-6, the latter by a 20,000-call
arc-length work bound (normal searches: <=45) instead of the deadline.
Worker: a timeout is rerun once with 60 s before it is a harness failure;
off Linux it is built without GNU ld --wrap and the shim refuses extension
steps instead of running them unguarded.
Dispatch: new BaseOffset op compares GetBaseSurface()->CreateOffsetSurface
through SmSurface* (4 fixtures, 81 generated over every base kind).
Generator covers magnitudes 1e-9..1e150, tiny revolutions, zero/negative
scales and orders up to 8 (484 such cases pass, 41,252 values).
nurb_of documented: a NURB-less revolution base is UB upstream before
GetOrCreateGwNurbPointer runs. nurbs.b_spline_surface_p1 note counts fixed.
surface.offset_surface: 3066 cases, 2853 pass, 0 failed, 213 deferred;
6000 seeds: 6066 cases, 5620 pass, 0 failed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolve conflicts with the newly ported surface p3-p6, srf_in_volume,
topology face/vertexuse/edge and query units:
- Add OffsetSurface to the new SurfaceKind dispatch arms and SrfInVolume
to the offset nesting walk; GetSingularities now runs (surface_p3).
- Thread the kernel through SrfInVolume copy/split and the surface cache
subdivision split, which now call Surface::copy/split_at.
- Implement the new SurfaceEvaluate solver methods for OffsetEval on a
snapshot that keeps this evaluation's extension.
- Renumber this PR's upstream issues past main and every open PR:
UB-99..102 -> UB-116..119, WR-81..87 -> WR-97..103,
HANG-13/14 -> HANG-14/15; link HANG-15 to main's UB-107.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Main added UB-98, HANG-12 and WR-73 (topology.proto_topology_p1), so this
branch's upstream issues are renumbered: UB-98..101 -> UB-99..102,
HANG-12/13 -> HANG-13/14, WR-73..79 -> WR-74..80, in the plan files and in
the offset FFI, shim and difftest README. The offset unit's notes keep
main's CO-PORTED record from blend.fillet_custom_solver (PR #78).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shim, FFI wrapper, runner and fixtures (upstream TestSmCreateOffsetSurface,
smTopoTest nested offsets, smMergeTest .sms offsets, edge cases). 3057 cases:
1479 bit-identical, 0 failed, 1578 deferred (GetSingularities, surface_p3).
Fixes found by the difftest: N_SrfIsClosedSmooth stores its flag before
returning a failed-angle error, so N_SrfEvalPtDerivsUnbounded keeps the copy
and flag for a retry (nlib.srf_nurb, nlib.srf_adv_p1); SmSurface's base
CalculateBoundingBox maps a failed cache to SM_ERR_NULL_POINTER (NER).
WIP: a 30k-seed run still has one C++ hang to guard (case gen120xx).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>