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