Salome HOME
dbd5ef788bde3bbb419b788d369949e2d764d624
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_Revolution.cpp
1 // Copyright (C) 2014-2023  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "GeomAlgoAPI_Revolution.h"
21
22 #include <GeomAPI_Face.h>
23 #include <GeomAPI_Pln.h>
24 #include <GeomAPI_ShapeExplorer.h>
25 #include <GeomAlgoAPI_DFLoader.h>
26 #include <GeomAlgoAPI_FaceBuilder.h>
27 #include <GeomAlgoAPI_MakeShapeList.h>
28 #include <GeomAlgoAPI_ShapeTools.h>
29
30 #include <BRep_Builder.hxx>
31 #include <BRep_Tool.hxx>
32 #include <BRepAlgoAPI_Cut.hxx>
33 #include <BRepBuilderAPI_FindPlane.hxx>
34 #include <BRepBuilderAPI_MakeFace.hxx>
35 #include <BRepBuilderAPI_Transform.hxx>
36 #include <BRepCheck_Analyzer.hxx>
37 #include <Geom_Curve.hxx>
38 #include <Geom2d_Curve.hxx>
39 #include <BRepLib_CheckCurveOnSurface.hxx>
40 #include <BRepPrimAPI_MakeRevol.hxx>
41 #include <BRepGProp.hxx>
42 #include <GC_MakePlane.hxx>
43 #include <Geom_Plane.hxx>
44 #include <GeomLib_IsPlanarSurface.hxx>
45 #include <gp_Pln.hxx>
46 #include <GProp_GProps.hxx>
47 #include <IntTools_Context.hxx>
48 #include <TopExp_Explorer.hxx>
49 #include <TopoDS.hxx>
50 #include <TopoDS_Edge.hxx>
51 #include <TopTools_ListIteratorOfListOfShape.hxx>
52
53 /// \brief Constructs infinite face from thePlane, and with axis located on the same side
54 /// of the plane as thePoint. Modifies thePlane axis direction.
55 /// \param[in,out] thePlane plane to construct face.
56 /// \param[in] thePoint point to locate plane axis.
57 /// \return constructed face.
58 static TopoDS_Face makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint);
59
60 /// \return solid created from face or shell.
61 static TopoDS_Solid makeSolidFromShape(const TopoDS_Shape& theShape);
62
63 /// \brief return centre of mass for theShape.
64 /// \param[in] theShape shape.
65 static gp_Pnt centreOfMass(const TopoDS_Shape& theShape);
66
67 /// \brief Selects solid from theShape with closest center of mass to thePoint
68 /// \param[in] theShape compound with solids.
69 /// \param[in] thePoint point.
70 /// \return solid.
71 static TopoDS_Shape findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint);
72
73 /// \brief Create plane by 3 points. Return empty handle if failed.
74 static Handle(Geom_Plane) makePlane(const gp_Pnt& theP1, const gp_Pnt& theP2, const gp_Pnt& theP3);
75
76 static void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo,
77                                    const TopoDS_Shape& theBase,
78                                    const TopAbs_ShapeEnum theType,
79                                    BRepPrimAPI_MakeRevol* theRevolBuilder);
80
81 static void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo,
82                                    const TopoDS_Shape& theResult,
83                                    const TopAbs_ShapeEnum theType,
84                                    const TopoDS_Shape& theToFace,
85                                    const TopoDS_Shape& theFromFace);
86
87 static void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo,
88                                    const TopoDS_Shape& theResult,
89                                    const TopAbs_ShapeEnum theType,
90                                    const TopoDS_Shape& theRotatedBoundingFace,
91                                    const TopoDS_Shape& theModifiedBaseShape,
92                                    const bool theIsFromFaceSet);
93
94 //==================================================================================================
95 GeomAlgoAPI_Revolution::GeomAlgoAPI_Revolution(const GeomShapePtr                 theBaseShape,
96                                                const std::shared_ptr<GeomAPI_Ax1> theAxis,
97                                                const GeomShapePtr                 theToShape,
98                                                const double                       theToAngle,
99                                                const GeomShapePtr                 theFromShape,
100                                                const double                       theFromAngle)
101 {
102   build(theBaseShape, theAxis, theToShape, theToAngle, theFromShape, theFromAngle);
103 }
104
105 //==================================================================================================
106 void GeomAlgoAPI_Revolution::build(const GeomShapePtr&                 theBaseShape,
107                                    const std::shared_ptr<GeomAPI_Ax1>& theAxis,
108                                    const GeomShapePtr&                 theToShape,
109                                    const double                        theToAngle,
110                                    const GeomShapePtr&                 theFromShape,
111                                    const double                        theFromAngle)
112 {
113   if(!theBaseShape || !theAxis ||
114     (((!theFromShape && !theToShape) ||
115     (theFromShape && theToShape && theFromShape->isEqual(theToShape)))
116     && (theFromAngle == -theToAngle))) {
117     return;
118   }
119
120   // Getting base shape.
121   const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
122   TopAbs_ShapeEnum aShapeTypeToExp;
123   switch(aBaseShape.ShapeType()) {
124     case TopAbs_VERTEX:
125       aShapeTypeToExp = TopAbs_VERTEX;
126       break;
127     case TopAbs_EDGE:
128     case TopAbs_WIRE:
129       aShapeTypeToExp = TopAbs_EDGE;
130       break;
131     case TopAbs_FACE:
132     case TopAbs_SHELL:
133       aShapeTypeToExp = TopAbs_FACE;
134       break;
135     case TopAbs_COMPOUND:
136       aShapeTypeToExp = TopAbs_COMPOUND;
137       break;
138     default:
139       return;
140   }
141
142   // Getting axis.
143   gp_Ax1 anAxis = theAxis->impl<gp_Ax1>();
144
145   // Getting base plane.
146   Handle(Geom_Plane) aBasePlane;
147   BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
148   if(aShapeTypeToExp == TopAbs_FACE && aFindPlane.Found() == Standard_True) {
149     aBasePlane = aFindPlane.Plane();
150   } else {
151     gp_Pnt aPnt1 = anAxis.Location();
152
153     TopExp_Explorer anExp(aBaseShape, TopAbs_VERTEX);
154     gp_Pnt aPnt2 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
155     gp_Pnt aPnt3 = aPnt1;
156
157     for (anExp.Next(); anExp.More() && aBasePlane.IsNull(); anExp.Next()) {
158       aPnt3 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current()));
159       aBasePlane = makePlane(aPnt1, aPnt2, aPnt3);
160     }
161
162     if(aBasePlane.IsNull()) {
163       gp_Pnt aPossiblePoints[] = { aPnt1.Translated(anAxis.Direction()), centreOfMass(aBaseShape) };
164       for (auto it = std::begin(aPossiblePoints);
165            it != std::end(aPossiblePoints) && aBasePlane.IsNull(); ++it)
166         aBasePlane = makePlane(aPnt1, aPnt2, *it);
167     }
168   }
169
170   if(aShapeTypeToExp == TopAbs_FACE) {
171     if(aBasePlane->Axis().Angle(anAxis) < Precision::Confusion()) {
172       return;
173     }
174   }
175
176   gp_Pnt aBaseCentre = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape)->impl<gp_Pnt>();
177
178   TopoDS_Shape aResult;
179   if(!theFromShape && !theToShape) { // Case 1: When only angles was set.
180     // Rotating base face with the negative value of "from angle".
181     gp_Trsf aBaseTrsf;
182     aBaseTrsf.SetRotation(anAxis, -theFromAngle / 180.0 * M_PI);
183     BRepBuilderAPI_Transform* aBaseTransform = new BRepBuilderAPI_Transform(aBaseShape,
184                                                                             aBaseTrsf,
185                                                                             true);
186     if(!aBaseTransform) {
187       return;
188     }
189     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
190       new GeomAlgoAPI_MakeShape(aBaseTransform)));
191     if(!aBaseTransform->IsDone()) {
192       return;
193     }
194     TopoDS_Shape aRotatedBase = aBaseTransform->Shape();
195
196     // Making revolution to the angle equal to the sum of "from angle" and "to angle".
197     BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aRotatedBase,
198                                                         anAxis,
199                                                         (theFromAngle + theToAngle) / 180 * M_PI,
200                                                         Standard_True);
201     if(!aRevolBuilder) {
202       return;
203     }
204     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
205       new GeomAlgoAPI_MakeShape(aRevolBuilder)));
206     if(!aRevolBuilder->IsDone()) {
207       return;
208     }
209     aResult = aRevolBuilder->Shape();
210
211     // Setting naming.
212     if(aShapeTypeToExp == TopAbs_COMPOUND) {
213       storeGenerationHistory(this, aRotatedBase, TopAbs_EDGE, aRevolBuilder);
214       storeGenerationHistory(this, aRotatedBase, TopAbs_FACE, aRevolBuilder);
215     } else {
216       storeGenerationHistory(this, aRotatedBase, aShapeTypeToExp, aRevolBuilder);
217     }
218   } else if(theFromShape && theToShape) { // Case 2: When both bounding planes were set.
219     // Making revolution to the 360 angle.
220     BRepPrimAPI_MakeRevol* aRevolBuilder =
221       new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True);
222     if(!aRevolBuilder) {
223       return;
224     }
225     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
226       new GeomAlgoAPI_MakeShape(aRevolBuilder)));
227     if(!aRevolBuilder->IsDone()) {
228       return;
229     }
230     aResult = aRevolBuilder->Shape();
231
232     // Getting bounding faces.
233     TopoDS_Face aFromFace = TopoDS::Face(theFromShape->impl<TopoDS_Shape>());
234     TopoDS_Face aToFace   = TopoDS::Face(theToShape->impl<TopoDS_Shape>());
235
236     // Getting planes from bounding face.
237     GeomLib_IsPlanarSurface isFromPlanar(BRep_Tool::Surface(aFromFace));
238     GeomLib_IsPlanarSurface isToPlanar(BRep_Tool::Surface(aToFace));
239     if(!isFromPlanar.IsPlanar() || !isToPlanar.IsPlanar()) {
240       // non-planar shapes is not supported for revolution bounding
241       return;
242     }
243
244     std::shared_ptr<GeomAPI_Face> aGeomFromFace(new GeomAPI_Face(theFromShape));
245     std::shared_ptr<GeomAPI_Face> aGeomToFace(new GeomAPI_Face(theToShape));
246
247     gp_Pln aFromPln = aGeomFromFace->getPlane()->impl<gp_Pln>();
248     gp_Pln aToPln   = aGeomToFace->getPlane()->impl<gp_Pln>();
249
250     // Orienting bounding planes properly so that the center of mass of the base face stays
251     // on the result shape after cut.
252     aFromFace = makeFaceFromPlane(aFromPln, aBaseCentre);
253     aToFace   = makeFaceFromPlane(aToPln, aBaseCentre);
254
255     // Making solids from bounding planes and putting them in compound.
256     TopoDS_Shape aFromSolid = makeSolidFromShape(aFromFace);
257     TopoDS_Shape aToSolid   = makeSolidFromShape(aToFace);
258
259     // Rotating bounding planes to the specified angle.
260     gp_Trsf aFromTrsf;
261     gp_Trsf aToTrsf;
262     double aFromRotAngle =
263       ((aFromPln.Axis().Direction() * aBasePlane->Axis().Direction()) > 0) ? -theFromAngle :
264                                                                               theFromAngle;
265     double aToRotAngle =
266       ((aToPln.Axis().Direction() * aBasePlane->Axis().Direction()) > 0) ? -theToAngle :
267                                                                             theToAngle;
268     aFromTrsf.SetRotation(anAxis,aFromRotAngle / 180.0 * M_PI);
269     aToTrsf.SetRotation(anAxis, aToRotAngle / 180.0 * M_PI);
270     BRepBuilderAPI_Transform aFromTransform(aFromSolid, aFromTrsf, true);
271     BRepBuilderAPI_Transform aToTransform(aToSolid, aToTrsf, true);
272     TopoDS_Shape aRotatedFromFace = aFromTransform.Modified(aFromFace).First();
273     TopoDS_Shape aRotatedToFace = aToTransform.Modified(aToFace).First();
274     aFromSolid = aFromTransform.Shape();
275     aToSolid = aToTransform.Shape();
276
277     // Cutting revolution with from plane.
278     BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
279     aFromCutBuilder->Build();
280     if(!aFromCutBuilder->IsDone()) {
281       return;
282     }
283     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
284       new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
285     aResult = aFromCutBuilder->Shape();
286     if(aResult.ShapeType() == TopAbs_COMPOUND) {
287       aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
288     }
289
290     // Cutting revolution with to plane.
291     BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
292     aToCutBuilder->Build();
293     if(!aToCutBuilder->IsDone()) {
294       return;
295     }
296     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
297       new GeomAlgoAPI_MakeShape(aToCutBuilder)));
298     aResult = aToCutBuilder->Shape();
299     TopoDS_Iterator aCheckIt(aResult);
300     if(!aCheckIt.More()) {
301       return;
302     }
303     if(aResult.ShapeType() == TopAbs_COMPOUND) {
304       aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
305     }
306     if(aResult.ShapeType() == TopAbs_COMPOUND) {
307       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
308       aGeomShape->setImpl(new TopoDS_Shape(aResult));
309       ListOfShape aResults;
310       aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
311                                                          GeomAPI_Shape::COMPSOLID,
312                                                          aResults);
313       aResult = aGeomShape->impl<TopoDS_Shape>();
314     }
315
316     // If after cut we got more than one solids then take closest
317     // to the center of mass of the base face.
318     aResult = findClosest(aResult, aBaseCentre);
319
320     // Setting naming.
321     if(aShapeTypeToExp == TopAbs_COMPOUND) {
322       storeGenerationHistory(this, aResult, TopAbs_EDGE, aRotatedToFace, aRotatedFromFace);
323       storeGenerationHistory(this, aResult, TopAbs_FACE, aRotatedToFace, aRotatedFromFace);
324     } else {
325       storeGenerationHistory(this, aResult, aShapeTypeToExp, aRotatedToFace, aRotatedFromFace);
326     }
327   } else { //Case 3: When only one bounding plane was set.
328     // Making revolution to the 360 angle.
329     BRepPrimAPI_MakeRevol* aRevolBuilder =
330       new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True);
331     if(!aRevolBuilder) {
332       return;
333     }
334     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
335       new GeomAlgoAPI_MakeShape(aRevolBuilder)));
336     if(!aRevolBuilder->IsDone()) {
337       return;
338     }
339     aResult = aRevolBuilder->Shape();
340
341     // Getting bounding face.
342     bool isFromFaceSet = false;
343     std::shared_ptr<GeomAPI_Face> aGeomBoundingFace;
344     if(theFromShape) {
345       aGeomBoundingFace.reset(new GeomAPI_Face(theFromShape));
346       isFromFaceSet = true;
347     } else if(theToShape) {
348       aGeomBoundingFace.reset(new GeomAPI_Face(theToShape));
349     }
350     TopoDS_Face aBoundingFace = TopoDS::Face(aGeomBoundingFace->impl<TopoDS_Shape>());
351
352     // Getting plane from bounding face.
353     GeomLib_IsPlanarSurface isBoundingPlanar(BRep_Tool::Surface(aBoundingFace));
354     if(!isBoundingPlanar.IsPlanar()) { // non-planar shapes is not supported for revolution bounding
355       return;
356     }
357
358     gp_Pln aBoundingPln = aGeomBoundingFace->getPlane()->impl<gp_Pln>();
359
360     // Orienting bounding plane properly so that the center of mass of the base face stays
361     // on the result shape after cut.
362     aBoundingFace = makeFaceFromPlane(aBoundingPln, aBaseCentre);
363
364     // Making solid from bounding plane.
365     TopoDS_Shape aBoundingSolid = makeSolidFromShape(aBoundingFace);
366
367     // Rotating bounding plane to the specified angle.
368     double aBoundingRotAngle = isFromFaceSet ? theFromAngle : theToAngle;
369     if(aBoundingPln.Axis().IsParallel(aBasePlane->Axis(), Precision::Confusion())) {
370       if(isFromFaceSet) aBoundingRotAngle = -aBoundingRotAngle;
371     } else {
372       double aSign = (aBoundingPln.Axis().Direction() ^ aBasePlane->Axis().Direction()) *
373                      anAxis.Direction();
374       if((aSign <= 0 && !isFromFaceSet) || (aSign > 0 && isFromFaceSet)) {
375         aBoundingRotAngle = -aBoundingRotAngle;
376       }
377     }
378     gp_Trsf aBoundingTrsf;
379     aBoundingTrsf.SetRotation(anAxis, aBoundingRotAngle / 180.0 * M_PI);
380     BRepBuilderAPI_Transform aBoundingTransform(aBoundingSolid, aBoundingTrsf, true);
381     TopoDS_Shape aRotatedBoundingFace = aBoundingTransform.Modified(aBoundingFace).First();
382     aBoundingSolid = aBoundingTransform.Shape();
383
384     // Cutting revolution with bounding plane.
385     BRepAlgoAPI_Cut* aBoundingCutBuilder = new BRepAlgoAPI_Cut(aResult, aBoundingSolid);
386     aBoundingCutBuilder->Build();
387     if(!aBoundingCutBuilder->IsDone()) {
388       return;
389     }
390     this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
391       new GeomAlgoAPI_MakeShape(aBoundingCutBuilder)));
392     aResult = aBoundingCutBuilder->Shape();
393     if(aResult.ShapeType() == TopAbs_COMPOUND) {
394       aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
395     }
396
397     // Setting naming.
398     if(aShapeTypeToExp == TopAbs_FACE || aShapeTypeToExp == TopAbs_COMPOUND) {
399       const TopTools_ListOfShape& aBndShapes = aBoundingCutBuilder->Modified(aBoundingFace);
400       for(TopTools_ListIteratorOfListOfShape anIt(aBndShapes); anIt.More(); anIt.Next()) {
401         GeomShapePtr aShape(new GeomAPI_Shape());
402         aShape->setImpl(new TopoDS_Shape(anIt.Value()));
403         fixOrientation(aShape);
404         isFromFaceSet ? this->addFromShape(aShape) : this->addToShape(aShape);
405       }
406     }
407
408     // Try to cut with base face. If it can not be done then keep result of cut with bounding plane.
409     TopoDS_Shape aModifiedBaseShape;
410     if(aShapeTypeToExp != TopAbs_FACE) {
411       ListOfShape aList;
412       GeomShapePtr aSh(new GeomAPI_Shape());
413       aSh->setImpl(new TopoDS_Shape(aBaseShape));
414       std::shared_ptr<GeomAPI_Pnt> theCenter(new GeomAPI_Pnt(aBasePlane->Location().X(),
415                                                              aBasePlane->Location().Y(),
416                                                              aBasePlane->Location().Z()));
417       std::shared_ptr<GeomAPI_Dir> theNormal(new GeomAPI_Dir(aBasePlane->Axis().Direction().X(),
418                                                              aBasePlane->Axis().Direction().Y(),
419                                                              aBasePlane->Axis().Direction().Z()));
420       GeomShapePtr aPln = GeomAlgoAPI_FaceBuilder::planarFace(theCenter, theNormal);
421       aList.push_back(aSh);
422       std::list<std::shared_ptr<GeomAPI_Pnt> >
423         aBoundingPoints = GeomAlgoAPI_ShapeTools::getBoundingBox(aList);
424       aSh = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPln, aBoundingPoints);
425       aModifiedBaseShape = aSh->impl<TopoDS_Shape>();
426     } else {
427       aModifiedBaseShape = aBaseShape;
428     }
429     if(isFromFaceSet) {
430       if(aModifiedBaseShape.ShapeType() == TopAbs_FACE) {
431         aModifiedBaseShape.Orientation(TopAbs_REVERSED);
432       } else {
433         gp_Trsf aMirrorTrsf;
434         aMirrorTrsf.SetMirror(aBasePlane->Position().Ax2());
435         BRepBuilderAPI_Transform aMirrorTransform(aModifiedBaseShape, aMirrorTrsf, true);
436         aModifiedBaseShape = aMirrorTransform.Shape();
437       }
438     }
439
440     // Making solid from base face.
441     TopoDS_Shape aBaseSolid = makeSolidFromShape(aModifiedBaseShape);
442
443     // Rotating base face to the specified angle.
444     gp_Trsf aBaseTrsf;
445     double aBaseRotAngle = isFromFaceSet ? theToAngle : -theFromAngle;
446     aBaseTrsf.SetRotation(anAxis, aBaseRotAngle / 180.0 * M_PI);
447     BRepBuilderAPI_Transform aBaseTransform(aBaseSolid, aBaseTrsf, true);
448     aBaseSolid = aBaseTransform.Shape();
449
450     // Cutting revolution with base.
451     BRepAlgoAPI_Cut* aBaseCutBuilder = new BRepAlgoAPI_Cut(aResult, aBaseSolid);
452     aBaseCutBuilder->Build();
453     if(aBaseCutBuilder->IsDone()) {
454       TopoDS_Shape aCutResult = aBaseCutBuilder->Shape();
455       TopoDS_Iterator aCheckIt(aCutResult);
456       if(aCheckIt.More()) {
457         this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(
458           new GeomAlgoAPI_MakeShape(aBaseCutBuilder)));
459         aResult = aCutResult;
460         if(aResult.ShapeType() == TopAbs_COMPOUND) {
461           aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
462         }
463         if(aShapeTypeToExp == TopAbs_FACE || aShapeTypeToExp == TopAbs_COMPOUND) {
464           const TopTools_ListOfShape& aBsShapes = aBaseCutBuilder->Modified(aBoundingFace);
465           for(TopTools_ListIteratorOfListOfShape anIt(aBsShapes); anIt.More(); anIt.Next()) {
466             GeomShapePtr aShape(new GeomAPI_Shape());
467             aShape->setImpl(new TopoDS_Shape(anIt.Value()));
468             fixOrientation(aShape);
469             isFromFaceSet ? this->addToShape(aShape) : this->addFromShape(aShape);
470           }
471         }
472       }
473     }
474
475     if(aResult.ShapeType() == TopAbs_COMPOUND) {
476       std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
477       aGeomShape->setImpl(new TopoDS_Shape(aResult));
478       ListOfShape aResults;
479       aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape,
480                                                          GeomAPI_Shape::COMPSOLID,
481                                                          aResults);
482       aResult = aGeomShape->impl<TopoDS_Shape>();
483     }
484
485     // If after cut we got more than one solids then take
486     // closest to the center of mass of the base face.
487     aResult = findClosest(aResult, aBaseCentre);
488
489     // Setting naming.
490     if(aShapeTypeToExp == TopAbs_COMPOUND) {
491       storeGenerationHistory(this, aResult, TopAbs_EDGE,
492         aRotatedBoundingFace, aModifiedBaseShape, isFromFaceSet);
493       storeGenerationHistory(this, aResult, TopAbs_FACE,
494         aRotatedBoundingFace, aModifiedBaseShape, isFromFaceSet);
495     } else {
496       storeGenerationHistory(this, aResult, aShapeTypeToExp,
497         aRotatedBoundingFace, aModifiedBaseShape, isFromFaceSet);
498     }
499   }
500
501   // Setting result.
502   if(aResult.IsNull()) {
503     return;
504   }
505   aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
506   GeomShapePtr aShape(new GeomAPI_Shape());
507   aShape->setImpl(new TopoDS_Shape(aResult));
508   this->setShape(aShape);
509   this->setDone(true);
510 }
511
512 //==================================================================================================
513 TopoDS_Face makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint)
514 {
515   if(!thePlane.Contains(thePoint, Precision::Confusion())) {
516     gp_XYZ aVec = thePoint.XYZ() - thePlane.Location().XYZ();
517     double aSign = aVec * thePlane.Axis().Direction().XYZ();
518     if(aSign < 0) thePlane.SetAxis(thePlane.Axis().Reversed());
519   }
520
521   BRepBuilderAPI_MakeFace aMakeFace(thePlane);
522   TopoDS_Face aResultFace = TopoDS::Face(aMakeFace.Shape());
523
524   return aResultFace;
525 }
526
527 //==================================================================================================
528 TopoDS_Solid makeSolidFromShape(const TopoDS_Shape& theShape)
529 {
530   TopoDS_Shell aShell;
531   TopoDS_Solid aSolid;
532
533   BRep_Builder aBoundingBuilder;
534   if(theShape.ShapeType() == TopAbs_SHELL) {
535     aShell = TopoDS::Shell(theShape);
536   } else {
537     aBoundingBuilder.MakeShell(aShell);
538     aBoundingBuilder.Add(aShell, theShape);
539   }
540   aBoundingBuilder.MakeSolid(aSolid);
541   aBoundingBuilder.Add(aSolid, aShell);
542
543   return aSolid;
544 }
545
546 //================================================================================================
547 gp_Pnt centreOfMass(const TopoDS_Shape& theShape)
548 {
549   TopAbs_ShapeEnum aShType = theShape.ShapeType();
550   GProp_GProps aGProps;
551
552   if(aShType == TopAbs_EDGE || aShType == TopAbs_WIRE) {
553     BRepGProp::LinearProperties(theShape, aGProps);
554   } else if(aShType == TopAbs_FACE || aShType == TopAbs_SHELL) {
555     BRepGProp::SurfaceProperties(theShape, aGProps);
556   } else if(aShType == TopAbs_SOLID || aShType == TopAbs_COMPSOLID) {
557     BRepGProp::VolumeProperties(theShape, aGProps);
558   }
559
560   return aGProps.CentreOfMass();
561 }
562
563 //================================================================================================
564 TopoDS_Shape findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint)
565 {
566   TopoDS_Shape aResult = theShape;
567
568   if(theShape.ShapeType() == TopAbs_COMPOUND) {
569     double aMinDistance = Precision::Infinite();
570     double aCurDistance;
571     gp_Pnt aCentr;
572     for (TopoDS_Iterator anItr(theShape); anItr.More(); anItr.Next()) {
573       TopoDS_Shape aValue = anItr.Value();
574       aCentr = centreOfMass(aValue);
575       aCurDistance = aCentr.Distance(thePoint);
576
577       if(aCurDistance < aMinDistance) {
578         aMinDistance = aCurDistance;
579         aResult = aValue;
580       }
581     }
582   }
583
584   return aResult;
585 }
586
587 //================================================================================================
588 Handle(Geom_Plane) makePlane(const gp_Pnt& theP1, const gp_Pnt& theP2, const gp_Pnt& theP3)
589 {
590   Handle(Geom_Plane) aPlane;
591   GC_MakePlane aMkPlane(theP1, theP2, theP3);
592   if (aMkPlane.IsDone())
593     aPlane = aMkPlane.Value();
594   return aPlane;
595 }
596
597 //================================================================================================
598 void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo,
599                             const TopoDS_Shape& theBase,
600                             const TopAbs_ShapeEnum theType,
601                             BRepPrimAPI_MakeRevol* theRevolBuilder)
602 {
603   for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) {
604     const TopoDS_Shape& aShape = anExp.Current();
605     GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
606     aFromShape->setImpl(new TopoDS_Shape(theRevolBuilder->FirstShape(aShape)));
607     aToShape->setImpl(new TopoDS_Shape(theRevolBuilder->LastShape(aShape)));
608     theRevolutionAlgo->fixOrientation(aFromShape);
609     theRevolutionAlgo->fixOrientation(aToShape);
610     theRevolutionAlgo->addFromShape(aFromShape);
611     theRevolutionAlgo->addToShape(aToShape);
612   }
613 }
614
615 //================================================================================================
616 void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo,
617                             const TopoDS_Shape& theResult,
618                             const TopAbs_ShapeEnum theType,
619                             const TopoDS_Shape& theToFace,
620                             const TopoDS_Shape& theFromFace)
621 {
622   for(TopExp_Explorer anExp(theResult, theType); anExp.More (); anExp.Next ()) {
623     const TopoDS_Shape& aShape = anExp.Current();
624     GeomShapePtr aGeomSh(new GeomAPI_Shape());
625     if(theType == TopAbs_VERTEX) {
626       gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
627       IntTools_Context anIntTools;
628       if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theToFace),
629           Precision::Confusion()) == Standard_True) {
630         aGeomSh->setImpl(new TopoDS_Shape(aShape));
631         theRevolutionAlgo->fixOrientation(aGeomSh);
632         theRevolutionAlgo->addToShape(aGeomSh);
633       }
634       if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theFromFace),
635           Precision::Confusion()) == Standard_True) {
636         aGeomSh->setImpl(new TopoDS_Shape(aShape));
637         theRevolutionAlgo->fixOrientation(aGeomSh);
638         theRevolutionAlgo->addFromShape(aGeomSh);
639       }
640     } else if(theType == TopAbs_EDGE) {
641       TopoDS_Edge anEdge = TopoDS::Edge(aShape);
642       BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, TopoDS::Face(theToFace));
643       anEdgeCheck.Perform();
644       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
645         aGeomSh->setImpl(new TopoDS_Shape(aShape));
646         theRevolutionAlgo->fixOrientation(aGeomSh);
647         theRevolutionAlgo->addToShape(aGeomSh);
648       }
649       anEdgeCheck.Init(anEdge, TopoDS::Face(theFromFace));
650       anEdgeCheck.Perform();
651       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
652         aGeomSh->setImpl(new TopoDS_Shape(aShape));
653         theRevolutionAlgo->fixOrientation(aGeomSh);
654         theRevolutionAlgo->addFromShape(aGeomSh);
655       }
656     } else {
657       Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aShape));
658       Handle(Geom_Surface) aFromSurface = BRep_Tool::Surface(TopoDS::Face(theFromFace));
659       Handle(Geom_Surface) aToSurface = BRep_Tool::Surface(TopoDS::Face(theToFace));
660       if(aFaceSurface == aFromSurface) {
661         aGeomSh->setImpl(new TopoDS_Shape(aShape));
662         theRevolutionAlgo->fixOrientation(aGeomSh);
663         theRevolutionAlgo->addFromShape(aGeomSh);
664       }
665       if(aFaceSurface == aToSurface) {
666         aGeomSh->setImpl(new TopoDS_Shape(aShape));
667         theRevolutionAlgo->fixOrientation(aGeomSh);
668         theRevolutionAlgo->addToShape(aGeomSh);
669       }
670     }
671   }
672 }
673
674 void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo,
675                             const TopoDS_Shape& theResult,
676                             const TopAbs_ShapeEnum theType,
677                             const TopoDS_Shape& theRotatedBoundingFace,
678                             const TopoDS_Shape& theModifiedBaseShape,
679                             const bool theIsFromFaceSet)
680 {
681   for(TopExp_Explorer anExp(theResult, theType); anExp.More (); anExp.Next ()) {
682     const TopoDS_Shape& aShape = anExp.Current();
683     GeomShapePtr aGeomSh(new GeomAPI_Shape());
684     if(theType == TopAbs_VERTEX) {
685       gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape));
686       IntTools_Context anIntTools;
687       if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theRotatedBoundingFace),
688           Precision::Confusion()) == Standard_True) {
689         aGeomSh->setImpl(new TopoDS_Shape(aShape));
690         theRevolutionAlgo->fixOrientation(aGeomSh);
691         theIsFromFaceSet ? theRevolutionAlgo->addFromShape(aGeomSh) :
692                            theRevolutionAlgo->addToShape(aGeomSh);
693       }
694       if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theModifiedBaseShape),
695          Precision::Confusion()) == Standard_True) {
696         aGeomSh->setImpl(new TopoDS_Shape(aShape));
697         theRevolutionAlgo->fixOrientation(aGeomSh);
698         theIsFromFaceSet ? theRevolutionAlgo->addToShape(aGeomSh) :
699                            theRevolutionAlgo->addFromShape(aGeomSh);
700       }
701     } else if(theType == TopAbs_EDGE) {
702       TopoDS_Edge anEdge = TopoDS::Edge(aShape);
703       BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, TopoDS::Face(theRotatedBoundingFace));
704       anEdgeCheck.Perform();
705       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
706         aGeomSh->setImpl(new TopoDS_Shape(aShape));
707         theRevolutionAlgo->fixOrientation(aGeomSh);
708         theIsFromFaceSet ? theRevolutionAlgo->addFromShape(aGeomSh) :
709                            theRevolutionAlgo->addToShape(aGeomSh);
710       }
711       anEdgeCheck.Init(anEdge, TopoDS::Face(theModifiedBaseShape));
712       anEdgeCheck.Perform();
713       if(anEdgeCheck.MaxDistance() < Precision::Confusion()) {
714         aGeomSh->setImpl(new TopoDS_Shape(aShape));
715         theRevolutionAlgo->fixOrientation(aGeomSh);
716         theIsFromFaceSet ? theRevolutionAlgo->addToShape(aGeomSh) :
717                            theRevolutionAlgo->addFromShape(aGeomSh);
718       }
719     } else {
720       Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aShape));
721       Handle(Geom_Surface) aBoundingSurface =
722         BRep_Tool::Surface(TopoDS::Face(theRotatedBoundingFace));
723       Handle(Geom_Surface) aBaseSurface = BRep_Tool::Surface(TopoDS::Face(theModifiedBaseShape));
724       if(aFaceSurface == aBoundingSurface) {
725         aGeomSh->setImpl(new TopoDS_Shape(aShape));
726         theRevolutionAlgo->fixOrientation(aGeomSh);
727         theIsFromFaceSet ? theRevolutionAlgo->addFromShape(aGeomSh) :
728                            theRevolutionAlgo->addToShape(aGeomSh);
729       }
730       if(aFaceSurface == aBaseSurface) {
731         aGeomSh->setImpl(new TopoDS_Shape(aShape));
732         theRevolutionAlgo->fixOrientation(aGeomSh);
733         theIsFromFaceSet ? theRevolutionAlgo->addToShape(aGeomSh) :
734                            theRevolutionAlgo->addFromShape(aGeomSh);
735       }
736     }
737   }
738 }