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