Salome HOME
Merge remote-tracking branch 'origin/PortingSalome760' into Dev_1.3.0
[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 <GeomAlgoAPI_DFLoader.h>
10 #include <GeomAlgoAPI_MakeShapeList.h>
11 #include <GeomAlgoAPI_Rotation.h>
12 #include <GeomAlgoAPI_ShapeProps.h>
13
14 #include <BRep_Builder.hxx>
15 #include <BRep_Tool.hxx>
16 #include <BRepAlgoAPI_Cut.hxx>
17 #include <BRepBuilderAPI_MakeFace.hxx>
18 #include <BRepBuilderAPI_Transform.hxx>
19 #include <BRepCheck_Analyzer.hxx>
20 #include <BRepPrimAPI_MakeRevol.hxx>
21 #include <BRepGProp.hxx>
22 #include <Geom_Plane.hxx>
23 #include <Geom_RectangularTrimmedSurface.hxx>
24 #include <GeomLib_IsPlanarSurface.hxx>
25 #include <gp_Pln.hxx>
26 #include <GProp_GProps.hxx>
27 #include <TopExp_Explorer.hxx>
28 #include <TopoDS.hxx>
29
30 //=================================================================================================
31 GeomAlgoAPI_Revolution::GeomAlgoAPI_Revolution(std::shared_ptr<GeomAPI_Shape> theBasis,
32                                                std::shared_ptr<GeomAPI_Ax1>   theAxis,
33                                                std::shared_ptr<GeomAPI_Shape> theFromShape,
34                                                double                         theFromAngle,
35                                                std::shared_ptr<GeomAPI_Shape> theToShape,
36                                                double                         theToAngle)
37 : myAxis(theAxis),
38   myFromShape(theFromShape),
39   myFromAngle(theFromAngle),
40   myToShape(theToShape),
41   myToAngle(theToAngle),
42   myDone(false),
43   myShape(new GeomAPI_Shape()),
44   myFirst(new GeomAPI_Shape()),myLast(new GeomAPI_Shape())
45 {
46   build(theBasis);
47 }
48
49 //=================================================================================================
50 TopoDS_Face GeomAlgoAPI_Revolution::makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint)
51 {
52   gp_XYZ aVec = thePoint.XYZ() - thePlane.Location().XYZ();
53   double aSign = aVec * thePlane.Axis().Direction().XYZ();
54   if(aSign < 0) thePlane.SetAxis(thePlane.Axis().Reversed());
55
56   BRepBuilderAPI_MakeFace aMakeFace(thePlane);
57   TopoDS_Face aResultFace = TopoDS::Face(aMakeFace.Shape());
58
59   return aResultFace;
60 }
61
62 //=================================================================================================
63 TopoDS_Solid GeomAlgoAPI_Revolution::makeSolidFromFace(const TopoDS_Face& theFace)
64 {
65   TopoDS_Shell aShell;
66   TopoDS_Solid aSolid;
67
68   BRep_Builder aBoundingBuilder;
69   aBoundingBuilder.MakeShell(aShell);
70   aBoundingBuilder.Add(aShell, theFace);
71   aBoundingBuilder.MakeSolid(aSolid);
72   aBoundingBuilder.Add(aSolid, aShell);
73
74   return aSolid;
75 }
76
77 //=================================================================================================
78 TopoDS_Shape GeomAlgoAPI_Revolution::findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint)
79 {
80   TopoDS_Shape aResult = theShape;
81
82   if(theShape.ShapeType() == TopAbs_COMPOUND) {
83     double aMinDistance = Precision::Infinite();
84     double aCurDistance;
85     GProp_GProps aGProps;
86     gp_Pnt aCentr;
87
88     for (TopoDS_Iterator anItr(theShape); anItr.More(); anItr.Next()) {
89       TopoDS_Shape aValue = anItr.Value();
90       BRepGProp::VolumeProperties(aValue, aGProps);
91       aCentr = aGProps.CentreOfMass();
92       aCurDistance = aCentr.Distance(thePoint);
93
94       if(aCurDistance < aMinDistance) {
95         aMinDistance = aCurDistance;
96         aResult = aValue;
97       }
98     }
99   }
100
101   return aResult;
102 }
103
104 //=================================================================================================
105 void GeomAlgoAPI_Revolution::build(const std::shared_ptr<GeomAPI_Shape>& theBasis)
106 {
107   if(!theBasis || !myAxis ||
108     (((!myFromShape && !myToShape) || (myFromShape && myToShape && myFromShape->isEqual(myToShape)))
109     && (myFromAngle == 0.0 && myToAngle == 0.0))) {
110     return;
111   }
112
113   TopoDS_Face aBasisFace = TopoDS::Face(theBasis->impl<TopoDS_Shape>());
114   GeomLib_IsPlanarSurface isBasisPlanar(BRep_Tool::Surface(aBasisFace));
115   if(!isBasisPlanar.IsPlanar()) {// non-planar shapes is not supported for revolution
116     return;
117   }
118   gp_Pln aBasisPln = isBasisPlanar.Plan();
119   gp_Ax1 anAxis = myAxis->impl<gp_Ax1>();
120
121   ListOfMakeShape aListOfMakeShape;
122
123   TopoDS_Shape aResult;
124   if(!myFromShape && !myToShape) { // Case 1: When only angles was set.
125     // Rotating base face with the negative value of "from angle".
126     gp_Trsf aBaseTrsf;
127     aBaseTrsf.SetRotation(anAxis, -myFromAngle / 180.0 * M_PI);
128     BRepBuilderAPI_Transform* aBaseTransform = new BRepBuilderAPI_Transform(aBasisFace,
129                                                                             aBaseTrsf,
130                                                                             true);
131     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBaseTransform)));
132     TopoDS_Shape aRotatedBaseShape = aBaseTransform->Shape();
133
134     // Making revolution to the angle equal to the sum of "from angle" and "to angle".
135     double anAngle = myFromAngle + myToAngle;
136     BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aRotatedBaseShape,
137                                                                      anAxis,
138                                                                      anAngle / 180 * M_PI,
139                                                                      Standard_True);
140     aRevolBuilder->Build();
141     if(!aRevolBuilder->IsDone()) {
142       return;
143     }
144     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
145     aResult = aRevolBuilder->Shape();
146
147     // Setting naming.
148     myFirst->setImpl(new TopoDS_Shape(aRevolBuilder->FirstShape()));
149     myLast->setImpl(new TopoDS_Shape(aRevolBuilder->LastShape()));
150   } else if(myFromShape && myToShape) { // Case 2: When both bounding planes were set.
151     // Getting bounding faces.
152     TopoDS_Face aFromFace = TopoDS::Face(myFromShape->impl<TopoDS_Shape>());
153     TopoDS_Face aToFace   = TopoDS::Face(myToShape->impl<TopoDS_Shape>());
154
155     // Getting planes from bounding face.
156     GeomLib_IsPlanarSurface isFromPlanar(BRep_Tool::Surface(aFromFace));
157     GeomLib_IsPlanarSurface isToPlanar(BRep_Tool::Surface(aToFace));
158     if(!isFromPlanar.IsPlanar() || !isToPlanar.IsPlanar()) {// non-planar shapes is not supported for revolution bounding
159       return;
160     }
161     gp_Pln aFromPln = isFromPlanar.Plan();
162     gp_Pln aToPln   = isToPlanar.Plan();
163
164     // Orienting bounding planes properly so that the center of mass of the base face stays
165     // on the result shape after cut.
166     gp_Pnt aBasisCentr = GeomAlgoAPI_ShapeProps::centreOfMass(theBasis)->impl<gp_Pnt>();
167     aFromFace = makeFaceFromPlane(aFromPln, aBasisCentr);
168     aToFace   = makeFaceFromPlane(aToPln, aBasisCentr);
169
170     // Making solids from bounding planes and putting them in compound.
171     TopoDS_Shape aFromSolid = makeSolidFromFace(aFromFace);
172     TopoDS_Shape aToSolid   = makeSolidFromFace(aToFace);
173
174     // Rotating bounding planes to the specified angle.
175     gp_Trsf aFromTrsf;
176     gp_Trsf aToTrsf;
177     double aFromRotAngle = ((aFromPln.Axis().Direction() * aBasisPln.Axis().Direction()) > 0) ? -myFromAngle : myFromAngle;
178     double aToRotAngle = ((aToPln.Axis().Direction() * aBasisPln.Axis().Direction()) > 0) ? -myToAngle : myToAngle;
179     aFromTrsf.SetRotation(anAxis,aFromRotAngle / 180.0 * M_PI);
180     aToTrsf.SetRotation(anAxis, aToRotAngle / 180.0 * M_PI);
181     BRepBuilderAPI_Transform aFromTransform(aFromSolid, aFromTrsf, true);
182     BRepBuilderAPI_Transform aToTransform(aToSolid, aToTrsf, true);
183     TopoDS_Shape aRotatedFromFace = aFromTransform.Modified(aFromFace).First();
184     TopoDS_Shape aRotatedToFace = aToTransform.Modified(aToFace).First();
185     aFromSolid = aFromTransform.Shape();
186     aToSolid = aToTransform.Shape();
187
188     // Making revolution to the 360 angle.
189     BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBasisFace, anAxis, 2 * M_PI, Standard_True);
190     aRevolBuilder->Build();
191     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
192     TopoDS_Shape aRevolShape = aRevolBuilder->Shape();
193
194     // Cutting revolution with from plane.
195     BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aRevolShape, aFromSolid);
196     aFromCutBuilder->Build();
197     if(!aFromCutBuilder->IsDone()) {
198       return;
199     }
200     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
201     aResult = aFromCutBuilder->Shape();
202
203     // Cutting revolution with to plane.
204     BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
205     aToCutBuilder->Build();
206     if(!aToCutBuilder->IsDone()) {
207       return;
208     }
209     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
210     aResult = aToCutBuilder->Shape();
211
212     // If after cut we got more than one solids then take closest to the center of mass of the base face.
213     aResult = findClosest(aResult, aBasisCentr);
214
215     // Setting naming.
216     for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) {
217       const TopoDS_Shape& aFaceOnResult = anExp.Current();
218       Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aFaceOnResult));
219       Handle(Geom_Surface) aFromSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedFromFace));
220       Handle(Geom_Surface) aToSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedToFace));
221       if(aFaceSurface == aFromSurface) {
222         myFirst->setImpl(new TopoDS_Shape(aFaceOnResult));
223       }
224       if(aFaceSurface == aToSurface) {
225         myLast->setImpl(new TopoDS_Shape(aFaceOnResult));
226       }
227     }
228   } else { //Case 3: When only one bounding plane was set.
229     // Getting bounding face.
230     TopoDS_Face aBoundingFace;
231     bool isFromFaceSet = false;
232     if(myFromShape) {
233       aBoundingFace = TopoDS::Face(myFromShape->impl<TopoDS_Shape>());
234       isFromFaceSet = true;
235     } else if(myToShape) {
236       aBoundingFace = TopoDS::Face(myToShape->impl<TopoDS_Shape>());
237     }
238
239     // Getting plane from bounding face.
240     GeomLib_IsPlanarSurface isBoundingPlanar(BRep_Tool::Surface(aBoundingFace));
241     if(!isBoundingPlanar.IsPlanar()) { // non-planar shapes is not supported for revolution bounding
242       return;
243     }
244     gp_Pln aBoundingPln = isBoundingPlanar.Plan();
245
246     // Orienting bounding plane properly so that the center of mass of the base face stays
247     // on the result shape after cut.
248     gp_Pnt aBasisCentr = GeomAlgoAPI_ShapeProps::centreOfMass(theBasis)->impl<gp_Pnt>();
249     aBoundingFace = makeFaceFromPlane(aBoundingPln, aBasisCentr);
250
251     // Making solid from bounding plane.
252     TopoDS_Shape aBoundingSolid = makeSolidFromFace(aBoundingFace);
253
254     // Rotating bounding plane to the specified angle.
255     double aBoundingRotAngle = isFromFaceSet ? myFromAngle : myToAngle;
256     if(aBoundingPln.Axis().IsParallel(aBasisPln.Axis(), Precision::Confusion())) {
257       if(isFromFaceSet) aBoundingRotAngle = -aBoundingRotAngle;
258     } else {
259       double aSign = (aBoundingPln.Axis().Direction() ^ aBasisPln.Axis().Direction()) *
260                      anAxis.Direction();
261       if((aSign <= 0 && !isFromFaceSet) || (aSign > 0 && isFromFaceSet)) {
262         aBoundingRotAngle = -aBoundingRotAngle;
263       }
264     }
265     gp_Trsf aBoundingTrsf;
266     aBoundingTrsf.SetRotation(anAxis, aBoundingRotAngle / 180.0 * M_PI);
267     BRepBuilderAPI_Transform aBoundingTransform(aBoundingSolid, aBoundingTrsf, true);
268     TopoDS_Shape aRotatedBoundingFace = aBoundingTransform.Modified(aBoundingFace).First();
269     aBoundingSolid = aBoundingTransform.Shape();
270
271     // Making revolution to the 360 angle.
272     BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBasisFace, anAxis, 2 * M_PI, Standard_True);
273     aRevolBuilder->Build();
274     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
275     TopoDS_Shape aRevolShape = aRevolBuilder->Shape();
276
277     // Cutting revolution with bounding plane.
278     BRepAlgoAPI_Cut* aBoundingCutBuilder = new BRepAlgoAPI_Cut(aRevolShape, aBoundingSolid);
279     aBoundingCutBuilder->Build();
280     if(!aBoundingCutBuilder->IsDone()) {
281       return;
282     }
283     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBoundingCutBuilder)));
284     aResult = aBoundingCutBuilder->Shape();
285     TopExp_Explorer anExp1(aResult, TopAbs_SOLID);
286
287     // Setting naming.
288     if(aBoundingCutBuilder->Modified(aBoundingFace).Extent() > 0) {
289       std::shared_ptr<GeomAPI_Shape> aPtr = isFromFaceSet ? myFirst : myLast;
290       aPtr->setImpl(new TopoDS_Shape(aBoundingCutBuilder->Modified(aBoundingFace).First()));
291     }
292
293     // Try to cut with base face. If it can not be done then keep result of cut with bounding plane.
294     if(isFromFaceSet) {
295       aBasisFace.Orientation(TopAbs_REVERSED);
296     }
297
298     // Making solid from basis face.
299     TopoDS_Shape aBasisSolid = makeSolidFromFace(aBasisFace);
300
301     // Rotating basis face to the specified angle.
302     gp_Trsf aBasisTrsf;
303     double aBasisRotAngle = isFromFaceSet ? myToAngle : -myFromAngle;
304     aBasisTrsf.SetRotation(anAxis, aBasisRotAngle / 180.0 * M_PI);
305     BRepBuilderAPI_Transform aBasisTransform(aBasisSolid, aBasisTrsf, true);
306     TopoDS_Shape aRotatedBasisFace = aBasisTransform.Modified(aBasisFace).First();
307     aBasisSolid = aBasisTransform.Shape();
308
309     // Cutting revolution with basis face.
310     BRepAlgoAPI_Cut* aBasisCutBuilder = new BRepAlgoAPI_Cut(aResult, aBasisSolid);
311     aBasisCutBuilder->Build();
312     if(aBasisCutBuilder->IsDone()) {
313       TopoDS_Shape aCutResult = aBasisCutBuilder->Shape();
314       TopExp_Explorer anExp(aCutResult, TopAbs_SOLID);
315       if(anExp.More()) {
316         aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBasisCutBuilder)));
317         aResult = aCutResult;
318       }
319     }
320
321     // If after cut we got more than one solids then take closest to the center of mass of the base face.
322     aResult = findClosest(aResult, aBasisCentr);
323
324     // Setting naming.
325     for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) {
326       const TopoDS_Shape& aFaceOnResult = anExp.Current();
327       Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aFaceOnResult));
328       Handle(Geom_Surface) aBoundingSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedBoundingFace));
329       Handle(Geom_Surface) aBasisSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedBasisFace));
330       if(aFaceSurface == aBoundingSurface) {
331         std::shared_ptr<GeomAPI_Shape> aPtr = isFromFaceSet ? myFirst : myLast;
332         aPtr->setImpl(new TopoDS_Shape(aFaceOnResult));
333       }
334       if(aFaceSurface == aBasisSurface) {
335         std::shared_ptr<GeomAPI_Shape> aPtr = isFromFaceSet ? myLast : myFirst;
336         aPtr->setImpl(new TopoDS_Shape(aFaceOnResult));
337       }
338     }
339   }
340
341   TopExp_Explorer anExp(aResult, TopAbs_SOLID);
342   if(!anExp.More()) {
343     return;
344   }
345
346   // fill data map to keep correct orientation of sub-shapes
347   for (TopExp_Explorer Exp(aResult,TopAbs_FACE); Exp.More(); Exp.Next()) {
348     std::shared_ptr<GeomAPI_Shape> aCurrentShape(new GeomAPI_Shape());
349     aCurrentShape->setImpl(new TopoDS_Shape(Exp.Current()));
350     myMap.bind(aCurrentShape, aCurrentShape);
351   }
352   myShape->setImpl(new TopoDS_Shape(aResult));
353   myMkShape = new GeomAlgoAPI_MakeShapeList(aListOfMakeShape);
354   myDone = true;
355   return;
356 }
357
358 //=================================================================================================
359 const bool GeomAlgoAPI_Revolution::isDone() const
360 {
361   return myDone;
362 }
363
364 //=================================================================================================
365 const bool GeomAlgoAPI_Revolution::isValid() const
366 {
367   BRepCheck_Analyzer aChecker(myShape->impl<TopoDS_Shape>());
368   return (aChecker.IsValid() == Standard_True);
369 }
370
371 //=================================================================================================
372 const bool GeomAlgoAPI_Revolution::hasVolume() const
373 {
374   bool hasVolume(false);
375   if(isValid()) {
376     const TopoDS_Shape& aRShape = myShape->impl<TopoDS_Shape>();
377     GProp_GProps aGProp;
378     BRepGProp::VolumeProperties(aRShape, aGProp);
379     if(aGProp.Mass() > Precision::Confusion())
380       hasVolume = true;
381   }
382   return hasVolume;
383 }
384
385 //=================================================================================================
386 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::shape () const
387 {
388   return myShape;
389 }
390
391 //=================================================================================================
392 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::firstShape()
393 {
394   return myFirst;
395 }
396
397 //=================================================================================================
398 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::lastShape()
399 {
400   return myLast;
401 }
402
403 //=================================================================================================
404 void GeomAlgoAPI_Revolution::mapOfShapes (GeomAPI_DataMapOfShapeShape& theMap) const
405 {
406   theMap = myMap;
407 }
408
409 //=================================================================================================
410 GeomAlgoAPI_MakeShape* GeomAlgoAPI_Revolution::makeShape() const
411 {
412   return myMkShape;
413 }
414
415 //=================================================================================================
416 GeomAlgoAPI_Revolution::~GeomAlgoAPI_Revolution()
417 {
418   if (myImpl) {
419     myMap.clear();
420   }
421 }