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