mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 02:41:17 +00:00
A body carries its own name, because a body is not its first feature
User report 2026-08-23, and it is right: "you have renamed the feature extrusion,
not the body. i clicked rename on the body feature tree and the feature extrude
changed name. this means that you consider the extrusion = the body. this is very
far from truth as a body can contain several extrusions."
That is exactly what the previous commit did. It resolved a selected body to
CadBody::source_feature and renamed THAT feature, on the reasoning that a body has
no name of its own. The reasoning described an implementation detail — CadBody::
name is derived and restamped on every recompute — and mistook it for the user's
model. An Extrude, a Cut and a Fillet all land on the same body: the maker is one
operation in its history, and renaming it renames the wrong object.
A body now has a name of its own. CadBody::user_name, set only by a rename, is:
- carried across recompute() by body index, next to the per-body colour override
and under the same index contract the GUI already relies on for visibility and
Move — without which a name would survive exactly until the next feature;
- written into the recipe, because bodies are recomputed and never serialised, so
a name has nowhere else to live and would otherwise vanish on reopen;
- shown on the Bodies row ahead of the derived maker name, as "Body N — name",
with the number still leading because every status line, the interference
report and the mate errors identify a body that way.
The recipe block is APPENDED after the variables block rather than given a version
bump. A build that predates it reads features and variables, returns, and never
looks at the trailing bytes — so yesterday's projects open here and today's
projects still open there. A bump would have cost every project written today its
readability by the previous build, for one optional field.
Renaming a FEATURE is unchanged. The feature tree renames features; the Bodies
list renames bodies; neither reaches into the other.
WHAT THIS COST, and why it is written down. Getting here took two wrong turns
inside one fix, both mine:
1. UnselectAll() -> Unselect(). Both trees are wxTR_SINGLE, where UnselectAll()
— the MULTI-selection call — does nothing. That was the one-word reason the
rename had been vetoed everywhere (BEGIN_LABEL_EDIT refuses while
tree_body_selection() >= 0). Fixing it turned a pair of harmless no-ops into
a real loop: the two lists clear each other so "the target" is unambiguous,
so clicking a body row ran apply_body_row -> m_tree->Unselect() -> the feature
tree's SEL_CHANGED -> m_parts->Unselect(), which cleared the row just clicked.
The handler now clears the other list only when it actually holds a selection.
2. Trusting a screenshot taken after a polluted run. A leftover Rib card had
shifted the whole panel, so a click measured against it landed nowhere near
the row. Relaunch, then measure.
VERIFIED, on the rig and in the kernel:
body renamed ('Extrude', user_name=False) -> ('Bracket', user_name=True)
features untouched ['Sketch', 'Extrude'] before and after
survives a recompute add a Hole to the same body: features become
['Sketch', 'Extrude', 'Hole'], body stays 'Bracket'
survives the recipe serialize -> deserialize -> 'Bracket'
New kernel test "a body carries its own name, through recompute and the recipe"
pins all three properties; the suite is 189 cases / 2547 assertions.
Gate green: ALL LADDERS HELD — offer table matches the atlas, kernel suite,
engine rungs 1-8, 977-sheet corpus + the heaviest sheets, gesture ladder 98/98,
offer ladder 108/108.
This commit is contained in:
@@ -8097,3 +8097,51 @@ TEST_CASE("A sketch-only document recomputes and round-trips", "[CadDocument]")
|
||||
REQUIRE_FALSE(bad.recompute());
|
||||
REQUIRE_FALSE(bad.error.empty());
|
||||
}
|
||||
|
||||
// A body is NOT the feature that created it. Reported 2026-08-23, in these words: "you have
|
||||
// renamed the feature extrusion, not the body ... this means that you consider the extrusion =
|
||||
// the body, which is very far from truth as a body can contain several extrusions." The rename
|
||||
// used to resolve CadBody::source_feature and rename THAT, so naming a body edited one operation
|
||||
// in its history. A body now carries its own name, and this pins the three properties that make
|
||||
// it a name rather than a label: it does not touch the features, it survives a recompute that
|
||||
// adds more features to the same body, and it survives the recipe round trip.
|
||||
TEST_CASE("a body carries its own name, through recompute and the recipe", "[CadDocument]")
|
||||
{
|
||||
CadDocument doc;
|
||||
std::vector<SketchEntity> ents;
|
||||
auto line = [&](double x0, double y0, double x1, double y1) {
|
||||
SketchEntity e; e.type = SketchEntity::Type::Line;
|
||||
e.p0 = Vec2d(x0, y0); e.p1 = Vec2d(x1, y1); ents.push_back(e); };
|
||||
line(0, 0, 40, 0); line(40, 0, 40, 30); line(40, 30, 0, 30); line(0, 30, 0, 0);
|
||||
|
||||
const int sk = doc.add_sketch_entities(ents, SketchPlane::XY(), "Profile");
|
||||
doc.add_extrude(sk, 10.0, false, BooleanMode::New, "Extrude");
|
||||
REQUIRE(doc.recompute());
|
||||
REQUIRE(doc.bodies.size() == 1);
|
||||
|
||||
doc.bodies[0].has_user_name = true;
|
||||
doc.bodies[0].user_name = "Bracket";
|
||||
|
||||
// A SECOND feature lands on the same body — the case the report is about.
|
||||
doc.add_hole(6.0, 5.0, true, 20.0, 15.0, SketchPlane::XY(), "Hole");
|
||||
REQUIRE(doc.recompute());
|
||||
REQUIRE(doc.bodies.size() == 1);
|
||||
CHECK(doc.bodies[0].has_user_name);
|
||||
CHECK(doc.bodies[0].user_name == "Bracket");
|
||||
|
||||
// The features keep their own names: renaming the body renamed nothing else.
|
||||
REQUIRE(doc.features.size() == 3);
|
||||
CHECK(doc.features[0].name == "Profile");
|
||||
CHECK(doc.features[1].name == "Extrude");
|
||||
CHECK(doc.features[2].name == "Hole");
|
||||
|
||||
// ...and the name is part of what gets saved. Bodies are recomputed, never serialised, so
|
||||
// without the recipe block a body name would live exactly until the project was reopened.
|
||||
const std::string blob = doc.serialize_recipe();
|
||||
REQUIRE_FALSE(blob.empty());
|
||||
CadDocument fresh;
|
||||
REQUIRE(fresh.deserialize_recipe(blob));
|
||||
REQUIRE(fresh.bodies.size() == 1);
|
||||
CHECK(fresh.bodies[0].has_user_name);
|
||||
CHECK(fresh.bodies[0].user_name == "Bracket");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user