]> SALOME platform Git repositories - modules/shaper.git/blob - src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
Salome HOME
Merge branch 'master' into cgt/devCEA
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_ShapeTools.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        GeomAlgoAPI_ShapeTools.h
4 // Created:     3 August 2015
5 // Author:      Dmitry Bobylev
6
7 #include "GeomAlgoAPI_ShapeTools.h"
8
9 #include "GeomAlgoAPI_SketchBuilder.h"
10
11 #include <GeomAPI_Ax1.h>
12 #include <GeomAPI_Edge.h>
13 #include <GeomAPI_Dir.h>
14 #include <GeomAPI_Face.h>
15 #include <GeomAPI_Pln.h>
16 #include <GeomAPI_Pnt.h>
17
18 #include <Bnd_Box.hxx>
19 #include <BOPTools.hxx>
20 #include <BRep_Builder.hxx>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRepAlgo_FaceRestrictor.hxx>
23 #include <BRepBndLib.hxx>
24 #include <BRepBuilderAPI_FindPlane.hxx>
25 #include <BRepBuilderAPI_MakeEdge.hxx>
26 #include <BRepBuilderAPI_MakeFace.hxx>
27 #include <BRepCheck_Analyzer.hxx>
28 #include <BRepExtrema_DistShapeShape.hxx>
29 #include <BRepExtrema_ExtCF.hxx>
30 #include <BRepGProp.hxx>
31 #include <BRepTools.hxx>
32 #include <BRepTopAdaptor_FClass2d.hxx>
33 #include <Geom2d_Curve.hxx>
34 #include <Geom2d_Curve.hxx>
35 #include <BRepLib_CheckCurveOnSurface.hxx>
36 #include <BRep_Tool.hxx>
37 #include <Geom_Line.hxx>
38 #include <Geom_Plane.hxx>
39 #include <GeomAPI_ProjectPointOnCurve.hxx>
40 #include <GeomLib_IsPlanarSurface.hxx>
41 #include <GeomLib_Tool.hxx>
42 #include <gp_Pln.hxx>
43 #include <GProp_GProps.hxx>
44 #include <IntAna_IntConicQuad.hxx>
45 #include <IntAna_Quadric.hxx>
46 #include <NCollection_Vector.hxx>
47 #include <ShapeAnalysis.hxx>
48 #include <ShapeAnalysis_Surface.hxx>
49 #include <TopoDS_Builder.hxx>
50 #include <TopoDS_Edge.hxx>
51 #include <TopoDS_Face.hxx>
52 #include <TopoDS_Shape.hxx>
53 #include <TopoDS_Shell.hxx>
54 #include <TopoDS_Vertex.hxx>
55 #include <TopoDS.hxx>
56 #include <TopExp_Explorer.hxx>
57 #include <TopTools_ListIteratorOfListOfShape.hxx>
58
59 #include <BOPAlgo_Builder.hxx>
60 #include <BRepBuilderAPI_MakeVertex.hxx>
61 #include <TopoDS_Edge.hxx>
62
63 //==================================================================================================
64 double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theShape)
65 {
66   GProp_GProps aGProps;
67   if(!theShape.get()) {
68     return 0.0;
69   }
70   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
71   if(aShape.IsNull()) {
72     return 0.0;
73   }
74   const Standard_Real anEps = 1.e-6;
75   BRepGProp::VolumeProperties(aShape, aGProps, anEps);
76   return aGProps.Mass();
77 }
78
79 //==================================================================================================
80 std::shared_ptr<GeomAPI_Pnt>
81   GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr<GeomAPI_Shape> theShape)
82 {
83   GProp_GProps aGProps;
84   if(!theShape) {
85     return std::shared_ptr<GeomAPI_Pnt>();
86   }
87   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
88   if(aShape.IsNull()) {
89     return std::shared_ptr<GeomAPI_Pnt>();
90   }
91   gp_Pnt aCentre;
92   if(aShape.ShapeType() == TopAbs_VERTEX) {
93     aCentre = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
94   } else if(aShape.ShapeType() == TopAbs_EDGE || aShape.ShapeType() == TopAbs_WIRE) {
95     BRepGProp::LinearProperties(aShape, aGProps);
96     aCentre = aGProps.CentreOfMass();
97   } else {
98     BRepGProp::SurfaceProperties(aShape, aGProps);
99     aCentre = aGProps.CentreOfMass();
100   }
101   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aCentre.X(), aCentre.Y(), aCentre.Z()));
102 }
103
104 //==================================================================================================
105 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
106   const std::shared_ptr<GeomAPI_Shape> theCompound,
107   const GeomAPI_Shape::ShapeType theType,
108   ListOfShape& theCombinedShapes,
109   ListOfShape& theFreeShapes)
110 {
111   GeomShapePtr aResult = theCompound;
112
113   if(!theCompound.get()) {
114     return aResult;
115   }
116
117   if(theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) {
118     return aResult;
119   }
120
121   TopAbs_ShapeEnum aTS = TopAbs_EDGE;
122   TopAbs_ShapeEnum aTA = TopAbs_FACE;
123   if(theType == GeomAPI_Shape::COMPSOLID) {
124     aTS = TopAbs_FACE;
125     aTA = TopAbs_SOLID;
126   }
127
128   theCombinedShapes.clear();
129   theFreeShapes.clear();
130
131   // Get free shapes.
132   const TopoDS_Shape& aShapesComp = theCompound->impl<TopoDS_Shape>();
133   for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next() ) {
134     const TopoDS_Shape& aShape = anIter.Value();
135     if(aShape.ShapeType() > aTA) {
136       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
137       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
138       theFreeShapes.push_back(aGeomShape);
139     }
140   }
141
142   // Map subshapes and shapes.
143   BOPCol_IndexedDataMapOfShapeListOfShape aMapSA;
144   BOPTools::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA);
145   if(aMapSA.IsEmpty()) {
146     return aResult;
147   }
148
149   // Get all shapes with common subshapes and free shapes.
150   NCollection_Map<TopoDS_Shape> aFreeShapes;
151   NCollection_Vector<NCollection_Map<TopoDS_Shape>> aShapesWithCommonSubshapes;
152   for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator
153       anIter(aMapSA); anIter.More(); anIter.Next()) {
154     const TopoDS_Shape& aShape = anIter.Key();
155     BOPCol_ListOfShape& aListOfShape = anIter.ChangeValue();
156     if(aListOfShape.IsEmpty()) {
157       continue;
158     }
159     else if(aListOfShape.Size() == 1) {
160       const TopoDS_Shape& aF = aListOfShape.First();
161       aFreeShapes.Add(aF);
162       aListOfShape.Clear();
163     } else {
164       NCollection_List<TopoDS_Shape> aTempList;
165       NCollection_Map<TopoDS_Shape> aTempMap;
166       const TopoDS_Shape& aF = aListOfShape.First();
167       const TopoDS_Shape& aL = aListOfShape.Last();
168       aTempList.Append(aF);
169       aTempList.Append(aL);
170       aTempMap.Add(aF);
171       aTempMap.Add(aL);
172       aFreeShapes.Remove(aF);
173       aFreeShapes.Remove(aL);
174       aListOfShape.Clear();
175       for(NCollection_List<TopoDS_Shape>::Iterator
176           aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) {
177         const TopoDS_Shape& aTempShape = aTempIter.Value();
178         for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator
179             anIter(aMapSA); anIter.More(); anIter.Next()) {
180           BOPCol_ListOfShape& aTempListOfShape = anIter.ChangeValue();
181           if(aTempListOfShape.IsEmpty()) {
182             continue;
183           } else if(aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) {
184             aTempListOfShape.Clear();
185           } else if(aTempListOfShape.Size() > 1) {
186             if(aTempListOfShape.First() == aTempShape) {
187               const TopoDS_Shape& aTL = aTempListOfShape.Last();
188               if(aTempMap.Add(aTL)) {
189                 aTempList.Append(aTL);
190                 aFreeShapes.Remove(aTL);
191               }
192               aTempListOfShape.Clear();
193             } else if(aTempListOfShape.Last() == aTempShape) {
194               const TopoDS_Shape& aTF = aTempListOfShape.First();
195               if(aTempMap.Add(aTF)) {
196                 aTempList.Append(aTF);
197                 aFreeShapes.Remove(aTF);
198               }
199               aTempListOfShape.Clear();
200             }
201           }
202         }
203       }
204       aShapesWithCommonSubshapes.Append(aTempMap);
205     }
206   }
207
208   // Combine shapes with common subshapes.
209   for(NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator
210       anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) {
211     TopoDS_Shell aShell;
212     TopoDS_CompSolid aCSolid;
213     TopoDS_Builder aBuilder;
214     theType ==
215       GeomAPI_Shape::COMPSOLID ? aBuilder.MakeCompSolid(aCSolid) : aBuilder.MakeShell(aShell);
216     NCollection_Map<TopoDS_Shape>& aShapesMap = anIter.ChangeValue();
217     for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
218       const TopoDS_Shape& aShape = anExp.Current();
219       if(aShapesMap.Contains(aShape)) {
220         theType ==
221           GeomAPI_Shape::COMPSOLID ? aBuilder.Add(aCSolid, aShape) : aBuilder.Add(aShell, aShape);
222         aShapesMap.Remove(aShape);
223       }
224     }
225     std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
226     TopoDS_Shape* aSh = theType == GeomAPI_Shape::COMPSOLID ? new TopoDS_Shape(aCSolid) :
227                                                               new TopoDS_Shape(aShell);
228     aGeomShape->setImpl<TopoDS_Shape>(aSh);
229     theCombinedShapes.push_back(aGeomShape);
230   }
231
232   // Adding free shapes.
233   for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
234     const TopoDS_Shape& aShape = anExp.Current();
235     if(aFreeShapes.Contains(aShape)) {
236       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
237       aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
238       theFreeShapes.push_back(aGeomShape);
239     }
240   }
241
242   if(theCombinedShapes.size() == 1 && theFreeShapes.size() == 0) {
243     aResult = theCombinedShapes.front();
244   } else if(theCombinedShapes.size() == 0 && theFreeShapes.size() == 1) {
245     aResult = theFreeShapes.front();
246   } else {
247     TopoDS_Compound aResultComp;
248     TopoDS_Builder aBuilder;
249     aBuilder.MakeCompound(aResultComp);
250     for(ListOfShape::const_iterator anIter = theCombinedShapes.cbegin();
251         anIter != theCombinedShapes.cend(); anIter++) {
252       aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
253     }
254     for(ListOfShape::const_iterator anIter = theFreeShapes.cbegin();
255         anIter != theFreeShapes.cend(); anIter++) {
256       aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
257     }
258     aResult->setImpl(new TopoDS_Shape(aResultComp));
259   }
260
261   return aResult;
262 }
263
264 //==================================================================================================
265 static void addSimpleShapeToList(const TopoDS_Shape& theShape,
266                                  NCollection_List<TopoDS_Shape>& theList)
267 {
268   if(theShape.IsNull()) {
269     return;
270   }
271
272   if(theShape.ShapeType() == TopAbs_COMPOUND) {
273     for(TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) {
274       addSimpleShapeToList(anIt.Value(), theList);
275     }
276   } else {
277     theList.Append(theShape);
278   }
279 }
280
281 //==================================================================================================
282 static TopoDS_Compound makeCompound(const NCollection_List<TopoDS_Shape> theShapes)
283 {
284   TopoDS_Compound aCompound;
285
286   BRep_Builder aBuilder;
287   aBuilder.MakeCompound(aCompound);
288
289   for(NCollection_List<TopoDS_Shape>::Iterator anIt(theShapes); anIt.More(); anIt.Next()) {
290     aBuilder.Add(aCompound, anIt.Value());
291   }
292
293   return aCompound;
294 }
295
296 //==================================================================================================
297 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::groupSharedTopology(
298   const std::shared_ptr<GeomAPI_Shape> theCompound)
299 {
300   GeomShapePtr aResult = theCompound;
301
302   if(!theCompound.get()) {
303     return aResult;
304   }
305
306   TopoDS_Shape anInShape = aResult->impl<TopoDS_Shape>();
307   NCollection_List<TopoDS_Shape> anUngroupedShapes, aStillUngroupedShapes;
308   addSimpleShapeToList(anInShape, anUngroupedShapes);
309
310   NCollection_Vector<NCollection_List<TopoDS_Shape>> aGroups;
311   while(!anUngroupedShapes.IsEmpty()) {
312     NCollection_List<TopoDS_Shape> aGroupedShapes;
313     aGroupedShapes.Append(anUngroupedShapes.First());
314     anUngroupedShapes.RemoveFirst();
315     for(NCollection_List<TopoDS_Shape>::Iterator aGroupIt(aGroupedShapes);
316         aGroupIt.More(); aGroupIt.Next()) {
317       const TopoDS_Shape& aGroupedShape = aGroupIt.Value();
318       for(TopExp_Explorer aGroupShapeExp(aGroupedShape, TopAbs_VERTEX);
319           aGroupShapeExp.More();
320           aGroupShapeExp.Next()) {
321         // Find all shapes which have same vertex.
322         aStillUngroupedShapes.Clear();
323         const TopoDS_Shape& aVertex1 = aGroupShapeExp.Current();
324         for(NCollection_List<TopoDS_Shape>::Iterator anUngroupedIt(anUngroupedShapes);
325             anUngroupedIt.More();
326             anUngroupedIt.Next()) {
327           const TopoDS_Shape& anUngroupedShape = anUngroupedIt.Value();
328           bool isAdded = false;
329           for(TopExp_Explorer anUgroupedShapeExp(anUngroupedShape, TopAbs_VERTEX);
330               anUgroupedShapeExp.More();
331               anUgroupedShapeExp.Next()) {
332             const TopoDS_Shape& aVertex2 = anUgroupedShapeExp.Current();
333             if(aVertex1.IsSame(aVertex2)) {
334               aGroupedShapes.Append(anUngroupedShape);
335               isAdded = true;
336               break;
337             }
338           }
339           if(!isAdded) {
340             aStillUngroupedShapes.Append(anUngroupedShape);
341           }
342         }
343         anUngroupedShapes = aStillUngroupedShapes;
344         if(anUngroupedShapes.IsEmpty()) {
345           break;
346         }
347       }
348       if(anUngroupedShapes.IsEmpty()) {
349         break;
350       }
351     }
352     aGroups.Append(aGroupedShapes);
353   }
354
355   TopoDS_Compound aCompound;
356   BRep_Builder aBuilder;
357   aBuilder.MakeCompound(aCompound);
358   ListOfShape aCompSolids, aFreeSolids;
359   for(NCollection_Vector<NCollection_List<TopoDS_Shape>>::Iterator
360       anIt(aGroups); anIt.More(); anIt.Next()) {
361     NCollection_List<TopoDS_Shape> aGroup = anIt.Value();
362     GeomShapePtr aGeomShape(new GeomAPI_Shape());
363     if(aGroup.Size() == 1) {
364       aGeomShape->setImpl(new TopoDS_Shape(aGroup.First()));
365     } else {
366       aGeomShape->setImpl(new TopoDS_Shape(makeCompound(aGroup)));
367       aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
368                                                          GeomAPI_Shape::COMPSOLID,
369                                                          aCompSolids,
370                                                          aFreeSolids);
371     }
372     aBuilder.Add(aCompound, aGeomShape->impl<TopoDS_Shape>());
373   }
374
375   if(!aCompound.IsNull()) {
376     aResult->setImpl(new TopoDS_Shape(aCompound));
377   }
378
379   return aResult;
380 }
381
382 //==================================================================================================
383 std::list<std::shared_ptr<GeomAPI_Pnt> >
384   GeomAlgoAPI_ShapeTools::getBoundingBox(const ListOfShape& theShapes, const double theEnlarge)
385 {
386   // Bounding box of all objects.
387   Bnd_Box aBndBox;
388
389   // Getting box.
390   for (ListOfShape::const_iterator
391     anObjectsIt = theShapes.begin(); anObjectsIt != theShapes.end(); anObjectsIt++) {
392     const TopoDS_Shape& aShape = (*anObjectsIt)->impl<TopoDS_Shape>();
393     BRepBndLib::Add(aShape, aBndBox);
394   }
395
396   if(theEnlarge != 0.0) {
397     // We enlarge bounding box just to be sure that plane will be large enough to cut all objects.
398     aBndBox.Enlarge(theEnlarge);
399   }
400
401   Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
402   Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
403   Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
404   std::list<std::shared_ptr<GeomAPI_Pnt> > aResultPoints;
405   int aNum = 0;
406   for(int i = 0; i < 2; i++) {
407     for(int j = 0; j < 2; j++) {
408       for(int k = 0; k < 2; k++) {
409         std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aXArr[i], aYArr[j], aZArr[k]));
410         aResultPoints.push_back(aPnt);
411       }
412     }
413   }
414
415   return aResultPoints;
416 }
417
418 //==================================================================================================
419 std::shared_ptr<GeomAPI_Shape>
420   GeomAlgoAPI_ShapeTools::faceToInfinitePlane(const std::shared_ptr<GeomAPI_Shape> theFace)
421 {
422   if (!theFace.get())
423     return std::shared_ptr<GeomAPI_Shape>();
424
425   TopoDS_Face aPlaneFace = TopoDS::Face(theFace->impl<TopoDS_Shape>());
426   if (aPlaneFace.IsNull())
427     return std::shared_ptr<GeomAPI_Shape>();
428
429   Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(aPlaneFace));
430   if (aPlane.IsNull())
431     return std::shared_ptr<GeomAPI_Shape>();
432
433   // make an infinity face on the plane
434   TopoDS_Shape anInfiniteFace = BRepBuilderAPI_MakeFace(aPlane->Pln()).Shape();
435
436   std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
437   aResult->setImpl(new TopoDS_Shape(anInfiniteFace));
438   return aResult;
439 }
440
441 //==================================================================================================
442 std::shared_ptr<GeomAPI_Face> GeomAlgoAPI_ShapeTools::fitPlaneToBox(
443   const std::shared_ptr<GeomAPI_Shape> thePlane,
444   const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints)
445 {
446   std::shared_ptr<GeomAPI_Face> aResultFace;
447
448   if(!thePlane.get()) {
449     return aResultFace;
450   }
451
452   const TopoDS_Shape& aShape = thePlane->impl<TopoDS_Shape>();
453   if(aShape.ShapeType() != TopAbs_FACE) {
454     return aResultFace;
455   }
456
457   TopoDS_Face aFace = TopoDS::Face(aShape);
458   Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
459   if(aSurf.IsNull()) {
460     return aResultFace;
461   }
462
463   GeomLib_IsPlanarSurface isPlanar(aSurf);
464   if(!isPlanar.IsPlanar()) {
465     return aResultFace;
466   }
467
468   if(thePoints.size() != 8) {
469     return aResultFace;
470   }
471
472   const gp_Pln& aFacePln = isPlanar.Plan();
473   Handle(Geom_Plane) aFacePlane = new Geom_Plane(aFacePln);
474   IntAna_Quadric aQuadric(aFacePln);
475   Standard_Real UMin, UMax, VMin, VMax;
476   UMin = UMax = VMin = VMax = 0;
477   for (std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator
478        aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) {
479     const gp_Pnt& aPnt = (*aPointsIt)->impl<gp_Pnt>();
480     gp_Lin aLin(aPnt, aFacePln.Axis().Direction());
481     IntAna_IntConicQuad anIntAna(aLin, aQuadric);
482     const gp_Pnt& aPntOnFace = anIntAna.Point(1);
483     Standard_Real aPntU(0), aPntV(0);
484     GeomLib_Tool::Parameters(aFacePlane, aPntOnFace, Precision::Confusion(), aPntU, aPntV);
485     if(aPntU < UMin) UMin = aPntU;
486     if(aPntU > UMax) UMax = aPntU;
487     if(aPntV < VMin) VMin = aPntV;
488     if(aPntV > VMax) VMax = aPntV;
489   }
490   aResultFace.reset(new GeomAPI_Face());
491   aResultFace->setImpl(new TopoDS_Face(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face()));
492
493   return aResultFace;
494 }
495
496 //==================================================================================================
497 void GeomAlgoAPI_ShapeTools::findBounds(const std::shared_ptr<GeomAPI_Shape> theShape,
498                                         std::shared_ptr<GeomAPI_Vertex>& theV1,
499                                         std::shared_ptr<GeomAPI_Vertex>& theV2)
500 {
501   if(!theShape.get()) {
502     std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex);
503     aVertex->setImpl(new TopoDS_Vertex());
504     theV1 = aVertex;
505     theV2 = aVertex;
506     return;
507   }
508
509   const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
510   TopoDS_Vertex aV1, aV2;
511   ShapeAnalysis::FindBounds(aShape, aV1, aV2);
512
513   std::shared_ptr<GeomAPI_Vertex> aGeomV1(new GeomAPI_Vertex()), aGeomV2(new GeomAPI_Vertex());
514   aGeomV1->setImpl(new TopoDS_Vertex(aV1));
515   aGeomV2->setImpl(new TopoDS_Vertex(aV2));
516   theV1 = aGeomV1;
517   theV2 = aGeomV2;
518 }
519
520 //==================================================================================================
521 void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr<GeomAPI_Pnt> theOrigin,
522                                                 const std::shared_ptr<GeomAPI_Dir> theDirection,
523                                                 const ListOfShape& theWires,
524                                                 ListOfShape& theFaces)
525 {
526   BRepBuilderAPI_MakeFace aMKFace(gp_Pln(theOrigin->impl<gp_Pnt>(),
527                                           theDirection->impl<gp_Dir>()));
528   TopoDS_Face aFace = aMKFace.Face();
529
530   BRepAlgo_FaceRestrictor aFRestrictor;
531   aFRestrictor.Init(aFace, Standard_False, Standard_True);
532   for(ListOfShape::const_iterator anIt = theWires.cbegin();
533       anIt != theWires.cend();
534       ++anIt) {
535     TopoDS_Wire aWire = TopoDS::Wire((*anIt)->impl<TopoDS_Shape>());
536     aFRestrictor.Add(aWire);
537   }
538
539   aFRestrictor.Perform();
540
541   if(!aFRestrictor.IsDone()) {
542     return;
543   }
544
545   for(; aFRestrictor.More(); aFRestrictor.Next()) {
546     GeomShapePtr aShape(new GeomAPI_Shape());
547     aShape->setImpl(new TopoDS_Shape(aFRestrictor.Current()));
548     theFaces.push_back(aShape);
549   }
550 }
551
552 //==================================================================================================
553 std::shared_ptr<GeomAPI_Pln> GeomAlgoAPI_ShapeTools::findPlane(const ListOfShape& theShapes)
554 {
555   TopoDS_Compound aCompound;
556   BRep_Builder aBuilder;
557   aBuilder.MakeCompound(aCompound);
558
559   for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) {
560     aBuilder.Add(aCompound, (*anIt)->impl<TopoDS_Shape>());
561   }
562   BRepBuilderAPI_FindPlane aFindPlane(aCompound);
563
564   if(aFindPlane.Found() != Standard_True) {
565     return std::shared_ptr<GeomAPI_Pln>();
566   }
567
568   Handle(Geom_Plane) aPlane = aFindPlane.Plane();
569   gp_Pnt aLoc = aPlane->Location();
570   gp_Dir aDir = aPlane->Axis().Direction();
571
572   std::shared_ptr<GeomAPI_Pnt> aGeomPnt(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
573   std::shared_ptr<GeomAPI_Dir> aGeomDir(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z()));
574
575   std::shared_ptr<GeomAPI_Pln> aPln(new GeomAPI_Pln(aGeomPnt, aGeomDir));
576
577   return aPln;
578 }
579
580 //==================================================================================================
581 bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape(
582   const std::shared_ptr<GeomAPI_Shape> theSubShape,
583   const std::shared_ptr<GeomAPI_Shape> theBaseShape)
584 {
585   if(!theSubShape.get() || !theBaseShape.get()) {
586     return false;
587   }
588
589   const TopoDS_Shape& aSubShape = theSubShape->impl<TopoDS_Shape>();
590   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
591
592   if(aSubShape.ShapeType() == TopAbs_VERTEX) {
593     // If sub-shape is a vertex check distance to shape. If it is <= Precision::Confusion() then OK.
594     BRepExtrema_DistShapeShape aDist(aBaseShape, aSubShape);
595     aDist.Perform();
596     if(!aDist.IsDone() || aDist.Value() > Precision::Confusion()) {
597       return false;
598     }
599   } else if (aSubShape.ShapeType() == TopAbs_EDGE) {
600     if(aBaseShape.ShapeType() == TopAbs_FACE) {
601       // Check that edge is on face surface.
602       TopoDS_Face aFace = TopoDS::Face(aBaseShape);
603       TopoDS_Edge anEdge = TopoDS::Edge(aSubShape);
604       BRepLib_CheckCurveOnSurface aCheck(anEdge, aFace);
605       aCheck.Perform();
606       if(!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) {
607         return false;
608       }
609
610       // Check intersections.
611       TopoDS_Vertex aV1, aV2;
612       ShapeAnalysis::FindBounds(anEdge, aV1, aV2);
613       gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1);
614       gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2);
615       for(TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
616         const TopoDS_Shape& anEdgeOnFace = anExp.Current();
617         BRepExtrema_DistShapeShape aDist(anEdgeOnFace, anEdge);
618         aDist.Perform();
619         if(aDist.IsDone() && aDist.Value() <= Precision::Confusion()) {
620           // Edge intersect face bound. Check that it is not on edge begin or end.
621           for(Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) {
622             gp_Pnt aPntOnSubShape = aDist.PointOnShape2(anIndex);
623             if(aPntOnSubShape.Distance(aPnt1) > Precision::Confusion()
624                 && aPntOnSubShape.Distance(aPnt2) > Precision::Confusion()) {
625               return false;
626             }
627           }
628         }
629       }
630
631       // No intersections found. Edge is inside or outside face. Check it.
632       BRepAdaptor_Curve aCurveAdaptor(anEdge);
633       gp_Pnt aPointToCheck =
634         aCurveAdaptor.Value((aCurveAdaptor.FirstParameter() +
635                               aCurveAdaptor.LastParameter()) / 2.0);
636       Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace);
637       ShapeAnalysis_Surface aSAS(aSurface);
638       gp_Pnt2d aPointOnFace = aSAS.ValueOfUV(aPointToCheck, Precision::Confusion());
639       BRepTopAdaptor_FClass2d aFClass2d(aFace, Precision::Confusion());
640       if(aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) {
641         return false;
642       }
643
644     } else {
645       return false;
646     }
647   } else {
648     return false;
649   }
650
651   return true;
652 }
653
654 //==================================================================================================
655 bool GeomAlgoAPI_ShapeTools::isShapeValid(const std::shared_ptr<GeomAPI_Shape> theShape)
656 {
657   if(!theShape.get()) {
658     return false;
659   }
660
661   BRepCheck_Analyzer aChecker(theShape->impl<TopoDS_Shape>());
662   return (aChecker.IsValid() == Standard_True);
663 }
664
665 //==================================================================================================
666 std::shared_ptr<GeomAPI_Shape>
667   GeomAlgoAPI_ShapeTools::getFaceOuterWire(const std::shared_ptr<GeomAPI_Shape> theFace)
668 {
669   GeomShapePtr anOuterWire;
670
671   if(!theFace.get() || !theFace->isFace()) {
672     return anOuterWire;
673   }
674
675   TopoDS_Face aFace = TopoDS::Face(theFace->impl<TopoDS_Shape>());
676   TopoDS_Wire aWire = BRepTools::OuterWire(aFace);
677
678   anOuterWire.reset(new GeomAPI_Shape());
679   anOuterWire->setImpl(new TopoDS_Shape(aWire));
680
681   return anOuterWire;
682 }
683
684 //==================================================================================================
685 bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr<GeomAPI_Edge> theEdge,
686                                         const std::shared_ptr<GeomAPI_Face> theFace)
687 {
688   if(!theEdge.get() || !theFace.get()) {
689     return false;
690   }
691
692   TopoDS_Edge anEdge = TopoDS::Edge(theEdge->impl<TopoDS_Shape>());
693   TopoDS_Face aFace  = TopoDS::Face(theFace->impl<TopoDS_Shape>());
694
695   BRepExtrema_ExtCF anExt(anEdge, aFace);
696   return anExt.IsParallel() == Standard_True;
697 }
698
699 //==================================================================================================
700 void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
701                                       const GeomAlgoAPI_ShapeTools::PointToRefsMap& thePointsInfo,
702                                       std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes)
703 {
704   // General Fuse to split edge by vertices
705   BOPAlgo_Builder aBOP;
706   TopoDS_Edge aBaseEdge = theBaseShape->impl<TopoDS_Edge>();
707   // Rebuild closed edge to place vertex to one of split points.
708   // This will prevent edge to be split on same vertex.
709   if (BRep_Tool::IsClosed(aBaseEdge))
710   {
711     Standard_Real aFirst, aLast;
712     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aBaseEdge, aFirst, aLast);
713
714     PointToRefsMap::const_iterator aPIt = thePointsInfo.begin();
715     std::shared_ptr<GeomAPI_Pnt> aPnt = aPIt->first;
716     gp_Pnt aPoint(aPnt->x(), aPnt->y(), aPnt->z());
717
718     TopAbs_Orientation anOrientation = aBaseEdge.Orientation();
719     aBaseEdge = BRepBuilderAPI_MakeEdge(aCurve, aPoint, aPoint).Edge();
720     aBaseEdge.Orientation(anOrientation);
721   }
722   aBOP.AddArgument(aBaseEdge);
723
724   PointToRefsMap::const_iterator aPIt = thePointsInfo.begin();
725   for (; aPIt != thePointsInfo.end(); ++aPIt) {
726     std::shared_ptr<GeomAPI_Pnt> aPnt = aPIt->first;
727     TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z()));
728     aBOP.AddArgument(aV);
729   }
730
731   aBOP.Perform();
732   if (aBOP.ErrorStatus())
733     return;
734
735   // Collect splits
736   const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge);
737   TopTools_ListIteratorOfListOfShape anIt(aSplits);
738   for (; anIt.More(); anIt.Next()) {
739     std::shared_ptr<GeomAPI_Shape> anEdge(new GeomAPI_Shape);
740     anEdge->setImpl(new TopoDS_Shape(anIt.Value()));
741     theShapes.insert(anEdge);
742   }
743 }
744
745 //==================================================================================================
746 void GeomAlgoAPI_ShapeTools::splitShape_p(const std::shared_ptr<GeomAPI_Shape>& theBaseShape,
747                                           const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
748                                           std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes)
749 {
750   // General Fuse to split edge by vertices
751   BOPAlgo_Builder aBOP;
752   TopoDS_Edge aBaseEdge = theBaseShape->impl<TopoDS_Edge>();
753   // Rebuild closed edge to place vertex to one of split points.
754   // This will prevent edge to be split on seam vertex.
755   if (BRep_Tool::IsClosed(aBaseEdge))
756   {
757     Standard_Real aFirst, aLast;
758     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aBaseEdge, aFirst, aLast);
759
760     std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPIt = thePoints.begin();
761     gp_Pnt aPoint((*aPIt)->x(), (*aPIt)->y(), (*aPIt)->z());
762
763     TopAbs_Orientation anOrientation = aBaseEdge.Orientation();
764     aBaseEdge = BRepBuilderAPI_MakeEdge(aCurve, aPoint, aPoint).Edge();
765     aBaseEdge.Orientation(anOrientation);
766   }
767   aBOP.AddArgument(aBaseEdge);
768
769   std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPtIt = thePoints.begin();
770   for (; aPtIt != thePoints.end(); ++aPtIt) {
771     std::shared_ptr<GeomAPI_Pnt> aPnt = *aPtIt;
772     TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z()));
773     aBOP.AddArgument(aV);
774   }
775
776   aBOP.Perform();
777   if (aBOP.ErrorStatus())
778     return;
779
780   // Collect splits
781   const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge);
782   TopTools_ListIteratorOfListOfShape anIt(aSplits);
783   for (; anIt.More(); anIt.Next()) {
784     std::shared_ptr<GeomAPI_Shape> anEdge(new GeomAPI_Shape);
785     anEdge->setImpl(new TopoDS_Shape(anIt.Value()));
786     theShapes.insert(anEdge);
787   }
788 }
789
790 //==================================================================================================
791 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::findShape(
792                                   const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints,
793                                   const std::set<std::shared_ptr<GeomAPI_Shape> >& theShapes)
794 {
795   std::shared_ptr<GeomAPI_Shape> aResultShape;
796
797   if (thePoints.size() == 2) {
798     std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPntIt = thePoints.begin();
799     std::shared_ptr<GeomAPI_Pnt> aFirstPoint = *aPntIt;
800     aPntIt++;
801     std::shared_ptr<GeomAPI_Pnt> aLastPoint = *aPntIt;
802
803     std::set<std::shared_ptr<GeomAPI_Shape> >::const_iterator anIt = theShapes.begin(),
804                                                               aLast = theShapes.end();
805     for (; anIt != aLast; anIt++) {
806       GeomShapePtr aShape = *anIt;
807       std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aShape));
808       if (anEdge.get()) {
809         std::shared_ptr<GeomAPI_Pnt> anEdgeFirstPoint = anEdge->firstPoint();
810         std::shared_ptr<GeomAPI_Pnt> anEdgeLastPoint = anEdge->lastPoint();
811         if (anEdgeFirstPoint->isEqual(aFirstPoint) &&
812             anEdgeLastPoint->isEqual(aLastPoint))
813             aResultShape = aShape;
814       }
815     }
816   }
817
818   return aResultShape;
819 }
820
821 //==================================================================================================
822 std::shared_ptr<GeomAPI_Dir> GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape(
823                                     const std::shared_ptr<GeomAPI_Shape> theBaseShape,
824                                     const std::shared_ptr<GeomAPI_Ax1> theAxis)
825 {
826   gp_Pnt aCentreOfMassPoint =
827     GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape)->impl<gp_Pnt>();
828   Handle(Geom_Line) aLine = new Geom_Line(theAxis->impl<gp_Ax1>());
829   GeomAPI_ProjectPointOnCurve aPrjTool(aCentreOfMassPoint, aLine);
830   gp_Pnt aPoint = aPrjTool.NearestPoint();
831
832   std::shared_ptr<GeomAPI_Dir> aDir(new GeomAPI_Dir(aCentreOfMassPoint.X()-aPoint.X(),
833                                                     aCentreOfMassPoint.Y()-aPoint.Y(),
834                                                     aCentreOfMassPoint.Z()-aPoint.Z()));
835   return aDir;
836 }