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