From: azv Date: Wed, 26 Jun 2019 13:15:35 +0000 (+0300) Subject: Implement filter "F6: On plane side" X-Git-Tag: VEDF2019Lot4~101^2~16 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=7c1c7182a7f40ed1a9baf285de9d99bd6f81f893;p=modules%2Fshaper.git Implement filter "F6: On plane side" --- diff --git a/src/FiltersAPI/FiltersAPI_Feature.cpp b/src/FiltersAPI/FiltersAPI_Feature.cpp index ea9894fd6..b6646abfd 100644 --- a/src/FiltersAPI/FiltersAPI_Feature.cpp +++ b/src/FiltersAPI/FiltersAPI_Feature.cpp @@ -53,6 +53,12 @@ void FiltersAPI_Feature::setFilters(const std::list& theFilters) std::dynamic_pointer_cast(*aFIt); if (aSelList) fillAttribute(anArgs, aSelList); + else { + AttributeSelectionPtr aSelection = + std::dynamic_pointer_cast(*aFIt); + if (aSelection && anArgs.size() == 1) + fillAttribute(anArgs.front(), aSelection); + } } } } diff --git a/src/FiltersPlugin/CMakeLists.txt b/src/FiltersPlugin/CMakeLists.txt index 8fd0b5d3a..8f6941ee7 100644 --- a/src/FiltersPlugin/CMakeLists.txt +++ b/src/FiltersPlugin/CMakeLists.txt @@ -30,6 +30,7 @@ SET(PROJECT_HEADERS FiltersPlugin_OnPlane.h FiltersPlugin_OnLine.h FiltersPlugin_OnGeometry.h + FiltersPlugin_OnPlaneSide.h ) SET(PROJECT_SOURCES @@ -41,6 +42,7 @@ SET(PROJECT_SOURCES FiltersPlugin_OnPlane.cpp FiltersPlugin_OnLine.cpp FiltersPlugin_OnGeometry.cpp + FiltersPlugin_OnPlaneSide.cpp ) SET(PROJECT_LIBRARIES @@ -77,6 +79,8 @@ ADD_UNIT_TESTS( TestFilter_OnLine.py TestFilter_OnGeometry_Edge.py TestFilter_OnGeometry_Face.py + TestFilter_OnPlaneSide_Face.py + TestFilter_OnPlaneSide_Plane.py TestFilter_HorizontalFaces.py TestFilter_VerticalFaces.py ) diff --git a/src/FiltersPlugin/FiltersPlugin_OnPlaneSide.cpp b/src/FiltersPlugin/FiltersPlugin_OnPlaneSide.cpp new file mode 100644 index 000000000..b19a98ec5 --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_OnPlaneSide.cpp @@ -0,0 +1,77 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "FiltersPlugin_OnPlaneSide.h" + +#include + +#include +#include +#include +#include + + +bool FiltersPlugin_OnPlaneSide::isSupported(GeomAPI_Shape::ShapeType theType) const +{ + return true; +} + +bool FiltersPlugin_OnPlaneSide::isOk(const GeomShapePtr& theShape, + const ModelAPI_FiltersArgs& theArgs) const +{ + static const double THE_TOLERANCE = 1.e-7; + + AttributePtr aAttr = theArgs.argument("OnPlaneSide"); + AttributeSelectionPtr aList = std::dynamic_pointer_cast(aAttr); + if (!aList.get()) + return false; + GeomShapePtr aPlanarShape = aList->value(); + if (!aPlanarShape) + aPlanarShape = aList->context()->shape(); + + GeomPlanePtr aPlane = aPlanarShape->face()->getPlane(); + GeomPointPtr aPlaneLoc = aPlane->location(); + GeomDirPtr aPlaneNorm = aPlane->direction(); + + GeomPointPtr aShapeCenter = theShape->middlePoint(); + GeomXYZPtr aVec = aShapeCenter->xyz()->decreased(aPlaneLoc->xyz()); + + return aVec->dot(aPlaneNorm->xyz()) > THE_TOLERANCE; +} + +static std::string XMLRepresentation = +"" +" " +" " +" " +""; + + +std::string FiltersPlugin_OnPlaneSide::xmlRepresentation() const +{ + return XMLRepresentation; +} + +void FiltersPlugin_OnPlaneSide::initAttributes(ModelAPI_FiltersArgs& theArguments) +{ + theArguments.initAttribute("OnPlaneSide", ModelAPI_AttributeSelection::typeId()); +} diff --git a/src/FiltersPlugin/FiltersPlugin_OnPlaneSide.h b/src/FiltersPlugin/FiltersPlugin_OnPlaneSide.h new file mode 100644 index 000000000..ef3f4a88a --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_OnPlaneSide.h @@ -0,0 +1,57 @@ +// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef FILTERSPLUGIN_ONPLANESIDE_H_ +#define FILTERSPLUGIN_ONPLANESIDE_H_ + +#include "FiltersPlugin.h" + +#include + +/**\class FiltersPlugin_OnPlaneSide +* \ingroup DataModel +* \brief Filter for objects which lying on the side of selected plane +*/ +class FiltersPlugin_OnPlaneSide : public ModelAPI_Filter +{ +public: + FiltersPlugin_OnPlaneSide() : ModelAPI_Filter() {} + + virtual const std::string& name() const { + static const std::string kName("On plane side"); + return kName; + } + + /// Returns true for any type because it supports all selection types + virtual bool isSupported(GeomAPI_Shape::ShapeType theType) const override; + + /// This method should contain the filter logic. It returns true if the given shape + /// is accepted by the filter. + /// \param theShape the given shape + virtual bool isOk(const GeomShapePtr& theShape, + const ModelAPI_FiltersArgs& theArgs) const override; + + /// Returns XML string which represents GUI of the filter + virtual std::string xmlRepresentation() const override; + + /// Initializes arguments of a filter. + virtual void initAttributes(ModelAPI_FiltersArgs& theArguments) override; +}; + +#endif \ No newline at end of file diff --git a/src/FiltersPlugin/FiltersPlugin_Plugin.cpp b/src/FiltersPlugin/FiltersPlugin_Plugin.cpp index 1780ec50f..67a8c8fce 100644 --- a/src/FiltersPlugin/FiltersPlugin_Plugin.cpp +++ b/src/FiltersPlugin/FiltersPlugin_Plugin.cpp @@ -25,6 +25,7 @@ #include "FiltersPlugin_OnPlane.h" #include "FiltersPlugin_OnLine.h" #include "FiltersPlugin_OnGeometry.h" +#include "FiltersPlugin_OnPlaneSide.h" #include #include @@ -43,6 +44,7 @@ FiltersPlugin_Plugin::FiltersPlugin_Plugin() aFactory->registerFilter("OnPlane", new FiltersPlugin_OnPlane); aFactory->registerFilter("OnLine", new FiltersPlugin_OnLine); aFactory->registerFilter("OnGeometry", new FiltersPlugin_OnGeometry); + aFactory->registerFilter("OnPlaneSide", new FiltersPlugin_OnPlaneSide); ModelAPI_Session::get()->registerPlugin(this); } diff --git a/src/FiltersPlugin/Test/TestFilter_OnPlaneSide_Face.py b/src/FiltersPlugin/Test/TestFilter_OnPlaneSide_Face.py new file mode 100644 index 000000000..7ab2dfdb4 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_OnPlaneSide_Face.py @@ -0,0 +1,169 @@ +# Copyright (C) 2014-2019 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from SketchAPI import * +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Box_1_1/Left"), model.selection("FACE", "Box_1_1/Right")) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_1_1"), model.selection("FACE", "Plane_1")], 20190506) +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OX"), 20) +Sketch_1 = model.addSketch(Part_1_doc, model.standardPlane("XOY")) +SketchCircle_1 = Sketch_1.addCircle(-15, 4, 10) +SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 10) +SketchLine_1 = Sketch_1.addLine(-24.53939201417305, 7, -5.460607985826952, 7) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchCircle_1.results()[1]) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchCircle_1.results()[1]) +SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result()) +SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchLine_1.result(), 3, True) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left]"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchCircle_1.center(), SketchAPI_Point(SketchPoint_1).coordinates(), 15) +SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 4) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), 15, 5) +Filters = model.filters(Part_1_doc, [model.addFilter(name = "OnPlaneSide", args = [model.selection("FACE", "Partition_1_1_2/Modified_Face&Plane_1/Plane_1")])]) +model.end() + +ResultBox_1 = Partition_1.result().subResult(0).resultSubShapePair()[0] +ResultBox_2 = Partition_1.result().subResult(1).resultSubShapePair()[0] +ResultCylinder = Cylinder_1.result().resultSubShapePair()[0] +ResultExtrusion_1 = Extrusion_1.result().subResult(0).resultSubShapePair()[0] +ResultExtrusion_2 = Extrusion_1.result().subResult(1).resultSubShapePair()[0] + +from GeomAPI import GeomAPI_Shape +emptyShape = GeomAPI_Shape() + +Reference = { + # Solids + model.selection(ResultBox_1, emptyShape): True, + model.selection(ResultBox_2, emptyShape): False, + model.selection(ResultCylinder, emptyShape): True, + model.selection(ResultExtrusion_1, emptyShape): True, + model.selection(ResultExtrusion_2, emptyShape): False, + # Faces of the box + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Back"): True, + model.selection("FACE", "Box_1_1/Left"): True, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Bottom"): True, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Plane_1/Plane_1"): False, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Top"): True, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Front"): True, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Back"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Plane_1/Plane_1"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Bottom"): False, + model.selection("FACE", "Box_1_1/Right"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Top"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Front"): False, + # Faces of the extrusion + model.selection("FACE", "Extrusion_1_1_1/From_Face"): True, + model.selection("FACE", "Extrusion_1_1_1/To_Face"): True, + model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1"): True, + model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2"): False, + model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1"): False, + model.selection("FACE", "Extrusion_1_1_2/From_Face"): False, + model.selection("FACE", "Extrusion_1_1_2/To_Face"): False, + model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1"): False, + model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2"): False, + # Faces of the cylinder + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"): True, + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_2"): True, + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_3"): True, + # Edges of the box + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Bottom]"): True, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Back"): False, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Box_1_1/Left]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Top]"): True, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Bottom"): False, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Top"): False, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Top][Box_1_1/Left]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Front"): False, + model.selection("EDGE", "[Box_1_1/Left][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Top][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Partition_1_1_2/Modified_Face&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Box_1_1/Right]"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Back"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Partition_1_1_2/Modified_Face&Box_1_1/Top]"): False, + model.selection("EDGE", "[Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Top][Box_1_1/Right]"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Top"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Bottom"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Bottom][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + model.selection("EDGE", "[Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Front"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Top][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + # Edges of the extrusion + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_2/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][weak_name_2]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][weak_name_1]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/To_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_2/To_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/From_Face]"): True, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2]"): True, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/To_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/To_Face]"): True, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/To_Face]"): False, + # Edges of the cylinder + model.selection("EDGE", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]"): True, + model.selection("EDGE", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_3]"): True, + model.selection("EDGE", "([Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2])([Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_3])"): True, + # Vertices of the box + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Top][Box_1_1/Left][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_4"): False, + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Top][Box_1_1/Left]"): True, + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_2"): False, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_3"): False, + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left]"): True, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_1"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_3"): False, + model.selection("VERTEX", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Partition_1_1_2/Modified_Face&Box_1_1/Top][Box_1_1/Right]"): False, + model.selection("VERTEX", "[Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Bottom][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_1"): False, + model.selection("VERTEX", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Bottom]"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_2"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_4"): False, + model.selection("VERTEX", "[Partition_1_1_2/Modified_Face&Box_1_1/Top][Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + # Vertices of the extrusion + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/To_Face]"): True, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/To_Face]"): False, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/To_Face]"): False, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/From_Face]"): True, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/From_Face]"): False, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/From_Face]"): False, + model.selection("VERTEX", "[_weak_name_6_Extrusion_1_1_2]e[_weak_name_5_Extrusion_1_1_2]e[_weak_name_3_Extrusion_1_1_2]e"): False, + model.selection("VERTEX", "[_weak_name_1_Extrusion_1_1_2]e[_weak_name_5_Extrusion_1_1_2]e[_weak_name_3_Extrusion_1_1_2]e"): False, + model.selection("VERTEX", "[_weak_name_6_Extrusion_1_1_2]e[_weak_name_4_Extrusion_1_1_2]e[_weak_name_2_Extrusion_1_1_2]e"): False, + model.selection("VERTEX", "[_weak_name_1_Extrusion_1_1_2]e[_weak_name_4_Extrusion_1_1_2]e[_weak_name_2_Extrusion_1_1_2]e"): False, + # Vertices of the cylinder + model.selection("VERTEX", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]"): True, + model.selection("VERTEX", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_3]"): True, +} +model.checkFilter(Part_1_doc, model, Filters, Reference) diff --git a/src/FiltersPlugin/Test/TestFilter_OnPlaneSide_Plane.py b/src/FiltersPlugin/Test/TestFilter_OnPlaneSide_Plane.py new file mode 100644 index 000000000..0656e1993 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_OnPlaneSide_Plane.py @@ -0,0 +1,169 @@ +# Copyright (C) 2014-2019 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from SketchAPI import * +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "Box_1_1/Left"), model.selection("FACE", "Box_1_1/Right")) +Partition_1 = model.addPartition(Part_1_doc, [model.selection("SOLID", "Box_1_1"), model.selection("FACE", "Plane_1")], 20190506) +Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10) +Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Cylinder_1_1")], model.selection("EDGE", "PartSet/OX"), 20) +Sketch_1 = model.addSketch(Part_1_doc, model.standardPlane("XOY")) +SketchCircle_1 = Sketch_1.addCircle(-15, 4, 10) +SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 10) +SketchLine_1 = Sketch_1.addLine(-24.53939201417305, 7, -5.460607985826952, 7) +SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchCircle_1.results()[1]) +SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchCircle_1.results()[1]) +SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result()) +SketchConstraintDistance_1 = Sketch_1.setDistance(SketchCircle_1.center(), SketchLine_1.result(), 3, True) +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left]"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchCircle_1.center(), SketchAPI_Point(SketchPoint_1).coordinates(), 15) +SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchAPI_Point(SketchPoint_1).coordinates(), SketchCircle_1.center(), 4) +model.do() +Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_1")], model.selection(), 15, 5) +Filters = model.filters(Part_1_doc, [model.addFilter(name = "OnPlaneSide", args = [model.selection("FACE", "Plane_1")])]) +model.end() + +ResultBox_1 = Partition_1.result().subResult(0).resultSubShapePair()[0] +ResultBox_2 = Partition_1.result().subResult(1).resultSubShapePair()[0] +ResultCylinder = Cylinder_1.result().resultSubShapePair()[0] +ResultExtrusion_1 = Extrusion_1.result().subResult(0).resultSubShapePair()[0] +ResultExtrusion_2 = Extrusion_1.result().subResult(1).resultSubShapePair()[0] + +from GeomAPI import GeomAPI_Shape +emptyShape = GeomAPI_Shape() + +Reference = { + # Solids + model.selection(ResultBox_1, emptyShape): True, + model.selection(ResultBox_2, emptyShape): False, + model.selection(ResultCylinder, emptyShape): True, + model.selection(ResultExtrusion_1, emptyShape): True, + model.selection(ResultExtrusion_2, emptyShape): False, + # Faces of the box + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Back"): True, + model.selection("FACE", "Box_1_1/Left"): True, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Bottom"): True, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Plane_1/Plane_1"): False, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Top"): True, + model.selection("FACE", "Partition_1_1_1/Modified_Face&Box_1_1/Front"): True, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Back"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Plane_1/Plane_1"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Bottom"): False, + model.selection("FACE", "Box_1_1/Right"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Top"): False, + model.selection("FACE", "Partition_1_1_2/Modified_Face&Box_1_1/Front"): False, + # Faces of the extrusion + model.selection("FACE", "Extrusion_1_1_1/From_Face"): True, + model.selection("FACE", "Extrusion_1_1_1/To_Face"): True, + model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1"): True, + model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2"): False, + model.selection("FACE", "Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1"): False, + model.selection("FACE", "Extrusion_1_1_2/From_Face"): False, + model.selection("FACE", "Extrusion_1_1_2/To_Face"): False, + model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1"): False, + model.selection("FACE", "Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2"): False, + # Faces of the cylinder + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"): True, + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_2"): True, + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_3"): True, + # Edges of the box + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Bottom]"): True, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Back"): False, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Box_1_1/Left]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Top]"): True, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Bottom"): False, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Top"): False, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Top][Box_1_1/Left]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("EDGE", "Partition_1_1_1/Generated_Edge&Plane_1/Plane_1&Box_1_1/Front"): False, + model.selection("EDGE", "[Box_1_1/Left][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("EDGE", "[Partition_1_1_1/Modified_Face&Box_1_1/Top][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Partition_1_1_2/Modified_Face&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Box_1_1/Right]"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Back"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Partition_1_1_2/Modified_Face&Box_1_1/Top]"): False, + model.selection("EDGE", "[Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Top][Box_1_1/Right]"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Top"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Bottom"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Bottom][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + model.selection("EDGE", "[Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + model.selection("EDGE", "Partition_1_1_2/Generated_Edge&Plane_1/Plane_1&Box_1_1/Front"): False, + model.selection("EDGE", "[Partition_1_1_2/Modified_Face&Box_1_1/Top][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + # Edges of the extrusion + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_2/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][weak_name_2]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][weak_name_1]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1_2/To_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_2/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_2/To_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/From_Face]"): True, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/From_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2]"): True, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/To_Face]"): False, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/To_Face]"): True, + model.selection("EDGE", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/To_Face]"): False, + # Edges of the cylinder + model.selection("EDGE", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]"): True, + model.selection("EDGE", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_3]"): True, + model.selection("EDGE", "([Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2])([Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_3])"): True, + # Vertices of the box + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Top][Box_1_1/Left][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_4"): False, + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Top][Box_1_1/Left]"): True, + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left][Partition_1_1_1/Modified_Face&Box_1_1/Front]"): True, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_2"): False, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_3"): False, + model.selection("VERTEX", "[Partition_1_1_1/Modified_Face&Box_1_1/Back][Partition_1_1_1/Modified_Face&Box_1_1/Bottom][Box_1_1/Left]"): True, + model.selection("VERTEX", "Partition_1_1_1/Generated_Vertex&Plane_1/Plane_1&weak_name_1"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_3"): False, + model.selection("VERTEX", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Partition_1_1_2/Modified_Face&Box_1_1/Top][Box_1_1/Right]"): False, + model.selection("VERTEX", "[Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Bottom][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_1"): False, + model.selection("VERTEX", "[Partition_1_1_2/Modified_Face&Box_1_1/Back][Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Bottom]"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_2"): False, + model.selection("VERTEX", "Partition_1_1_2/Generated_Vertex&Plane_1/Plane_1&weak_name_4"): False, + model.selection("VERTEX", "[Partition_1_1_2/Modified_Face&Box_1_1/Top][Box_1_1/Right][Partition_1_1_2/Modified_Face&Box_1_1/Front]"): False, + # Vertices of the extrusion + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/To_Face]"): True, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/To_Face]"): False, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/To_Face]"): False, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/From_Face]"): True, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_2][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/From_Face]"): False, + model.selection("VERTEX", "[Extrusion_1_1_1/Generated_Face&Sketch_1/SketchCircle_1_2&weak_name_1][Extrusion_1_1_1/Generated_Face&Sketch_1/SketchLine_1][Extrusion_1_1_1/From_Face]"): False, + model.selection("VERTEX", "[_weak_name_6_Extrusion_1_1_2]e[_weak_name_5_Extrusion_1_1_2]e[_weak_name_3_Extrusion_1_1_2]e"): False, + model.selection("VERTEX", "[_weak_name_1_Extrusion_1_1_2]e[_weak_name_5_Extrusion_1_1_2]e[_weak_name_3_Extrusion_1_1_2]e"): False, + model.selection("VERTEX", "[_weak_name_6_Extrusion_1_1_2]e[_weak_name_4_Extrusion_1_1_2]e[_weak_name_2_Extrusion_1_1_2]e"): False, + model.selection("VERTEX", "[_weak_name_1_Extrusion_1_1_2]e[_weak_name_4_Extrusion_1_1_2]e[_weak_name_2_Extrusion_1_1_2]e"): False, + # Vertices of the cylinder + model.selection("VERTEX", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_2]"): True, + model.selection("VERTEX", "[Translation_1_1/MF:Translated&Cylinder_1_1/Face_1][Translation_1_1/MF:Translated&Cylinder_1_1/Face_3]"): True, +} +model.checkFilter(Part_1_doc, model, Filters, Reference) diff --git a/src/PythonAPI/model/tests/tests.py b/src/PythonAPI/model/tests/tests.py index 17fd989eb..167f5c2bf 100644 --- a/src/PythonAPI/model/tests/tests.py +++ b/src/PythonAPI/model/tests/tests.py @@ -342,6 +342,8 @@ def checkFilter(thePartDoc, theModel, theFilter, theShapesList): needUndo = False if sel.variantType() == ModelHighAPI_Selection.VT_ResultSubShapePair: shape = sel.resultSubShapePair()[1] + if shape.isNull(): + shape = sel.resultSubShapePair()[0].shape() else: needUndo = True theModel.begin()