From febe5c3d9ef98ec896fa8def6612f26098ed7ec8 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Tue, 21 May 2024 21:41:26 -0400 Subject: [PATCH 1/3] Toponaming: fix shapebinder selection error --- src/Mod/PartDesign/App/ShapeBinder.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Mod/PartDesign/App/ShapeBinder.cpp b/src/Mod/PartDesign/App/ShapeBinder.cpp index 7b4544439d..e2cdffd3de 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.cpp +++ b/src/Mod/PartDesign/App/ShapeBinder.cpp @@ -638,7 +638,8 @@ void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { subs.erase(none); for (const auto& sub : subs) { try { - auto shape = Part::Feature::getTopoShape(obj, sub.c_str(), true); + auto name = Data::oldElementName(sub.c_str()).c_str(); + auto shape = Part::Feature::getTopoShape(obj, name, true); if (!shape.isNull()) { shapes.push_back(shape); shapeMats.push_back(&res.first->second); From 12619b2c2d2ba1ab973601282718b3b5bc38e9d0 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Tue, 21 May 2024 21:42:05 -0400 Subject: [PATCH 2/3] TopoNaming: restore defenses against multisolids when enabled --- src/Mod/PartDesign/App/FeatureChamfer.cpp | 3 +++ src/Mod/PartDesign/App/FeatureExtrude.cpp | 13 +++++++++++-- src/Mod/PartDesign/App/FeatureFillet.cpp | 3 +++ src/Mod/PartDesign/App/FeatureGroove.cpp | 6 +++++- src/Mod/PartDesign/App/FeatureLoft.cpp | 6 +++++- 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/Mod/PartDesign/App/FeatureChamfer.cpp b/src/Mod/PartDesign/App/FeatureChamfer.cpp index c2833871b5..29771edfc0 100644 --- a/src/Mod/PartDesign/App/FeatureChamfer.cpp +++ b/src/Mod/PartDesign/App/FeatureChamfer.cpp @@ -198,6 +198,9 @@ App::DocumentObjectExecReturn *Chamfer::execute() shape = refineShapeIfActive(shape); shape = getSolid(shape); } + if (!isSingleSolidRuleSatisfied(shape.getShape())) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); + } this->Shape.setValue(shape); if (failed) { return new App::DocumentObjectExecReturn( diff --git a/src/Mod/PartDesign/App/FeatureExtrude.cpp b/src/Mod/PartDesign/App/FeatureExtrude.cpp index 02f73792a1..e93cce5107 100644 --- a/src/Mod/PartDesign/App/FeatureExtrude.cpp +++ b/src/Mod/PartDesign/App/FeatureExtrude.cpp @@ -717,8 +717,10 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt return new App::DocumentObjectExecReturn( QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid")); } - solRes = refineShapeIfActive(solRes); + if (!isSingleSolidRuleSatisfied(solRes.getShape())) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); + } this->Shape.setValue(getSolid(solRes)); } else if (prism.hasSubShape(TopAbs_SOLID)) { @@ -726,10 +728,17 @@ App::DocumentObjectExecReturn* FeatureExtrude::buildExtrusion(ExtrudeOptions opt prism.makeElementFuse(prism.getSubTopoShapes(TopAbs_SOLID)); } prism = refineShapeIfActive(prism); - this->Shape.setValue(getSolid(prism)); + prism = getSolid(prism); + if (!isSingleSolidRuleSatisfied(prism.getShape())) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); + } + this->Shape.setValue(prism); } else { prism = refineShapeIfActive(prism); + if (!isSingleSolidRuleSatisfied(prism.getShape())) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); + } this->Shape.setValue(prism); } diff --git a/src/Mod/PartDesign/App/FeatureFillet.cpp b/src/Mod/PartDesign/App/FeatureFillet.cpp index bf4d1e7453..032a523e2d 100644 --- a/src/Mod/PartDesign/App/FeatureFillet.cpp +++ b/src/Mod/PartDesign/App/FeatureFillet.cpp @@ -114,6 +114,9 @@ App::DocumentObjectExecReturn *Fillet::execute() shape = refineShapeIfActive(shape); shape = getSolid(shape); } + if (!isSingleSolidRuleSatisfied(shape.getShape())) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); + } this->Shape.setValue(shape); if (failed) { diff --git a/src/Mod/PartDesign/App/FeatureGroove.cpp b/src/Mod/PartDesign/App/FeatureGroove.cpp index f77e6a84b7..8245452a2f 100644 --- a/src/Mod/PartDesign/App/FeatureGroove.cpp +++ b/src/Mod/PartDesign/App/FeatureGroove.cpp @@ -352,7 +352,11 @@ App::DocumentObjectExecReturn *Groove::execute() return new App::DocumentObjectExecReturn("Resulting shape is not a solid"); boolOp = refineShapeIfActive(boolOp); - Shape.setValue(getSolid(boolOp)); + boolOp = getSolid(boolOp); + if (!isSingleSolidRuleSatisfied(boolOp.getShape())) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); + } + Shape.setValue(boolOp); return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { diff --git a/src/Mod/PartDesign/App/FeatureLoft.cpp b/src/Mod/PartDesign/App/FeatureLoft.cpp index 121d294db7..2a3612d3ba 100644 --- a/src/Mod/PartDesign/App/FeatureLoft.cpp +++ b/src/Mod/PartDesign/App/FeatureLoft.cpp @@ -532,7 +532,11 @@ App::DocumentObjectExecReturn *Loft::execute(void) return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Resulting shape is not a solid")); boolOp = refineShapeIfActive(boolOp); - Shape.setValue(getSolid(boolOp)); + boolOp = getSolid(boolOp); + if (!isSingleSolidRuleSatisfied(boolOp.getShape())) { + return new App::DocumentObjectExecReturn(QT_TRANSLATE_NOOP("Exception", "Result has multiple solids: that is not currently supported.")); + } + Shape.setValue(boolOp); return App::DocumentObject::StdReturn; } catch (Standard_Failure& e) { From b7bbc2ed11a70c03b61c356480141890d4f0ec97 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Thu, 23 May 2024 09:47:25 -0400 Subject: [PATCH 3/3] Toponaming: Missing code for shapebinder --- src/App/PropertyLinks.h | 2 +- src/Mod/PartDesign/App/ShapeBinder.cpp | 96 +++++++++++++++++++++++++- src/Mod/PartDesign/App/ShapeBinder.h | 2 + 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/src/App/PropertyLinks.h b/src/App/PropertyLinks.h index c08262fc4a..acda02b28f 100644 --- a/src/App/PropertyLinks.h +++ b/src/App/PropertyLinks.h @@ -1206,10 +1206,10 @@ class AppExport PropertyXLinkSubList: public PropertyLinkBase { TYPESYSTEM_HEADER_WITH_OVERRIDE(); +public: using atomic_change = typename AtomicPropertyChangeInterface::AtomicPropertyChange; friend atomic_change; -public: PropertyXLinkSubList(); ~PropertyXLinkSubList() override; diff --git a/src/Mod/PartDesign/App/ShapeBinder.cpp b/src/Mod/PartDesign/App/ShapeBinder.cpp index e2cdffd3de..b5ce97ac48 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.cpp +++ b/src/Mod/PartDesign/App/ShapeBinder.cpp @@ -43,6 +43,8 @@ #include #include "ShapeBinder.h" +#include "Mod/Part/App/TopoShapeOpCode.h" +#include "Base/Tools.h" FC_LOG_LEVEL_INIT("PartDesign",true,true) @@ -486,6 +488,7 @@ void SubShapeBinder::clearCopiedObjects() { void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { Part::TopoShape result; std::vector shapes; + std::vector > shapeOwners; std::vector shapeMats; bool forced = (Shape.getValue().IsNull() || (options & UpdateForced)) ? true : false; @@ -519,7 +522,9 @@ void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { bool first = false; std::unordered_map mats; + int idx = -1; for (auto& l : Support.getSubListValues()) { + ++idx; auto obj = l.getValue(); if (!obj || !obj->isAttachedToDocument()) continue; @@ -631,17 +636,20 @@ void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { const auto& subvals = copied ? _CopiedLink.getSubValues() : l.getSubValues(); std::set subs(subvals.begin(), subvals.end()); + int sidx = copied?-1:idx; + int subidx = -1; static std::string none; if (subs.empty()) subs.insert(none); else if (subs.size() > 1) subs.erase(none); for (const auto& sub : subs) { + ++subidx; try { - auto name = Data::oldElementName(sub.c_str()).c_str(); - auto shape = Part::Feature::getTopoShape(obj, name, true); + auto shape = Part::Feature::getTopoShape(obj, sub.c_str(), true); if (!shape.isNull()) { shapes.push_back(shape); + shapeOwners.emplace_back(sidx, subidx); shapeMats.push_back(&res.first->second); } } @@ -696,7 +704,28 @@ void SubShapeBinder::update(SubShapeBinder::UpdateOption options) { if (hit) return; } +#ifdef FC_USE_TNP_FIX + std::ostringstream ss; + int idx = -1; + for(auto &shape : shapes) { + ++idx; + if(shape.Hasher + && shape.getElementMapSize() + && shape.Hasher != getDocument()->getStringHasher()) + { + ss.str(""); + ss << Data::POSTFIX_EXTERNAL_TAG + << Data::ComplexGeoData::elementMapPrefix() + << Part::OpCodes::Shapebinder << ':' << shapeOwners[idx].first + << ':' << shapeOwners[idx].second; + shape.reTagElementMap(-getID(), + getDocument()->getStringHasher(),ss.str().c_str()); + } + if (!shape.hasSubShape(TopAbs_FACE) && shape.hasSubShape(TopAbs_EDGE)) + shape = shape.makeElementCopy(); + } +#endif if (shapes.size() == 1 && !Relative.getValue()) shapes.back().setPlacement(Base::Placement()); else { @@ -868,6 +897,68 @@ void SubShapeBinder::onDocumentRestored() { inherited::onDocumentRestored(); } +void SubShapeBinder::collapseGeoChildren() +{ + // Geo children, i.e. children of GeoFeatureGroup may group some tool + // features under itself but does not function as a container. In addition, + // its parent group can directly reference the tool feature grouped without + // referencing the child. The purpose of this function is to remove any + // intermediate Non group features in the object path to avoid unnecessary + // dependencies. + if (Support.testStatus(App::Property::User3)) + return; + + Base::ObjectStatusLocker + guard(App::Property::User3, &Support); + App::PropertyXLinkSubList::atomic_change guard2(Support, false); + + std::vector removes; + std::map > newVals; + std::ostringstream ss; + for(auto &l : Support.getSubListValues()) { + auto obj = l.getValue(); + if(!obj || !obj->getNameInDocument()) + continue; + auto subvals = l.getSubValues(); + if (subvals.empty()) + continue; + bool touched = false; + for (auto itSub=subvals.begin(); itSub!=subvals.end();) { + auto &sub = *itSub; + App::SubObjectT sobjT(obj, sub.c_str()); + if (sobjT.normalize(App::SubObjectT::NormalizeOption::KeepSubName)) { + touched = true; + auto newobj = sobjT.getObject(); + sub = sobjT.getSubName(); + if (newobj != obj) { + newVals[newobj].push_back(std::move(sub)); + itSub = subvals.erase(itSub); + continue; + } + } + ++itSub; + } + if (touched) + removes.push_back(obj); + if (!subvals.empty() && touched) { + auto &newSubs = newVals[obj]; + if (newSubs.empty()) + newSubs = std::move(subvals); + else + newSubs.insert(newSubs.end(), + std::make_move_iterator(subvals.begin()), + std::make_move_iterator(subvals.end())); + } + } + + if (removes.size() || newVals.size()) + guard2.aboutToChange(); + for (auto obj : removes) + Support.removeValue(obj); + if (newVals.size()) + setLinks(std::move(newVals)); +} + void SubShapeBinder::onChanged(const App::Property* prop) { if (prop == &Context || prop == &Relative) { if (!Context.getValue() || !Relative.getValue()) { @@ -885,6 +976,7 @@ void SubShapeBinder::onChanged(const App::Property* prop) { } else if (!isRestoring()) { if (prop == &Support) { + collapseGeoChildren(); clearCopiedObjects(); setupCopyOnChange(); if (!Support.getSubListValues().empty()) { diff --git a/src/Mod/PartDesign/App/ShapeBinder.h b/src/Mod/PartDesign/App/ShapeBinder.h index f0ca398047..a32841b3bd 100644 --- a/src/Mod/PartDesign/App/ShapeBinder.h +++ b/src/Mod/PartDesign/App/ShapeBinder.h @@ -138,6 +138,8 @@ protected: void checkPropertyStatus(); + void collapseGeoChildren(); + void slotRecomputedObject(const App::DocumentObject& Obj); using Connection = boost::signals2::scoped_connection;