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