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