]> SALOME platform Git repositories - modules/shaper.git/blob - src/GeomAlgoAPI/GeomAlgoAPI_Revolution.cpp
Salome HOME
Algo 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 <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     myFirst->setImpl(new TopoDS_Shape(aRevolBuilder->FirstShape()));
147     myLast->setImpl(new TopoDS_Shape(aRevolBuilder->LastShape()));
148   } else if(myFromShape && myToShape) { // Case 2: When both bounding planes were set.
149     // Getting bounding faces.
150     TopoDS_Face aFromFace = TopoDS::Face(myFromShape->impl<TopoDS_Shape>());
151     TopoDS_Face aToFace   = TopoDS::Face(myToShape->impl<TopoDS_Shape>());
152
153     // Getting planes from bounding face.
154     GeomLib_IsPlanarSurface isFromPlanar(BRep_Tool::Surface(aFromFace));
155     GeomLib_IsPlanarSurface isToPlanar(BRep_Tool::Surface(aToFace));
156     if(!isFromPlanar.IsPlanar() || !isToPlanar.IsPlanar()) {// non-planar shapes is not supported for revolution bounding
157       return;
158     }
159     gp_Pln aFromPln = isFromPlanar.Plan();
160     gp_Pln aToPln   = isToPlanar.Plan();
161
162     // Orienting bounding planes properly so that the center of mass of the base face stays
163     // on the result shape after cut.
164     gp_Pnt aBasisCentr = GeomAlgoAPI_ShapeProps::centreOfMass(theBasis)->impl<gp_Pnt>();
165     aFromFace = makeFaceFromPlane(aFromPln, aBasisCentr);
166     aToFace   = makeFaceFromPlane(aToPln, aBasisCentr);
167
168     // Making solids from bounding planes and putting them in compound.
169     TopoDS_Shape aFromSolid = makeSolidFromFace(aFromFace);
170     TopoDS_Shape aToSolid   = makeSolidFromFace(aToFace);
171
172     // Rotating bounding planes to the specified angle.
173     gp_Trsf aFromTrsf;
174     gp_Trsf aToTrsf;
175     double aFromRotAngle = ((aFromPln.Axis().Direction() * aBasisPln.Axis().Direction()) > 0) ? -myFromAngle : myFromAngle;
176     double aToRotAngle = ((aToPln.Axis().Direction() * aBasisPln.Axis().Direction()) > 0) ? -myToAngle : myToAngle;
177     aFromTrsf.SetRotation(anAxis,aFromRotAngle / 180.0 * M_PI);
178     aToTrsf.SetRotation(anAxis, aToRotAngle / 180.0 * M_PI);
179     BRepBuilderAPI_Transform aFromTransform(aFromSolid, aFromTrsf, true);
180     BRepBuilderAPI_Transform aToTransform(aToSolid, aToTrsf, true);
181     aFromSolid = aFromTransform.Shape();
182     TopoDS_Shape aRotatedFromFace = aFromTransform.Modified(aFromFace).First();
183     TopoDS_Shape aRotatedToFace = aToTransform.Modified(aToFace).First();
184     aToSolid   = aToTransform.Shape();
185
186     // Making revolution to the 360 angle.
187     BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBasisFace, anAxis, 2 * M_PI, Standard_True);
188     aRevolBuilder->Build();
189     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
190     TopoDS_Shape aRevolShape = aRevolBuilder->Shape();
191
192     // Cutting revolution with from plane.
193     BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aRevolShape, aFromSolid);
194     aFromCutBuilder->Build();
195     if(!aFromCutBuilder->IsDone()) {
196       return;
197     }
198     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
199     aResult = aFromCutBuilder->Shape();
200     if(aFromCutBuilder->Modified(aRotatedFromFace).Extent() > 0) {
201       myFirst->setImpl(new TopoDS_Shape(aFromCutBuilder->Modified(aRotatedFromFace).First()));
202     }
203
204     // Cutting revolution with to plane.
205     BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
206     aToCutBuilder->Build();
207     if(!aToCutBuilder->IsDone()) {
208       return;
209     }
210     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
211     aResult = aToCutBuilder->Shape();
212     if(aToCutBuilder->Modified(aRotatedToFace).Extent() > 0) {
213       myLast->setImpl(new TopoDS_Shape(aToCutBuilder->Modified(aRotatedToFace).First()));
214     }
215     if(aToCutBuilder->Modified(myFirst->impl<TopoDS_Shape>()).Extent() > 0) {
216       myFirst->setImpl(new TopoDS_Shape(aToCutBuilder->Modified(myFirst->impl<TopoDS_Shape>()).First()));
217     }
218
219     // If after cut we got more than one solids then take closest to the center of mass of the base face.
220     aResult = findClosest(aResult, aBasisCentr);
221
222   } else { //Case 3: When only one bounding plane was set.
223     // Getting bounding face.
224     TopoDS_Face aBoundingFace;
225     bool isFromFaceSet = false;
226     if(myFromShape) {
227       aBoundingFace = TopoDS::Face(myFromShape->impl<TopoDS_Shape>());
228       isFromFaceSet = true;
229     } else if(myToShape) {
230       aBoundingFace = TopoDS::Face(myToShape->impl<TopoDS_Shape>());
231     }
232
233     // Getting plane from bounding face.
234     GeomLib_IsPlanarSurface isBoundingPlanar(BRep_Tool::Surface(aBoundingFace));
235     if(!isBoundingPlanar.IsPlanar()) { // non-planar shapes is not supported for revolution bounding
236       return;
237     }
238     gp_Pln aBoundingPln = isBoundingPlanar.Plan();
239
240     // Orienting bounding plane properly so that the center of mass of the base face stays
241     // on the result shape after cut.
242     gp_Pnt aBasisCentr = GeomAlgoAPI_ShapeProps::centreOfMass(theBasis)->impl<gp_Pnt>();
243     aBoundingFace = makeFaceFromPlane(aBoundingPln, aBasisCentr);
244
245     // Making solid from bounding plane.
246     TopoDS_Shape aBoundingSolid = makeSolidFromFace(aBoundingFace);
247
248     // Rotating bounding plane to the specified angle.
249     double aBoundingRotAngle = isFromFaceSet ? myFromAngle : myToAngle;
250     if(aBoundingPln.Axis().IsParallel(aBasisPln.Axis(), Precision::Confusion())) {
251       if(isFromFaceSet) aBoundingRotAngle = -aBoundingRotAngle;
252     } else {
253       double aSign = (aBoundingPln.Axis().Direction() ^ aBasisPln.Axis().Direction()) *
254                      anAxis.Direction();
255       if((aSign <= 0 && !isFromFaceSet) || (aSign > 0 && isFromFaceSet)) {
256         aBoundingRotAngle = -aBoundingRotAngle;
257       }
258     }
259     gp_Trsf aBoundingTrsf;
260     aBoundingTrsf.SetRotation(anAxis, aBoundingRotAngle / 180.0 * M_PI);
261     BRepBuilderAPI_Transform aBoundingTransform(aBoundingSolid, aBoundingTrsf, true);
262     aBoundingSolid = aBoundingTransform.Shape();
263
264     // Making revolution to the 360 angle.
265     BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBasisFace, anAxis, 2 * M_PI, Standard_True);
266     aRevolBuilder->Build();
267     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
268     TopoDS_Shape aRevolShape = aRevolBuilder->Shape();
269
270     // Cutting revolution with bounding plane.
271     BRepAlgoAPI_Cut* aBoundingCutBuilder = new BRepAlgoAPI_Cut(aRevolShape, aBoundingSolid);
272     aBoundingCutBuilder->Build();
273     if(!aBoundingCutBuilder->IsDone()) {
274       return;
275     }
276     aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBoundingCutBuilder)));
277     aResult = aBoundingCutBuilder->Shape();
278     TopExp_Explorer anExp1(aResult, TopAbs_SOLID);
279     if(aBoundingCutBuilder->Modified(aBoundingFace).Extent() > 0) {
280       myLast->setImpl(new TopoDS_Shape(aBoundingCutBuilder->Modified(aBoundingFace).First()));
281     }
282
283     // Try to cut with base face. If it can not be done then keep result of cut with bounding plane.
284     if(isFromFaceSet) {
285       aBasisFace.Orientation(TopAbs_REVERSED);
286     }
287
288     // Making solid from basis face.
289     TopoDS_Shape aBasisSolid = makeSolidFromFace(aBasisFace);
290
291     // Rotating basis face to the specified angle.
292     gp_Trsf aBasisTrsf;
293     double aBasisRotAngle = isFromFaceSet ? myToAngle : -myFromAngle;
294     aBasisTrsf.SetRotation(anAxis, aBasisRotAngle / 180.0 * M_PI);
295     BRepBuilderAPI_Transform aBasisTransform(aBasisSolid, aBasisTrsf, true);
296     aBasisSolid = aBasisTransform.Shape();
297
298     // Cutting revolution with basis face.
299     BRepAlgoAPI_Cut* aBasisCutBuilder = new BRepAlgoAPI_Cut(aResult, aBasisSolid);
300     aBasisCutBuilder->Build();
301     if(aBasisCutBuilder->IsDone()) {
302       TopoDS_Shape aCutResult = aBasisCutBuilder->Shape();
303       TopExp_Explorer anExp(aCutResult, TopAbs_SOLID);
304       if(anExp.More()) {
305         aListOfMakeShape.push_back(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBasisCutBuilder)));
306         aResult = aCutResult;
307         if(aBasisCutBuilder->Modified(aBasisFace).Extent() > 0) {
308           myFirst->setImpl(new TopoDS_Shape(aBasisCutBuilder->Modified(aBasisFace).First()));
309         }
310       }
311     }
312
313     // If after cut we got more than one solids then take closest to the center of mass of the base face.
314     aResult = findClosest(aResult, aBasisCentr);
315   }
316
317   TopExp_Explorer anExp(aResult, TopAbs_SOLID);
318   if(!anExp.More()) {
319     return;
320   }
321
322   // fill data map to keep correct orientation of sub-shapes
323   for (TopExp_Explorer Exp(aResult,TopAbs_FACE); Exp.More(); Exp.Next()) {
324     std::shared_ptr<GeomAPI_Shape> aCurrentShape(new GeomAPI_Shape());
325     aCurrentShape->setImpl(new TopoDS_Shape(Exp.Current()));
326     myMap.bind(aCurrentShape, aCurrentShape);
327   }
328   myShape->setImpl(new TopoDS_Shape(aResult));
329   myMkShape = new GeomAlgoAPI_MakeShapeList(aListOfMakeShape);
330   myDone = true;
331   return;
332 }
333
334 //=================================================================================================
335 const bool GeomAlgoAPI_Revolution::isDone() const
336 {
337   return myDone;
338 }
339
340 //=================================================================================================
341 const bool GeomAlgoAPI_Revolution::isValid() const
342 {
343   BRepCheck_Analyzer aChecker(myShape->impl<TopoDS_Shape>());
344   return (aChecker.IsValid() == Standard_True);
345 }
346
347 //=================================================================================================
348 const bool GeomAlgoAPI_Revolution::hasVolume() const
349 {
350   bool hasVolume(false);
351   if(isValid()) {
352     const TopoDS_Shape& aRShape = myShape->impl<TopoDS_Shape>();
353     GProp_GProps aGProp;
354     BRepGProp::VolumeProperties(aRShape, aGProp);
355     if(aGProp.Mass() > Precision::Confusion())
356       hasVolume = true;
357   }
358   return hasVolume;
359 }
360
361 //=================================================================================================
362 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::shape () const
363 {
364   return myShape;
365 }
366
367 //=================================================================================================
368 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::firstShape()
369 {
370   return myFirst;
371 }
372
373 //=================================================================================================
374 const std::shared_ptr<GeomAPI_Shape>& GeomAlgoAPI_Revolution::lastShape()
375 {
376   return myLast;
377 }
378
379 //=================================================================================================
380 void GeomAlgoAPI_Revolution::mapOfShapes (GeomAPI_DataMapOfShapeShape& theMap) const
381 {
382   theMap = myMap;
383 }
384
385 //=================================================================================================
386 GeomAlgoAPI_MakeShape* GeomAlgoAPI_Revolution::makeShape() const
387 {
388   return myMkShape;
389 }
390
391 //=================================================================================================
392 GeomAlgoAPI_Revolution::~GeomAlgoAPI_Revolution()
393 {
394   if (myImpl) {
395     myMap.clear();
396   }
397 }