From 33cc397d2c9451088abc265617698299c124bf00 Mon Sep 17 00:00:00 2001 From: NATHALIE GORE Date: Wed, 6 Nov 2019 11:18:23 +0100 Subject: [PATCH] Start to add a new filter on planar faces --- src/FiltersPlugin/CMakeLists.txt | 2 + src/FiltersPlugin/FiltersPlugin_Plugin.cpp | 1 + .../FiltersPlugin_SameNormalFaces.py | 122 ++++++++++++++++++ src/FiltersPlugin/doc/FiltersPlugin.rst | 12 +- src/FiltersPlugin/filter-SameNormalFaces.xml | 9 ++ 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/FiltersPlugin/FiltersPlugin_SameNormalFaces.py create mode 100644 src/FiltersPlugin/filter-SameNormalFaces.xml diff --git a/src/FiltersPlugin/CMakeLists.txt b/src/FiltersPlugin/CMakeLists.txt index 9e9977276..904f5f65d 100644 --- a/src/FiltersPlugin/CMakeLists.txt +++ b/src/FiltersPlugin/CMakeLists.txt @@ -64,6 +64,7 @@ SET(PROJECT_LIBRARIES SET(PROJECT_PYFILES FiltersPlugin_TopoConnectedFaces.py + FiltersPlugin_SameNormalFaces.py ) SET(XML_RESOURCES @@ -76,6 +77,7 @@ SET(XML_RESOURCES filter-OppositeToEdge.xml filter-RelativeToSolid.xml filter-TopoConnectedFaces.xml + filter-SameNormalFaces.xml ) ADD_DEFINITIONS(-DFILTERS_EXPORTS ${OpenCASCADE_DEFINITIONS}) diff --git a/src/FiltersPlugin/FiltersPlugin_Plugin.cpp b/src/FiltersPlugin/FiltersPlugin_Plugin.cpp index e7bc6a9ad..28291eddf 100644 --- a/src/FiltersPlugin/FiltersPlugin_Plugin.cpp +++ b/src/FiltersPlugin/FiltersPlugin_Plugin.cpp @@ -56,6 +56,7 @@ FiltersPlugin_Plugin::FiltersPlugin_Plugin() aFactory->registerFilter("ExternalFaces", new FiltersPlugin_ExternalFaces); Config_ModuleReader::loadScript("FiltersPlugin_TopoConnectedFaces"); + Config_ModuleReader::loadScript("FiltersPlugin_SameNormalFaces"); // register validators ModelAPI_ValidatorsFactory* aValidators = aMgr->validators(); diff --git a/src/FiltersPlugin/FiltersPlugin_SameNormalFaces.py b/src/FiltersPlugin/FiltersPlugin_SameNormalFaces.py new file mode 100644 index 000000000..8405213c8 --- /dev/null +++ b/src/FiltersPlugin/FiltersPlugin_SameNormalFaces.py @@ -0,0 +1,122 @@ +# 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 ModelAPI import * +from GeomAPI import * +from GeomAlgoAPI import GeomAlgoAPI_MapShapesAndAncestors as mapShapesAndAncestors + +FILTER_ID = "SameNormalFaces" + +def singleton(cls): + instance = cls() + instance.__call__ = lambda: instance + return instance + +@singleton +class FiltersPlugin_SameNormalFaces(ModelAPI_Filter): + """ + Filter for faces topologically connected to the selected object. + """ + + def __init__(self): + """x.__init__(...) initializes x; see x.__class__.__doc__ for signature""" + ModelAPI_Filter.__init__(self) + self.myCached = {} + + def name(self): + """ Description of the filter """ + return "Same normal faces" + + def isSupported(self, theType): + """ Supported types of filtered shapes """ + return theType == GeomAPI_Shape.FACE + + def isOk(self, theShape, theResult, theArgs): + """ True if theShape is applicable for the filter """ + selectedShapeAttr = modelAPI_AttributeSelection(theArgs.argument("Shape")) + if selectedShapeAttr is None: + return False + selectedShape = selectedShapeAttr.value() + isPropagated = modelAPI_AttributeBoolean(theArgs.argument("Propagation")).value() + + # cache selected shape and applicable faces + if selectedShape not in self.myCached: + anOwner = bodyOwner(theResult, True) + if anOwner is None: + anOwner = modelAPI_ResultBody(theResult) + if anOwner is None: + return False + topLevelShape = anOwner.shape() + if not topLevelShape.isSubShape(selectedShape): + return False; + + mapVFAlgo = mapShapesAndAncestors(topLevelShape, GeomAPI_Shape.VERTEX, GeomAPI_Shape.FACE) + mapVF = mapVFAlgo.map() + mapEFAlgo = mapShapesAndAncestors(topLevelShape, GeomAPI_Shape.EDGE, GeomAPI_Shape.FACE) + mapEF = mapEFAlgo.map() + + # faces adjacent to the selected shape + applicableFaces = OriShapeSet() + if selectedShape.shapeType() == GeomAPI_Shape.VERTEX: + if selectedShape in mapVF: applicableFaces = mapVF[selectedShape] + elif selectedShape.shapeType() == GeomAPI_Shape.EDGE: + if selectedShape in mapEF: applicableFaces = mapEF[selectedShape] + elif selectedShape.shapeType() == GeomAPI_Shape.FACE: + applicableFaces.insert(selectedShape) + self.adjacentFaces(selectedShape, mapVF, GeomAPI_Shape.VERTEX, applicableFaces, False) + else: + return False + # propagate the connection + if isPropagated: + appFacesCopy = applicableFaces + for ind in range(appFacesCopy.size()): + self.adjacentFaces(appFacesCopy[ind], mapEF, GeomAPI_Shape.EDGE, applicableFaces) + self.myCached[selectedShape] = applicableFaces + + return theShape in self.myCached[selectedShape] + + def xmlRepresentation(self): + """ Returns XML string which represents GUI of the filter """ + return self.xmlFromFile("filter-SameNormalFaces.xml") + + def initAttributes(self, theArgs): + """ Initializes arguments of a filter """ + theArgs.initAttribute("Shape", ModelAPI_AttributeSelection_typeId()) + theArgs.initAttribute("Propagation", ModelAPI_AttributeBoolean_typeId()) + + def adjacentFaces(self, theFace, theMapSA, theShapeType, theApplicableFaces, theRecursive = True): + """ Find all faces neighbour to theFace """ + exp = GeomAPI_ShapeExplorer(theFace, theShapeType) + while exp.more(): + if exp.current() in theMapSA: + faces = theMapSA[exp.current()] + for ind in range(faces.size()): + f = faces[ind] + if f not in theApplicableFaces: + theApplicableFaces.insert(f) + if theRecursive: + self.adjacentFaces(f, theMapSA, theShapeType, theApplicableFaces) + exp.next() + + +# Register the filter object +filter = FiltersPlugin_SameNormalFaces +aSession = ModelAPI_Session.get() +aSession.filters().registerFilter(FILTER_ID, filter) diff --git a/src/FiltersPlugin/doc/FiltersPlugin.rst b/src/FiltersPlugin/doc/FiltersPlugin.rst index 8e6d0babd..2cde97911 100644 --- a/src/FiltersPlugin/doc/FiltersPlugin.rst +++ b/src/FiltersPlugin/doc/FiltersPlugin.rst @@ -135,4 +135,14 @@ This algorithm finds all the faces topologically connected the argument selected - **Arguments:** A point, an edge or a face. A “propagation” flag (check-box). - **Algorithm:** - If a point of an edge is selected as an argument, the result is all faces that contain this argument.If a face is selected, the result is all faces that have shared edges or vertices with this selection. - - If “propagation” flag is enabled (it is disabled by default), the algorithm becomes recursive: all connected faces are added to the results. So, for the solid shape there will be all faces except internal-volumes faces, not connected to any external faces. \ No newline at end of file + - If “propagation” flag is enabled (it is disabled by default), the algorithm becomes recursive: all connected faces are added to the results. So, for the solid shape there will be all faces except internal-volumes faces, not connected to any external faces. + +**Same normal Faces** + +This algorithm finds all the planar faces with the same normal than the argument selected by the user. + +- **Result type:** Face +- **Arguments:** A planar Face. +- **Algorithm:** + - If a point of an edge is selected as an argument, the result is all faces that contain this argument.If a face is selected, the result is all faces that have shared edges or vertices with this selection. + - If “propagation” flag is enabled (it is disabled by default), the algorithm becomes recursive: all connected faces are added to the results. So, for the solid shape there will be all faces except internal-volumes faces, not connected to any external faces. diff --git a/src/FiltersPlugin/filter-SameNormalFaces.xml b/src/FiltersPlugin/filter-SameNormalFaces.xml new file mode 100644 index 000000000..6bdeb22c3 --- /dev/null +++ b/src/FiltersPlugin/filter-SameNormalFaces.xml @@ -0,0 +1,9 @@ + + + + + + -- 2.39.2