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