1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: GeomAlgoAPI_Revolution.cpp
4 // Created: 12 May 2015
5 // Author: Dmitry Bobylev
7 #include "GeomAlgoAPI_Revolution.h"
9 #include <GeomAPI_Face.h>
10 #include <GeomAPI_ShapeExplorer.h>
11 #include <GeomAlgoAPI_DFLoader.h>
12 #include <GeomAlgoAPI_MakeShapeList.h>
13 #include <GeomAlgoAPI_ShapeTools.h>
15 #include <BRep_Builder.hxx>
16 #include <BRep_Tool.hxx>
17 #include <BRepAlgoAPI_Cut.hxx>
18 #include <BRepBuilderAPI_FindPlane.hxx>
19 #include <BRepBuilderAPI_MakeFace.hxx>
20 #include <BRepBuilderAPI_Transform.hxx>
21 #include <BRepCheck_Analyzer.hxx>
22 #include <BRepPrimAPI_MakeRevol.hxx>
23 #include <BRepGProp.hxx>
24 #include <Geom_Plane.hxx>
25 #include <GeomLib_IsPlanarSurface.hxx>
27 #include <GProp_GProps.hxx>
28 #include <TopExp_Explorer.hxx>
30 #include <TopTools_ListIteratorOfListOfShape.hxx>
32 /// \brief Constructs infinite face from thePlane, and with axis located on the same side
33 /// of the plane as thePoint. Modifies thePlane axis direction.
34 /// \param[in,out] thePlane plane to construct face.
35 /// \param[in] thePoint point to locate plane axis.
36 /// \return constructed face.
37 static TopoDS_Face makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint);
39 /// \return solid created from face or shell.
40 static TopoDS_Solid makeSolidFromShape(const TopoDS_Shape& theShape);
42 /// \brief Selects solid from theShape with closest center of mass to thePoint
43 /// \param[in] theShape compound with solids.
44 /// \param[in] thePoint point.
46 static TopoDS_Shape findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint);
48 //=================================================================================================
49 GeomAlgoAPI_Revolution::GeomAlgoAPI_Revolution(const GeomShapePtr theBaseShape,
50 const std::shared_ptr<GeomAPI_Ax1> theAxis,
51 const double theToAngle,
52 const double theFromAngle)
54 build(theBaseShape, theAxis, GeomShapePtr(), theToAngle, GeomShapePtr(), theFromAngle);
57 //=================================================================================================
58 GeomAlgoAPI_Revolution::GeomAlgoAPI_Revolution(const GeomShapePtr theBaseShape,
59 const std::shared_ptr<GeomAPI_Ax1> theAxis,
60 const GeomShapePtr theToShape,
61 const double theToAngle,
62 const GeomShapePtr theFromShape,
63 const double theFromAngle)
65 build(theBaseShape, theAxis, theToShape, theToAngle, theFromShape, theFromAngle);
68 //=================================================================================================
69 void GeomAlgoAPI_Revolution::build(const GeomShapePtr& theBaseShape,
70 const std::shared_ptr<GeomAPI_Ax1>& theAxis,
71 const GeomShapePtr& theToShape,
72 const double theToAngle,
73 const GeomShapePtr& theFromShape,
74 const double theFromAngle)
76 if(!theBaseShape || !theAxis ||
77 (((!theFromShape && !theToShape) || (theFromShape && theToShape && theFromShape->isEqual(theToShape)))
78 && (theFromAngle == -theToAngle))) {
82 // Getting base shape.
83 const TopoDS_Shape& aBaseShape = theBaseShape->impl<TopoDS_Shape>();
84 TopAbs_ShapeEnum aShapeTypeToExp;
85 switch(aBaseShape.ShapeType()) {
87 aShapeTypeToExp = TopAbs_VERTEX;
91 aShapeTypeToExp = TopAbs_EDGE;
95 aShapeTypeToExp = TopAbs_FACE;
101 // Getting base plane.
102 Handle(Geom_Plane) aBasePlane;
103 BRepBuilderAPI_FindPlane aFindPlane(aBaseShape);
104 if(aShapeTypeToExp == TopAbs_FACE && aFindPlane.Found() == Standard_True) {
105 aBasePlane = aFindPlane.Plane();
109 gp_Ax1 anAxis = theAxis->impl<gp_Ax1>();
110 if(aShapeTypeToExp == TopAbs_FACE) {
111 if(aBasePlane->Axis().Angle(anAxis) < Precision::Confusion()) {
116 gp_Pnt aBaseCentre = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape)->impl<gp_Pnt>();
118 TopoDS_Shape aResult;
119 if(!theFromShape && !theToShape) { // Case 1: When only angles was set.
120 // Rotating base face with the negative value of "from angle".
122 aBaseTrsf.SetRotation(anAxis, -theFromAngle / 180.0 * M_PI);
123 BRepBuilderAPI_Transform* aBaseTransform = new BRepBuilderAPI_Transform(aBaseShape,
126 if(!aBaseTransform) {
129 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBaseTransform)));
130 if(!aBaseTransform->IsDone()) {
133 TopoDS_Shape aRotatedBase = aBaseTransform->Shape();
135 // Making revolution to the angle equal to the sum of "from angle" and "to angle".
136 BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aRotatedBase,
138 (theFromAngle + theToAngle) / 180 * M_PI,
143 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
144 if(!aRevolBuilder->IsDone()) {
147 aResult = aRevolBuilder->Shape();
150 for(TopExp_Explorer anExp(aRotatedBase, aShapeTypeToExp); anExp.More(); anExp.Next()) {
151 const TopoDS_Shape& aShape = anExp.Current();
152 GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape);
153 aFromShape->setImpl(new TopoDS_Shape(aRevolBuilder->FirstShape(aShape)));
154 aToShape->setImpl(new TopoDS_Shape(aRevolBuilder->LastShape(aShape)));
155 this->addFromShape(aFromShape);
156 this->addToShape(aToShape);
158 } else if(theFromShape && theToShape) { // Case 2: When both bounding planes were set.
159 // Making revolution to the 360 angle.
160 BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True);
164 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
165 if(!aRevolBuilder->IsDone()) {
168 aResult = aRevolBuilder->Shape();
170 // Getting bounding faces.
171 TopoDS_Face aFromFace = TopoDS::Face(theFromShape->impl<TopoDS_Shape>());
172 TopoDS_Face aToFace = TopoDS::Face(theToShape->impl<TopoDS_Shape>());
174 // Getting planes from bounding face.
175 GeomLib_IsPlanarSurface isFromPlanar(BRep_Tool::Surface(aFromFace));
176 GeomLib_IsPlanarSurface isToPlanar(BRep_Tool::Surface(aToFace));
177 if(!isFromPlanar.IsPlanar() || !isToPlanar.IsPlanar()) {// non-planar shapes is not supported for revolution bounding
180 gp_Pln aFromPln = isFromPlanar.Plan();
181 gp_Pln aToPln = isToPlanar.Plan();
183 // Orienting bounding planes properly so that the center of mass of the base face stays
184 // on the result shape after cut.
185 aFromFace = makeFaceFromPlane(aFromPln, aBaseCentre);
186 aToFace = makeFaceFromPlane(aToPln, aBaseCentre);
188 // Making solids from bounding planes and putting them in compound.
189 TopoDS_Shape aFromSolid = makeSolidFromShape(aFromFace);
190 TopoDS_Shape aToSolid = makeSolidFromShape(aToFace);
192 // Rotating bounding planes to the specified angle.
195 double aFromRotAngle = ((aFromPln.Axis().Direction() * aBasePlane->Axis().Direction()) > 0) ? -theFromAngle : theFromAngle;
196 double aToRotAngle = ((aToPln.Axis().Direction() * aBasePlane->Axis().Direction()) > 0) ? -theToAngle : theToAngle;
197 aFromTrsf.SetRotation(anAxis,aFromRotAngle / 180.0 * M_PI);
198 aToTrsf.SetRotation(anAxis, aToRotAngle / 180.0 * M_PI);
199 BRepBuilderAPI_Transform aFromTransform(aFromSolid, aFromTrsf, true);
200 BRepBuilderAPI_Transform aToTransform(aToSolid, aToTrsf, true);
201 TopoDS_Shape aRotatedFromFace = aFromTransform.Modified(aFromFace).First();
202 TopoDS_Shape aRotatedToFace = aToTransform.Modified(aToFace).First();
203 aFromSolid = aFromTransform.Shape();
204 aToSolid = aToTransform.Shape();
206 // Cutting revolution with from plane.
207 BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid);
208 aFromCutBuilder->Build();
209 if(!aFromCutBuilder->IsDone()) {
212 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aFromCutBuilder)));
213 aResult = aFromCutBuilder->Shape();
215 // Cutting revolution with to plane.
216 BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid);
217 aToCutBuilder->Build();
218 if(!aToCutBuilder->IsDone()) {
221 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aToCutBuilder)));
222 aResult = aToCutBuilder->Shape();
224 TopExp_Explorer anExp(aResult, TopAbs_SOLID);
228 if(aResult.ShapeType() == TopAbs_COMPOUND) {
229 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
231 if(aResult.ShapeType() == TopAbs_COMPOUND) {
232 GeomShapePtr aCompound(new GeomAPI_Shape);
233 aCompound->setImpl(new TopoDS_Shape(aResult));
234 ListOfShape aCompSolids, aFreeSolids;
235 GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids);
236 if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) {
237 aResult = aCompSolids.front()->impl<TopoDS_Shape>();
238 } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) {
239 TopoDS_Compound aResultComp;
240 TopoDS_Builder aBuilder;
241 aBuilder.MakeCompound(aResultComp);
242 for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) {
243 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
245 for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) {
246 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
248 aResult = aResultComp;
252 // If after cut we got more than one solids then take closest to the center of mass of the base face.
253 aResult = findClosest(aResult, aBaseCentre);
256 for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) {
257 const TopoDS_Shape& aFaceOnResult = anExp.Current();
258 Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aFaceOnResult));
259 Handle(Geom_Surface) aFromSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedFromFace));
260 Handle(Geom_Surface) aToSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedToFace));
261 if(aFaceSurface == aFromSurface) {
262 GeomShapePtr aFSHape(new GeomAPI_Shape);
263 aFSHape->setImpl(new TopoDS_Shape(aFaceOnResult));
264 this->addFromShape(aFSHape);
266 if(aFaceSurface == aToSurface) {
267 GeomShapePtr aTSHape(new GeomAPI_Shape);
268 aTSHape->setImpl(new TopoDS_Shape(aFaceOnResult));
269 this->addToShape(aTSHape);
272 } else { //Case 3: When only one bounding plane was set.
273 // Making revolution to the 360 angle.
274 BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True);
278 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aRevolBuilder)));
279 if(!aRevolBuilder->IsDone()) {
282 aResult = aRevolBuilder->Shape();
284 // Getting bounding face.
285 TopoDS_Face aBoundingFace;
286 bool isFromFaceSet = false;
288 aBoundingFace = TopoDS::Face(theFromShape->impl<TopoDS_Shape>());
289 isFromFaceSet = true;
290 } else if(theToShape) {
291 aBoundingFace = TopoDS::Face(theToShape->impl<TopoDS_Shape>());
294 // Getting plane from bounding face.
295 GeomLib_IsPlanarSurface isBoundingPlanar(BRep_Tool::Surface(aBoundingFace));
296 if(!isBoundingPlanar.IsPlanar()) { // non-planar shapes is not supported for revolution bounding
299 gp_Pln aBoundingPln = isBoundingPlanar.Plan();
301 // Orienting bounding plane properly so that the center of mass of the base face stays
302 // on the result shape after cut.
303 aBoundingFace = makeFaceFromPlane(aBoundingPln, aBaseCentre);
305 // Making solid from bounding plane.
306 TopoDS_Shape aBoundingSolid = makeSolidFromShape(aBoundingFace);
308 // Rotating bounding plane to the specified angle.
309 double aBoundingRotAngle = isFromFaceSet ? theFromAngle : theToAngle;
310 if(aBoundingPln.Axis().IsParallel(aBasePlane->Axis(), Precision::Confusion())) {
311 if(isFromFaceSet) aBoundingRotAngle = -aBoundingRotAngle;
313 double aSign = (aBoundingPln.Axis().Direction() ^ aBasePlane->Axis().Direction()) *
315 if((aSign <= 0 && !isFromFaceSet) || (aSign > 0 && isFromFaceSet)) {
316 aBoundingRotAngle = -aBoundingRotAngle;
319 gp_Trsf aBoundingTrsf;
320 aBoundingTrsf.SetRotation(anAxis, aBoundingRotAngle / 180.0 * M_PI);
321 BRepBuilderAPI_Transform aBoundingTransform(aBoundingSolid, aBoundingTrsf, true);
322 TopoDS_Shape aRotatedBoundingFace = aBoundingTransform.Modified(aBoundingFace).First();
323 aBoundingSolid = aBoundingTransform.Shape();
325 // Cutting revolution with bounding plane.
326 BRepAlgoAPI_Cut* aBoundingCutBuilder = new BRepAlgoAPI_Cut(aResult, aBoundingSolid);
327 aBoundingCutBuilder->Build();
328 if(!aBoundingCutBuilder->IsDone()) {
331 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBoundingCutBuilder)));
332 aResult = aBoundingCutBuilder->Shape();
335 const TopTools_ListOfShape& aBndShapes = aBoundingCutBuilder->Modified(aBoundingFace);
336 for(TopTools_ListIteratorOfListOfShape anIt(aBndShapes); anIt.More(); anIt.Next()) {
337 GeomShapePtr aShape(new GeomAPI_Shape());
338 aShape->setImpl(new TopoDS_Shape(anIt.Value()));
339 isFromFaceSet ? this->addFromShape(aShape) : this->addToShape(aShape);
342 // Try to cut with base face. If it can not be done then keep result of cut with bounding plane.
343 TopoDS_Shape aModifiedBaseShape = aBaseShape;
345 if(aModifiedBaseShape.ShapeType() == TopAbs_FACE) {
346 aModifiedBaseShape.Orientation(TopAbs_REVERSED);
349 aMirrorTrsf.SetMirror(aBasePlane->Position().Ax2());
350 BRepBuilderAPI_Transform aMirrorTransform(aModifiedBaseShape, aMirrorTrsf, true);
351 aModifiedBaseShape = aMirrorTransform.Shape();
355 // Making solid from base face.
356 TopoDS_Shape aBaseSolid = makeSolidFromShape(aModifiedBaseShape);
358 // Rotating base face to the specified angle.
360 double aBaseRotAngle = isFromFaceSet ? theToAngle : -theFromAngle;
361 aBaseTrsf.SetRotation(anAxis, aBaseRotAngle / 180.0 * M_PI);
362 BRepBuilderAPI_Transform aBaseTransform(aBaseSolid, aBaseTrsf, true);
363 aBaseSolid = aBaseTransform.Shape();
365 // Cutting revolution with base.
366 BRepAlgoAPI_Cut* aBaseCutBuilder = new BRepAlgoAPI_Cut(aResult, aBaseSolid);
367 aBaseCutBuilder->Build();
368 if(aBaseCutBuilder->IsDone()) {
369 TopoDS_Shape aCutResult = aBaseCutBuilder->Shape();
370 TopExp_Explorer anExp(aCutResult, TopAbs_SOLID);
372 this->appendAlgo(std::shared_ptr<GeomAlgoAPI_MakeShape>(new GeomAlgoAPI_MakeShape(aBaseCutBuilder)));
373 aResult = aCutResult;
377 const TopTools_ListOfShape& aBsShapes = aBaseCutBuilder->Modified(aBoundingFace);
378 for(TopTools_ListIteratorOfListOfShape anIt(aBsShapes); anIt.More(); anIt.Next()) {
379 GeomShapePtr aShape(new GeomAPI_Shape());
380 aShape->setImpl(new TopoDS_Shape(anIt.Value()));
381 isFromFaceSet ? this->addToShape(aShape) : this->addFromShape(aShape);
384 TopExp_Explorer anExp(aResult, TopAbs_SOLID);
388 if(aResult.ShapeType() == TopAbs_COMPOUND) {
389 aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
391 if(aResult.ShapeType() == TopAbs_COMPOUND) {
392 GeomShapePtr aCompound(new GeomAPI_Shape);
393 aCompound->setImpl(new TopoDS_Shape(aResult));
394 ListOfShape aCompSolids, aFreeSolids;
395 GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids);
396 if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) {
397 aResult = aCompSolids.front()->impl<TopoDS_Shape>();
398 } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) {
399 TopoDS_Compound aResultComp;
400 TopoDS_Builder aBuilder;
401 aBuilder.MakeCompound(aResultComp);
402 for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) {
403 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
405 for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) {
406 aBuilder.Add(aResultComp, (*anIter)->impl<TopoDS_Shape>());
408 aResult = aResultComp;
412 // If after cut we got more than one solids then take closest to the center of mass of the base face.
413 aResult = findClosest(aResult, aBaseCentre);
416 for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) {
417 const TopoDS_Shape& aFaceOnResult = anExp.Current();
418 Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aFaceOnResult));
419 Handle(Geom_Surface) aBoundingSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedBoundingFace));
420 if(aFaceSurface == aBoundingSurface) {
421 GeomShapePtr aShape(new GeomAPI_Shape());
422 aShape->setImpl(new TopoDS_Shape(aFaceOnResult));
423 isFromFaceSet ? this->addFromShape(aShape) : this->addToShape(aShape);
429 if(aResult.IsNull()) {
432 GeomShapePtr aShape(new GeomAPI_Shape());
433 aShape->setImpl(new TopoDS_Shape(aResult));
434 this->setShape(aShape);
438 //=================================================================================================
439 TopoDS_Face makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint)
441 if(!thePlane.Contains(thePoint, Precision::Confusion())) {
442 gp_XYZ aVec = thePoint.XYZ() - thePlane.Location().XYZ();
443 double aSign = aVec * thePlane.Axis().Direction().XYZ();
444 if(aSign < 0) thePlane.SetAxis(thePlane.Axis().Reversed());
447 BRepBuilderAPI_MakeFace aMakeFace(thePlane);
448 TopoDS_Face aResultFace = TopoDS::Face(aMakeFace.Shape());
453 //=================================================================================================
454 TopoDS_Solid makeSolidFromShape(const TopoDS_Shape& theShape)
459 BRep_Builder aBoundingBuilder;
460 if(theShape.ShapeType() == TopAbs_SHELL) {
461 aShell = TopoDS::Shell(theShape);
463 aBoundingBuilder.MakeShell(aShell);
464 aBoundingBuilder.Add(aShell, theShape);
466 aBoundingBuilder.MakeSolid(aSolid);
467 aBoundingBuilder.Add(aSolid, aShell);
472 //=================================================================================================
473 TopoDS_Shape findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint)
475 TopoDS_Shape aResult = theShape;
477 if(theShape.ShapeType() == TopAbs_COMPOUND) {
478 double aMinDistance = Precision::Infinite();
480 GProp_GProps aGProps;
483 for (TopoDS_Iterator anItr(theShape); anItr.More(); anItr.Next()) {
484 TopoDS_Shape aValue = anItr.Value();
485 BRepGProp::VolumeProperties(aValue, aGProps);
486 aCentr = aGProps.CentreOfMass();
487 aCurDistance = aCentr.Distance(thePoint);
489 if(aCurDistance < aMinDistance) {
490 aMinDistance = aCurDistance;