Salome HOME
updated copyright message
[modules/shaper.git] / src / FiltersPlugin / FiltersPlugin_OppositeToEdge.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "FiltersPlugin_OppositeToEdge.h"
21
22 #include <ModelAPI_AttributeSelection.h>
23 #include <ModelAPI_ResultBody.h>
24 #include <ModelAPI_Tools.h>
25
26 #include <GeomAPI_Edge.h>
27 #include <GeomAPI_Shape.h>
28 #include <GeomAPI_ShapeExplorer.h>
29 #include <GeomAPI_Wire.h>
30 #include <GeomAPI_WireExplorer.h>
31
32 #include <map>
33
34 typedef std::map<GeomShapePtr, SetOfShapes, GeomAPI_Shape::Comparator> MapShapeAndAncestors;
35
36 static void mapEdgesAndFaces(const GeomShapePtr theShape, MapShapeAndAncestors& theMap)
37 {
38   GeomAPI_ShapeExplorer aFExp(theShape, GeomAPI_Shape::FACE);
39   for (; aFExp.more(); aFExp.next()) {
40     GeomShapePtr aFace = aFExp.current();
41     GeomAPI_ShapeExplorer aEExp(aFace, GeomAPI_Shape::EDGE);
42     for (; aEExp.more(); aEExp.next())
43       theMap[aEExp.current()].insert(aFace);
44   }
45 }
46
47 // Return edge in the quadratic face opposite to the given one.
48 // If the face is not quadratic, returns empty shape.
49 static GeomShapePtr oppositeEdgeInQuadFace(const GeomShapePtr theEdge,
50                                            const GeomShapePtr theFace)
51 {
52   static int THE_QUAD = 4;
53
54   int aNbEdges = 0;
55   int anOriginalEdgeIndex = -THE_QUAD;
56   GeomShapePtr anOppositeEdge;
57   GeomAPI_ShapeExplorer aWExp(theFace, GeomAPI_Shape::WIRE);
58   GeomWirePtr aWire = aWExp.current()->wire();
59   aWExp.next();
60   if (aWExp.more()) {
61     // face with a hole is not a quadrangle
62     return anOppositeEdge;
63   }
64
65   GeomAPI_WireExplorer anExp(aWire);
66   while (anExp.more()) {
67     if (anExp.current()->isSame(theEdge))
68       anOriginalEdgeIndex = aNbEdges;
69     else if (aNbEdges == anOriginalEdgeIndex + THE_QUAD / 2) {
70       if (anOriginalEdgeIndex < THE_QUAD)
71         anOppositeEdge = anExp.current();
72       if (aNbEdges >= THE_QUAD)
73         break;
74     }
75
76     ++aNbEdges;
77     anExp.next();
78     if (!anExp.more()) {
79       if (aNbEdges != THE_QUAD) {
80         // not quad face
81         anOppositeEdge = GeomShapePtr();
82         break;
83       }
84       if (!anOppositeEdge)
85         anExp.init(aWire);
86     }
87   }
88   return anOppositeEdge;
89 }
90
91 // Find all opposite edges for the given.
92 static void cacheOppositeEdge(const GeomShapePtr theEdge,
93                               const MapShapeAndAncestors& theEdgeToFaces,
94                               SetOfShapes& theCache)
95 {
96   MapShapeAndAncestors::const_iterator aFound = theEdgeToFaces.find(theEdge);
97   if (aFound == theEdgeToFaces.end())
98     return;
99
100   for (SetOfShapes::const_iterator aFIt = aFound->second.begin();
101        aFIt != aFound->second.end(); ++aFIt) {
102     GeomShapePtr anOpposite = oppositeEdgeInQuadFace(theEdge, *aFIt);
103     if (anOpposite && theCache.find(anOpposite) == theCache.end()) {
104       theCache.insert(anOpposite);
105       cacheOppositeEdge(anOpposite, theEdgeToFaces, theCache);
106     }
107   }
108 }
109
110 static void cacheOppositeEdges(const GeomShapePtr theTopLevelShape,
111                                const GeomShapePtr theEdge,
112                                SetOfShapes& theCache)
113 {
114   if (!theTopLevelShape || !theEdge)
115     return;
116
117   MapShapeAndAncestors anEdgesToFaces;
118   mapEdgesAndFaces(theTopLevelShape, anEdgesToFaces);
119
120   // keep the original edge
121   theCache.insert(theEdge);
122   // cache opposite edges
123   cacheOppositeEdge(theEdge, anEdgesToFaces, theCache);
124 }
125
126
127 bool FiltersPlugin_OppositeToEdge::isSupported(GeomAPI_Shape::ShapeType theType) const
128 {
129   return theType == GeomAPI_Shape::EDGE;
130 }
131
132 bool FiltersPlugin_OppositeToEdge::isOk(const GeomShapePtr& theShape, const ResultPtr&,
133                                         const ModelAPI_FiltersArgs& theArgs) const
134 {
135   AttributePtr aAttr = theArgs.argument("OppositeToEdge");
136   AttributeSelectionPtr aList = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(aAttr);
137   if (!aList.get())
138     return false;
139   GeomShapePtr anEdge = aList->value();
140   if (!myOriginalEdge || !myOriginalEdge->isSame(anEdge)) {
141     // new edge is selected, need to update the cache
142     const_cast<FiltersPlugin_OppositeToEdge*>(this)->myOriginalEdge = anEdge;
143     const_cast<FiltersPlugin_OppositeToEdge*>(this)->myCachedShapes.clear();
144   }
145
146   if (myCachedShapes.empty()) {
147     ResultBodyPtr aBaseResult = ModelAPI_Tools::bodyOwner(aList->context(), true);
148     if (!aBaseResult.get()) {
149       aBaseResult = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aList->context());
150       if (!aBaseResult.get())
151         return false;
152     }
153
154     cacheOppositeEdges(aBaseResult->shape(), anEdge,
155         const_cast<FiltersPlugin_OppositeToEdge*>(this)->myCachedShapes);
156   }
157
158   return myCachedShapes.find(theShape) != myCachedShapes.end();
159 }
160
161 std::string FiltersPlugin_OppositeToEdge::xmlRepresentation() const
162 {
163   return xmlFromFile("filter-OppositeToEdge.xml");
164 }
165
166 void FiltersPlugin_OppositeToEdge::initAttributes(ModelAPI_FiltersArgs& theArguments)
167 {
168   theArguments.initAttribute("OppositeToEdge", ModelAPI_AttributeSelection::typeId());
169 }