mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 02:11:18 +00:00
Thicken Surface: fill the corners of a closed-loop wall
snaporca-wm4s. Thickening the 4-walled open box (60x60 in plan, 40 tall, no caps) by 5 produced volume 29648.15 where the geometry requires (60^2-50^2)*40 = 44000 — about 67% of it. The corner material at the four vertical edges was simply absent. CAUSE. MakeThickSolidBySimple offsets each face along its own normal and sews; it never extends neighbours to meet, so wherever two faces join at an angle the corner is empty. A flat sheet has no such join and was always exact (18000.000), which is why the defect looked like a measurement artefact. WHY THE TWO EARLIER ATTEMPTS COULD NOT HAVE WORKED. Both switched to ByJoin — plain, then with Intersection/GeomAbs_Intersection — and both returned a shell, not a solid, so the body lost its volume entirely and both were reverted. That is not a parameter problem: in OCCT, BRepOffset_MakeOffset::MakeThickSolid builds a solid only inside `if (!myFaces.IsEmpty())` (BRepOffset_MakeOffset.cxx:1115). Handed an open sheet with no closing faces, it stops after the offset shell and returns it, reporting IsDone() with a non-null shape containing no TopAbs_SOLID. ByJoin hollows a CLOSED solid by removing faces; an open sheet is outside its contract. FIX. Close the sheet, then use the call that mitres: cap the free rims (ShapeAnalysis_FreeBounds -> MakeFace), sew shell+caps into a closed shell, make a solid, and hollow it inward passing the caps as the faces to remove — the caps come back off and leave the wall. Two details, each found by measurement rather than reasoning: * A shell sewn from an extruded sheet carries no guarantee of outward orientation, and MakeSolid does not fix it. Inside-out, the inward offset goes OUTWARD: measured bbox 70x70x40 and volume 339141.59, larger than its own bounding box because the result overlaps itself. A negative GProp mass is exactly that inversion, so it is the test; Reverse() on it. * A SINGLE face has no neighbour to mitre and must keep the BySimple path. It does have a free boundary, so "has free wires" is the wrong question — capping a lone face with its own rim sews a zero-thickness shell and measures 6000 against 18000. Also: IsDone() is not a success test here, since both failed attempts had it true. The code now explores for TopAbs_SOLID and refuses a shell. Tests: new case asserts 44000 with the wall's bbox at 60x60x40 (catching the inverted-orientation shape, which has the right volume nowhere near the right place), plus the flat-sheet control at 18000 that must not regress. Full kernel suite green: 2502 assertions in 187 test cases. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
98135cf529
commit
799f840218
@@ -5159,6 +5159,51 @@ TEST_CASE("mass properties of a sheet body report area only, never a volume",
|
||||
REQUIRE(solid.inertia[8] > 0.0);
|
||||
}
|
||||
|
||||
// snaporca-wm4s. The wall of a thickened open box must contain the corner material. Thickening
|
||||
// each face along its own normal and sewing (MakeThickSolidBySimple) leaves the four vertical
|
||||
// corners empty and measured 29648.15 where the geometry requires 44000; the two controls below
|
||||
// were exact before and must stay exact, since they are what a corner-only fix must not disturb.
|
||||
TEST_CASE("thicken surface fills the corners of a closed-loop wall", "[CadDocument][surface]")
|
||||
{
|
||||
using Catch::Matchers::WithinRel;
|
||||
|
||||
SECTION("open box: (60^2 - 50^2) * 40") {
|
||||
CadDocument doc;
|
||||
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 60, 60, 0, "Rect");
|
||||
REQUIRE(sk >= 0);
|
||||
doc.add_surface_extrude(sk, 40.0, "Skin"); // 4 walls, no caps
|
||||
REQUIRE(doc.recompute());
|
||||
REQUIRE(doc.body_mass_properties(0).surface_area == Approx(9600.0)); // the sheet is what we think
|
||||
|
||||
REQUIRE(doc.add_thicken_surface(0, 5.0, false, "Wall") >= 0);
|
||||
REQUIRE(doc.recompute());
|
||||
REQUIRE(doc.error.empty());
|
||||
|
||||
auto w = doc.body_mass_properties(1);
|
||||
REQUIRE(w.is_solid); // NOT a shell: the old ByJoin attempts
|
||||
REQUIRE_THAT(w.volume, WithinRel(44000.0, 1e-6)); // returned volume 0.0 / is_solid false
|
||||
// The wall must sit ON the sheet, not around it: an inverted capped solid offsets the
|
||||
// wrong way and lands at 70x70 with a volume larger than its own bounding box.
|
||||
const auto bb = doc.display_body_meshes[1].bounding_box();
|
||||
REQUIRE_THAT(bb.max.x() - bb.min.x(), WithinRel(60.0, 1e-3));
|
||||
REQUIRE_THAT(bb.max.z() - bb.min.z(), WithinRel(40.0, 1e-3));
|
||||
}
|
||||
|
||||
SECTION("control, flat sheet stays exact: 3600 * 5") {
|
||||
CadDocument doc;
|
||||
int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 60, 60, 0, "Rect");
|
||||
REQUIRE(doc.add_surface_fill(sk, "Face") >= 0); // one flat face, no rim to mitre
|
||||
REQUIRE(doc.recompute());
|
||||
REQUIRE(doc.add_thicken_surface(0, 5.0, false, "Plate") >= 0);
|
||||
REQUIRE(doc.recompute());
|
||||
REQUIRE(doc.error.empty());
|
||||
|
||||
auto p = doc.body_mass_properties(1);
|
||||
REQUIRE(p.is_solid);
|
||||
REQUIRE_THAT(p.volume, WithinRel(18000.0, 1e-6));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("surface-offset creates another sheet shifted outward", "[CadDocument][surface]")
|
||||
{
|
||||
using Catch::Matchers::WithinAbs;
|
||||
|
||||
Reference in New Issue
Block a user