From be72afc9f7d6c5a750b9524f12a1809e50474e01 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Sun, 4 Oct 2026 22:21:06 +0800 Subject: [PATCH] Fix hidden features refusing to show again after their body's feature was hidden --- src/libslic3r/CAD/CadDocument.cpp | 7 ++++++- tests/libslic3r/test_caddocument.cpp | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/CAD/CadDocument.cpp b/src/libslic3r/CAD/CadDocument.cpp index 2a838354af..df3c1f7135 100644 --- a/src/libslic3r/CAD/CadDocument.cpp +++ b/src/libslic3r/CAD/CadDocument.cpp @@ -2197,11 +2197,16 @@ static void stage_history_change(std::vector& features, ref = nn >= 0 ? 3 + nn : 3 + int(after.size()) + 1000; }); if (f.body_ref_ids.size() != size_t(kBodyRefCount)) continue; // never resolved: nothing to follow + // A feature hidden after the change is not replayed, so a hidden source is no reason to + // drop its body: it keeps following it and re-points when shown. Shown while the source + // is still hidden, it is staged as replayed and loses the body then. Only deleting the + // source drops a hidden feature's body. + const bool replayed = enabled_after(j); int k = 0; for_each_body_ref(f, [&](int& ref, bool) { CadFeature::BodyId& id = f.body_ref_ids[k++]; if (ref < 0 || id.src < 0) return; - if (!alive(id.src)) { ref = kBodyGone; id = {}; return; } + if (replayed ? !alive(id.src) : map_feature(id.src) < 0) { ref = kBodyGone; id = {}; return; } id.src = map_feature(id.src); }); f.body_refs_pending = true; diff --git a/tests/libslic3r/test_caddocument.cpp b/tests/libslic3r/test_caddocument.cpp index 5be9364cfc..56f2cfb0b3 100644 --- a/tests/libslic3r/test_caddocument.cpp +++ b/tests/libslic3r/test_caddocument.cpp @@ -8801,6 +8801,29 @@ TEST_CASE("Hiding a body-making feature keeps later features on their body", "[C CHECK(doc.features[lift].target_body == 1); } +TEST_CASE("A hidden feature can be shown again once the feature that made its body is shown", + "[CadDocument][history]") +{ + CadDocument doc; + const int sk = doc.add_sketch(SketchShape::Rectangle, SketchPlane::XY(), 10, 10, 0, "S"); + const int ex = doc.add_extrude(sk, 5, false, BooleanMode::New, "E"); + const int ch = doc.add_chamfer(1.0, FaceGroup::All, "C"); + doc.features[ch].target_body = 0; // as the Design tab sets it from picked edges; -1 has no body to follow + REQUIRE(doc.recompute()); + const double chamfered = double(doc.display_mesh.volume()); + + REQUIRE(doc.set_feature_enabled(ch, false)); + REQUIRE(doc.set_feature_enabled(ex, false)); + // The chamfer has no body while the extrude is hidden... + CHECK_FALSE(doc.set_feature_enabled(ch, true)); + CHECK_FALSE(doc.features[ch].enabled); + // ...and gets it back once the extrude is shown. + REQUIRE(doc.set_feature_enabled(ex, true)); + REQUIRE(doc.set_feature_enabled(ch, true)); + CHECK(doc.features[ch].target_body == 0); + CHECK_THAT(double(doc.display_mesh.volume()), Catch::Matchers::WithinRel(chamfered, 1e-6)); +} + TEST_CASE("Datum-plane references follow their plane when an earlier plane is deleted", "[CadDocument][history]") {