From 6158b5983040f4a4cf2056a28f29bc7916af1d67 Mon Sep 17 00:00:00 2001 From: azv Date: Mon, 24 Jun 2019 15:30:49 +0300 Subject: [PATCH] Unit tests for already implemented filters. --- src/FiltersAPI/FiltersAPI_Feature.cpp | 14 +++ src/FiltersAPI/FiltersAPI_Filter.h | 1 + src/FiltersAPI/FiltersAPI_Selection.cpp | 5 + src/FiltersAPI/FiltersAPI_Selection.h | 4 + src/FiltersPlugin/CMakeLists.txt | 9 ++ .../FiltersPlugin_HorizontalFace.cpp | 2 +- .../FiltersPlugin_VerticalFace.cpp | 14 +-- .../Test/TestFilter_BelongsTo.py | 84 ++++++++++++++ .../Test/TestFilter_HorizontalFaces.py | 63 ++++++++++ src/FiltersPlugin/Test/TestFilter_OnPlane.py | 108 ++++++++++++++++++ .../Test/TestFilter_VerticalFaces.py | 63 ++++++++++ src/FiltersPlugin/Test/TestFilters.py | 37 ++++++ src/Model/Model_Session.cpp | 2 +- src/ModelAPI/ModelAPI.i | 5 + src/ModelAPI/ModelAPI_swig.h | 4 + src/PythonAPI/model/tests/tests.py | 32 +++++- 16 files changed, 436 insertions(+), 11 deletions(-) create mode 100644 src/FiltersPlugin/Test/TestFilter_BelongsTo.py create mode 100644 src/FiltersPlugin/Test/TestFilter_HorizontalFaces.py create mode 100644 src/FiltersPlugin/Test/TestFilter_OnPlane.py create mode 100644 src/FiltersPlugin/Test/TestFilter_VerticalFaces.py create mode 100644 src/FiltersPlugin/Test/TestFilters.py diff --git a/src/FiltersAPI/FiltersAPI_Feature.cpp b/src/FiltersAPI/FiltersAPI_Feature.cpp index 9829d9b87..ea9894fd6 100644 --- a/src/FiltersAPI/FiltersAPI_Feature.cpp +++ b/src/FiltersAPI/FiltersAPI_Feature.cpp @@ -22,6 +22,7 @@ #include #include +#include FiltersAPI_Feature::FiltersAPI_Feature( const std::shared_ptr & theFeature) @@ -41,6 +42,19 @@ void FiltersAPI_Feature::setFilters(const std::list& theFilters) anIt != theFilters.end(); ++anIt) { aBase->addFilter((*anIt)->name()); aBase->setReversed((*anIt)->name(), (*anIt)->isReversed()); + + const std::list& anArgs = (*anIt)->arguments(); + if (!anArgs.empty()) { + // find selectionList argument and fill it + std::list aFilterArgs = aBase->filterArgs((*anIt)->name()); + for (std::list::iterator aFIt = aFilterArgs.begin(); + aFIt != aFilterArgs.end(); ++aFIt) { + AttributeSelectionListPtr aSelList = + std::dynamic_pointer_cast(*aFIt); + if (aSelList) + fillAttribute(anArgs, aSelList); + } + } } } diff --git a/src/FiltersAPI/FiltersAPI_Filter.h b/src/FiltersAPI/FiltersAPI_Filter.h index 7621b819b..27b576b97 100644 --- a/src/FiltersAPI/FiltersAPI_Filter.h +++ b/src/FiltersAPI/FiltersAPI_Filter.h @@ -51,6 +51,7 @@ public: const std::string& name() const { return myName; } bool isReversed() const { return myReversed; } + const std::list& arguments() const { return myFilterArguments; } /// Dump wrapped feature FILTERSAPI_EXPORT diff --git a/src/FiltersAPI/FiltersAPI_Selection.cpp b/src/FiltersAPI/FiltersAPI_Selection.cpp index 93a4444d9..dd4736a13 100644 --- a/src/FiltersAPI/FiltersAPI_Selection.cpp +++ b/src/FiltersAPI/FiltersAPI_Selection.cpp @@ -29,6 +29,11 @@ FiltersAPI_Selection::~FiltersAPI_Selection() { } +FiltersFeaturePtr FiltersAPI_Selection::feature() const +{ + return myFilterFeature; +} + // ================================================================================================ FiltersAPI_Selection filters(const std::shared_ptr& thePart, const std::list& theFilters) diff --git a/src/FiltersAPI/FiltersAPI_Selection.h b/src/FiltersAPI/FiltersAPI_Selection.h index 10e9b4560..4a0cc3742 100644 --- a/src/FiltersAPI/FiltersAPI_Selection.h +++ b/src/FiltersAPI/FiltersAPI_Selection.h @@ -40,6 +40,10 @@ public: /// Destructor FILTERSAPI_EXPORT virtual ~FiltersAPI_Selection(); + + /// Return filters feature + FILTERSAPI_EXPORT + FiltersFeaturePtr feature() const; }; /// Create list of filters diff --git a/src/FiltersPlugin/CMakeLists.txt b/src/FiltersPlugin/CMakeLists.txt index a764abe5e..4ff7f61f2 100644 --- a/src/FiltersPlugin/CMakeLists.txt +++ b/src/FiltersPlugin/CMakeLists.txt @@ -18,6 +18,7 @@ ## INCLUDE(Common) +INCLUDE(UnitTest) SET(PROJECT_HEADERS FiltersPlugin.h @@ -64,3 +65,11 @@ INCLUDE_DIRECTORIES( INSTALL(TARGETS Filters DESTINATION ${SHAPER_INSTALL_PLUGIN_FILES}) INSTALL(FILES ${XML_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}) + +ADD_UNIT_TESTS( + TestFilters.py + TestFilter_BelongsTo.py + TestFilter_OnPlane.py + TestFilter_HorizontalFaces.py + TestFilter_VerticalFaces.py +) diff --git a/src/FiltersPlugin/FiltersPlugin_HorizontalFace.cpp b/src/FiltersPlugin/FiltersPlugin_HorizontalFace.cpp index c602e421e..6bda6a6cf 100644 --- a/src/FiltersPlugin/FiltersPlugin_HorizontalFace.cpp +++ b/src/FiltersPlugin/FiltersPlugin_HorizontalFace.cpp @@ -30,7 +30,7 @@ bool FiltersPlugin_HorizontalFace::isSupported(GeomAPI_Shape::ShapeType theType) bool FiltersPlugin_HorizontalFace::isOk( const GeomShapePtr& theShape, const ModelAPI_FiltersArgs& theArgs) const { - if (!theShape->isPlanar()) + if (!theShape->isFace() || !theShape->isPlanar()) return false; GeomFacePtr aFace(new GeomAPI_Face(theShape)); diff --git a/src/FiltersPlugin/FiltersPlugin_VerticalFace.cpp b/src/FiltersPlugin/FiltersPlugin_VerticalFace.cpp index 97235249f..49fd944c6 100644 --- a/src/FiltersPlugin/FiltersPlugin_VerticalFace.cpp +++ b/src/FiltersPlugin/FiltersPlugin_VerticalFace.cpp @@ -33,14 +33,12 @@ bool FiltersPlugin_VerticalFace::isSupported(GeomAPI_Shape::ShapeType theType) c bool FiltersPlugin_VerticalFace::isOk( const GeomShapePtr& theShape, const ModelAPI_FiltersArgs& theArgs) const { - if (!theShape->isFace()) + if (!theShape->isFace() || !theShape->isPlanar()) return false; - if (theShape->isPlanar()) { - GeomFacePtr aFace(new GeomAPI_Face(theShape)); - GeomPlanePtr aPlane = aFace->getPlane(); - GeomDirPtr aDir = aPlane->direction(); - return fabs(aDir->z()) <= 1.e-7; - } - return false; + GeomFacePtr aFace(new GeomAPI_Face(theShape)); + + GeomPlanePtr aPlane = aFace->getPlane(); + GeomDirPtr aDir = aPlane->direction(); + return fabs(aDir->z()) <= 1.e-7; } diff --git a/src/FiltersPlugin/Test/TestFilter_BelongsTo.py b/src/FiltersPlugin/Test/TestFilter_BelongsTo.py new file mode 100644 index 000000000..420a17350 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_BelongsTo.py @@ -0,0 +1,84 @@ +# 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 salome.shaper import model +from GeomAPI import * + +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) +LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 20, 2, model.selection("EDGE", "PartSet/OY"), 20, 3) +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"), 50) +Filters = model.filters(Part_1_doc, [model.addFilter(name = "BelongsTo", args = [model.selection("SOLID", "LinearCopy_1_1_1"), model.selection("SOLID", "Translation_1_1")])]) +model.end() + +Reference = {} +# Faces of the original box +ResultBox_1 = LinearCopy_1.result().subResult(0).resultSubShapePair()[0] +exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.FACE) +while exp.more(): + Reference[model.selection(ResultBox_1, exp.current())] = True + exp.next() +# Faces of another box +ResultBox_2 = LinearCopy_1.result().subResult(1).resultSubShapePair()[0] +exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.FACE) +while exp.more(): + Reference[model.selection(ResultBox_2, exp.current())] = False + exp.next() +# Faces of the cylinder +ResultCylinder_1 = Translation_1.result().resultSubShapePair()[0] +exp = GeomAPI_ShapeExplorer(ResultCylinder_1.shape(), GeomAPI_Shape.FACE) +while exp.more(): + Reference[model.selection(ResultCylinder_1, exp.current())] = True + exp.next() +# Edges of the original box +exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.EDGE) +while exp.more(): + Reference[model.selection(ResultBox_1, exp.current())] = True + exp.next() +# Edges of another box +exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.EDGE) +while exp.more(): + Reference[model.selection(ResultBox_2, exp.current())] = False + exp.next() +# Edges of the cylinder +exp = GeomAPI_ShapeExplorer(ResultCylinder_1.shape(), GeomAPI_Shape.EDGE) +while exp.more(): + Reference[model.selection(ResultCylinder_1, exp.current())] = True + exp.next() +# Vertices of the original box +exp = GeomAPI_ShapeExplorer(ResultBox_1.shape(), GeomAPI_Shape.VERTEX) +while exp.more(): + Reference[model.selection(ResultBox_1, exp.current())] = True + exp.next() +# Vertices of another box +exp = GeomAPI_ShapeExplorer(ResultBox_2.shape(), GeomAPI_Shape.VERTEX) +while exp.more(): + Reference[model.selection(ResultBox_2, exp.current())] = False + exp.next() +# Vertices of the cylinder +exp = GeomAPI_ShapeExplorer(ResultCylinder_1.shape(), GeomAPI_Shape.VERTEX) +while exp.more(): + Reference[model.selection(ResultCylinder_1, exp.current())] = True + exp.next() + +model.checkFilter(Part_1_doc, model, Filters, Reference) diff --git a/src/FiltersPlugin/Test/TestFilter_HorizontalFaces.py b/src/FiltersPlugin/Test/TestFilter_HorizontalFaces.py new file mode 100644 index 000000000..d019ff82d --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_HorizontalFaces.py @@ -0,0 +1,63 @@ +# 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 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) +LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 20, 2, model.selection("EDGE", "PartSet/OY"), 20, 3) +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"), 50) +Filters = model.filters(Part_1_doc, [model.addFilter(name = "HorizontalFaces")]) +model.end() + +Reference = { + # Faces of the original box + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Top"): True, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom"): True, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Front"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Back"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Right"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Left"): False, + # Translated box + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Top"): True, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Bottom"): True, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Front"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Back"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Right"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Left"): False, + # Box translated along another direction + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Top"): True, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Bottom"): True, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Front"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Back"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Right"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Left"): False, + # Faces of the cylinder + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"): False, + 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 and vertices are not applicable + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): False, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): False, + } +model.checkFilter(Part_1_doc, model, Filters, Reference) diff --git a/src/FiltersPlugin/Test/TestFilter_OnPlane.py b/src/FiltersPlugin/Test/TestFilter_OnPlane.py new file mode 100644 index 000000000..fa07283fc --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_OnPlane.py @@ -0,0 +1,108 @@ +# 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 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) +LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 20, 2, model.selection("EDGE", "PartSet/OY"), 20, 3) +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"), 50) +Filters = model.filters(Part_1_doc, [model.addFilter(name = "OnPlane", args = [model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Top"), model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Left")])]) +model.end() + +Reference = { + # Faces of the original box + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Top"): True, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Front"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Back"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Right"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Left"): True, + # Translated box + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Top"): True, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Bottom"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Front"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Back"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Right"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Left"): True, + # Box translated along another direction + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Top"): True, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Bottom"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Front"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Back"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Right"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Left"): False, + # Faces of the cylinder + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"): False, + 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"): False, + # Edges of the original box + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Left]"): True, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Left]"): True, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right]"): False, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right]"): False, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): True, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): False, + # Edges of translated box + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Left][LinearCopy_1_1_6/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Right][LinearCopy_1_1_6/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Front][LinearCopy_1_1_6/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Back][LinearCopy_1_1_6/MF:Translated&Box_1_1/Top]"): True, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Back][LinearCopy_1_1_6/MF:Translated&Box_1_1/Left]"): False, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Front][LinearCopy_1_1_6/MF:Translated&Box_1_1/Left]"): False, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Front][LinearCopy_1_1_6/MF:Translated&Box_1_1/Right]"): False, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Back][LinearCopy_1_1_6/MF:Translated&Box_1_1/Right]"): False, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Left][LinearCopy_1_1_6/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Right][LinearCopy_1_1_6/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Front][LinearCopy_1_1_6/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("EDGE", "[LinearCopy_1_1_6/MF:Translated&Box_1_1/Back][LinearCopy_1_1_6/MF:Translated&Box_1_1/Bottom]"): 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]"): False, + 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 original box + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Front][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): False, + # Vertices of translated box + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Front][LinearCopy_1_1_5/MF:Translated&Box_1_1/Left][LinearCopy_1_1_5/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Back][LinearCopy_1_1_5/MF:Translated&Box_1_1/Left][LinearCopy_1_1_5/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Front][LinearCopy_1_1_5/MF:Translated&Box_1_1/Right][LinearCopy_1_1_5/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Back][LinearCopy_1_1_5/MF:Translated&Box_1_1/Right][LinearCopy_1_1_5/MF:Translated&Box_1_1/Top]"): True, + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Front][LinearCopy_1_1_5/MF:Translated&Box_1_1/Left][LinearCopy_1_1_5/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Back][LinearCopy_1_1_5/MF:Translated&Box_1_1/Left][LinearCopy_1_1_5/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Front][LinearCopy_1_1_5/MF:Translated&Box_1_1/Right][LinearCopy_1_1_5/MF:Translated&Box_1_1/Bottom]"): False, + model.selection("VERTEX", "[LinearCopy_1_1_5/MF:Translated&Box_1_1/Back][LinearCopy_1_1_5/MF:Translated&Box_1_1/Right][LinearCopy_1_1_5/MF:Translated&Box_1_1/Bottom]"): False, + } +model.checkFilter(Part_1_doc, model, Filters, Reference) diff --git a/src/FiltersPlugin/Test/TestFilter_VerticalFaces.py b/src/FiltersPlugin/Test/TestFilter_VerticalFaces.py new file mode 100644 index 000000000..b60dfdbc2 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilter_VerticalFaces.py @@ -0,0 +1,63 @@ +# 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 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) +LinearCopy_1 = model.addMultiTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 20, 2, model.selection("EDGE", "PartSet/OY"), 20, 3) +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"), 50) +Filters = model.filters(Part_1_doc, [model.addFilter(name = "VerticalFaces")]) +model.end() + +Reference = { + # Faces of the original box + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Top"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom"): False, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Front"): True, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Back"): True, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Right"): True, + model.selection("FACE", "LinearCopy_1_1_1/MF:Translated&Box_1_1/Left"): True, + # Translated box + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Top"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Bottom"): False, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Front"): True, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Back"): True, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Right"): True, + model.selection("FACE", "LinearCopy_1_1_2/MF:Translated&Box_1_1/Left"): True, + # Box translated along another direction + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Top"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Bottom"): False, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Front"): True, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Back"): True, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Right"): True, + model.selection("FACE", "LinearCopy_1_1_3/MF:Translated&Box_1_1/Left"): True, + # Faces of the cylinder + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_1"): False, + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_2"): False, + model.selection("FACE", "Translation_1_1/MF:Translated&Cylinder_1_1/Face_3"): False, + # Edges and vertices are not applicable + model.selection("EDGE", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Left][LinearCopy_1_1_1/MF:Translated&Box_1_1/Top]"): False, + model.selection("VERTEX", "[LinearCopy_1_1_1/MF:Translated&Box_1_1/Back][LinearCopy_1_1_1/MF:Translated&Box_1_1/Right][LinearCopy_1_1_1/MF:Translated&Box_1_1/Bottom]"): False, + } +model.checkFilter(Part_1_doc, model, Filters, Reference) diff --git a/src/FiltersPlugin/Test/TestFilters.py b/src/FiltersPlugin/Test/TestFilters.py new file mode 100644 index 000000000..c08497fe8 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilters.py @@ -0,0 +1,37 @@ +# 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 salome.shaper import model +from ModelAPI import * + +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) +Group_1 = model.addGroup(Part_1_doc, [model.selection("FACE", "Box_1_1/Bottom"), model.selection("FACE", "Box_1_1/Top"), model.filters(Part_1_doc, [model.addFilter(name = "BelongsTo", args = []), model.addFilter(name = "HorizontalFaces")])]) +model.end() + +aFactory = ModelAPI_Session.get().validators() + +GroupFeature = Group_1.feature() +assert(aFactory.validate(GroupFeature)) +assert(GroupFeature.selectionList("group_list").size() == 2) + +assert(model.checkPythonDump()) diff --git a/src/Model/Model_Session.cpp b/src/Model/Model_Session.cpp index 5a8f6f736..c555fac10 100644 --- a/src/Model/Model_Session.cpp +++ b/src/Model/Model_Session.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/ModelAPI/ModelAPI.i b/src/ModelAPI/ModelAPI.i index b08f5daf1..505045649 100644 --- a/src/ModelAPI/ModelAPI.i +++ b/src/ModelAPI/ModelAPI.i @@ -65,6 +65,7 @@ %shared_ptr(ModelAPI_Feature) %shared_ptr(ModelAPI_CompositeFeature) %shared_ptr(ModelAPI_Data) +%shared_ptr(ModelAPI_FiltersFeature) %shared_ptr(ModelAPI_Folder) %shared_ptr(ModelAPI_Attribute) %shared_ptr(ModelAPI_AttributeDocRef) @@ -157,6 +158,10 @@ %include "ModelAPI_ResultParameter.h" %include "ModelAPI_Tools.h" %include "ModelAPI_Folder.h" +%include "ModelAPI_Filter.h" +%include "ModelAPI_FiltersArgs.h" +%include "ModelAPI_FiltersFactory.h" +%include "ModelAPI_FiltersFeature.h" // std::list -> [] %template(StringList) std::list; diff --git a/src/ModelAPI/ModelAPI_swig.h b/src/ModelAPI/ModelAPI_swig.h index 243359d68..2187c2ae4 100644 --- a/src/ModelAPI/ModelAPI_swig.h +++ b/src/ModelAPI/ModelAPI_swig.h @@ -59,6 +59,10 @@ #include "ModelAPI_ResultField.h" #include "ModelAPI_Tools.h" #include "ModelAPI_Folder.h" + #include "ModelAPI_Filter.h" + #include "ModelAPI_FiltersArgs.h" + #include "ModelAPI_FiltersFactory.h" + #include "ModelAPI_FiltersFeature.h" #include #include diff --git a/src/PythonAPI/model/tests/tests.py b/src/PythonAPI/model/tests/tests.py index 0a99e7c48..17fd989eb 100644 --- a/src/PythonAPI/model/tests/tests.py +++ b/src/PythonAPI/model/tests/tests.py @@ -20,7 +20,8 @@ from GeomAlgoAPI import * from GeomAPI import * from GeomDataAPI import * -from ModelAPI import ModelAPI_Feature +from ModelAPI import ModelAPI_Feature, ModelAPI_Session +from ModelHighAPI import * import math from salome.shaper.model import sketcher @@ -321,3 +322,32 @@ def checkGroup(theGroup, theShapeType): assert(name != ""), "String empty" presented_names.add(name) assert(len(presented_names) == groupSelectionList.size()), "Some names are not unique" + +def createSubShape(thePartDoc, theModel, theSelection): + """ Create feature according to the type of the given subshape + """ + if theSelection.shapeType() == "VERTEX": + return theModel.addVertex(thePartDoc, [theSelection]) + elif theSelection.shapeType() == "EDGE": + return theModel.addEdge(thePartDoc, [theSelection]) + elif theSelection.shapeType() == "FACE": + return theModel.addFace(thePartDoc, [theSelection]) + +def checkFilter(thePartDoc, theModel, theFilter, theShapesList): + """ Check filter's work on specified shape. + Shapes given as a dictionary of selection and expected result. + """ + aFiltersFactory = ModelAPI_Session.get().filters() + for sel, res in theShapesList.items(): + needUndo = False + if sel.variantType() == ModelHighAPI_Selection.VT_ResultSubShapePair: + shape = sel.resultSubShapePair()[1] + else: + needUndo = True + theModel.begin() + subShapeFeature = createSubShape(thePartDoc, theModel, sel) + theModel.end() + shape = subShapeFeature.results()[0].resultSubShapePair()[0].shape() + assert(aFiltersFactory.isValid(theFilter.feature(), shape) == res) + if needUndo: + theModel.undo() -- 2.39.2