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