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") ||