fix(assembly): use instance suffixes for duplicate part labels
All checks were successful
Build and Test / build (pull_request) Successful in 29m11s
All checks were successful
Build and Test / build (pull_request) Successful in 29m11s
When parts with structured part numbers (e.g., P03-0001) are inserted into an assembly multiple times, UniqueNameManager::decomposeName() treats the trailing digits as an auto-generated suffix and increments them (P03-0002, P03-0003), corrupting the part number. Add a makeInstanceLabel() helper in AssemblyLink.cpp that appends -N instance suffixes instead (P03-0001-1, P03-0001-2). All instances get a suffix starting at -1 so the original part number is never modified. Applied at all three Label.setValue() sites in synchronizeComponents() (AssemblyLink, link group, and regular link creation paths). Also add a UniqueNameManager test documenting the trailing-digit decomposition behavior for structured part numbers. Closes #327
This commit is contained in:
@@ -311,6 +311,19 @@ void AssemblyLink::updateContents()
|
|||||||
purgeTouched();
|
purgeTouched();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate an instance label for assembly components by appending a -N suffix.
|
||||||
|
// All instances get a suffix (starting at -1) so that structured part numbers
|
||||||
|
// like "P03-0001" are never mangled by UniqueNameManager's trailing-digit logic.
|
||||||
|
static std::string makeInstanceLabel(App::Document* doc, const std::string& baseLabel)
|
||||||
|
{
|
||||||
|
for (int i = 1;; ++i) {
|
||||||
|
std::string candidate = baseLabel + "-" + std::to_string(i);
|
||||||
|
if (!doc->containsLabel(candidate)) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AssemblyLink::synchronizeComponents()
|
void AssemblyLink::synchronizeComponents()
|
||||||
{
|
{
|
||||||
App::Document* doc = getDocument();
|
App::Document* doc = getDocument();
|
||||||
@@ -428,7 +441,7 @@ void AssemblyLink::synchronizeComponents()
|
|||||||
auto* subAsmLink = static_cast<AssemblyLink*>(newObj);
|
auto* subAsmLink = static_cast<AssemblyLink*>(newObj);
|
||||||
subAsmLink->LinkedObject.setValue(obj);
|
subAsmLink->LinkedObject.setValue(obj);
|
||||||
subAsmLink->Rigid.setValue(asmLink->Rigid.getValue());
|
subAsmLink->Rigid.setValue(asmLink->Rigid.getValue());
|
||||||
subAsmLink->Label.setValue(obj->Label.getValue());
|
subAsmLink->Label.setValue(makeInstanceLabel(doc, obj->Label.getValue()));
|
||||||
addObject(subAsmLink);
|
addObject(subAsmLink);
|
||||||
link = subAsmLink;
|
link = subAsmLink;
|
||||||
}
|
}
|
||||||
@@ -440,7 +453,7 @@ void AssemblyLink::synchronizeComponents()
|
|||||||
);
|
);
|
||||||
newLink->LinkedObject.setValue(srcLink->getTrueLinkedObject(false));
|
newLink->LinkedObject.setValue(srcLink->getTrueLinkedObject(false));
|
||||||
|
|
||||||
newLink->Label.setValue(obj->Label.getValue());
|
newLink->Label.setValue(makeInstanceLabel(doc, obj->Label.getValue()));
|
||||||
addObject(newLink);
|
addObject(newLink);
|
||||||
|
|
||||||
newLink->ElementCount.setValue(srcLink->ElementCount.getValue());
|
newLink->ElementCount.setValue(srcLink->ElementCount.getValue());
|
||||||
@@ -461,7 +474,7 @@ void AssemblyLink::synchronizeComponents()
|
|||||||
App::DocumentObject* newObj = doc->addObject("App::Link", obj->getNameInDocument());
|
App::DocumentObject* newObj = doc->addObject("App::Link", obj->getNameInDocument());
|
||||||
auto* newLink = static_cast<App::Link*>(newObj);
|
auto* newLink = static_cast<App::Link*>(newObj);
|
||||||
newLink->LinkedObject.setValue(obj);
|
newLink->LinkedObject.setValue(obj);
|
||||||
newLink->Label.setValue(obj->Label.getValue());
|
newLink->Label.setValue(makeInstanceLabel(doc, obj->Label.getValue()));
|
||||||
addObject(newLink);
|
addObject(newLink);
|
||||||
link = newLink;
|
link = newLink;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,4 +122,15 @@ TEST(UniqueNameManager, UniqueNameWith9NDigits)
|
|||||||
manager.addExactName("Compound123456789");
|
manager.addExactName("Compound123456789");
|
||||||
EXPECT_EQ(manager.makeUniqueName("Compound", 3), "Compound123456790");
|
EXPECT_EQ(manager.makeUniqueName("Compound", 3), "Compound123456790");
|
||||||
}
|
}
|
||||||
|
TEST(UniqueNameManager, StructuredPartNumberDecomposition)
|
||||||
|
{
|
||||||
|
// Structured part numbers like P03-0001 have their trailing digits
|
||||||
|
// treated as the uniquifying suffix by UniqueNameManager. This is
|
||||||
|
// correct for default FreeCAD objects (Body -> Body001) but wrong
|
||||||
|
// for structured identifiers. Assembly module handles this separately
|
||||||
|
// via makeInstanceLabel which appends -N instance suffixes instead.
|
||||||
|
Base::UniqueNameManager manager;
|
||||||
|
manager.addExactName("P03-0001");
|
||||||
|
EXPECT_EQ(manager.makeUniqueName("P03-0001", 3), "P03-0002");
|
||||||
|
}
|
||||||
// NOLINTEND(cppcoreguidelines-*,readability-*)
|
// NOLINTEND(cppcoreguidelines-*,readability-*)
|
||||||
|
|||||||
Reference in New Issue
Block a user