An entity sketch that forms no wire fails, instead of extruding a default box

entities_to_wire handles exactly two shapes: one lone closed entity
(Circle/Ellipse), or a chain of open ones (Line/Arc/EllipseArc/BSpline).
Anything else -- a circle coexisting with a line, two circles -- returns a
null wire. build_sketch_wire answered that by falling through to its
legacy tail, which ends in a rectangle built from width/height. For an
entity sketch those fields are whatever they were initialised to, so the
extrude produced a box the user never drew, silently and with ok:true.
That is how the ellipse+stray-arc case in the P2 Tier-B.1 verification
turned into a default-rectangle solid.

Throw there instead. The legacy profile/shape paths below are still
reached by sketches that legitimately carry no entities at all, so the
enum and profile constructors are untouched -- only the case where
entities exist and cannot be turned into a wire now fails, which is
exactly the case that was fabricating geometry.

This does NOT implement the multi-loop support the issue asks for. Doing
that properly means deciding containment -- a circle inside a rectangle is
a hole, a circle beside it is a second region -- and make_extrude_regions
cannot be reused because it takes flattened Vec2d contours for imported
Text/SVG art and would discard the analytic circle. Guessing containment
would trade a visible failure for a wrong solid, which is the opposite of
the point. Left scoped on snaporca-88v.

Also converts the three float comparisons in the two test cases added this
session from Approx to WithinAbs/WithinRel, per tests/CLAUDE.md, which
rules Approx out for being asymmetric and double-only. The rest of the
file's pre-existing Approx uses are left alone.

153 cases / 2090 assertions green on both forks; no existing test depended
on the default-rectangle fallback.

snaporca-88v (partial: the silent-fallback half).
This commit is contained in:
Tommaso Bianchi
2026-07-30 09:56:18 +02:00
parent 5f1811c2c5
commit 7f0a8c85ee
2 changed files with 61 additions and 4 deletions
+12 -1
View File
@@ -1930,7 +1930,18 @@ TopoDS_Wire CadDocument::build_sketch_wire(const CadFeature& sketch) const
if (!sketch.entities.empty()) {
TopoDS_Wire w = SketchEngine::entities_to_wire(sketch.entities, sketch.plane);
if (!w.IsNull()) return w;
// fall through to legacy paths if entities produced nothing
// An entity sketch that yields no wire is an ERROR, not a cue to fall through. The
// legacy tail of this function ends in a default rectangle built from width/height,
// which for an entity sketch are whatever they happened to be initialised to — so a
// sketch entities_to_wire cannot handle (a circle coexisting with a line, two circles:
// snaporca-88v) used to extrude into a box the user never drew, silently. Failing here
// costs the caller an error message; falling through cost them wrong geometry that
// looked deliberate. The legacy profile/shape paths below are still reached by sketches
// that legitimately carry no entities at all.
throw std::runtime_error(
"sketch has entities but they do not form a single closed wire — a closed entity "
"(circle/ellipse) combined with other entities, or several closed entities, is not "
"supported yet");
}
if (!sketch.profile.points.empty()) {
SketchProfile prof = sketch.profile;