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