From 731ed820b5ec24a52a3a8d7a2fe802663f554980 Mon Sep 17 00:00:00 2001 From: mwganson Date: Mon, 28 Feb 2022 00:46:10 -0600 Subject: [PATCH] Part:Improve support for Links --- src/Mod/Part/App/FeatureOffset.cpp | 11 +- src/Mod/Part/App/PartFeatures.cpp | 8 +- src/Mod/Part/BasicShapes/ShapeContent.py | 36 +-- src/Mod/Part/Gui/Command.cpp | 304 ++++++++++++++--------- src/Mod/Part/Gui/CrossSections.cpp | 11 +- src/Mod/Part/Gui/DlgExtrusion.cpp | 63 +++-- src/Mod/Part/Gui/DlgRevolution.cpp | 32 ++- src/Mod/Part/Gui/Mirroring.cpp | 15 +- src/Mod/Part/Gui/TaskLoft.cpp | 12 +- src/Mod/Part/Gui/TaskSweep.cpp | 128 ++++++---- 10 files changed, 379 insertions(+), 241 deletions(-) diff --git a/src/Mod/Part/App/FeatureOffset.cpp b/src/Mod/Part/App/FeatureOffset.cpp index dedc2aa486..785b1effbc 100644 --- a/src/Mod/Part/App/FeatureOffset.cpp +++ b/src/Mod/Part/App/FeatureOffset.cpp @@ -26,6 +26,7 @@ #include "FeatureOffset.h" +#include using namespace Part; @@ -131,8 +132,14 @@ short Offset2D::mustExecute() const App::DocumentObjectExecReturn *Offset2D::execute(void) { App::DocumentObject* source = Source.getValue(); - if (!(source && source->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) + + if (!source) { + return new App::DocumentObjectExecReturn("No source shape linked."); + } + const TopoShape shape = Part::Feature::getTopoShape(source); + if (shape.isNull()) { return new App::DocumentObjectExecReturn("No source shape linked."); + } double offset = Value.getValue(); short mode = (short)Mode.getValue(); short join = (short)Join.getValue(); @@ -140,7 +147,7 @@ App::DocumentObjectExecReturn *Offset2D::execute(void) bool inter = Intersection.getValue(); if (mode == 2) return new App::DocumentObjectExecReturn("Mode 'Recto-Verso' is not supported for 2D offset."); - const TopoShape& shape = static_cast(source)->Shape.getShape(); + this->Shape.setValue(shape.makeOffset2D(offset, join, fill, mode == 0, inter)); return App::DocumentObject::StdReturn; } diff --git a/src/Mod/Part/App/PartFeatures.cpp b/src/Mod/Part/App/PartFeatures.cpp index 9e597d9d42..e0c4767aa6 100644 --- a/src/Mod/Part/App/PartFeatures.cpp +++ b/src/Mod/Part/App/PartFeatures.cpp @@ -46,6 +46,7 @@ #include "PartFeatures.h" +#include using namespace Part; @@ -82,20 +83,21 @@ App::DocumentObjectExecReturn* RuledSurface::getShape(const App::PropertyLinkSub TopoDS_Shape& shape) const { App::DocumentObject* obj = link.getValue(); - if (!(obj && obj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) + const Part::TopoShape part = Part::Feature::getShape(obj, "", false, 0, 0, true, false); + if (part.isNull()) { return new App::DocumentObjectExecReturn("No shape linked."); + } // if no explicit sub-shape is selected use the whole part const std::vector& element = link.getSubValues(); if (element.empty()) { - shape = static_cast(obj)->Shape.getValue(); + shape = part.getShape(); return nullptr; } else if (element.size() != 1) { return new App::DocumentObjectExecReturn("Not exactly one sub-shape linked."); } - const Part::TopoShape& part = static_cast(obj)->Shape.getValue(); if (!part.getShape().IsNull()) { if (!element[0].empty()) { shape = part.getSubShape(element[0].c_str()); diff --git a/src/Mod/Part/BasicShapes/ShapeContent.py b/src/Mod/Part/BasicShapes/ShapeContent.py index b9cac5b5ad..59efb35294 100644 --- a/src/Mod/Part/BasicShapes/ShapeContent.py +++ b/src/Mod/Part/BasicShapes/ShapeContent.py @@ -12,11 +12,17 @@ import FreeCAD as App def roundVector(v,dec): return str([round(v[0],dec), round(v[1],dec), round(v[2],dec)]) -def buildShapeContent(obj, decimals=2, advancedShapeContent=True): +def buildShapeContent(objArg, decimals=2, advancedShapeContent=True): + linkName = "" + if objArg.isDerivedFrom("App::Link"): + obj = objArg.getLinkedObject() + linkName = "<" + objArg.Name + "> " + else: + obj = objArg shp = obj.Shape typeStr = str(shp.ShapeType) lbl = '' if obj.Name == obj.Label else '(' + obj.Label + ')' - result = obj.Name + lbl + '\n' + result = linkName + obj.Name + lbl + '\n' result += 'Shape type: '+typeStr+'\n' result += 'Vertices: '+str(len(shp.Vertexes))+'\n' result += 'Edges: '+str(len(shp.Edges))+'\n' @@ -64,17 +70,17 @@ def buildShapeContent(obj, decimals=2, advancedShapeContent=True): result += str(p)+': '+roundVector(props[p],decimals) +'\n' else: result += str(p)+': '+str(props[p])+'\n' - - if obj.getGlobalPlacement() != obj.Placement: - rpl = obj.getGlobalPlacement() * obj.Placement.inverse() - rot = rpl.Rotation - if hasattr(shp, 'CenterOfMass'): - result += 'Global CenterOfMass: '+roundVector(rpl.multVec(shp.CenterOfMass),decimals)+'\n' - if hasattr(shp, 'PrincipalProperties'): - props = shp.PrincipalProperties - for p in props: - if 'AxisOfInertia' in p: - result += 'Global ' + str(p)+': '+roundVector(rot.multVec(props[p]),decimals) +'\n' - else: - result += 'Global Placement = Placement' + if hasattr(obj,"getGlobalPlacement"): + if obj.getGlobalPlacement() != obj.Placement: + rpl = obj.getGlobalPlacement() * obj.Placement.inverse() + rot = rpl.Rotation + if hasattr(shp, 'CenterOfMass'): + result += 'Global CenterOfMass: '+roundVector(rpl.multVec(shp.CenterOfMass),decimals)+'\n' + if hasattr(shp, 'PrincipalProperties'): + props = shp.PrincipalProperties + for p in props: + if 'AxisOfInertia' in p: + result += 'Global ' + str(p)+': '+roundVector(rot.multVec(props[p]),decimals) +'\n' + else: + result += 'Global Placement = Placement' return result diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index e5916ebace..28ddf79631 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,38 @@ bool checkForSolids(const TopoDS_Shape& shape) return true; } +/* + * returns vector of Part::TopoShapes from selected Part::Feature derived objects, + * App::Links linked to Part::Features, or App::Part containers with visible Part::Features + */ +std::vector getShapesFromSelection() +{ + std::vector objs = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + std::vector shapes; + for (std::vector::iterator it = objs.begin(); it != objs.end(); ++it) { + Part::TopoShape shp = Part::Feature::getTopoShape(*it); + if (!shp.isNull()){ + shapes.push_back(shp); + } + } + return shapes; +} +/* + * returns true if selected objects contain valid Part::TopoShapes. + * Objects can be Part::Features, App::Links, or App::Parts + */ +bool hasShapesInSelection() +{ + bool hasShapes = false; + std::vector docobjs = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + for (std::vector::iterator it = docobjs.begin(); it != docobjs.end(); ++it) { + if (!Part::Feature::getTopoShape(*it).isNull()) { + hasShapes = true; + break; + } + } + return hasShapes; +} } //=========================================================================== @@ -1005,7 +1038,7 @@ void CmdPartImport::activated(int iMsg) Gui::WaitCursor wc; App::Document* pDoc = getDocument(); if (!pDoc) // no document - return; + return; fn = Base::Tools::escapeEncodeFilename(fn); openCommand(QT_TRANSLATE_NOOP("Command", "Import Part")); @@ -1067,7 +1100,7 @@ void CmdPartExport::activated(int iMsg) if (!fn.isEmpty()) { App::Document* pDoc = getDocument(); if (!pDoc) // no document - return; + return; if (select == filter[1] || select == filter[3]) { Gui::Application::Instance->exportTo((const char*)fn.toUtf8(),pDoc->getName(),"ImportGui"); @@ -1270,7 +1303,7 @@ void CmdPartReverseShape::activated(int iMsg) bool CmdPartReverseShape::isActive(void) { return Gui::Selection().countObjectsOfType - (Part::Feature::getClassTypeId()) > 0; + (Part::Feature::getClassTypeId(), 0, 3) > 0; } //=========================================================================== @@ -1518,11 +1551,10 @@ void CmdPartCrossSections::activated(int iMsg) Q_UNUSED(iMsg); Gui::TaskView::TaskDialog* dlg = Gui::Control().activeDialog(); if (!dlg) { - std::vector obj = Gui::Selection().getObjectsOfType - (Part::Feature::getClassTypeId()); + std::vector shapes = PartGui::getShapesFromSelection(); Base::BoundBox3d bbox; - for (std::vector::iterator it = obj.begin(); it != obj.end(); ++it) { - bbox.Add(static_cast(*it)->Shape.getBoundingBox()); + for (std::vector::iterator it = shapes.begin(); it != shapes.end(); ++it) { + bbox.Add((*it).getBoundBox()); } dlg = new PartGui::TaskCrossSections(bbox); } @@ -1531,8 +1563,8 @@ void CmdPartCrossSections::activated(int iMsg) bool CmdPartCrossSections::isActive(void) { - return (Gui::Selection().countObjectsOfType(Part::Feature::getClassTypeId()) > 0 && - !Gui::Control().activeDialog()); + bool hasShapes = PartGui::hasShapesInSelection(); + return (hasShapes && !Gui::Control().activeDialog()); } //=========================================================================== @@ -1643,9 +1675,16 @@ CmdPartOffset::CmdPartOffset() void CmdPartOffset::activated(int iMsg) { Q_UNUSED(iMsg); - auto shapes = getSelection().getObjectsOfType(Part::Feature::getClassTypeId(),nullptr,3); - if(shapes.empty()) + std::vector docobjs = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + std::vector shapes; + for (std::vector::iterator it = docobjs.begin(); it != docobjs.end(); ++it) { + if (!Part::Feature::getTopoShape(*it).isNull()) { + shapes.push_back(*it); + } + } + if (shapes.size() != 1) { return; + } App::DocumentObject* shape = shapes.front(); std::string offset = getUniqueObjectName("Offset"); @@ -1668,9 +1707,15 @@ void CmdPartOffset::activated(int iMsg) bool CmdPartOffset::isActive(void) { - Base::Type partid = Base::Type::fromName("Part::Feature"); - bool objectsSelected = Gui::Selection().countObjectsOfType(partid,nullptr,3) == 1; - return (objectsSelected && !Gui::Control().activeDialog()); + { + bool hasShapes = PartGui::hasShapesInSelection(); + std::vector docobjs = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + return (hasShapes && !Gui::Control().activeDialog() && docobjs.size() == 1); + } + +// Base::Type partid = Base::Type::fromName("Part::Feature"); +// bool objectsSelected = Gui::Selection().countObjectsOfType(partid,0,3) == 1; +// return (objectsSelected && !Gui::Control().activeDialog()); } @@ -1695,9 +1740,17 @@ CmdPartOffset2D::CmdPartOffset2D() void CmdPartOffset2D::activated(int iMsg) { Q_UNUSED(iMsg); - auto shapes = getSelection().getObjectsOfType(Part::Feature::getClassTypeId(),nullptr,3); - if(shapes.empty()) + std::vector docobjs = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + std::vector shapes; + + for (std::vector::iterator it = docobjs.begin(); it != docobjs.end(); ++it) { + if (!Part::Feature::getTopoShape(*it).isNull()) { + shapes.push_back(*it); + } + } + if (shapes.size() != 1) { return; + } App::DocumentObject* shape = shapes.front(); std::string offset = getUniqueObjectName("Offset2D"); @@ -1720,9 +1773,9 @@ void CmdPartOffset2D::activated(int iMsg) bool CmdPartOffset2D::isActive(void) { - Base::Type partid = Base::Type::fromName("Part::Feature"); - bool objectsSelected = Gui::Selection().countObjectsOfType(partid,nullptr,3) == 1; - return (objectsSelected && !Gui::Control().activeDialog()); + bool hasShapes = PartGui::hasShapesInSelection(); + std::vector docobjs = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + return (hasShapes && !Gui::Control().activeDialog() && docobjs.size() == 1); } //=========================================================================== @@ -1813,11 +1866,10 @@ void CmdPartCompOffset::languageChange() bool CmdPartCompOffset::isActive(void) { - Base::Type partid = Base::Type::fromName("Part::Feature"); - bool objectsSelected = Gui::Selection().countObjectsOfType(partid,nullptr,3) == 1; - return (objectsSelected && !Gui::Control().activeDialog()); + bool hasShapes = PartGui::hasShapesInSelection(); + std::vector docobjs = Gui::Selection().getObjectsOfType(App::DocumentObject::getClassTypeId()); + return (hasShapes && !Gui::Control().activeDialog() && docobjs.size() == 1); } - //=========================================================================== // Part_Thickness //=========================================================================== @@ -1839,31 +1891,48 @@ CmdPartThickness::CmdPartThickness() void CmdPartThickness::activated(int iMsg) { Q_UNUSED(iMsg); - Gui::SelectionFilter faceFilter ("SELECT Part::Feature SUBELEMENT Face COUNT 1.."); - if (!faceFilter.match()) { - QMessageBox::warning(Gui::getMainWindow(), - QApplication::translate("CmdPartThickness", "Wrong selection"), - QApplication::translate("CmdPartThickness", "Selected one or more faces of a shape")); - return; + const App::DocumentObject* obj = nullptr; + std::string selection; + const std::vector selobjs = Gui::Selection().getSelectionEx(); + std::vector subShapes; + Part::TopoShape topoShape = Part::TopoShape(); + + bool ok = true; + if (selobjs.size() == 1) { + selection = selobjs[0].getAsPropertyLinkSubString(); + const std::vector& subnames = selobjs[0].getSubNames(); + obj = selobjs[0].getObject(); + topoShape = Part::Feature::getTopoShape(obj); + if (!topoShape.isNull()) { + for (std::vector::const_iterator it = subnames.begin(); it != subnames.end(); ++it) { + subShapes.push_back(topoShape.getSubShape(subnames[0].c_str())); + } + for (std::vector::iterator it = subShapes.begin(); it != subShapes.end(); ++it) { + TopoDS_Shape dsShape = (*it).getShape(); + if (dsShape.IsNull() || dsShape.ShapeType() != TopAbs_FACE) { //only face selection allowed + ok = false; + } + } + } else { //could be not a part::feature or app:link to non-part::feature or app::part without a visible part::feature + ok = false; + } + + } else { //not just one object selected + ok = false; } - // get the selected object - const std::vector& result = faceFilter.Result[0]; - std::string selection = result.front().getAsPropertyLinkSubString(); - - const Part::Feature* shape = static_cast(result.front().getObject()); - if (shape->Shape.getValue().IsNull()) - return; int countSolids = 0; TopExp_Explorer xp; - xp.Init(shape->Shape.getValue(),TopAbs_SOLID); - for (;xp.More(); xp.Next()) { - countSolids++; + if (!topoShape.isNull()){ + xp.Init(topoShape.getShape(), TopAbs_SOLID); + for (;xp.More(); xp.Next()) { + countSolids++; + } } - if (countSolids != 1) { + if (countSolids != 1 || !ok) { QMessageBox::warning(Gui::getMainWindow(), - QApplication::translate("CmdPartThickness", "Wrong selection"), - QApplication::translate("CmdPartThickness", "Selected shape is not a solid")); + QApplication::translate("CmdPartThickness", "Wrong selection"), + QApplication::translate("CmdPartThickness", "Selected shape is not a solid")); return; } @@ -1874,22 +1943,24 @@ void CmdPartThickness::activated(int iMsg) doCommand(Doc,"App.ActiveDocument.%s.Faces = %s" ,thick.c_str(), selection.c_str()); doCommand(Doc,"App.ActiveDocument.%s.Value = 1.0",thick.c_str()); updateActive(); - if (isActiveObjectValid()) - doCommand(Gui,"Gui.ActiveDocument.hide(\"%s\")",shape->getNameInDocument()); + if (isActiveObjectValid()) { + doCommand(App,"App.getDocument(\"%s\").getObject(\"%s\").ViewObject.Visibility = False", + obj->getDocument()->getName(), obj->getNameInDocument()); + } doCommand(Gui,"Gui.ActiveDocument.setEdit('%s')",thick.c_str()); //commitCommand(); adjustCameraPosition(); - copyVisual(thick.c_str(), "ShapeColor", shape->getNameInDocument()); - copyVisual(thick.c_str(), "LineColor" , shape->getNameInDocument()); - copyVisual(thick.c_str(), "PointColor", shape->getNameInDocument()); + copyVisual(thick.c_str(), "ShapeColor", obj->getNameInDocument()); + copyVisual(thick.c_str(), "LineColor" , obj->getNameInDocument()); + copyVisual(thick.c_str(), "PointColor", obj->getNameInDocument()); } bool CmdPartThickness::isActive(void) { Base::Type partid = Base::Type::fromName("Part::Feature"); - bool objectsSelected = Gui::Selection().countObjectsOfType(partid) > 0; + bool objectsSelected = Gui::Selection().countObjectsOfType(partid, 0, 3) > 0; return (objectsSelected && !Gui::Control().activeDialog()); } @@ -2014,92 +2085,83 @@ CmdPartRuledSurface::CmdPartRuledSurface() void CmdPartRuledSurface::activated(int iMsg) { Q_UNUSED(iMsg); - bool ok = false; + bool ok = true; TopoDS_Shape curve1, curve2; std::string link1, link2, obj1, obj2; - Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1..2"); - Gui::SelectionFilter wireFilter ("SELECT Part::Feature SUBELEMENT Wire COUNT 1..2"); - Gui::SelectionFilter partFilter ("SELECT Part::Feature COUNT 2"); - bool matchEdge = edgeFilter.match(); - bool matchWire = wireFilter.match(); - if (matchEdge || matchWire) { - // get the selected object - const std::vector& result = matchEdge - ? edgeFilter.Result[0] : wireFilter.Result[0]; - // two edges from one object - if (result.size() == 1) { - const Part::Feature* part = static_cast(result[0].getObject()); - const std::vector& edges = result[0].getSubNames(); - if (edges.size() != 2) { - ok = false; - } - else { - ok = true; - // get the selected sub-shapes - const Part::TopoShape& shape = part->Shape.getValue(); - curve1 = shape.getSubShape(edges[0].c_str()); - curve2 = shape.getSubShape(edges[1].c_str()); - obj1 = result[0].getObject()->getNameInDocument(); - link1 = edges[0]; - obj2 = result[0].getObject()->getNameInDocument(); - link2 = edges[1]; - } - } - // two objects and one edge per object - else if (result.size() == 2) { - const Part::Feature* part1 = static_cast(result[0].getObject()); - const std::vector& edges1 = result[0].getSubNames(); - const Part::Feature* part2 = static_cast(result[1].getObject()); - const std::vector& edges2 = result[1].getSubNames(); - if (edges1.size() != 1 || edges2.size() != 1) { - ok = false; - } - else { - ok = true; - const Part::TopoShape& shape1 = part1->Shape.getValue(); - curve1 = shape1.getSubShape(edges1[0].c_str()); - const Part::TopoShape& shape2 = part2->Shape.getValue(); - curve2 = shape2.getSubShape(edges2[0].c_str()); - obj1 = result[0].getObject()->getNameInDocument(); - link1 = edges1[0]; - obj2 = result[1].getObject()->getNameInDocument(); - link2 = edges2[0]; - } - } - } - else if (partFilter.match()) { - const std::vector& result = partFilter.Result[0]; - const Part::Feature* part1 = static_cast(result[0].getObject()); - const Part::Feature* part2 = static_cast(result[1].getObject()); - const Part::TopoShape& shape1 = part1->Shape.getValue(); - curve1 = shape1.getShape(); - const Part::TopoShape& shape2 = part2->Shape.getValue(); - curve2 = shape2.getShape(); - obj1 = part1->getNameInDocument(); - obj2 = part2->getNameInDocument(); + const std::vector selobjs = Gui::Selection().getSelectionEx(); + const App::DocumentObject* docobj1 = nullptr; + const App::DocumentObject* docobj2 = nullptr; + if (selobjs.size() != 1 && selobjs.size() != 2) { + ok = false; + } + + if (ok && selobjs.size() <= 2) { + if (selobjs.size() >= 1) { + const std::vector& subnames1= selobjs[0].getSubNames(); + docobj1 = selobjs[0].getObject(); + obj1 = docobj1->getNameInDocument(); + obj2 = obj1; //changed later if 2 objects were selected + const Part::TopoShape& shape1 = Part::Feature::getTopoShape(docobj1); + if (shape1.isNull()) { + ok = false; + } + if (ok && subnames1.size() <= 2) { + if (subnames1.size() >= 1) { + curve1 = shape1.getSubShape(subnames1[0].c_str()); + link1 = subnames1[0]; + } + if (subnames1.size() == 2) { + curve2 = shape1.getSubShape(subnames1[1].c_str()); + link2 = subnames1[1]; + } + if (subnames1.size() == 0) { + curve1 = shape1.getShape(); + } + } else { + ok = false; + } + } + if (selobjs.size() == 2) { + const std::vector& subnames2 = selobjs[1].getSubNames(); + docobj2 = selobjs[1].getObject(); + obj2 = docobj2->getNameInDocument(); + + const Part::TopoShape& shape2 = Part::Feature::getTopoShape(docobj2); + if (shape2.isNull()) { + ok = false; + } + if (ok && subnames2.size() == 1) { + curve2 = shape2.getSubShape(subnames2[0].c_str()); + link2 = subnames2[0]; + } else { + if (subnames2.size() == 0) { + curve2 = shape2.getShape(); + } + } + } if (!curve1.IsNull() && !curve2.IsNull()) { - if (curve1.ShapeType() == TopAbs_EDGE && - curve2.ShapeType() == TopAbs_EDGE) - ok = true; - if (curve1.ShapeType() == TopAbs_WIRE && - curve2.ShapeType() == TopAbs_WIRE) + if ((curve1.ShapeType() == TopAbs_EDGE || curve1.ShapeType() == TopAbs_WIRE) + && (curve2.ShapeType() == TopAbs_EDGE || curve2.ShapeType() == TopAbs_WIRE)) { ok = true; + } } } + + if (!ok) { QMessageBox::warning(Gui::getMainWindow(), QObject::tr("Wrong selection"), - QObject::tr("You have to select either two edges or two wires.")); + QObject::tr("You have to select either two edges or two wires.")); return; } openCommand(QT_TRANSLATE_NOOP("Command", "Create ruled surface")); doCommand(Doc, "FreeCAD.ActiveDocument.addObject('Part::RuledSurface', 'Ruled Surface')"); doCommand(Doc, "FreeCAD.ActiveDocument.ActiveObject.Curve1=(FreeCAD.ActiveDocument.%s,['%s'])" - ,obj1.c_str(), link1.c_str()); + ,obj1.c_str(), link1.c_str()); doCommand(Doc, "FreeCAD.ActiveDocument.ActiveObject.Curve2=(FreeCAD.ActiveDocument.%s,['%s'])" - ,obj2.c_str(), link2.c_str()); + ,obj2.c_str(), link2.c_str()); commitCommand(); updateActive(); } @@ -2138,9 +2200,8 @@ void CmdCheckGeometry::activated(int iMsg) bool CmdCheckGeometry::isActive(void) { - Base::Type partid = Base::Type::fromName("Part::Feature"); - bool objectsSelected = Gui::Selection().countObjectsOfType(partid) > 0; - return (hasActiveDocument() && !Gui::Control().activeDialog() && objectsSelected); + bool hasShapes = PartGui::hasShapesInSelection(); + return (hasShapes && !Gui::Control().activeDialog()); } //=========================================================================== @@ -2502,8 +2563,7 @@ void CmdPartSectionCut::activated(int iMsg) bool CmdPartSectionCut::isActive(void) { - Gui::View3DInventor* view = dynamic_cast(Gui::getMainWindow()->activeWindow()); - return view ? true : false; + return hasActiveDocument(); } //--------------------------------------------------------------- diff --git a/src/Mod/Part/Gui/CrossSections.cpp b/src/Mod/Part/Gui/CrossSections.cpp index 59708502b7..368ae5bb44 100644 --- a/src/Mod/Part/Gui/CrossSections.cpp +++ b/src/Mod/Part/Gui/CrossSections.cpp @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -194,8 +195,14 @@ void CrossSections::accept() void CrossSections::apply() { - std::vector obj = Gui::Selection(). - getObjectsOfType(Part::Feature::getClassTypeId()); + std::vector docobjs = Gui::Selection(). + getObjectsOfType(App::DocumentObject::getClassTypeId()); + std::vector obj; + for (std::vector::iterator it = docobjs.begin(); it != docobjs.end(); ++it){ + if (!Part::Feature::getTopoShape(*it).isNull()) { + obj.push_back((*it)->getLinkedObject()); + } + } std::vector d; if (ui->sectionsBox->isChecked()) diff --git a/src/Mod/Part/Gui/DlgExtrusion.cpp b/src/Mod/Part/Gui/DlgExtrusion.cpp index 1d8a610b8e..c9c8593cf9 100644 --- a/src/Mod/Part/Gui/DlgExtrusion.cpp +++ b/src/Mod/Part/Gui/DlgExtrusion.cpp @@ -38,8 +38,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -69,16 +70,18 @@ public: bool allow(App::Document* /*pDoc*/, App::DocumentObject* pObj, const char* sSubName) { this->canSelect = false; - if (!pObj->isDerivedFrom(Part::Feature::getClassTypeId())) - return false; + if (!sSubName || sSubName[0] == '\0') return false; std::string element(sSubName); if (element.substr(0,4) != "Edge") return false; - Part::Feature* fea = static_cast(pObj); + Part::TopoShape part = Part::Feature::getTopoShape(pObj); + if (part.isNull()) { + return false; + } try { - TopoDS_Shape sub = fea->Shape.getShape().getSubShape(sSubName); + TopoDS_Shape sub = part.getSubShape(sSubName); if (!sub.IsNull() && sub.ShapeType() == TopAbs_EDGE) { const TopoDS_Edge& edge = TopoDS::Edge(sub); BRepAdaptor_Curve adapt(edge); @@ -112,6 +115,8 @@ DlgExtrusion::DlgExtrusion(QWidget* parent, Qt::WindowFlags fl) Gui::ItemViewSelection sel(ui->treeWidget); sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Link::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Part::getClassTypeId())); this->on_DirMode_changed(); ui->spinLenFwd->selectAll(); @@ -317,27 +322,28 @@ void DlgExtrusion::fetchDir() void DlgExtrusion::autoSolid() { try{ - App::DocumentObject &dobj = this->getShapeToExtrude(); - if (dobj.isDerivedFrom(Part::Feature::getClassTypeId())){ - Part::Feature &feature = static_cast(dobj); - TopoDS_Shape sh = feature.Shape.getValue(); - if (sh.IsNull()) + App::DocumentObject* dobj = &this->getShapeToExtrude(); + Part::TopoShape shape = Part::Feature::getTopoShape(dobj); + if (shape.isNull()) { + return; + } + TopoDS_Shape sh = shape.getShape(); + if (sh.IsNull()) + return; + ShapeExtend_Explorer xp; + Handle(TopTools_HSequenceOfShape) leaves = xp.SeqFromCompound(sh, /*recursive= */Standard_True); + int cntClosedWires = 0; + for(int i = 0; i < leaves->Length(); i++){ + const TopoDS_Shape &leaf = leaves->Value(i+1); + if (leaf.IsNull()) return; - ShapeExtend_Explorer xp; - Handle(TopTools_HSequenceOfShape) leaves = xp.SeqFromCompound(sh, /*recursive= */Standard_True); - int cntClosedWires = 0; - for(int i = 0; i < leaves->Length(); i++){ - const TopoDS_Shape &leaf = leaves->Value(i+1); - if (leaf.IsNull()) - return; - if (leaf.ShapeType() == TopAbs_WIRE || leaf.ShapeType() == TopAbs_EDGE){ - if (BRep_Tool::IsClosed(leaf)){ - cntClosedWires++; - } + if (leaf.ShapeType() == TopAbs_WIRE || leaf.ShapeType() == TopAbs_EDGE){ + if (BRep_Tool::IsClosed(leaf)){ + cntClosedWires++; } } - ui->chkSolid->setChecked( cntClosedWires == leaves->Length() ); } + ui->chkSolid->setChecked( cntClosedWires == leaves->Length() ); } catch(...) { } @@ -352,10 +358,15 @@ void DlgExtrusion::findShapes() this->document = activeDoc->getName(); this->label = activeDoc->Label.getValue(); - std::vector objs = activeDoc->getObjectsOfType - (Part::Feature::getClassTypeId()); + std::vector objs = activeDoc->getObjectsOfType(); + for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { - const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue(); + Part::TopoShape topoShape = Part::Feature::getTopoShape(*it); + if (topoShape.isNull()) { + continue; + } + TopoDS_Shape shape = topoShape.getShape(); + if (shape.IsNull()) continue; if (canExtrude(shape)) { QTreeWidgetItem* item = new QTreeWidgetItem(ui->treeWidget); item->setText(0, QString::fromUtf8((*it)->Label.getValue())); @@ -429,7 +440,7 @@ void DlgExtrusion::apply() for (App::DocumentObject* sourceObj: objects) { assert(sourceObj); - if (!sourceObj->isDerivedFrom(Part::Feature::getClassTypeId())){ + if (Part::Feature::getTopoShape(sourceObj).isNull()){ FC_ERR("Object " << sourceObj->getFullName() << " is not Part object (has no OCC shape). Can't extrude it."); continue; diff --git a/src/Mod/Part/Gui/DlgRevolution.cpp b/src/Mod/Part/Gui/DlgRevolution.cpp index 61ab1a62fa..787ee39b4b 100644 --- a/src/Mod/Part/Gui/DlgRevolution.cpp +++ b/src/Mod/Part/Gui/DlgRevolution.cpp @@ -44,6 +44,8 @@ #include #include #include +#include +#include #include #include #include @@ -73,16 +75,18 @@ public: bool allow(App::Document* /*pDoc*/, App::DocumentObject*pObj, const char*sSubName) { this->canSelect = false; - if (!pObj->isDerivedFrom(Part::Feature::getClassTypeId())) - return false; + if (!sSubName || sSubName[0] == '\0') return false; std::string element(sSubName); if (element.substr(0,4) != "Edge") return false; - Part::Feature* fea = static_cast(pObj); + Part::TopoShape part = Part::Feature::getTopoShape(pObj); + if (part.isNull()) { + return false; + } try { - TopoDS_Shape sub = fea->Shape.getShape().getSubShape(sSubName); + TopoDS_Shape sub = part.getSubShape(sSubName); if (!sub.IsNull() && sub.ShapeType() == TopAbs_EDGE) { const TopoDS_Edge& edge = TopoDS::Edge(sub); BRepAdaptor_Curve adapt(edge); @@ -127,6 +131,8 @@ DlgRevolution::DlgRevolution(QWidget* parent, Qt::WindowFlags fl) Gui::ItemViewSelection sel(ui->treeWidget); sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Link::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Part::getClassTypeId())); connect(ui->txtAxisLink, SIGNAL(textChanged(QString)), this, SLOT(on_txtAxisLink_textChanged(QString))); @@ -327,10 +333,14 @@ void DlgRevolution::findShapes() return; Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc); - std::vector objs = activeDoc->getObjectsOfType - (Part::Feature::getClassTypeId()); + std::vector objs = activeDoc->getObjectsOfType(); + for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { - const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue(); + Part::TopoShape topoShape = Part::Feature::getTopoShape(*it); + if (topoShape.isNull()) { + continue; + } + TopoDS_Shape shape = topoShape.getShape(); if (shape.IsNull()) continue; TopExp_Explorer xp; @@ -521,9 +531,11 @@ void DlgRevolution::autoSolid() { try{ App::DocumentObject &dobj = this->getShapeToRevolve(); - if (dobj.isDerivedFrom(Part::Feature::getClassTypeId())){ - Part::Feature &feature = static_cast(dobj); - TopoDS_Shape sh = feature.Shape.getValue(); + Part::TopoShape topoShape = Part::Feature::getTopoShape(&dobj); + if (topoShape.isNull()) { + return; + } else { + TopoDS_Shape sh = topoShape.getShape(); if (sh.IsNull()) return; ShapeExtend_Explorer xp; diff --git a/src/Mod/Part/Gui/Mirroring.cpp b/src/Mod/Part/Gui/Mirroring.cpp index c3adead1e0..cb800e05bb 100644 --- a/src/Mod/Part/Gui/Mirroring.cpp +++ b/src/Mod/Part/Gui/Mirroring.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,6 +70,8 @@ Mirroring::Mirroring(QWidget* parent) Gui::ItemViewSelection sel(ui->shapes); sel.applyFrom(Gui::Selection().getObjectsOfType(Part::Feature::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Link::getClassTypeId())); + sel.applyFrom(Gui::Selection().getObjectsOfType(App::Part::getClassTypeId())); } /* @@ -89,19 +93,18 @@ void Mirroring::changeEvent(QEvent *e) void Mirroring::findShapes() { App::Document* activeDoc = App::GetApplication().getActiveDocument(); - if (!activeDoc) + if (!activeDoc) return; Gui::Document* activeGui = Gui::Application::Instance->getDocument(activeDoc); - if (!activeGui) + if (!activeGui) return; this->document = QString::fromLatin1(activeDoc->getName()); - std::vector objs = activeDoc->getObjectsOfType - (Part::Feature::getClassTypeId()); + std::vector objs = activeDoc->getObjectsOfType(); for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { - const TopoDS_Shape& shape = static_cast(*it)->Shape.getValue(); - if (!shape.IsNull()) { + Part::TopoShape shape = Part::Feature::getTopoShape(*it); + if (!shape.isNull()) { QString label = QString::fromUtf8((*it)->Label.getValue()); QString name = QString::fromLatin1((*it)->getNameInDocument()); diff --git a/src/Mod/Part/Gui/TaskLoft.cpp b/src/Mod/Part/Gui/TaskLoft.cpp index 8ad5edf8a0..e4a40eb229 100644 --- a/src/Mod/Part/Gui/TaskLoft.cpp +++ b/src/Mod/Part/Gui/TaskLoft.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -102,10 +103,14 @@ void LoftWidget::findShapes() return; d->document = activeDoc->getName(); - std::vector objs = activeDoc->getObjectsOfType(); + std::vector objs = activeDoc->getObjectsOfType(); - for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { - TopoDS_Shape shape = (*it)->Shape.getValue(); + for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { + Part::TopoShape topoShape = Part::Feature::getTopoShape(*it); + if (topoShape.isNull()) { + continue; + } + TopoDS_Shape shape = topoShape.getShape(); if (shape.IsNull()) continue; // also allow compounds with a single face, wire or vertex or @@ -145,7 +150,6 @@ void LoftWidget::findShapes() shape.ShapeType() == TopAbs_VERTEX) { QString label = QString::fromUtf8((*it)->Label.getValue()); QString name = QString::fromLatin1((*it)->getNameInDocument()); - QTreeWidgetItem* child = new QTreeWidgetItem(); child->setText(0, label); child->setToolTip(0, label); diff --git a/src/Mod/Part/Gui/TaskSweep.cpp b/src/Mod/Part/Gui/TaskSweep.cpp index ce676c0eca..94a720696e 100644 --- a/src/Mod/Part/Gui/TaskSweep.cpp +++ b/src/Mod/Part/Gui/TaskSweep.cpp @@ -56,6 +56,7 @@ #include #include #include +#include #include @@ -83,39 +84,41 @@ public: } bool allow(App::Document* /*pDoc*/, App::DocumentObject*pObj, const char*sSubName) { - if (pObj->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId())) { - if (!sSubName || sSubName[0] == '\0') { - // If selecting again the same edge the passed sub-element is empty. If the whole - // shape is an edge or wire we can use it completely. - const TopoDS_Shape& shape = static_cast(pObj)->Shape.getValue(); - if (!shape.IsNull()) { - // a single edge - if (shape.ShapeType() == TopAbs_EDGE) { - return true; - } - // a single wire - if (shape.ShapeType() == TopAbs_WIRE) { - return true; - } - // a compound of only edges or wires - if (shape.ShapeType() == TopAbs_COMPOUND) { - TopoDS_Iterator it(shape); - for (; it.More(); it.Next()) { - if (it.Value().IsNull()) - return false; - if ((it.Value().ShapeType() != TopAbs_EDGE) && + if (!sSubName || sSubName[0] == '\0') { + // If selecting again the same edge the passed sub-element is empty. If the whole + // shape is an edge or wire we can use it completely. + Part::TopoShape topoShape = Part::Feature::getTopoShape(pObj); + if (topoShape.isNull()) { + return false; + } + const TopoDS_Shape shape = topoShape.getShape(); + if (!shape.IsNull()) { + // a single edge + if (shape.ShapeType() == TopAbs_EDGE) { + return true; + } + // a single wire + if (shape.ShapeType() == TopAbs_WIRE) { + return true; + } + // a compound of only edges or wires + if (shape.ShapeType() == TopAbs_COMPOUND) { + TopoDS_Iterator it(shape); + for (; it.More(); it.Next()) { + if (it.Value().IsNull()) + return false; + if ((it.Value().ShapeType() != TopAbs_EDGE) && (it.Value().ShapeType() != TopAbs_WIRE)) - return false; - } - - return true; + return false; } + + return true; } } - else { - std::string element(sSubName); - return element.substr(0,4) == "Edge"; - } + } + else { + std::string element(sSubName); + return element.substr(0,4) == "Edge"; } return false; @@ -159,10 +162,14 @@ void SweepWidget::findShapes() return; d->document = activeDoc->getName(); - std::vector objs = activeDoc->getObjectsOfType(); + std::vector objs = activeDoc->getObjectsOfType(); - for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { - TopoDS_Shape shape = (*it)->Shape.getValue(); + for (std::vector::iterator it = objs.begin(); it!=objs.end(); ++it) { + Part::TopoShape topoShape = Part::Feature::getTopoShape(*it); + if (topoShape.isNull()) { + continue; + } + TopoDS_Shape shape = topoShape.getShape(); if (shape.IsNull()) continue; // also allow compounds with a single face, wire or vertex or @@ -217,13 +224,13 @@ void SweepWidget::findShapes() bool SweepWidget::isPathValid(const Gui::SelectionObject& sel) const { const App::DocumentObject* path = sel.getObject(); - if (!(path && path->getTypeId().isDerivedFrom(Part::Feature::getClassTypeId()))) - return false; const std::vector& sub = sel.getSubNames(); - TopoDS_Shape pathShape; - const Part::TopoShape& shape = static_cast(path)->Shape.getValue(); + const Part::TopoShape& shape = Part::Feature::getTopoShape(path); + if (shape.isNull()){ + return false; + } if (!sub.empty()) { try { BRepBuilderAPI_MakeWire mkWire; @@ -276,23 +283,38 @@ bool SweepWidget::accept() { if (d->ui.buttonPath->isChecked()) return false; - Gui::SelectionFilter edgeFilter ("SELECT Part::Feature SUBELEMENT Edge COUNT 1.."); - Gui::SelectionFilter partFilter ("SELECT Part::Feature COUNT 1"); - bool matchEdge = edgeFilter.match(); - bool matchPart = partFilter.match(); - if (!matchEdge && !matchPart) { - QMessageBox::critical(this, tr("Sweep path"), tr("Select one or more connected edges you want to sweep along.")); - return false; - } - - // get the selected object + const App::DocumentObject* docobj = nullptr; std::string selection; + const std::vector selobjs = Gui::Selection().getSelectionEx(); + std::vector subShapes; + Part::TopoShape topoShape = Part::TopoShape(); std::string spineObject, spineLabel; - const std::vector& result = matchEdge - ? edgeFilter.Result[0] : partFilter.Result[0]; - selection = result.front().getAsPropertyLinkSubString(); - spineObject = result.front().getFeatName(); - spineLabel = result.front().getObject()->Label.getValue(); + + bool ok = true; + if (selobjs.size() == 1) { + selection = selobjs[0].getAsPropertyLinkSubString(); + const std::vector& subnames = selobjs[0].getSubNames(); + docobj = selobjs[0].getObject(); + spineObject = selobjs[0].getFeatName(); + spineLabel = docobj->Label.getValue(); + topoShape = Part::Feature::getTopoShape(docobj); + if (!topoShape.isNull()) { + for (std::vector::const_iterator it = subnames.begin(); it != subnames.end(); ++it) { + subShapes.push_back(topoShape.getSubShape(subnames[0].c_str())); + } + for (std::vector::iterator it = subShapes.begin(); it != subShapes.end(); ++it) { + TopoDS_Shape dsShape = (*it).getShape(); + if (dsShape.IsNull() || dsShape.ShapeType() != TopAbs_EDGE) { //only edge selection allowed + ok = false; + } + } + } else { //could be not a part::feature or app:link to non-part::feature or app::part without a visible part::feature + ok = false; + } + + } else { //not just one object selected + ok = false; + } QString list, solid, frenet; if (d->ui.checkSolid->isChecked()) @@ -312,6 +334,10 @@ bool SweepWidget::accept() QMessageBox::critical(this, tr("Too few elements"), tr("At least one edge or wire is required.")); return false; } + if (!ok) { + QMessageBox::critical(this, tr("Invalid selection"), tr("Select one or more edges from a single object.")); + return false; + } for (int i=0; iui.selector->selectedTreeWidget()->topLevelItem(i); QString name = child->data(0, Qt::UserRole).toString();