Salome HOME
Copyright update 2020
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_MakeShape.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
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 "GeomAlgoAPI_MakeShape.h"
21
22 #include <BOPAlgo_Builder.hxx>
23 #include <BRep_Tool.hxx>
24 #include <BRepBuilderAPI_MakeShape.hxx>
25 #include <BRepCheck_Analyzer.hxx>
26 #include <BRepGProp.hxx>
27 #include <GProp_GProps.hxx>
28 #include <Precision.hxx>
29 #include <TopExp_Explorer.hxx>
30 #include <TopTools_ListOfShape.hxx>
31 #include <TopTools_ListIteratorOfListOfShape.hxx>
32 #include <GeomAPI_ShapeExplorer.h>
33 #include <GeomAPI_ShapeIterator.h>
34 #include <TopoDS.hxx>
35 #include <TopoDS_Builder.hxx>
36 #include <TopoDS_Edge.hxx>
37
38 // new shape -> old shapes -> index in the old shape
39 typedef NCollection_DataMap<TopoDS_Shape,
40   NCollection_DataMap<TopoDS_Shape, int, TopTools_ShapeMapHasher>, TopTools_ShapeMapHasher>
41   MapNewToOld;
42 typedef
43   NCollection_DataMap<int, NCollection_DataMap<TopoDS_Shape, MapNewToOld, TopTools_ShapeMapHasher> >
44   HistoryMap;
45
46 //==================================================================================================
47 GeomAlgoAPI_MakeShape::GeomAlgoAPI_MakeShape()
48 : myBuilderType(Unknown),
49   myDone(false)
50 {
51   myHist = 0;
52 }
53
54 //==================================================================================================
55 GeomAlgoAPI_MakeShape::~GeomAlgoAPI_MakeShape()
56 {
57   if (myHist) {
58     delete (HistoryMap*)myHist;
59   }
60 }
61
62 //==================================================================================================
63 bool GeomAlgoAPI_MakeShape::isDone() const
64 {
65   return myDone;
66 }
67
68 //==================================================================================================
69 const GeomShapePtr GeomAlgoAPI_MakeShape::shape() const
70 {
71   return myShape;
72 }
73
74 //==================================================================================================
75 bool GeomAlgoAPI_MakeShape::isValid() const
76 {
77   BRepCheck_Analyzer aChecker(myShape->impl<TopoDS_Shape>());
78   return (aChecker.IsValid() == Standard_True);
79 }
80
81 //==================================================================================================
82 std::shared_ptr<GeomAPI_DataMapOfShapeShape> GeomAlgoAPI_MakeShape::mapOfSubShapes() const
83 {
84   return myMap;
85 }
86
87 //==================================================================================================
88 void GeomAlgoAPI_MakeShape::generated(const GeomShapePtr theOldShape,
89                                       ListOfShape& theNewShapes)
90 {
91   TopTools_ListOfShape aList;
92   if(myBuilderType == OCCT_BRepBuilderAPI_MakeShape) {
93     BRepBuilderAPI_MakeShape* aMakeShape = implPtr<BRepBuilderAPI_MakeShape>();
94     aList = aMakeShape->Generated(theOldShape->impl<TopoDS_Shape>());
95   } else if(myBuilderType == OCCT_BOPAlgo_Builder) {
96     BOPAlgo_Builder* aBOPBuilder = implPtr<BOPAlgo_Builder>();
97     aList = aBOPBuilder->Generated(theOldShape->impl<TopoDS_Shape>());
98   }
99   for(TopTools_ListIteratorOfListOfShape anIt(aList); anIt.More(); anIt.Next()) {
100     GeomShapePtr aShape(new GeomAPI_Shape());
101     aShape->setImpl(new TopoDS_Shape(anIt.Value()));
102     if (!isValidForHistory(aShape)) continue;
103     fixOrientation(aShape);
104     theNewShapes.push_back(aShape);
105   }
106 }
107
108 //==================================================================================================
109 void GeomAlgoAPI_MakeShape::modified(const GeomShapePtr theOldShape,
110                                      ListOfShape& theNewShapes)
111 {
112   TopTools_ListOfShape aList;
113   if(myBuilderType == OCCT_BRepBuilderAPI_MakeShape) {
114     BRepBuilderAPI_MakeShape* aMakeShape = implPtr<BRepBuilderAPI_MakeShape>();
115     try {
116       aList = aMakeShape->Modified(theOldShape->impl<TopoDS_Shape>());
117     } catch(Standard_NoSuchObject) {
118     }
119   } else if(myBuilderType == OCCT_BOPAlgo_Builder) {
120     BOPAlgo_Builder* aBOPBuilder = implPtr<BOPAlgo_Builder>();
121     aList = aBOPBuilder->Modified(theOldShape->impl<TopoDS_Shape>());
122   }
123   for(TopTools_ListIteratorOfListOfShape anIt(aList); anIt.More(); anIt.Next()) {
124     GeomShapePtr aShape(new GeomAPI_Shape());
125     aShape->setImpl(new TopoDS_Shape(anIt.Value()));
126     if (!isValidForHistory(aShape)) continue;
127     fixOrientation(aShape);
128     theNewShapes.push_back(aShape);
129   }
130 }
131
132 //==================================================================================================
133 bool GeomAlgoAPI_MakeShape::isDeleted(const GeomShapePtr theOldShape)
134 {
135   bool isDeleted = false;
136   if(myBuilderType == OCCT_BRepBuilderAPI_MakeShape) {
137     BRepBuilderAPI_MakeShape* aMakeShape = implPtr<BRepBuilderAPI_MakeShape>();
138     isDeleted = aMakeShape->IsDeleted(theOldShape->impl<TopoDS_Shape>()) == Standard_True;
139   } else if(myBuilderType == OCCT_BOPAlgo_Builder) {
140     BOPAlgo_Builder* aBOPBuilder = implPtr<BOPAlgo_Builder>();
141     isDeleted = aBOPBuilder->IsDeleted(theOldShape->impl<TopoDS_Shape>()) == Standard_True;
142   }
143
144   return isDeleted;
145 }
146
147 //==================================================================================================
148 void GeomAlgoAPI_MakeShape::setBuilderType(const BuilderType theBuilderType)
149 {
150   myBuilderType = theBuilderType;
151 }
152
153 //==================================================================================================
154 void GeomAlgoAPI_MakeShape::setDone(const bool theFlag)
155 {
156   myDone = theFlag;
157 }
158
159 //==================================================================================================
160 void GeomAlgoAPI_MakeShape::setShape(const GeomShapePtr theShape)
161 {
162   if(myShape.get() && myShape->isEqual(theShape)) {
163     return;
164   }
165
166   myShape = theShape;
167
168   // Filling data map to keep correct orientation of sub-shapes.
169   if(myShape.get()) {
170     if(myMap.get()) {
171       myMap->clear();
172     } else {
173       myMap.reset(new GeomAPI_DataMapOfShapeShape);
174     }
175
176     const TopoDS_Shape& aTopoDSShape = myShape->impl<TopoDS_Shape>();
177     for(TopExp_Explorer anExp(aTopoDSShape,TopAbs_VERTEX); anExp.More(); anExp.Next()) {
178       GeomShapePtr aCurrentShape(new GeomAPI_Shape());
179       aCurrentShape->setImpl(new TopoDS_Shape(anExp.Current()));
180       myMap->bind(aCurrentShape, aCurrentShape);
181     }
182     for(TopExp_Explorer anExp(aTopoDSShape,TopAbs_EDGE); anExp.More(); anExp.Next()) {
183       GeomShapePtr aCurrentShape(new GeomAPI_Shape());
184       aCurrentShape->setImpl(new TopoDS_Shape(anExp.Current()));
185       myMap->bind(aCurrentShape, aCurrentShape);
186     }
187     for(TopExp_Explorer anExp(aTopoDSShape,TopAbs_FACE); anExp.More(); anExp.Next()) {
188       GeomShapePtr aCurrentShape(new GeomAPI_Shape());
189       aCurrentShape->setImpl(new TopoDS_Shape(anExp.Current()));
190       myMap->bind(aCurrentShape, aCurrentShape);
191     }
192   } else {
193     if(myMap.get()) {
194       myMap->clear();
195     }
196   }
197 }
198
199 //==================================================================================================
200 bool GeomAlgoAPI_MakeShape::isValidForHistory(const GeomShapePtr theShape)
201 {
202   if (!theShape.get()) return false;
203
204   const TopoDS_Shape& aShape_ = theShape->impl<TopoDS_Shape>();
205   if (aShape_.IsNull()) return false;
206
207   if (aShape_.ShapeType() == TopAbs_EDGE) {
208     TopoDS_Edge anEdge_ = TopoDS::Edge(aShape_);
209     if (BRep_Tool::Degenerated(anEdge_)) return false;
210   }
211
212   return true;
213 }
214
215 //==================================================================================================
216 void GeomAlgoAPI_MakeShape::fixOrientation(GeomShapePtr& theShape) {
217   if (myMap->isBound(theShape)) theShape = myMap->find(theShape);
218 }
219
220 //==================================================================================================
221 void GeomAlgoAPI_MakeShape::initialize()
222 {
223   switch (myBuilderType) {
224     case OCCT_BRepBuilderAPI_MakeShape: {
225       myDone = implPtr<BRepBuilderAPI_MakeShape>()->IsDone() == Standard_True;
226       myShape.reset(new GeomAPI_Shape());
227       myShape->setImpl(new TopoDS_Shape(implPtr<BRepBuilderAPI_MakeShape>()->Shape()));
228       break;
229     }
230     case OCCT_BOPAlgo_Builder: {
231       myDone = true;
232       myShape.reset(new GeomAPI_Shape());
233       myShape->setImpl(new TopoDS_Shape(implPtr<BOPAlgo_Builder>()->Shape()));
234       break;
235     }
236   }
237
238   if(myMap.get()) {
239     myMap->clear();
240   } else {
241     myMap.reset(new GeomAPI_DataMapOfShapeShape);
242   }
243
244   const TopoDS_Shape& aTopoDSShape = myShape->impl<TopoDS_Shape>();
245   for(TopExp_Explorer anExp(aTopoDSShape,TopAbs_FACE); anExp.More(); anExp.Next()) {
246     GeomShapePtr aCurrentShape(new GeomAPI_Shape());
247     aCurrentShape->setImpl(new TopoDS_Shape(anExp.Current()));
248     myMap->bind(aCurrentShape, aCurrentShape);
249   }
250   myHist = 0;
251 }
252
253
254 //==================================================================================================
255 void GeomAlgoAPI_MakeShape::prepareNamingFaces()
256 {
257   long long index = 1;
258   GeomAPI_ShapeExplorer anExp(shape(), GeomAPI_Shape::FACE);
259   for(GeomAPI_ShapeExplorer anExp(shape(), GeomAPI_Shape::FACE); anExp.more(); anExp.next()) {
260     GeomShapePtr aFace = anExp.current();
261     myCreatedFaces["Face_" + std::to_string(index++)] = aFace;
262   }
263 }
264
265
266 //==================================================================================================
267 bool GeomAlgoAPI_MakeShape::checkValid(std::string theMessage)
268 {
269   // isValid() is called from this method
270   if (!isValid()) {
271     myError = theMessage + " :: resulting shape is not valid.";
272     return false;
273   }
274
275   // Check the number of volumes in myShape, make sure there's one and only one.
276   TopoDS_Shape aTopoDSShape = myShape->impl<TopoDS_Shape>();
277   int aNbVolumes = 0;
278   for(TopExp_Explorer anExp(aTopoDSShape,TopAbs_SOLID); anExp.More(); anExp.Next()) {
279     aNbVolumes ++;
280   }
281
282   if (aNbVolumes != 1) {
283     myError = theMessage +
284       " :: connexity error, the resulting shape is made of several separate solids.";
285     return false;
286   }
287
288   return true ;
289 }
290
291 //==================================================================================================
292 bool GeomAlgoAPI_MakeShape::isNewShapesCollected(GeomShapePtr theWholeOld,
293                                                  const int theShapeType)
294 {
295   if (!myHist)
296     return false;
297   HistoryMap* aHist = (HistoryMap*)myHist;
298   if (!aHist->IsBound(theShapeType))
299     return false;
300   return aHist->Find(theShapeType).IsBound(theWholeOld->impl<TopoDS_Shape>());
301 }
302
303 void GeomAlgoAPI_MakeShape::collectNewShapes(
304   GeomShapePtr theWholeOld, const int theShapeType)
305 {
306   if (!myHist)
307     myHist = new HistoryMap;
308   HistoryMap* aHist = (HistoryMap*)myHist;
309   if (!aHist->IsBound(theShapeType))
310     aHist->Bind(
311       theShapeType, NCollection_DataMap<TopoDS_Shape, MapNewToOld, TopTools_ShapeMapHasher>());
312   aHist->ChangeFind(theShapeType). // add a new in anyway
313     Bind(theWholeOld->impl<TopoDS_Shape>(), MapNewToOld());
314   MapNewToOld& aCurrent =
315     aHist->ChangeFind(theShapeType).ChangeFind(theWholeOld->impl<TopoDS_Shape>());
316   ListOfShape aNewList;
317   TopTools_MapOfShape aViewed; //avoid same shapes
318   GeomAPI_ShapeExplorer anExp(theWholeOld, GeomAPI_Shape::ShapeType(theShapeType));
319   for(int anIndexInWholeOld = 0; anExp.more(); anExp.next(), anIndexInWholeOld++) {
320     if (!aViewed.Add(anExp.current()->impl<TopoDS_Shape>()))
321       continue;
322     aNewList.clear();
323     modified(anExp.current(), aNewList);
324     for(ListOfShape::iterator aNew = aNewList.begin(); aNew != aNewList.end(); aNew++) {
325       const TopoDS_Shape& aNewShape = (*aNew)->impl<TopoDS_Shape>();
326       if (!aCurrent.IsBound(aNewShape)) {
327         aCurrent.Bind(
328           aNewShape, NCollection_DataMap<TopoDS_Shape, int, TopTools_ShapeMapHasher>());
329       }
330       aCurrent.ChangeFind(aNewShape).Bind(anExp.current()->impl<TopoDS_Shape>(), anIndexInWholeOld);
331     }
332   }
333 }
334
335 static void addAllSubs(const TopoDS_Shape& theNewShape,
336   MapNewToOld& theCurrent, std::map<int, TopoDS_Shape>& theResMap)
337 {
338   if (theCurrent.IsBound(theNewShape)) {
339     NCollection_DataMap<TopoDS_Shape, int, TopTools_ShapeMapHasher>::Iterator
340       anOldIter(theCurrent.Find(theNewShape));
341     for(; anOldIter.More(); anOldIter.Next()) {
342       theResMap[anOldIter.Value()] = anOldIter.Key();
343     }
344   }
345
346   TopoDS_Iterator anIter(theNewShape);
347   for(; anIter.More(); anIter.Next()) {
348     //if (anIter.Value().ShapeType() != TopAbs_VERTEX)
349     addAllSubs(anIter.Value(), theCurrent, theResMap); // add recursively
350   }
351 }
352
353 //==================================================================================================
354 GeomShapePtr GeomAlgoAPI_MakeShape::oldShapesForNew(GeomShapePtr theWholeOld,
355                                                     GeomShapePtr theNewShape,
356                                                     const int theShapeType)
357 {
358   GeomShapePtr aResult(new GeomAPI_Shape);
359   TopoDS_Compound aResComp;
360   TopoDS_Builder aBuilder;
361   aBuilder.MakeCompound(aResComp);
362   aResult->setImpl<TopoDS_Shape>(new TopoDS_Shape(aResComp));
363
364   HistoryMap* aHist = (HistoryMap*)myHist;
365   if (!aHist->IsBound(theShapeType))
366     return aResult; // not found, empty compound
367   const TopoDS_Shape& aWholeOld = theWholeOld->impl<TopoDS_Shape>();
368   if (!aHist->Find(theShapeType).IsBound(aWholeOld))
369     return aResult; // not found, empty compound
370   std::map<int, TopoDS_Shape> aResMap; // map with all results, ordered by index in whole old
371   MapNewToOld& aCurrent = aHist->ChangeFind(theShapeType).ChangeFind(aWholeOld);
372   // we don't know what type of new shapes were produced by the old theShapeType, so, iterate all
373   addAllSubs(theNewShape->impl<TopoDS_Shape>(), aCurrent, aResMap);
374
375   std::map<int, TopoDS_Shape>::iterator anOldIter = aResMap.begin();
376   for(; anOldIter != aResMap.end(); anOldIter++) {
377     if (anOldIter->second.ShapeType() == (TopAbs_ShapeEnum)theShapeType)
378       aBuilder.Add(aResComp, anOldIter->second);
379   }
380   aResult->setImpl<TopoDS_Shape>(new TopoDS_Shape(aResComp));
381   return aResult;
382 }