From a495280693392f847d88ed49bb01ebe6e15d3f40 Mon Sep 17 00:00:00 2001 From: bgbsww Date: Fri, 31 May 2024 20:45:15 -0400 Subject: [PATCH] Toponaming: fix bug with points in sketches --- src/Mod/PartDesign/Gui/Command.cpp | 114 +++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 5 deletions(-) diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index 77ec3e6381..017dd46d41 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -664,6 +664,103 @@ unsigned validateSketches(std::vector& sketches, return freeSketches; } +/** + * Partially pulled from Linkstage3 importExternalObjects for toponaming element map + * compatibility with sketches that contain point objects. By adding an empty + * subobject when appropriate, we allow those sketches to be used as profiles without error. + * + * @param prop The property ( generally a Profile link ) + * @param _sobjs Subobjects to use + * @param report True if we should raise a dialog, otherwise raise and exception + * @return True if elements were found + */ +bool importExternalElements(App::PropertyLinkSub& prop, std::vector _sobjs) +{ + if (!prop.getName() || !prop.getName()[0]) { + FC_THROWM(Base::RuntimeError, "Invalid property"); + } + auto editObj = Base::freecad_dynamic_cast(prop.getContainer()); + if (!editObj) { + FC_THROWM(Base::RuntimeError, "Editing object not found"); + } + auto body = PartDesign::Body::findBodyOf(editObj); + if (!body) { + FC_THROWM(Base::RuntimeError, + "No body for editing object: " << editObj->getNameInDocument()); + } + std::map> links; + std::vector sobjs; + auto docName = editObj->getDocument()->getName(); + auto inList = editObj->getInListEx(true); + for (auto sobjT : _sobjs) { + auto sobj = sobjT.getSubObject(); + if (sobj == editObj) { + continue; + } + if (!sobj) { + FC_THROWM(Base::RuntimeError, + "Object not found: " << sobjT.getSubObjectFullName(docName)); + } + if (inList.count(sobj)) { + FC_THROWM(Base::RuntimeError, + "Cyclic dependency on object " << sobjT.getSubObjectFullName(docName)); + } + sobjT.normalized(); + // Make sure that if a subelement is chosen for some object, + // we exclude whole object reference for that object. + auto& subs = links[sobj]; + std::string element = sobjT.getOldElementName(); + if (element.size()) { + if (subs.size() == 1 && subs.front().empty()) { + for (auto it = sobjs.begin(); it != sobjs.end();) { + if (it->getSubObject() == sobj) { + sobjs.erase(it); + break; + } + } + } + } + else if (subs.size() > 0) { + continue; + } + subs.push_back(std::move(element)); + sobjs.push_back(sobjT); + } + + int import = 0; + App::DocumentObject* obj = nullptr; + std::vector subs; + for (const auto& sobjT : sobjs) { + auto sobj = sobjT.getSubObject(); + if (PartDesign::Body::findBodyOf(sobj) != body) { + import = 1; + break; + } + if (!obj) { + obj = sobj; + } + else if (obj != sobj) { + if (!import) { + import = -1; + } + break; + } + subs.push_back(sobjT.getOldElementName()); + } + if (!import) { + if (subs.empty()) { + subs.emplace_back(); + } + if (obj == prop.getValue() && prop.getSubValues() == subs) { + return false; + } + prop.setValue(obj, std::move(subs)); + return true; + } + return false; +} + + void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, const std::string& which, std::function func) { @@ -687,6 +784,15 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons auto objCmd = Gui::Command::getObjectCmd(feature); + // Populate the subs parameter by checking for external elements before + // we construct our command. + auto ProfileFeature = Base::freecad_dynamic_cast(Feat); + + std::vector& cmdSubs = const_cast&>(subs); + if (subs.size() == 0) { + importExternalElements(ProfileFeature->Profile, {feature}); + cmdSubs = ProfileFeature->Profile.getSubValues(); + } // run the command in console to set the profile (without selected subelements) auto runProfileCmd = [=]() { @@ -698,7 +804,7 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons auto runProfileCmdWithSubs = [=]() { std::ostringstream ss; - for (auto &s : subs) + for (auto &s : cmdSubs) ss << "'" << s << "',"; FCMD_OBJ_CMD(Feat,"Profile = (" << objCmd << ", [" << ss.str() << "])"); }; @@ -772,10 +878,8 @@ void prepareProfileBased(PartDesign::Body *pcActiveBody, Gui::Command* cmd, cons } } else { - if (feature->isDerivedFrom(Part::Part2DObject::getClassTypeId()) || subs.empty()) - runProfileCmd(); - else - runProfileCmdWithSubs(); + // Always use the subs + runProfileCmdWithSubs(); } func(static_cast(feature), Feat);