]> SALOME platform Git repositories - modules/shaper.git/blob - src/GeomAlgoAPI/GeomAlgoAPI_Revolution.cpp
Salome HOME
Another fix for revolution naming.
[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     // Setting naming.
204     if(aFromCutBuilder->Modified(aRotatedFromFace).Extent() > 0) {
205       myFirst->setImpl(new TopoDS_Shape(aFromCutBuilder->Modified(aRotatedFromFace).First()));
206     }
207
208     // Cutting revolution with to plane.
209     BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
210     aToCutBuilder->Build();
211     if(!aToCutBuilder->IsDone()) {
212       return;
213     }
214     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
215     aResult = aToCutBuilder->Shape();
216
217     // Setting naming.
218     if(aToCutBuilder->Modified(myFirst->impl<TopoDS_Shape>()).Extent() > 0) {
219       myFirst->setImpl(new TopoDS_Shape(aToCutBuilder->Modified(myFirst->impl<TopoDS_Shape>()).First()));
220     } else {
221       for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) {
222         const TopoDS_Shape& aFace = anExp.Current();
223         if (aFace.IsPartner(myFirst->impl<TopoDS_Shape>())) {
224           myFirst->implPtr<TopoDS_Shape>()->Orientation(aFace.Orientation());
225         }
226       }
227     }
228     if(aToCutBuilder->Modified(aRotatedToFace).Extent() > 0) {
229       myLast->setImpl(new TopoDS_Shape(aToCutBuilder->Modified(aRotatedToFace).First()));
230     }
231
232     // If after cut we got more than one solids then take closest to the center of mass of the base face.
233     aResult = findClosest(aResult, aBasisCentr);
234
235   } else { //Case 3: When only one bounding plane was set.
236     // Getting bounding face.
237     TopoDS_Face aBoundingFace;
238     bool isFromFaceSet = false;
239     if(myFromShape) {
240       aBoundingFace = TopoDS::Face(myFromShape->impl<TopoDS_Shape>());
241       isFromFaceSet = true;
242     } else if(myToShape) {
243       aBoundingFace = TopoDS::Face(myToShape->impl<TopoDS_Shape>());
244     }
245
246     // Getting plane from bounding face.
247     GeomLib_IsPlanarSurface isBoundingPlanar(BRep_Tool::Surface(aBoundingFace));
248     if(!isBoundingPlanar.IsPlanar()) { // non-planar shapes is not supported for revolution bounding
249       return;
250     }
251     gp_Pln aBoundingPln = isBoundingPlanar.Plan();
252
253     // Orienting bounding plane properly so that the center of mass of the base face stays
254     // on the result shape after cut.
255     gp_Pnt aBasisCentr = GeomAlgoAPI_ShapeProps::centreOfMass(theBasis)->impl<gp_Pnt>();
256     aBoundingFace = makeFaceFromPlane(aBoundingPln, aBasisCentr);
257
258     // Making solid from bounding plane.
259     TopoDS_Shape aBoundingSolid = makeSolidFromFace(aBoundingFace);
260
261     // Rotating bounding plane to the specified angle.
262     double aBoundingRotAngle = isFromFaceSet ? myFromAngle : myToAngle;
263     if(aBoundingPln.Axis().IsParallel(aBasisPln.Axis(), Precision::Confusion())) {
264       if(isFromFaceSet) aBoundingRotAngle = -aBoundingRotAngle;
265     } else {
266       double aSign = (aBoundingPln.Axis().Direction() ^ aBasisPln.Axis().Direction()) *
267                      anAxis.Direction();
268       if((aSign <= 0 && !isFromFaceSet) || (aSign > 0 && isFromFaceSet)) {
269         aBoundingRotAngle = -aBoundingRotAngle;
270       }
271     }
272     gp_Trsf aBoundingTrsf;
273     aBoundingTrsf.SetRotation(anAxis, aBoundingRotAngle / 180.0 * M_PI);
274     BRepBuilderAPI_Transform aBoundingTransform(aBoundingSolid, aBoundingTrsf, true);
275     aBoundingSolid = aBoundingTransform.Shape();
276
277     // Making revolution to the 360 angle.
278     BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBasisFace, anAxis, 2 * M_PI, Standard_True);
279     aRevolBuilder->Build();
280     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
281     TopoDS_Shape aRevolShape = aRevolBuilder->Shape();
282
283     // Cutting revolution with bounding plane.
284     BRepAlgoAPI_Cut* aBoundingCutBuilder = new BRepAlgoAPI_Cut(aRevolShape, aBoundingSolid);
285     aBoundingCutBuilder->Build();
286     if(!aBoundingCutBuilder->IsDone()) {
287       return;
288     }
289     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBoundingCutBuilder)));
290     aResult = aBoundingCutBuilder->Shape();
291     TopExp_Explorer anExp1(aResult, TopAbs_SOLID);
292
293     // Setting naming.
294     if(aBoundingCutBuilder->Modified(aBoundingFace).Extent() > 0) {
295       std::shared_ptr<GeomAPI_Shape> aPtr = isFromFaceSet ? myFirst : myLast;
296       aPtr->setImpl(new TopoDS_Shape(aBoundingCutBuilder->Modified(aBoundingFace).First()));
297     }
298
299     // Try to cut with base face. If it can not be done then keep result of cut with bounding plane.
300     if(isFromFaceSet) {
301       aBasisFace.Orientation(TopAbs_REVERSED);
302     }
303
304     // Making solid from basis face.
305     TopoDS_Shape aBasisSolid = makeSolidFromFace(aBasisFace);
306
307     // Rotating basis face to the specified angle.
308     gp_Trsf aBasisTrsf;
309     double aBasisRotAngle = isFromFaceSet ? myToAngle : -myFromAngle;
310     aBasisTrsf.SetRotation(anAxis, aBasisRotAngle / 180.0 * M_PI);
311     BRepBuilderAPI_Transform aBasisTransform(aBasisSolid, aBasisTrsf, true);
312     aBasisSolid = aBasisTransform.Shape();
313
314     // Cutting revolution with basis face.
315     BRepAlgoAPI_Cut* aBasisCutBuilder = new BRepAlgoAPI_Cut(aResult, aBasisSolid);
316     aBasisCutBuilder->Build();
317     if(aBasisCutBuilder->IsDone()) {
318       TopoDS_Shape aCutResult = aBasisCutBuilder->Shape();
319       TopExp_Explorer anExp(aCutResult, TopAbs_SOLID);
320       if(anExp.More()) {
321         aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBasisCutBuilder)));
322         aResult = aCutResult;
323
324         // Setting naming.
325         std::shared_ptr<GeomAPI_Shape> aBoundPtr = isFromFaceSet ? myFirst : myLast;
326         if(aBasisCutBuilder->Modified(aBoundPtr->impl<TopoDS_Shape>()).Extent() > 0) {
327           aBoundPtr->setImpl(new TopoDS_Shape(aBasisCutBuilder->Modified(aBoundPtr->impl<TopoDS_Shape>()).First()));
328         } else {
329           for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) {
330             const TopoDS_Shape& aFace = anExp.Current();
331             if (aFace.IsPartner(aBoundPtr->impl<TopoDS_Shape>())) {
332               aBoundPtr->implPtr<TopoDS_Shape>()->Orientation(aFace.Orientation());
333             }
334           }
335         }
336
337         if(aBasisCutBuilder->Modified(aBasisFace).Extent() > 0) {
338           std::shared_ptr<GeomAPI_Shape> aPtr = isFromFaceSet ? myLast : myFirst;
339           aPtr->setImpl(new TopoDS_Shape(aBasisCutBuilder->Modified(aBasisFace).First()));
340         }
341       }
342     }
343
344     // If after cut we got more than one solids then take closest to the center of mass of the base face.
345     aResult = findClosest(aResult, aBasisCentr);
346   }
347
348   TopExp_Explorer anExp(aResult, TopAbs_SOLID);
349   if(!anExp.More()) {
350     return;
351   }
352
353   // fill data map to keep correct orientation of sub-shapes
354   for (TopExp_Explorer Exp(aResult,TopAbs_FACE); Exp.More(); Exp.Next()) {
355     std::shared_ptr<GeomAPI_Shape> aCurrentShape(new GeomAPI_Shape());
356     aCurrentShape->setImpl(new TopoDS_Shape(Exp.Current()));
357     myMap.bind(aCurrentShape, aCurrentShape);
358   }
359   myShape->setImpl(new TopoDS_Shape(aResult));
360   myMkShape = new GeomAlgoAPI_MakeShapeList(aListOfMakeShape);
361   myDone = true;
362   return;
363 }
364
365 //=================================================================================================
366 const bool GeomAlgoAPI_Revolution::isDone() const
367 {
368   return myDone;
369 }
370
371 //=================================================================================================
372 const bool GeomAlgoAPI_Revolution::isValid() const
373 {
374   BRepCheck_Analyzer aChecker(myShape->impl<TopoDS_Shape>());
375   return (aChecker.IsValid() == Standard_True);
376 }
377
378 //=================================================================================================
379 const bool GeomAlgoAPI_Revolution::hasVolume() const
380 {
381   bool hasVolume(false);
382   if(isValid()) {
383     const TopoDS_Shape& aRShape = myShape->impl<TopoDS_Shape>();
384     GProp_GProps aGProp;
385     BRepGProp::VolumeProperties(aRShape, aGProp);
386     if(aGProp.Mass() > Precision::Confusion())
387       hasVolume = true;
388   }
389   return hasVolume;
390 }
391
392 //=================================================================================================
393 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::shape () const
394 {
395   return myShape;
396 }
397
398 //=================================================================================================
399 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::firstShape()
400 {
401   return myFirst;
402 }
403
404 //=================================================================================================
405 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::lastShape()
406 {
407   return myLast;
408 }
409
410 //=================================================================================================
411 void GeomAlgoAPI_Revolution::mapOfShapes (GeomAPI_DataMapOfShapeShape& theMap) const
412 {
413   theMap = myMap;
414 }
415
416 //=================================================================================================
417 GeomAlgoAPI_MakeShape* GeomAlgoAPI_Revolution::makeShape() const
418 {
419   return myMkShape;
420 }
421
422 //=================================================================================================
423 GeomAlgoAPI_Revolution::~GeomAlgoAPI_Revolution()
424 {
425   if (myImpl) {
426     myMap.clear();
427   }
428 }