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