From 8b9ad46fa42dcc41f7928020ddb849eb5da9c277 Mon Sep 17 00:00:00 2001 From: "Zheng, Lei" Date: Sun, 25 Aug 2024 20:04:51 +0800 Subject: [PATCH] Sketcher: support external reference without subname Reference without subname deliberately disables geometry topo name tracking to handling some special cases, such as configuration table with explicit geometry reference. Whole object selection is only enabled by holding `Alt` key. Related #1028 --- src/Mod/Sketcher/App/SketchObject.cpp | 44 ++++++++++--- .../Sketcher/Gui/DrawSketchHandlerExternal.h | 64 ++++++++++++++----- 2 files changed, 84 insertions(+), 24 deletions(-) diff --git a/src/Mod/Sketcher/App/SketchObject.cpp b/src/Mod/Sketcher/App/SketchObject.cpp index cc0477031a22..5212adca43c5 100644 --- a/src/Mod/Sketcher/App/SketchObject.cpp +++ b/src/Mod/Sketcher/App/SketchObject.cpp @@ -7616,15 +7616,24 @@ int SketchObject::addExternal(App::DocumentObject *Obj, const char* SubName, boo if (!isExternalAllowed(Obj->getDocument(), Obj)) return -1; - auto wholeShape = Part::Feature::getTopoShape(Obj); - auto shape = wholeShape.getSubTopoShape(SubName, /*silent*/true); + Part::TopoShape wholeShape = Part::Feature::getTopoShape(Obj); + Part::TopoShape shape; TopAbs_ShapeEnum shapeType = TopAbs_SHAPE; - if (shape.shapeType(/*silent*/true) != TopAbs_FACE) { - if (shape.hasSubShape(TopAbs_FACE)) - shapeType = TopAbs_FACE; - else if (shape.shapeType(/*silent*/true) != TopAbs_EDGE - && shape.hasSubShape(TopAbs_EDGE)) - shapeType = TopAbs_EDGE; + if (!SubName && !SubName[0]) { + shape = wholeShape.getSubTopoShape(SubName, /*silent*/true); + if (shape.shapeType(/*silent*/true) != TopAbs_FACE + && shape.shapeType(/*silent*/true) != TopAbs_WIRE) { + if (shape.hasSubShape(TopAbs_FACE)) { + shapeType = TopAbs_FACE; + } + else if (shape.hasSubShape(TopAbs_WIRE)) { + shapeType = TopAbs_WIRE; + } + else if (shape.shapeType(/*silent*/true) != TopAbs_EDGE + && shape.hasSubShape(TopAbs_EDGE)) { + shapeType = TopAbs_EDGE; + } + } } if (shapeType != TopAbs_SHAPE) { @@ -8543,6 +8552,21 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) FC_WARN("Null shape from geometry reference in " << getFullName() << ": " << key); continue; } + if (refSubShape.ShapeType() != TopAbs_FACE + && refSubShape.ShapeType() != TopAbs_EDGE + && refSubShape.ShapeType() != TopAbs_VERTEX + && refSubShape.ShapeType() != TopAbs_WIRE) + { + const std::array types = { + TopAbs_FACE, TopAbs_WIRE, TopAbs_EDGE, TopAbs_VERTEX}; + Part::TopoShape shape(refSubShape); + for (auto type : types) { + if (shape.hasSubShape(type)) { + refSubShape = shape.getSubShape(type, 1); + break; + } + } + } auto importFace = [&](const TopoDS_Shape &refSubShape) { gp_Pln plane; @@ -9116,6 +9140,10 @@ void SketchObject::rebuildExternalGeometry(bool defining, bool addIntersection) if (!intersection) importFace(refSubShape); break; + case TopAbs_WIRE: + for (const auto &s : Part::TopoShape(refSubShape).getSubShapes(TopAbs_EDGE)) + importEdge(s); + break; case TopAbs_EDGE: importEdge(refSubShape); break; diff --git a/src/Mod/Sketcher/Gui/DrawSketchHandlerExternal.h b/src/Mod/Sketcher/Gui/DrawSketchHandlerExternal.h index 01e47bce0da4..796df83ed832 100644 --- a/src/Mod/Sketcher/Gui/DrawSketchHandlerExternal.h +++ b/src/Mod/Sketcher/Gui/DrawSketchHandlerExternal.h @@ -23,20 +23,7 @@ #ifndef SKETCHERGUI_DrawSketchHandlerExternal_H #define SKETCHERGUI_DrawSketchHandlerExternal_H -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "DrawSketchHandler.h" +#include #include "GeometryCreationMode.h" #include "Utils.h" #include "ViewProviderSketch.h" @@ -59,13 +46,52 @@ class ExternalSelection : public SketcherSelectionFilterGate bool allow(App::Document* pDoc, App::DocumentObject* pObj, const char* sSubName) override { Sketcher::SketchObject* sketch = static_cast(object); + static const std::array allowedTypes = {"Face", "Wire", "Edge", "Vertex"}; this->notAllowedReason = ""; - if (!sSubName || sSubName[0] == '\0') { - this->notAllowedReason = QT_TR_NOOP("No element. "); + bool checkShape = true; + if (sSubName && sSubName[0]) { + for (auto type : allowedTypes) { + if (boost::starts_with(sSubName, type)) { + checkShape = false; + break; + } + } + } + else if (!(QApplication::queryKeyboardModifiers() & Qt::AltModifier)) { + this->notAllowedReason = QT_TR_NOOP("Hold Alt key to enable whole object selection."); return false; } + + if (checkShape) { + auto shape = Part::TopoShape(Part::Feature::getShape(pObj)); + if (shape.isNull()) { + this->notAllowedReason = QT_TR_NOOP("No shape. "); + return false; + } + sSubName = nullptr; + for (auto type : allowedTypes) { + auto shapeType = Part::TopoShape::shapeType(type); + if (shape.shapeType() == shapeType) { + sSubName = type; + break; + } + int count = shape.countSubShapes(shapeType); + if (count == 1) { + sSubName = type; + break; + } + if (count > 1) { + this->notAllowedReason = QT_TR_NOOP("Multiple elements. "); + return false; + } + } + if (!sSubName) { + this->notAllowedReason = QT_TR_NOOP("Unknown element. "); + return false; + } + } if (!ViewProviderSketch::allowFaceExternalPick() && boost::starts_with(sSubName, "Face")) { this->notAllowedReason = QT_TR_NOOP("Face picking disabled in the task panel. "); @@ -272,10 +298,16 @@ class DrawSketchHandlerExternal: public DrawSketchHandler throw Base::ValueError("Sketcher: External geometry: Invalid object in selection"); } + if (msg.Object.getOldElementName().empty() + && !(QApplication::queryKeyboardModifiers() & Qt::AltModifier)) { + return false; + } + auto indexedName = Data::IndexedName(msg.Object.getOldElementName().c_str()); if (intersection || obj->getTypeId().isDerivedFrom(App::Plane::getClassTypeId()) || obj->getTypeId().isDerivedFrom(Part::Datum::getClassTypeId()) || + msg.Object.getOldElementName().empty() || boost::iends_with(indexedName.getType(), "edge") || boost::iends_with(indexedName.getType(), "vertex") || boost::iends_with(indexedName.getType(), "face") ||