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