Salome HOME
Merge branch 'V9_2_2_BR'
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_ShapeTools.cpp
1 // Copyright (C) 2014-2019  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_ShapeTools.h"
21
22 #include "GeomAlgoAPI_SketchBuilder.h"
23
24 #include <GeomAPI_Ax1.h>
25 #include <GeomAPI_Edge.h>
26 #include <GeomAPI_Dir.h>
27 #include <GeomAPI_Face.h>
28 #include <GeomAPI_Pln.h>
29 #include <GeomAPI_Pnt.h>
30 #include <GeomAPI_Wire.h>
31
32 #include <Bnd_Box.hxx>
33 #include <BRep_Builder.hxx>
34 #include <BRepAdaptor_Curve.hxx>
35 #include <BRepAlgo.hxx>
36 #include <BRepAlgo_FaceRestrictor.hxx>
37 #include <BRepBndLib.hxx>
38 #include <BRepBuilderAPI_FindPlane.hxx>
39 #include <BRepBuilderAPI_MakeEdge.hxx>
40 #include <BRepBuilderAPI_MakeFace.hxx>
41 #include <BRepCheck_Analyzer.hxx>
42 #include <BRepExtrema_DistShapeShape.hxx>
43 #include <BRepExtrema_ExtCF.hxx>
44 #include <BRepGProp.hxx>
45 #include <BRepTools.hxx>
46 #include <BRepTools_WireExplorer.hxx>
47 #include <BRepTopAdaptor_FClass2d.hxx>
48 #include <BRepClass_FaceClassifier.hxx>
49 #include <Geom2d_Curve.hxx>
50 #include <Geom2d_Curve.hxx>
51 #include <BRepLib_CheckCurveOnSurface.hxx>
52 #include <BRep_Tool.hxx>
53 #include  <Geom_CylindricalSurface.hxx>
54 #include <Geom_Line.hxx>
55 #include <Geom_Plane.hxx>
56 #include <GeomAPI_ProjectPointOnCurve.hxx>
57 #include <GeomAPI_ShapeIterator.h>
58 #include <GeomLib_IsPlanarSurface.hxx>
59 #include <GeomLib_Tool.hxx>
60 #include <GeomAPI_IntCS.hxx>
61 #include <gp_Pln.hxx>
62 #include <GProp_GProps.hxx>
63 #include <IntAna_IntConicQuad.hxx>
64 #include <IntAna_Quadric.hxx>
65 #include <NCollection_Vector.hxx>
66 #include <ShapeAnalysis.hxx>
67 #include <ShapeAnalysis_Surface.hxx>
68 #include <TopoDS_Builder.hxx>
69 #include <TopoDS_Edge.hxx>
70 #include <TopoDS_Face.hxx>
71 #include <TopoDS_Shape.hxx>
72 #include <TopoDS_Shell.hxx>
73 #include <TopoDS_Vertex.hxx>
74 #include <TopoDS.hxx>
75 #include <TopExp.hxx>
76 #include <TopExp_Explorer.hxx>
77 #include <TopTools_ListIteratorOfListOfShape.hxx>
78
79
80 #include <BOPAlgo_Builder.hxx>
81 #include <BRepBuilderAPI_MakeVertex.hxx>
82 #include <TopoDS_Edge.hxx>
83
84 //==================================================================================================
85 static GProp_GProps props(const TopoDS_Shape& theShape)
86 {
87   GProp_GProps aGProps;
88
89   if (theShape.ShapeType() == TopAbs_EDGE || theShape.ShapeType() == TopAbs_WIRE)
90   {
91     BRepGProp::LinearProperties(theShape, aGProps);
92   }
93   else if (theShape.ShapeType() == TopAbs_FACE || theShape.ShapeType() == TopAbs_SHELL)
94   {
95     const Standard_Real anEps = 1.e-6;
96     BRepGProp::SurfaceProperties(theShape, aGProps, anEps);
97   }
98   else if (theShape.ShapeType() == TopAbs_SOLID || theShape.ShapeType() == TopAbs_COMPSOLID)
99   {
100     BRepGProp::VolumeProperties(theShape, aGProps);
101   }
102   else if (theShape.ShapeType() == TopAbs_COMPOUND)
103   {
104     for (TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next())
105     {
106       aGProps.Add(props(anIt.Value()));
107     }
108   }
109
110   return aGProps;
111 }
112
113 //==================================================================================================
114 double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theShape)
115 {
116   GProp_GProps aGProps;
117   if(!theShape.get()) {
118     return 0.0;
119   }
120   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
121   if(aShape.IsNull()) {
122     return 0.0;
123   }
124   const Standard_Real anEps = 1.e-6;
125   if (aShape.ShapeType() <= TopAbs_SOLID)
126     BRepGProp::VolumeProperties(aShape, aGProps, anEps);
127   else
128     BRepGProp::SurfaceProperties(aShape, aGProps, anEps);
129   return aGProps.Mass();
130 }
131
132 //==================================================================================================
133 double GeomAlgoAPI_ShapeTools::area (const std::shared_ptr<GeomAPI_Shape> theShape)
134 {
135   GProp_GProps aGProps;
136   if(!theShape.get()) {
137     return 0.0;
138   }
139   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
140   if(aShape.IsNull()) {
141     return 0.0;
142   }
143   const Standard_Real anEps = 1.e-6;
144
145   BRepGProp::SurfaceProperties(aShape, aGProps, anEps);
146   return aGProps.Mass();
147 }
148
149 //==================================================================================================
150 std::shared_ptr<GeomAPI_Pnt>
151   GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr<GeomAPI_Shape> theShape)
152 {
153   GProp_GProps aGProps;
154   if(!theShape) {
155     return std::shared_ptr<GeomAPI_Pnt>();
156   }
157   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
158   if(aShape.IsNull()) {
159     return std::shared_ptr<GeomAPI_Pnt>();
160   }
161   gp_Pnt aCentre;
162   if(aShape.ShapeType() == TopAbs_VERTEX) {
163     aCentre = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
164   } else {
165     aGProps = props(aShape);
166     aCentre = aGProps.CentreOfMass();
167   }
168
169   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aCentre.X(), aCentre.Y(), aCentre.Z()));
170 }
171
172 //==================================================================================================
173 double GeomAlgoAPI_ShapeTools::radius(const std::shared_ptr<GeomAPI_Face>& theCylinder)
174 {
175   double aRadius = -1.0;
176   if (theCylinder->isCylindrical()) {
177     const TopoDS_Shape& aShape = theCylinder->impl<TopoDS_Shape>();
178     Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aShape));
179     Handle(Geom_CylindricalSurface) aCyl = Handle(Geom_CylindricalSurface)::DownCast(aSurf);
180     if (!aCyl.IsNull())
181       aRadius = aCyl->Radius();
182   }
183   return aRadius;
184 }
185
186 //==================================================================================================
187 double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
188                                                const GeomShapePtr& theShape2)
189 {
190   const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
191   const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
192
193   BRepExtrema_DistShapeShape aDist(aShape1, aShape2);
194   aDist.Perform();
195   return aDist.IsDone() ? aDist.Value() : Precision::Infinite();
196 }
197
198 //==================================================================================================
199 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
200   const std::shared_ptr<GeomAPI_Shape> theCompound,
201   const GeomAPI_Shape::ShapeType theType,
202   ListOfShape& theResuts)
203 {
204
205   ListOfShape aResCombinedShapes;
206   ListOfShape aResFreeShapes;
207
208   GeomShapePtr aResult = theCompound;
209
210   if(!theCompound.get()) {
211     return aResult;
212   }
213
214   if(theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) {
215     return aResult;
216   }
217
218   TopAbs_ShapeEnum aTS = TopAbs_EDGE;
219   TopAbs_ShapeEnum aTA = TopAbs_FACE;
220   if(theType == GeomAPI_Shape::COMPSOLID) {
221     aTS = TopAbs_FACE;
222     aTA = TopAbs_SOLID;
223   }
224
225   // map from the resulting shapes to minimal index of the used shape from theCompound list
226   std::map<GeomShapePtr, int> anInputOrder;
227   // map from ancestors-shapes to the index of shapes in theCompound
228   NCollection_DataMap<TopoDS_Shape, int> anAncestorsOrder;
229
230   // Get free shapes.
231   int anOrder = 0;
232   const TopoDS_Shape& aShapesComp = theCompound->impl<TopoDS_Shape>();
233   for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next(), anOrder++) {
234     const TopoDS_Shape& aShape = anIter.Value();
235     if(aShape.ShapeType() > aTA) {
236       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
237       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
238       aResFreeShapes.push_back(aGeomShape);
239       anInputOrder[aGeomShape] = anOrder;
240     } else {
241       for(TopExp_Explorer anExp(aShape, aTA); anExp.More(); anExp.Next()) {
242         anAncestorsOrder.Bind(anExp.Current(), anOrder);
243       }
244     }
245   }
246
247   // Map sub-shapes and shapes.
248   TopTools_IndexedDataMapOfShapeListOfShape aMapSA;
249   TopExp::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA);
250   if(aMapSA.IsEmpty()) {
251     return aResult;
252   }
253   theResuts.clear();
254
255   // Get all shapes with common sub-shapes and free shapes.
256   NCollection_Map<TopoDS_Shape> aFreeShapes;
257   NCollection_Vector<NCollection_Map<TopoDS_Shape>> aShapesWithCommonSubshapes;
258   for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator
259       anIter(aMapSA); anIter.More(); anIter.Next()) {
260     const TopoDS_Shape& aShape = anIter.Key();
261     TopTools_ListOfShape& aListOfShape = anIter.ChangeValue();
262     if(aListOfShape.IsEmpty()) {
263       continue;
264     }
265     else if(aListOfShape.Size() == 1) {
266       const TopoDS_Shape& aF = aListOfShape.First();
267       aFreeShapes.Add(aF);
268       aListOfShape.Clear();
269     } else {
270       NCollection_List<TopoDS_Shape> aTempList;
271       NCollection_Map<TopoDS_Shape> aTempMap;
272       for (TopTools_ListOfShape::Iterator aListIt(aListOfShape); aListIt.More(); aListIt.Next()) {
273         aTempList.Append(aListIt.Value());
274         aTempMap.Add(aListIt.Value());
275         aFreeShapes.Remove(aListIt.Value());
276       }
277       aListOfShape.Clear();
278       for(NCollection_List<TopoDS_Shape>::Iterator
279           aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) {
280         const TopoDS_Shape& aTempShape = aTempIter.Value();
281         for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator
282             anIter(aMapSA); anIter.More(); anIter.Next()) {
283           TopTools_ListOfShape& aTempListOfShape = anIter.ChangeValue();
284           if(aTempListOfShape.IsEmpty()) {
285             continue;
286           } else if(aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) {
287             aTempListOfShape.Clear();
288           } else if(aTempListOfShape.Size() > 1) {
289             TopTools_ListOfShape::Iterator anIt1(aTempListOfShape);
290             for (; anIt1.More(); anIt1.Next()) {
291               if (anIt1.Value() == aTempShape) {
292                 TopTools_ListOfShape::Iterator anIt2(aTempListOfShape);
293                 for (; anIt2.More(); anIt2.Next())
294                 {
295                   if (anIt2.Value() != anIt1.Value()) {
296                     if (aTempMap.Add(anIt2.Value())) {
297                       aTempList.Append(anIt2.Value());
298                       aFreeShapes.Remove(anIt2.Value());
299                     }
300                   }
301                 }
302                 aTempListOfShape.Clear();
303                 break;
304               }
305             }
306           }
307         }
308       }
309       aShapesWithCommonSubshapes.Append(aTempMap);
310     }
311   }
312
313   // Combine shapes with common sub-shapes.
314   for(NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
315       anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) {
316     TopoDS_Shell aShell;
317     TopoDS_CompSolid aCSolid;
318     TopoDS_Builder aBuilder;
319     anOrder = -1;
320     theType ==
321       GeomAPI_Shape::COMPSOLID ? aBuilder.MakeCompSolid(aCSolid) : aBuilder.MakeShell(aShell);
322     NCollection_Map<TopoDS_Shape>& aShapesMap = anIter.ChangeValue();
323     for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
324       const TopoDS_Shape& aShape = anExp.Current();
325       if(aShapesMap.Contains(aShape)) {
326         theType ==
327           GeomAPI_Shape::COMPSOLID ? aBuilder.Add(aCSolid, aShape) : aBuilder.Add(aShell, aShape);
328         aShapesMap.Remove(aShape);
329         int aThisOrder = anAncestorsOrder.Find(aShape);
330         if (anOrder == -1 || aThisOrder < anOrder)
331           anOrder = aThisOrder; // take the minimum order position
332       }
333     }
334     std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
335     TopoDS_Shape* aSh = theType == GeomAPI_Shape::COMPSOLID ? new TopoDS_Shape(aCSolid) :
336                                                               new TopoDS_Shape(aShell);
337     aGeomShape->setImpl<TopoDS_Shape>(aSh);
338     aResCombinedShapes.push_back(aGeomShape);
339     anInputOrder[aGeomShape] = anOrder;
340   }
341
342   // Adding free shapes.
343   for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
344     const TopoDS_Shape& aShape = anExp.Current();
345     if(aFreeShapes.Contains(aShape)) {
346       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
347       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
348       aResFreeShapes.push_back(aGeomShape);
349       anInputOrder[aGeomShape] = anAncestorsOrder.Find(aShape);
350     }
351   }
352
353   if(aResCombinedShapes.size() == 1 && aResFreeShapes.size() == 0) {
354     aResult = aResCombinedShapes.front();
355     theResuts.push_back(aResult);
356   } else if(aResCombinedShapes.size() == 0 && aResFreeShapes.size() == 1) {
357     aResult = aResFreeShapes.front();
358     theResuts.push_back(aResult);
359   } else {
360     TopoDS_Compound aResultComp;
361     TopoDS_Builder aBuilder;
362     aBuilder.MakeCompound(aResultComp);
363     // put to result compound and result list in accordance to the order numbers
364     std::map<GeomShapePtr, int>::iterator anInputIter = anInputOrder.begin();
365     std::map<int, GeomShapePtr> aNums;
366     for(; anInputIter != anInputOrder.end(); anInputIter++)
367       aNums[anInputIter->second] = anInputIter->first;
368     std::map<int, GeomShapePtr>::iterator aNumsIter = aNums.begin();
369     for(; aNumsIter != aNums.end(); aNumsIter++) {
370       aBuilder.Add(aResultComp, (aNumsIter->second)->impl<TopoDS_Shape>());
371       theResuts.push_back(aNumsIter->second);
372     }
373     aResult->setImpl(new TopoDS_Shape(aResultComp));
374   }
375
376   return aResult;
377 }
378
379 //==================================================================================================
380 static void addSimpleShapeToList(const TopoDS_Shape& theShape,
381                                  NCollection_List<TopoDS_Shape>& theList)
382 {
383   if(theShape.IsNull()) {
384     return;
385   }
386
387   if(theShape.ShapeType() == TopAbs_COMPOUND) {
388     for(TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) {
389       addSimpleShapeToList(anIt.Value(), theList);
390     }
391   } else {
392     theList.Append(theShape);
393   }
394 }
395
396 //==================================================================================================
397 static TopoDS_Compound makeCompound(const NCollection_List<TopoDS_Shape> theShapes)
398 {
399   TopoDS_Compound aCompound;
400
401   BRep_Builder aBuilder;
402   aBuilder.MakeCompound(aCompound);
403
404   for(NCollection_List<TopoDS_Shape>::Iterator anIt(theShapes); anIt.More(); anIt.Next()) {
405     aBuilder.Add(aCompound, anIt.Value());
406   }
407
408   return aCompound;
409 }
410
411 //==================================================================================================
412 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
413   const std::shared_ptr<GeomAPI_Shape> theCompound)
414 {
415   GeomShapePtr aResult = theCompound;
416
417   if (!theCompound.get()) {
418     return aResult;
419   }
420
421   TopoDS_Shape anInShape = aResult->impl<TopoDS_Shape>();
422   NCollection_List<TopoDS_Shape> anUngroupedShapes, aStillUngroupedShapes;
423   addSimpleShapeToList(anInShape, anUngroupedShapes);
424
425   // Iterate over all shapes and find shapes with shared vertices.
426   TopTools_ListOfShape allVertices;
427   TopTools_DataMapOfShapeListOfShape aVertexShapesMap;
428   for (NCollection_List<TopoDS_Shape>::Iterator aShapesIt(anUngroupedShapes);
429     aShapesIt.More();
430     aShapesIt.Next()) {
431     const TopoDS_Shape& aShape = aShapesIt.Value();
432     for (TopExp_Explorer aShapeExp(aShape, TopAbs_VERTEX);
433       aShapeExp.More();
434       aShapeExp.Next()) {
435       const TopoDS_Shape& aVertex = aShapeExp.Current();
436       if (!aVertexShapesMap.IsBound(aVertex)) {
437         NCollection_List<TopoDS_Shape> aList;
438         aList.Append(aShape);
439         allVertices.Append(aVertex);
440         aVertexShapesMap.Bind(aVertex, aList);
441       }
442       else {
443         if (!aVertexShapesMap.ChangeFind(aVertex).Contains(aShape)) {
444           aVertexShapesMap.ChangeFind(aVertex).Append(aShape);
445         }
446       }
447     }
448   }
449
450   // Iterate over the map and group shapes.
451   NCollection_Vector<TopTools_MapOfShape> aGroups; // groups of shapes connected by vertices
452   while (!allVertices.IsEmpty()) {
453     // Get first group of shapes in map, and then unbind it.
454     const TopoDS_Shape& aKey = allVertices.First();
455     TopTools_ListOfShape aConnectedShapes = aVertexShapesMap.Find(aKey);
456     aVertexShapesMap.UnBind(aKey);
457     allVertices.Remove(aKey);
458     // Iterate over shapes in this group and add to it shapes from groups in map.
459     for (TopTools_ListOfShape::Iterator aConnectedIt(aConnectedShapes);
460       aConnectedIt.More(); aConnectedIt.Next()) {
461       const TopoDS_Shape& aConnected = aConnectedIt.Value();
462       TopTools_ListOfShape aKeysToUnbind;
463       for (TopTools_ListOfShape::Iterator aKeysIt(allVertices);
464         aKeysIt.More();
465         aKeysIt.Next()) {
466         const TopTools_ListOfShape& anOtherConnected = aVertexShapesMap(aKeysIt.Value());
467         if (!anOtherConnected.Contains(aConnected)) {
468           // Other connected group does not contain shape from our connected group
469           continue;
470         }
471         // Other is connected to our, so add them to our connected
472         for (TopTools_ListOfShape::Iterator anOtherIt(anOtherConnected);
473           anOtherIt.More();
474           anOtherIt.Next()) {
475           const TopoDS_Shape& aShape = anOtherIt.Value();
476           if (!aConnectedShapes.Contains(aShape)) {
477             aConnectedShapes.Append(aShape);
478           }
479         }
480         // Save key to unbind from this map.
481         aKeysToUnbind.Append(aKeysIt.Value());
482       }
483       // Unbind groups from map that we added to our group.
484       for (TopTools_ListOfShape::Iterator aKeysIt(aKeysToUnbind);
485         aKeysIt.More();
486         aKeysIt.Next()) {
487         aVertexShapesMap.UnBind(aKeysIt.Value());
488         allVertices.Remove(aKeysIt.Value());
489       }
490     }
491     // Sort shapes from the most complicated to the simplest ones
492     TopTools_MapOfShape aSortedGroup;
493     for (int aST = TopAbs_COMPOUND; aST <= TopAbs_SHAPE; ++aST) {
494       TopTools_ListOfShape::Iterator anIt(aConnectedShapes);
495       while (anIt.More()) {
496         if (anIt.Value().ShapeType() == aST) {
497           aSortedGroup.Add(anIt.Value());
498           aConnectedShapes.Remove(anIt);
499         }
500         else {
501           anIt.Next();
502         }
503       }
504     }
505     aGroups.Append(aSortedGroup);
506   }
507
508   TopoDS_Compound aCompound;
509   BRep_Builder aBuilder;
510   aBuilder.MakeCompound(aCompound);
511   ListOfShape aSolids;
512   for (NCollection_Vector<TopTools_MapOfShape>::Iterator anIt(aGroups); anIt.More(); anIt.Next()) {
513     const TopTools_MapOfShape& aGroup = anIt.ChangeValue();
514     GeomShapePtr aGeomShape(new GeomAPI_Shape());
515     if(aGroup.Size() == 1) {
516       TopTools_MapOfShape::Iterator aOneShapeIter(aGroup);
517       aGeomShape->setImpl(new TopoDS_Shape(aOneShapeIter.Value()));
518     } else {
519       // make sub-shapes in the group have order same as in original shape
520       TopTools_ListOfShape anOrderedGoup;
521       NCollection_List<TopoDS_Shape>::Iterator anUngrouped(anUngroupedShapes);
522       for (; anUngrouped.More(); anUngrouped.Next()) {
523         if (aGroup.Contains(anUngrouped.Value()))
524           anOrderedGoup.Append(anUngrouped.Value());
525       }
526       aGeomShape->setImpl(new TopoDS_Shape(makeCompound(anOrderedGoup)));
527       aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
528                                                          GeomAPI_Shape::COMPSOLID,
529                                                          aSolids);
530     }
531     aBuilder.Add(aCompound, aGeomShape->impl<TopoDS_Shape>());
532   }
533
534   if(!aCompound.IsNull()) {
535     aResult->setImpl(new TopoDS_Shape(aCompound));
536   }
537
538   return aResult;
539 }
540
541 //==================================================================================================
542 std::list<std::shared_ptr<GeomAPI_Pnt> >
543   GeomAlgoAPI_ShapeTools::getBoundingBox(const ListOfShape& theShapes, const double theEnlarge)
544 {
545   // Bounding box of all objects.
546   Bnd_Box aBndBox;
547
548   // Getting box.
549   for (ListOfShape::const_iterator
550     anObjectsIt = theShapes.begin(); anObjectsIt != theShapes.end(); anObjectsIt++) {
551     const TopoDS_Shape& aShape = (*anObjectsIt)->impl<TopoDS_Shape>();
552     BRepBndLib::Add(aShape, aBndBox);
553   }
554
555   if(theEnlarge != 0.0) {
556     // We enlarge bounding box just to be sure that plane will be large enough to cut all objects.
557     aBndBox.Enlarge(theEnlarge);
558   }
559
560   Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
561   Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
562   Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
563   std::list<std::shared_ptr<GeomAPI_Pnt> > aResultPoints;
564   int aNum = 0;
565   for(int i = 0; i < 2; i++) {
566     for(int j = 0; j < 2; j++) {
567       for(int k = 0; k < 2; k++) {
568         std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aXArr[i], aYArr[j], aZArr[k]));
569         aResultPoints.push_back(aPnt);
570       }
571     }
572   }
573
574   return aResultPoints;
575 }
576
577 //==================================================================================================
578 std::shared_ptr<GeomAPI_Face> GeomAlgoAPI_ShapeTools::fitPlaneToBox(
579   const std::shared_ptr<GeomAPI_Shape> thePlane,
580   const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints)
581 {
582   std::shared_ptr<GeomAPI_Face> aResultFace;
583
584   if(!thePlane.get()) {
585     return aResultFace;
586   }
587
588   const TopoDS_Shape& aShape = thePlane->impl<TopoDS_Shape>();
589   if(aShape.ShapeType() != TopAbs_FACE) {
590     return aResultFace;
591   }
592
593   TopoDS_Face aFace = TopoDS::Face(aShape);
594   Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
595   if(aSurf.IsNull()) {
596     return aResultFace;
597   }
598
599   GeomLib_IsPlanarSurface isPlanar(aSurf);
600   if(!isPlanar.IsPlanar()) {
601     return aResultFace;
602   }
603
604   if(thePoints.size() != 8) {
605     return aResultFace;
606   }
607
608   const gp_Pln& aFacePln = isPlanar.Plan();
609   Handle(Geom_Plane) aFacePlane = new Geom_Plane(aFacePln);
610   IntAna_Quadric aQuadric(aFacePln);
611   Standard_Real UMin, UMax, VMin, VMax;
612   UMin = UMax = VMin = VMax = 0;
613   for (std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator
614        aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) {
615     const gp_Pnt& aPnt = (*aPointsIt)->impl<gp_Pnt>();
616     gp_Lin aLin(aPnt, aFacePln.Axis().Direction());
617     IntAna_IntConicQuad anIntAna(aLin, aQuadric);
618     const gp_Pnt& aPntOnFace = anIntAna.Point(1);
619     Standard_Real aPntU(0), aPntV(0);
620     GeomLib_Tool::Parameters(aFacePlane, aPntOnFace, Precision::Confusion(), aPntU, aPntV);
621     if(aPntU < UMin) UMin = aPntU;
622     if(aPntU > UMax) UMax = aPntU;
623     if(aPntV < VMin) VMin = aPntV;
624     if(aPntV > VMax) VMax = aPntV;
625   }
626   aResultFace.reset(new GeomAPI_Face());
627   aResultFace->setImpl(new TopoDS_Face(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face()));
628
629   return aResultFace;
630 }
631
632 //==================================================================================================
633 void GeomAlgoAPI_ShapeTools::findBounds(const std::shared_ptr<GeomAPI_Shape> theShape,
634                                         std::shared_ptr<GeomAPI_Vertex>& theV1,
635                                         std::shared_ptr<GeomAPI_Vertex>& theV2)
636 {
637   static GeomVertexPtr aVertex;
638   if (!aVertex) {
639     aVertex = GeomVertexPtr(new GeomAPI_Vertex);
640     aVertex->setImpl(new TopoDS_Vertex());
641   }
642
643   theV1 = aVertex;
644   theV2 = aVertex;
645
646   if (theShape) {
647     const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
648     TopoDS_Vertex aV1, aV2;
649     ShapeAnalysis::FindBounds(aShape, aV1, aV2);
650
651     std::shared_ptr<GeomAPI_Vertex> aGeomV1(new GeomAPI_Vertex()), aGeomV2(new GeomAPI_Vertex());
652     aGeomV1->setImpl(new TopoDS_Vertex(aV1));
653     aGeomV2->setImpl(new TopoDS_Vertex(aV2));
654     theV1 = aGeomV1;
655     theV2 = aGeomV2;
656   }
657 }
658
659 //==================================================================================================
660 void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr<GeomAPI_Pnt> theOrigin,
661                                                 const std::shared_ptr<GeomAPI_Dir> theDirection,
662                                                 const ListOfShape& theWires,
663                                                 ListOfShape& theFaces)
664 {
665   BRepBuilderAPI_MakeFace aMKFace(gp_Pln(theOrigin->impl<gp_Pnt>(),
666                                           theDirection->impl<gp_Dir>()));
667   TopoDS_Face aFace = aMKFace.Face();
668
669   BRepAlgo_FaceRestrictor aFRestrictor;
670   aFRestrictor.Init(aFace, Standard_False, Standard_True);
671   for(ListOfShape::const_iterator anIt = theWires.cbegin();
672       anIt != theWires.cend();
673       ++anIt) {
674     TopoDS_Wire aWire = TopoDS::Wire((*anIt)->impl<TopoDS_Shape>());
675     aFRestrictor.Add(aWire);
676   }
677
678   aFRestrictor.Perform();
679
680   if(!aFRestrictor.IsDone()) {
681     return;
682   }
683
684   for(; aFRestrictor.More(); aFRestrictor.Next()) {
685     GeomShapePtr aShape(new GeomAPI_Shape());
686     aShape->setImpl(new TopoDS_Shape(aFRestrictor.Current()));
687     theFaces.push_back(aShape);
688   }
689 }
690
691 //==================================================================================================
692 std::shared_ptr<GeomAPI_Pln> GeomAlgoAPI_ShapeTools::findPlane(const ListOfShape& theShapes)
693 {
694   TopoDS_Compound aCompound;
695   BRep_Builder aBuilder;
696   aBuilder.MakeCompound(aCompound);
697
698   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
699     aBuilder.Add(aCompound, (*anIt)->impl<TopoDS_Shape>());
700   }
701   BRepBuilderAPI_FindPlane aFindPlane(aCompound);
702
703   if(aFindPlane.Found() != Standard_True) {
704     return std::shared_ptr<GeomAPI_Pln>();
705   }
706
707   Handle(Geom_Plane) aPlane = aFindPlane.Plane();
708   gp_Pnt aLoc = aPlane->Location();
709   gp_Dir aDir = aPlane->Axis().Direction();
710
711   std::shared_ptr<GeomAPI_Pnt> aGeomPnt(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
712   std::shared_ptr<GeomAPI_Dir> aGeomDir(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z()));
713
714   std::shared_ptr<GeomAPI_Pln> aPln(new GeomAPI_Pln(aGeomPnt, aGeomDir));
715
716   return aPln;
717 }
718
719 //==================================================================================================
720 bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
721   const std::shared_ptr<GeomAPI_Shape> theSubShape,
722   const std::shared_ptr<GeomAPI_Shape> theBaseShape)
723 {
724   if(!theSubShape.get() || !theBaseShape.get()) {
725     return false;
726   }
727
728   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
729   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
730
731   if(aSubShape.ShapeType() == TopAbs_VERTEX) {
732     // If sub-shape is a vertex check distance to shape. If it is <= Precision::Confusion() then OK.
733     BRepExtrema_DistShapeShape aDist(aBaseShape, aSubShape);
734     aDist.Perform();
735     if(!aDist.IsDone() || aDist.Value() > Precision::Confusion()) {
736       return false;
737     }
738   } else if (aSubShape.ShapeType() == TopAbs_EDGE) {
739     if(aBaseShape.ShapeType() == TopAbs_FACE) {
740       // Check that edge is on face surface.
741       TopoDS_Face aFace = TopoDS::Face(aBaseShape);
742       TopoDS_Edge anEdge = TopoDS::Edge(aSubShape);
743       BRepLib_CheckCurveOnSurface aCheck(anEdge, aFace);
744       aCheck.Perform();
745       if(!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) {
746         return false;
747       }
748
749       // Check intersections.
750       TopoDS_Vertex aV1, aV2;
751       ShapeAnalysis::FindBounds(anEdge, aV1, aV2);
752       gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1);
753       gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2);
754       for(TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
755         const TopoDS_Shape& anEdgeOnFace = anExp.Current();
756         BRepExtrema_DistShapeShape aDist(anEdgeOnFace, anEdge);
757         aDist.Perform();
758         if(aDist.IsDone() && aDist.Value() <= Precision::Confusion()) {
759           // Edge intersect face bound. Check that it is not on edge begin or end.
760           for(Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) {
761             gp_Pnt aPntOnSubShape = aDist.PointOnShape2(anIndex);
762             if(aPntOnSubShape.Distance(aPnt1) > Precision::Confusion()
763                 && aPntOnSubShape.Distance(aPnt2) > Precision::Confusion()) {
764               return false;
765             }
766           }
767         }
768       }
769
770       // No intersections found. Edge is inside or outside face. Check it.
771       BRepAdaptor_Curve aCurveAdaptor(anEdge);
772       gp_Pnt aPointToCheck =
773         aCurveAdaptor.Value((aCurveAdaptor.FirstParameter() +
774                               aCurveAdaptor.LastParameter()) / 2.0);
775       Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace);
776       ShapeAnalysis_Surface aSAS(aSurface);
777       gp_Pnt2d aPointOnFace = aSAS.ValueOfUV(aPointToCheck, Precision::Confusion());
778       BRepTopAdaptor_FClass2d aFClass2d(aFace, Precision::Confusion());
779       if(aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) {
780         return false;
781       }
782
783     } else {
784       return false;
785     }
786   } else {
787     return false;
788   }
789
790   return true;
791 }
792
793 //==================================================================================================
794 bool GeomAlgoAPI_ShapeTools::isShapeValid(const std::shared_ptr<GeomAPI_Shape> theShape)
795 {
796   if(!theShape.get()) {
797     return false;
798   }
799
800   BRepCheck_Analyzer aChecker(theShape->impl<TopoDS_Shape>());
801   return (aChecker.IsValid() == Standard_True);
802 }
803
804 //==================================================================================================
805 std::shared_ptr<GeomAPI_Shape>
806   GeomAlgoAPI_ShapeTools::getFaceOuterWire(const std::shared_ptr<GeomAPI_Shape> theFace)
807 {
808   GeomShapePtr anOuterWire;
809
810   if(!theFace.get() || !theFace->isFace()) {
811     return anOuterWire;
812   }
813
814   TopoDS_Face aFace = TopoDS::Face(theFace->impl<TopoDS_Shape>());
815   TopoDS_Wire aWire = BRepTools::OuterWire(aFace);
816
817   anOuterWire.reset(new GeomAPI_Shape());
818   anOuterWire->setImpl(new TopoDS_Shape(aWire));
819
820   return anOuterWire;
821 }
822
823 //==================================================================================================
824 bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
825                                         const std::shared_ptr<GeomAPI_Face> theFace)
826 {
827   if(!theEdge.get() || !theFace.get()) {
828     return false;
829   }
830
831   TopoDS_Edge anEdge = TopoDS::Edge(theEdge->impl<TopoDS_Shape>());
832   TopoDS_Face aFace  = TopoDS::Face(theFace->impl<TopoDS_Shape>());
833
834   BRepExtrema_ExtCF anExt(anEdge, aFace);
835   return anExt.IsParallel() == Standard_True;
836 }
837
838 //==================================================================================================
839 std::list<std::shared_ptr<GeomAPI_Vertex> > GeomAlgoAPI_ShapeTools::intersect(
840   const std::shared_ptr<GeomAPI_Edge> theEdge, const std::shared_ptr<GeomAPI_Face> theFace,
841   const bool thePointsOutsideFace)
842 {
843   std::list<std::shared_ptr<GeomAPI_Vertex> > aResult;
844   if(!theEdge.get() || !theFace.get()) {
845     return aResult;
846   }
847
848   TopoDS_Edge anEdge = TopoDS::Edge(theEdge->impl<TopoDS_Shape>());
849   double aFirstOnCurve, aLastOnCurve;
850   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirstOnCurve, aLastOnCurve);
851
852   TopoDS_Face aFace  = TopoDS::Face(theFace->impl<TopoDS_Shape>());
853   Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
854
855   GeomAPI_IntCS anIntAlgo(aCurve, aSurf);
856   if (!anIntAlgo.IsDone())
857     return aResult;
858   // searching for points-intersection
859   for(int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) {
860     gp_Pnt anInt;
861     if (anIntNum <= anIntAlgo.NbPoints()) {
862       anInt = anIntAlgo.Point(anIntNum);
863     } else { // take the middle point on the segment of the intersection
864       Handle(Geom_Curve) anIntCurve = anIntAlgo.Segment(anIntNum - anIntAlgo.NbPoints());
865       anIntCurve->D0((anIntCurve->FirstParameter() + anIntCurve->LastParameter()) / 2., anInt);
866     }
867     aResult.push_back(std::shared_ptr<GeomAPI_Vertex>(
868       new GeomAPI_Vertex(anInt.X(), anInt.Y(), anInt.Z())));
869   }
870   return aResult;
871 }
872
873 //==================================================================================================
874 void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
875                                       const GeomAlgoAPI_ShapeTools::PointToRefsMap& thePointsInfo,
876                                       std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes)
877 {
878   // to split shape at least one point should be presented in the points container
879   if (thePointsInfo.empty())
880     return;
881
882     // General Fuse to split edge by vertices
883   BOPAlgo_Builder aBOP;
884   TopoDS_Edge aBaseEdge = theBaseShape->impl<TopoDS_Edge>();
885   // Rebuild closed edge to place vertex to one of split points.
886   // This will prevent edge to be split on same vertex.
887   if (BRep_Tool::IsClosed(aBaseEdge))
888   {
889     Standard_Real aFirst, aLast;
890     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aBaseEdge, aFirst, aLast);
891
892     PointToRefsMap::const_iterator aPIt = thePointsInfo.begin();
893     std::shared_ptr<GeomAPI_Pnt> aPnt = aPIt->first;
894     gp_Pnt aPoint(aPnt->x(), aPnt->y(), aPnt->z());
895
896     TopAbs_Orientation anOrientation = aBaseEdge.Orientation();
897     aBaseEdge = BRepBuilderAPI_MakeEdge(aCurve, aPoint, aPoint).Edge();
898     aBaseEdge.Orientation(anOrientation);
899   }
900   aBOP.AddArgument(aBaseEdge);
901
902   PointToRefsMap::const_iterator aPIt = thePointsInfo.begin();
903   for (; aPIt != thePointsInfo.end(); ++aPIt) {
904     std::shared_ptr<GeomAPI_Pnt> aPnt = aPIt->first;
905     TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z()));
906     aBOP.AddArgument(aV);
907   }
908
909   aBOP.Perform();
910   if (aBOP.HasErrors())
911     return;
912
913   // Collect splits
914   const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge);
915   TopTools_ListIteratorOfListOfShape anIt(aSplits);
916   for (; anIt.More(); anIt.Next()) {
917     std::shared_ptr<GeomAPI_Shape> anEdge(new GeomAPI_Shape);
918     anEdge->setImpl(new TopoDS_Shape(anIt.Value()));
919     theShapes.insert(anEdge);
920   }
921 }
922
923 //==================================================================================================
924 void GeomAlgoAPI_ShapeTools::splitShape_p(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
925                                           const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
926                                           std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes)
927 {
928   // General Fuse to split edge by vertices
929   BOPAlgo_Builder aBOP;
930   TopoDS_Edge aBaseEdge = theBaseShape->impl<TopoDS_Edge>();
931   // Rebuild closed edge to place vertex to one of split points.
932   // This will prevent edge to be split on seam vertex.
933   if (BRep_Tool::IsClosed(aBaseEdge))
934   {
935     Standard_Real aFirst, aLast;
936     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aBaseEdge, aFirst, aLast);
937
938     std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPIt = thePoints.begin();
939     gp_Pnt aPoint((*aPIt)->x(), (*aPIt)->y(), (*aPIt)->z());
940
941     TopAbs_Orientation anOrientation = aBaseEdge.Orientation();
942     aBaseEdge = BRepBuilderAPI_MakeEdge(aCurve, aPoint, aPoint).Edge();
943     aBaseEdge.Orientation(anOrientation);
944   }
945   aBOP.AddArgument(aBaseEdge);
946
947   std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPtIt = thePoints.begin();
948   for (; aPtIt != thePoints.end(); ++aPtIt) {
949     std::shared_ptr<GeomAPI_Pnt> aPnt = *aPtIt;
950     TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z()));
951     aBOP.AddArgument(aV);
952   }
953
954   aBOP.Perform();
955   if (aBOP.HasErrors())
956     return;
957
958   // Collect splits
959   const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge);
960   TopTools_ListIteratorOfListOfShape anIt(aSplits);
961   for (; anIt.More(); anIt.Next()) {
962     std::shared_ptr<GeomAPI_Shape> anEdge(new GeomAPI_Shape);
963     anEdge->setImpl(new TopoDS_Shape(anIt.Value()));
964     theShapes.insert(anEdge);
965   }
966 }
967
968 //==================================================================================================
969 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::findShape(
970                                   const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
971                                   const std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes)
972 {
973   std::shared_ptr<GeomAPI_Shape> aResultShape;
974
975   if (thePoints.size() == 2) {
976     std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPntIt = thePoints.begin();
977     std::shared_ptr<GeomAPI_Pnt> aFirstPoint = *aPntIt;
978     aPntIt++;
979     std::shared_ptr<GeomAPI_Pnt> aLastPoint = *aPntIt;
980
981     std::set<std::shared_ptr<GeomAPI_Shape> >::const_iterator anIt = theShapes.begin(),
982                                                               aLast = theShapes.end();
983     for (; anIt != aLast; anIt++) {
984       GeomShapePtr aShape = *anIt;
985       std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aShape));
986       if (anEdge.get()) {
987         std::shared_ptr<GeomAPI_Pnt> anEdgeFirstPoint = anEdge->firstPoint();
988         std::shared_ptr<GeomAPI_Pnt> anEdgeLastPoint = anEdge->lastPoint();
989         if (anEdgeFirstPoint->isEqual(aFirstPoint) &&
990             anEdgeLastPoint->isEqual(aLastPoint))
991             aResultShape = aShape;
992       }
993     }
994   }
995
996   return aResultShape;
997 }
998
999 //==================================================================================================
1000 #ifdef FEATURE_MULTIROTATION_TWO_DIRECTIONS
1001 std::shared_ptr<GeomAPI_Dir> GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape(
1002                                     const std::shared_ptr<GeomAPI_Shape> theBaseShape,
1003                                     const std::shared_ptr<GeomAPI_Ax1> theAxis)
1004 {
1005   gp_Pnt aCentreOfMassPoint =
1006     GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape)->impl<gp_Pnt>();
1007   Handle(Geom_Line) aLine = new Geom_Line(theAxis->impl<gp_Ax1>());
1008   GeomAPI_ProjectPointOnCurve aPrjTool(aCentreOfMassPoint, aLine);
1009   gp_Pnt aPoint = aPrjTool.NearestPoint();
1010
1011   std::shared_ptr<GeomAPI_Dir> aDir(new GeomAPI_Dir(aCentreOfMassPoint.X()-aPoint.X(),
1012                                                     aCentreOfMassPoint.Y()-aPoint.Y(),
1013                                                     aCentreOfMassPoint.Z()-aPoint.Z()));
1014   return aDir;
1015 }
1016 #endif
1017
1018 //==================================================================================================
1019 static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire)
1020 {
1021   TopoDS_Wire aFixedWire;
1022   Handle(Geom_Curve) aPrevCurve;
1023   double aPrevLastParam = 0.0;
1024
1025   BRep_Builder aBuilder;
1026   aBuilder.MakeWire(aFixedWire);
1027
1028   BRepTools_WireExplorer aWExp(theWire);
1029   for (; aWExp.More(); aWExp.Next()) {
1030     TopoDS_Edge anEdge = aWExp.Current();
1031     double aFirst, aLast;
1032     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
1033     if (aCurve == aPrevCurve) {
1034       // if parametric gap occurs, create new edge based on the copied curve
1035       aCurve = Handle(Geom_Curve)::DownCast(aCurve->Copy());
1036       TopoDS_Vertex aV1, aV2;
1037       TopExp::Vertices(anEdge, aV1, aV2);
1038       anEdge = TopoDS::Edge(anEdge.EmptyCopied());
1039       aBuilder.UpdateEdge(anEdge, aCurve, BRep_Tool::Tolerance(anEdge));
1040       aBuilder.Add(anEdge, aV1);
1041       aBuilder.Add(anEdge, aV2);
1042     }
1043
1044     aBuilder.Add(aFixedWire, anEdge);
1045
1046     aPrevCurve = aCurve;
1047     aPrevLastParam = aLast;
1048   }
1049
1050   return aFixedWire;
1051 }
1052
1053 std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_ShapeTools::wireToEdge(
1054       const std::shared_ptr<GeomAPI_Wire>& theWire)
1055 {
1056   GeomEdgePtr anEdge;
1057   if (theWire) {
1058     TopoDS_Wire aWire = theWire->impl<TopoDS_Wire>();
1059     // Workaround: when concatenate a wire consisting of two edges based on the same B-spline curve
1060     // (non-periodic, but having equal start and end points), first of which is placed at the end
1061     // on the curve and second is placed at the start, this workaround copies second curve to avoid
1062     // treating these edges as a single curve by setting trim parameters.
1063     aWire = fixParametricGaps(aWire);
1064     TopoDS_Edge aNewEdge = BRepAlgo::ConcatenateWireC0(aWire);
1065     anEdge = GeomEdgePtr(new GeomAPI_Edge);
1066     anEdge->setImpl(new TopoDS_Edge(aNewEdge));
1067   }
1068   return anEdge;
1069 }
1070
1071 ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& theShape)
1072 {
1073   ListOfShape aSubShapes;
1074
1075   if (!theShape->isCompound() && !theShape->isCompSolid() &&
1076       !theShape->isShell() && !theShape->isWire()) {
1077     return aSubShapes;
1078   }
1079
1080   for (GeomAPI_ShapeIterator anIt(theShape); anIt.more(); anIt.next()) {
1081     GeomShapePtr aSubShape = anIt.current();
1082     if (aSubShape->isVertex() || aSubShape->isEdge() ||
1083         aSubShape->isFace() || aSubShape->isSolid()) {
1084       aSubShapes.push_back(aSubShape);
1085     } else {
1086       aSubShapes.splice(aSubShapes.end(), getLowLevelSubShapes(aSubShape));
1087     }
1088   }
1089
1090   return aSubShapes;
1091 }