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