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