Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAPI / GeomAPI_ShapeHierarchy.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 "GeomAPI_ShapeHierarchy.h"
21
22 #include "GeomAPI_ShapeIterator.h"
23
24 #include <BRep_Builder.hxx>
25 #include <TopoDS_Shape.hxx>
26
27 void GeomAPI_ShapeHierarchy::addObject(const GeomShapePtr& theObject)
28 {
29   myObjects.push_back(theObject);
30 }
31
32 void GeomAPI_ShapeHierarchy::addParent(const GeomShapePtr& theShape,
33                                        const GeomShapePtr& theParent)
34 {
35   myParent[theShape] = theParent;
36
37   MapShapeToIndex::iterator aFound = myParentIndices.find(theParent);
38   size_t anIndex = myParentIndices.size();
39   if (aFound == myParentIndices.end()) {
40     myParentIndices[theParent] = anIndex;
41     mySubshapes.push_back(ShapeAndSubshapes(theParent, ListOfShape()));
42   } else
43     anIndex = aFound->second;
44
45   mySubshapes[anIndex].second.push_back(theShape);
46 }
47
48 GeomShapePtr GeomAPI_ShapeHierarchy::parent(const GeomShapePtr& theShape,
49                                             bool theMarkProcessed)
50 {
51   MapShapeToShape::const_iterator aFound = myParent.find(theShape);
52   GeomShapePtr aParent;
53   if (aFound != myParent.end()) {
54     aParent = aFound->second;
55     if (theMarkProcessed) {
56       // mark the parent and all its subs as processed by Boolean algorithm
57       markProcessed(aParent);
58     }
59   }
60   return aParent;
61 }
62
63 GeomShapePtr GeomAPI_ShapeHierarchy::root(const GeomShapePtr& theShape,
64                                           bool theMarkProcessed)
65 {
66   GeomShapePtr aParent = parent(theShape, theMarkProcessed);
67   GeomShapePtr aRoot = aParent;
68   while (aParent) {
69     aParent = parent(aRoot, theMarkProcessed);
70     if (aParent)
71       aRoot = aParent;
72   }
73   return aRoot;
74 }
75
76 void GeomAPI_ShapeHierarchy::markProcessed(const GeomShapePtr& theShape)
77 {
78   myProcessedObjects.insert(theShape);
79   // mark sub-shapes of the compound as processed too
80   MapShapeToIndex::iterator aFoundInd = myParentIndices.find(theShape);
81   if (aFoundInd != myParentIndices.end()) {
82     const ListOfShape& aSubs = mySubshapes[aFoundInd->second].second;
83     for (ListOfShape::const_iterator anIt = aSubs.begin(); anIt != aSubs.end(); ++anIt)
84       markProcessed(*anIt);
85   }
86 }
87
88 void GeomAPI_ShapeHierarchy::markProcessed(const ListOfShape& theShapes)
89 {
90   for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt)
91     markProcessed(*anIt);
92 }
93
94 void GeomAPI_ShapeHierarchy::markModified(const GeomShapePtr& theSource,
95                                           const GeomShapePtr& theModified)
96 {
97   myModifiedObjects[theSource] = theModified;
98 }
99
100 const ListOfShape& GeomAPI_ShapeHierarchy::objects(GeomShapePtr theParent) const
101 {
102   MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theParent);
103   if (aFoundIndex == myParentIndices.end()) {
104     static const ListOfShape THE_DUMMY = ListOfShape();
105     return THE_DUMMY; // no such shape
106   }
107
108   return mySubshapes[aFoundIndex->second].second;
109 }
110
111 void GeomAPI_ShapeHierarchy::objectsByType(
112     ListOfShape& theShapesByType,
113     ListOfShape& theOtherShapes,
114     const GeomAPI_Shape::ShapeType theMinType,
115     const GeomAPI_Shape::ShapeType theMaxType) const
116 {
117   if (theMinType > theMaxType)
118     return objectsByType(theShapesByType, theOtherShapes, theMaxType, theMinType);
119
120   // no need to select objects if whole range is specified
121   if (theMinType == GeomAPI_Shape::COMPOUND && theMaxType == GeomAPI_Shape::SHAPE) {
122     theShapesByType.insert(theShapesByType.end(), myObjects.begin(), myObjects.end());
123     return;
124   }
125
126   for (ListOfShape::const_iterator anIt = myObjects.begin(); anIt != myObjects.end(); ++anIt) {
127     GeomAPI_Shape::ShapeType aType = (*anIt)->shapeType();
128     if (aType >= theMinType && aType <= theMaxType)
129       theShapesByType.push_back(*anIt);
130     else
131       theOtherShapes.push_back(*anIt);
132   }
133 }
134
135
136 void GeomAPI_ShapeHierarchy::splitCompound(
137     const GeomShapePtr& theCompShape,
138     ListOfShape& theUsed,
139     ListOfShape& theNotUsed) const
140 {
141   theUsed.clear();
142   theNotUsed.clear();
143
144   MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(theCompShape);
145   if (aFoundIndex == myParentIndices.end())
146     return; // no such shape
147
148   theUsed = mySubshapes[aFoundIndex->second].second;
149   SetOfShape aSubsSet;
150   aSubsSet.insert(theUsed.begin(), theUsed.end());
151
152   for (GeomAPI_ShapeIterator anExp(theCompShape); anExp.more(); anExp.next()) {
153     GeomShapePtr aCurrent = anExp.current();
154     if (aSubsSet.find(aCurrent) == aSubsSet.end())
155       theNotUsed.push_back(aCurrent);
156   }
157 }
158
159 bool GeomAPI_ShapeHierarchy::empty() const
160 {
161   return myObjects.empty();
162 }
163
164 void GeomAPI_ShapeHierarchy::topLevelObjects(ListOfShape& theDestination) const
165 {
166   GeomAPI_ShapeHierarchy* aThis = const_cast<GeomAPI_ShapeHierarchy*>(this);
167   SetOfShape aProcessed = myProcessedObjects;
168   aThis->myProcessedObjects.clear();
169
170   iterator anIt = aThis->begin(), aEnd = aThis->end();
171   for (; anIt != aEnd; ++anIt) {
172     GeomShapePtr aShape = *anIt;
173     GeomShapePtr aRoot = aThis->root(aShape);
174     if (aRoot) {
175       // check the current shape was modified
176       MapShapeToShape::const_iterator aFound = myModifiedObjects.find(aRoot);
177       if (aFound != myModifiedObjects.end())
178         aShape = aFound->second;
179       else {
180         // compose a compund with the modified shapes
181         aShape = collectSubs(aRoot, SetOfShape(), myModifiedObjects);
182       }
183     }
184     else {
185       // check the current shape was modified
186       MapShapeToShape::const_iterator aFound = myModifiedObjects.find(aShape);
187       if (aFound != myModifiedObjects.end())
188         aShape = aFound->second;
189     }
190
191     theDestination.push_back(aShape);
192   }
193
194   aThis->myProcessedObjects = aProcessed;
195 }
196
197 void GeomAPI_ShapeHierarchy::compoundsOfUnusedObjects(
198     ListOfShape& theDestination) const
199 {
200   SetOfShape aUsedObjects = myProcessedObjects;
201   aUsedObjects.insert(myObjects.begin(), myObjects.end());
202
203   for (std::vector<ShapeAndSubshapes>::const_iterator anIt = mySubshapes.begin();
204        anIt != mySubshapes.end(); ++anIt) {
205     MapShapeToShape::const_iterator aParent = myParent.find(anIt->first);
206     if ((aParent == myParent.end() || !aParent->second) &&
207          anIt->first->shapeType() ==  GeomAPI_Shape::COMPOUND) {
208       // this is a top-level compound
209       GeomShapePtr aCompound = collectSubs(anIt->first, aUsedObjects);
210       // add to destination non-empty compounds only
211       if (aCompound)
212         theDestination.push_back(aCompound);
213     }
214   }
215 }
216
217 static void addSubShape(GeomShapePtr theTarget, GeomShapePtr theSub,
218     const std::map<GeomShapePtr, GeomShapePtr, GeomAPI_Shape::Comparator>& theModified)
219 {
220   if (!theTarget.get() || !theSub.get())
221     return;
222
223   TopoDS_Shape* aShape = theTarget->implPtr<TopoDS_Shape>();
224
225   std::map<GeomShapePtr, GeomShapePtr, GeomAPI_Shape::Comparator>::const_iterator
226     aFound = theModified.find(theSub);
227   const TopoDS_Shape& aShapeToAdd =
228       (aFound == theModified.end() ? theSub : aFound->second)->impl<TopoDS_Shape>();
229
230   static BRep_Builder aBuilder;
231   aBuilder.Add(*aShape, aShapeToAdd);
232 }
233
234 GeomShapePtr GeomAPI_ShapeHierarchy::collectSubs(
235     GeomShapePtr theTopLevelCompound,
236     const SetOfShape& theExcluded,
237     const MapShapeToShape& theModified) const
238 {
239   GeomShapePtr aResult = theTopLevelCompound->emptyCopied();
240   bool isResultEmpty = true;
241
242   for (GeomAPI_ShapeIterator aSub(theTopLevelCompound); aSub.more(); aSub.next()) {
243     GeomShapePtr aCurrent = aSub.current();
244     if (theExcluded.find(aCurrent) != theExcluded.end())
245       continue; // already used
246
247     MapShapeToIndex::const_iterator aFoundIndex = myParentIndices.find(aCurrent);
248     if (aCurrent->shapeType() > GeomAPI_Shape::COMPOUND ||
249         aFoundIndex == myParentIndices.end()) {
250       bool isAddShape = true;
251       // check compsolid is fully unused in the Boolean operation
252       if (aCurrent->shapeType() == GeomAPI_Shape::COMPSOLID) {
253         for (GeomAPI_ShapeIterator anIt(aCurrent); isAddShape && anIt.more(); anIt.next())
254           isAddShape = theExcluded.find(anIt.current()) == theExcluded.end();
255       }
256
257       if (isAddShape) { // low-level shape, add it
258         addSubShape(aResult, aCurrent, theModified);
259         isResultEmpty = false;
260       }
261     } else {
262       GeomShapePtr aCompound = collectSubs(aCurrent, theExcluded, theModified);
263       if (aCompound) {
264         addSubShape(aResult, aCompound, theModified);
265         isResultEmpty = false;
266       }
267     }
268   }
269   return isResultEmpty ? GeomShapePtr() : aResult;
270 }
271
272
273 GeomAPI_ShapeHierarchy::iterator GeomAPI_ShapeHierarchy::begin()
274 {
275   return iterator(this);
276 }
277
278 GeomAPI_ShapeHierarchy::iterator GeomAPI_ShapeHierarchy::end()
279 {
280   return iterator(this, false);
281 }
282
283 GeomAPI_ShapeHierarchy::iterator::iterator(
284     GeomAPI_ShapeHierarchy* theHierarchy, bool isBegin)
285   : myHierarchy(theHierarchy)
286 {
287   if (isBegin) {
288     myObject = myHierarchy->myObjects.begin();
289     skipAlreadyProcessed();
290   } else
291     myObject = myHierarchy->myObjects.end();
292 }
293
294 void GeomAPI_ShapeHierarchy::iterator::skipAlreadyProcessed()
295 {
296   while (myObject != myHierarchy->myObjects.end() &&
297          myHierarchy->myProcessedObjects.find(*myObject) != myHierarchy->myProcessedObjects.end())
298     ++myObject;
299 }
300
301 bool GeomAPI_ShapeHierarchy::iterator::operator==(const iterator& theOther) const
302 {
303   return myObject == theOther.myObject;
304 }
305
306 bool GeomAPI_ShapeHierarchy::iterator::operator!=(const iterator& theOther) const
307 {
308   return !operator==(theOther);
309 }
310
311 GeomAPI_ShapeHierarchy::iterator& GeomAPI_ShapeHierarchy::iterator::operator++()
312 {
313   ++myObject;
314   skipAlreadyProcessed();
315   return *this;
316 }
317
318 GeomAPI_ShapeHierarchy::iterator GeomAPI_ShapeHierarchy::iterator::operator++(int)
319 {
320   iterator aCurrent;
321   aCurrent.myHierarchy = myHierarchy;
322   aCurrent.myObject = myObject;
323
324   // increase iterator
325   operator++();
326
327   return aCurrent;
328 }
329
330 GeomShapePtr GeomAPI_ShapeHierarchy::iterator::operator*() const
331 {
332   myHierarchy->markProcessed(*myObject);
333   return *myObject;
334 }