From 54ff377298a07d18bec1ed7bb2946e44247eb94c Mon Sep 17 00:00:00 2001 From: jfa Date: Wed, 16 Feb 2022 22:06:08 +0300 Subject: [PATCH] bos #26374 In python, be able to use filters to select sub-shapes --- src/FiltersAPI/FiltersAPI_Selection.cpp | 32 ++++++++++ src/FiltersAPI/FiltersAPI_Selection.h | 6 ++ src/FiltersPlugin/Test/TestFilters_Select.py | 64 +++++++++++++++++++ src/FiltersPlugin/tests.set | 1 + src/GeomAPI/GeomAPI_Shape.cpp | 20 ++++-- src/GeomAPI/GeomAPI_Shape.h | 6 +- src/Model/Model_FiltersFactory.cpp | 54 ++++++++++++++++ src/Model/Model_FiltersFactory.h | 10 ++- src/ModelAPI/ModelAPI_FiltersFactory.h | 10 ++- .../ModuleBase_WidgetSelectionFilter.cpp | 64 ++++--------------- 10 files changed, 207 insertions(+), 60 deletions(-) create mode 100644 src/FiltersPlugin/Test/TestFilters_Select.py diff --git a/src/FiltersAPI/FiltersAPI_Selection.cpp b/src/FiltersAPI/FiltersAPI_Selection.cpp index 09eee7deb..378365131 100644 --- a/src/FiltersAPI/FiltersAPI_Selection.cpp +++ b/src/FiltersAPI/FiltersAPI_Selection.cpp @@ -19,6 +19,11 @@ #include "FiltersAPI_Selection.h" +#include "GeomAPI_Edge.h" +#include "ModelAPI_Session.h" +#include "ModelAPI_FiltersFactory.h" +#include "ModelHighAPI_Services.h" + FiltersAPI_Selection::FiltersAPI_Selection(const FiltersPtr & theFeature) { myVariantType = VT_Filtering; @@ -34,6 +39,33 @@ FiltersFeaturePtr FiltersAPI_Selection::feature() const return myFilterFeature; } +std::list FiltersAPI_Selection::select + (const std::string theShapeType) const +{ + return select(GeomAPI_Shape::shapeTypeByStr(theShapeType)); +} + +std::list FiltersAPI_Selection::select + (const GeomAPI_Shape::ShapeType theShapeType) const +{ + // finish operation to make sure the selection is done on the current state of the history + apply(); + + std::list aSelList; + static SessionPtr aSession = ModelAPI_Session::get(); + std::list< std::pair > aResList = + aSession->filters()->select(myFilterFeature, theShapeType); + + std::list< std::pair >::const_iterator itSelected = aResList.cbegin(); + for (; itSelected != aResList.cend(); itSelected++) { + ResultPtr aCurRes = (*itSelected).first; + GeomShapePtr aSubShape = (*itSelected).second; + aSelList.push_back(ModelHighAPI_Selection(aCurRes, aSubShape)); + } + + return aSelList; +} + // ================================================================================================ 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 9a9756a07..a520097f7 100644 --- a/src/FiltersAPI/FiltersAPI_Selection.h +++ b/src/FiltersAPI/FiltersAPI_Selection.h @@ -44,6 +44,12 @@ public: /// Return filters feature FILTERSAPI_EXPORT FiltersFeaturePtr feature() const; + + /// Return selected entities + FILTERSAPI_EXPORT + std::list select(const std::string theShapeType) const; + FILTERSAPI_EXPORT + std::list select(const GeomAPI_Shape::ShapeType theShapeType) const; }; /// Create list of filters diff --git a/src/FiltersPlugin/Test/TestFilters_Select.py b/src/FiltersPlugin/Test/TestFilters_Select.py new file mode 100644 index 000000000..165ede3a6 --- /dev/null +++ b/src/FiltersPlugin/Test/TestFilters_Select.py @@ -0,0 +1,64 @@ +# Copyright (C) 2014-2021 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 * +from GeomAPI import * +from ModelHighAPI import * +import math + +model.begin() +partSet = model.moduleDocument() +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +### Create Box +Box_1 = model.addBox(Part_1_doc, 10, 10, 10) +model.do() + +### Create Filters +filter_1 = model.addFilter(name = "OnPlane", + args = [model.selection("FACE", "Box_1_1/Left")]) + +filter_2 = model.addFilter(name = "OnPlane", + args = [model.selection("FACE", "Box_1_1/Top")]) + +filters = model.filters(Part_1_doc, [filter_1, filter_2]) + +### Select all (one) suitable edges +selected_edges = filters.select("Edges") + +group_1 = model.addGroup(Part_1_doc, "Edges", selected_edges) +assert(group_1.feature().results().size() == 1) + +# Check the selected edge +aResult = group_1.results()[0].resultSubShapePair()[0] +aShape = aResult.shape() +aShapeExplorer = GeomAPI_ShapeExplorer(aShape, GeomAPI_Shape.EDGE) +assert(aShapeExplorer.more()) +anEdge = aShapeExplorer.current() +assert(anEdge.edge().isLine() and math.fabs(anEdge.edge().line().direction().x() - 1.0) < 1.e-7) +aLoc = anEdge.edge().line().location() +assert(math.fabs(aLoc.x()) < 1.e-7) +assert(math.fabs(aLoc.y()) < 1.e-7) +assert(math.fabs(aLoc.z() - 10.0) < 1.e-7) +aShapeExplorer.next() +assert(not aShapeExplorer.more()) + +model.end() diff --git a/src/FiltersPlugin/tests.set b/src/FiltersPlugin/tests.set index 98aa0c340..2a61388bb 100644 --- a/src/FiltersPlugin/tests.set +++ b/src/FiltersPlugin/tests.set @@ -27,6 +27,7 @@ SET(TEST_NAMES TestFilters_FilterName.py TestFilters_IsReversed.py TestFilters_Remove.py + TestFilters_Select.py TestFilter_BelongsTo.py TestFilter_BelongsTo_Exclude.py TestFilter_OnPlane.py diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index 7168ccdb5..5e1c8f214 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -419,21 +419,25 @@ std::shared_ptr GeomAPI_Shape::solid() const } std::list > -GeomAPI_Shape::subShapes(ShapeType theSubShapeType) const +GeomAPI_Shape::subShapes(const ShapeType theSubShapeType, const bool theOnlyUnique) const { ListOfShape aSubs; const TopoDS_Shape& aShape = impl(); if (aShape.IsNull()) return aSubs; + TopTools_MapOfShape alreadyThere; + // process multi-level compounds if (shapeType() == COMPOUND && theSubShapeType == COMPOUND) { for (TopoDS_Iterator anIt(aShape); anIt.More(); anIt.Next()) { const TopoDS_Shape& aCurrent = anIt.Value(); if (aCurrent.ShapeType() == TopAbs_COMPOUND) { - GeomShapePtr aSub(new GeomAPI_Shape); - aSub->setImpl(new TopoDS_Shape(aCurrent)); - aSubs.push_back(aSub); + if (!theOnlyUnique || alreadyThere.Add(aCurrent)) { + GeomShapePtr aSub(new GeomAPI_Shape); + aSub->setImpl(new TopoDS_Shape(aCurrent)); + aSubs.push_back(aSub); + } } } // add self @@ -444,9 +448,11 @@ GeomAPI_Shape::subShapes(ShapeType theSubShapeType) const else { for (TopExp_Explorer anExp(aShape, (TopAbs_ShapeEnum)theSubShapeType); anExp.More(); anExp.Next()) { - GeomShapePtr aSub(new GeomAPI_Shape); - aSub->setImpl(new TopoDS_Shape(anExp.Current())); - aSubs.push_back(aSub); + if (!theOnlyUnique || alreadyThere.Add(anExp.Current())) { + GeomShapePtr aSub(new GeomAPI_Shape); + aSub->setImpl(new TopoDS_Shape(anExp.Current())); + aSubs.push_back(aSub); + } } } return aSubs; diff --git a/src/GeomAPI/GeomAPI_Shape.h b/src/GeomAPI/GeomAPI_Shape.h index fad3425c0..f8ed71971 100644 --- a/src/GeomAPI/GeomAPI_Shape.h +++ b/src/GeomAPI/GeomAPI_Shape.h @@ -156,8 +156,12 @@ public: std::shared_ptr solid() const; /// Returns list of sub-shapes of the given type + /// \param theSubShapeType type of sub-shapes to search. + /// \param theOnlyUnique set it to \c true to omit subsequent + /// inclusions of the same sub-shape. By default it is \c false. GEOMAPI_EXPORT - std::list > subShapes(ShapeType theSubShapeType) const; + std::list< std::shared_ptr > subShapes(const ShapeType theSubShapeType, + const bool theOnlyUnique = false) const; /// Returns the shape type GEOMAPI_EXPORT diff --git a/src/Model/Model_FiltersFactory.cpp b/src/Model/Model_FiltersFactory.cpp index df0f4e061..6c36f286e 100644 --- a/src/Model/Model_FiltersFactory.cpp +++ b/src/Model/Model_FiltersFactory.cpp @@ -23,6 +23,7 @@ #include "ModelAPI_AttributeSelectionList.h" #include +#include "GeomAPI_Edge.h" void Model_FiltersFactory::registerFilter(const std::string& theID, ModelAPI_Filter* theFilter) { @@ -112,6 +113,59 @@ bool Model_FiltersFactory::isValid(FeaturePtr theFiltersFeature, return true; } +std::list< std::pair > Model_FiltersFactory::select +(const FiltersFeaturePtr& theFilterFeature, + const GeomAPI_Shape::ShapeType theShapeType) +{ + std::list< std::pair > aResList; + + DocumentPtr aDoc = theFilterFeature->document(); + int aNb = aDoc->size(ModelAPI_ResultBody::group()); + ObjectPtr aObj; + ResultBodyPtr aBody; + for (int i = 0; i < aNb; i++) { + aObj = aDoc->object(ModelAPI_ResultBody::group(), i); + aBody = std::dynamic_pointer_cast(aObj); + GeomShapePtr aShape = aBody->shape(); + std::list aSubShapes = aShape->subShapes(theShapeType, true); + std::list::const_iterator aShapesIt; + for (aShapesIt = aSubShapes.cbegin(); aShapesIt != aSubShapes.cend(); aShapesIt++) { + GeomShapePtr aSubShape = (*aShapesIt); + + // degenerated edge is not valid selection + if (theShapeType == GeomAPI_Shape::EDGE) + if (aSubShape->edge()->isDegenerated()) + continue; + + bool isValid = this->isValid(theFilterFeature, aBody, aSubShape); + + if (isValid) { + // bos #24043: Naming on a compsolid works wrong. + // Find a simple sub-result for the ViewerPrs context: + ResultBodyPtr aContext = aBody; + bool isComposite = aContext->numberOfSubs() > 0; + while (isComposite) { + isComposite = false; + int nbSubs = aContext->numberOfSubs(); + for (int aSubIndex = 0; aSubIndex < nbSubs; aSubIndex++) { + ResultBodyPtr aSubResult = aContext->subResult(aSubIndex); + GeomShapePtr aSubResultShape = aSubResult->shape(); + if (aSubResultShape->isSubShape(aSubShape)) { + aContext = aSubResult; + isComposite = aContext->numberOfSubs() > 0; + break; + } + } + } + std::pair aPair (aContext, aSubShape); + aResList.push_back(aPair); + } + } + } + + return aResList; +} + /// Returns list of filters for the given shape type /// \param theType a shape type std::list Model_FiltersFactory::filters(GeomAPI_Shape::ShapeType theType) diff --git a/src/Model/Model_FiltersFactory.h b/src/Model/Model_FiltersFactory.h index d272d0a47..8dab74276 100644 --- a/src/Model/Model_FiltersFactory.h +++ b/src/Model/Model_FiltersFactory.h @@ -47,6 +47,14 @@ public: ResultPtr theResult, GeomShapePtr theShape); + /// Returns list of all shapes and subshapes in the study, satisfying + /// criteria of all filters of \a theFilterFeature. + /// \param theFiltersFeature feature that contains all information about the filters + /// \param theShapeType the type of sub-shapes to find + virtual std::list< std::pair > select + (const FiltersFeaturePtr& theFilterFeature, + const GeomAPI_Shape::ShapeType theShapeType); + /// Returns the filters that support the given shape type virtual std::list filters(GeomAPI_Shape::ShapeType theType); @@ -66,4 +74,4 @@ private: friend class Model_Session; }; -#endif \ No newline at end of file +#endif diff --git a/src/ModelAPI/ModelAPI_FiltersFactory.h b/src/ModelAPI/ModelAPI_FiltersFactory.h index 70b93bb09..d82a738c8 100644 --- a/src/ModelAPI/ModelAPI_FiltersFactory.h +++ b/src/ModelAPI/ModelAPI_FiltersFactory.h @@ -50,6 +50,14 @@ public: ResultPtr theResult, GeomShapePtr theShape) = 0; + /// Returns list of all shapes and subshapes in the study, satisfying + /// criteria of all filters of \a theFilterFeature. + /// \param theFiltersFeature feature that contains all information about the filters + /// \param theShapeType the type of sub-shapes to find + virtual std::list< std::pair > select + (const FiltersFeaturePtr& theFilterFeature, + const GeomAPI_Shape::ShapeType theShapeType) = 0; + /// Returns the filters that support the given shape type virtual std::list filters(GeomAPI_Shape::ShapeType theType) = 0; @@ -64,4 +72,4 @@ protected: ModelAPI_FiltersFactory() {} }; -#endif \ No newline at end of file +#endif diff --git a/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp b/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp index acfc5c633..e027461f6 100644 --- a/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp +++ b/src/ModuleBase/ModuleBase_WidgetSelectionFilter.cpp @@ -454,60 +454,24 @@ void ModuleBase_WidgetSelectionFilter::onSelect() clearCurrentSelection(); + FiltersFeaturePtr aFiltersFeature = + std::dynamic_pointer_cast(myFeature); + static SessionPtr aSession = ModelAPI_Session::get(); + std::list< std::pair > aResList = + aSession->filters()->select(aFiltersFeature, (GeomAPI_Shape::ShapeType)mySelectionType); + BRep_Builder aBuilder; TopoDS_Compound aComp; aBuilder.MakeCompound(aComp); - DocumentPtr aDoc = myFeature->document(); - int aNb = aDoc->size(ModelAPI_ResultBody::group()); - ObjectPtr aObj; - ResultBodyPtr aBody; - for (int i = 0; i < aNb; i++) { - aObj = aDoc->object(ModelAPI_ResultBody::group(), i); - aBody = std::dynamic_pointer_cast(aObj); - GeomShapePtr aShape = aBody->shape(); - std::list aSubShapes = - aShape->subShapes((GeomAPI_Shape::ShapeType)mySelectionType); - TopTools_MapOfShape alreadyThere; - std::list::const_iterator aShapesIt; - for (aShapesIt = aSubShapes.cbegin(); aShapesIt != aSubShapes.cend(); aShapesIt++) { - GeomShapePtr aSubShape = (*aShapesIt); - TopoDS_Shape aTShape = aSubShape->impl(); - if (!alreadyThere.Add(aTShape)) - continue; - - // degenerated edge is not valid selection - if ((GeomAPI_Shape::ShapeType)mySelectionType == GeomAPI_Shape::EDGE) - if (aSubShape->edge()->isDegenerated()) - continue; - - static SessionPtr aSession = ModelAPI_Session::get(); - bool isValid = aSession->filters()->isValid(myFeature, aBody, aSubShape); - - if (isValid) { - aBuilder.Add(aComp, aTShape); - // bos #24043: Naming on a compsolid works wrong. - // Find a simple sub-result for the ViewerPrs context: - ResultBodyPtr aContext = aBody; - bool isComposite = aContext->numberOfSubs() > 0; - while (isComposite) { - isComposite = false; - int nbSubs = aContext->numberOfSubs(); - for (int aSubIndex = 0; aSubIndex < nbSubs; aSubIndex++) { - ResultBodyPtr aSubResult = aContext->subResult(aSubIndex); - GeomShapePtr aSubResultShape = aSubResult->shape(); - if (aSubResultShape->isSubShape(aSubShape)) { - aContext = aSubResult; - isComposite = aContext->numberOfSubs() > 0; - break; - } - } - } - ModuleBase_ViewerPrsPtr aValue(new ModuleBase_ViewerPrs(aContext, aSubShape)); - //ModuleBase_ViewerPrsPtr aValue(new ModuleBase_ViewerPrs(aObj, aSubShape)); - myValues.append(aValue); - } - } + std::list< std::pair >::const_iterator itSelected = aResList.cbegin(); + for (; itSelected != aResList.cend(); itSelected++) { + ResultPtr aCurRes = (*itSelected).first; + GeomShapePtr aSubShape = (*itSelected).second; + TopoDS_Shape aTShape = aSubShape->impl(); + aBuilder.Add(aComp, aTShape); + ModuleBase_ViewerPrsPtr aValue (new ModuleBase_ViewerPrs(aCurRes, aSubShape)); + myValues.append(aValue); } if (myValues.size() > 0) -- 2.39.2