X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGeomAlgoAPI%2FGeomAlgoAPI_Revolution.cpp;h=dbd5ef788bde3bbb419b788d369949e2d764d624;hb=06e7f5859095193fc7f498bd89a7d28009794f53;hp=21eb56f29320d8bb9291b898013e361dfa8a2a0b;hpb=1b93f1881c5fec599aa79707f93c84dd9c287bc0;p=modules%2Fshaper.git diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Revolution.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Revolution.cpp index 21eb56f29..dbd5ef788 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Revolution.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Revolution.cpp @@ -1,155 +1,181 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: GeomAlgoAPI_Revolution.cpp -// Created: 12 May 2015 -// Author: Dmitry Bobylev - -#include +// Copyright (C) 2014-2023 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "GeomAlgoAPI_Revolution.h" #include +#include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include +#include +#include #include #include +#include #include #include #include #include +#include #include #include +#include #include -//================================================================================================= -GeomAlgoAPI_Revolution::GeomAlgoAPI_Revolution(std::shared_ptr theBaseShape, - std::shared_ptr theAxis, - double theToAngle, - double theFromAngle) -: myDone(false) -{ - build(theBaseShape, theAxis, std::shared_ptr(), theToAngle, std::shared_ptr(), theFromAngle); -} - -//================================================================================================= -GeomAlgoAPI_Revolution::GeomAlgoAPI_Revolution(std::shared_ptr theBaseShape, - std::shared_ptr theAxis, - std::shared_ptr theToShape, - double theToAngle, - std::shared_ptr theFromShape, - double theFromAngle) -: myDone(false) +/// \brief Constructs infinite face from thePlane, and with axis located on the same side +/// of the plane as thePoint. Modifies thePlane axis direction. +/// \param[in,out] thePlane plane to construct face. +/// \param[in] thePoint point to locate plane axis. +/// \return constructed face. +static TopoDS_Face makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint); + +/// \return solid created from face or shell. +static TopoDS_Solid makeSolidFromShape(const TopoDS_Shape& theShape); + +/// \brief return centre of mass for theShape. +/// \param[in] theShape shape. +static gp_Pnt centreOfMass(const TopoDS_Shape& theShape); + +/// \brief Selects solid from theShape with closest center of mass to thePoint +/// \param[in] theShape compound with solids. +/// \param[in] thePoint point. +/// \return solid. +static TopoDS_Shape findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint); + +/// \brief Create plane by 3 points. Return empty handle if failed. +static Handle(Geom_Plane) makePlane(const gp_Pnt& theP1, const gp_Pnt& theP2, const gp_Pnt& theP3); + +static void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo, + const TopoDS_Shape& theBase, + const TopAbs_ShapeEnum theType, + BRepPrimAPI_MakeRevol* theRevolBuilder); + +static void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo, + const TopoDS_Shape& theResult, + const TopAbs_ShapeEnum theType, + const TopoDS_Shape& theToFace, + const TopoDS_Shape& theFromFace); + +static void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo, + const TopoDS_Shape& theResult, + const TopAbs_ShapeEnum theType, + const TopoDS_Shape& theRotatedBoundingFace, + const TopoDS_Shape& theModifiedBaseShape, + const bool theIsFromFaceSet); + +//================================================================================================== +GeomAlgoAPI_Revolution::GeomAlgoAPI_Revolution(const GeomShapePtr theBaseShape, + const std::shared_ptr theAxis, + const GeomShapePtr theToShape, + const double theToAngle, + const GeomShapePtr theFromShape, + const double theFromAngle) { build(theBaseShape, theAxis, theToShape, theToAngle, theFromShape, theFromAngle); } -//================================================================================================= -TopoDS_Face GeomAlgoAPI_Revolution::makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint) +//================================================================================================== +void GeomAlgoAPI_Revolution::build(const GeomShapePtr& theBaseShape, + const std::shared_ptr& theAxis, + const GeomShapePtr& theToShape, + const double theToAngle, + const GeomShapePtr& theFromShape, + const double theFromAngle) { - gp_XYZ aVec = thePoint.XYZ() - thePlane.Location().XYZ(); - double aSign = aVec * thePlane.Axis().Direction().XYZ(); - if(aSign < 0) thePlane.SetAxis(thePlane.Axis().Reversed()); - - BRepBuilderAPI_MakeFace aMakeFace(thePlane); - TopoDS_Face aResultFace = TopoDS::Face(aMakeFace.Shape()); - - return aResultFace; -} - -//================================================================================================= -TopoDS_Solid GeomAlgoAPI_Revolution::makeSolidFromShape(const TopoDS_Shape& theShape) -{ - TopoDS_Shell aShell; - TopoDS_Solid aSolid; + if(!theBaseShape || !theAxis || + (((!theFromShape && !theToShape) || + (theFromShape && theToShape && theFromShape->isEqual(theToShape))) + && (theFromAngle == -theToAngle))) { + return; + } - BRep_Builder aBoundingBuilder; - if(theShape.ShapeType() == TopAbs_SHELL) { - aShell = TopoDS::Shell(theShape); - } else { - aBoundingBuilder.MakeShell(aShell); - aBoundingBuilder.Add(aShell, theShape); + // Getting base shape. + const TopoDS_Shape& aBaseShape = theBaseShape->impl(); + TopAbs_ShapeEnum aShapeTypeToExp; + switch(aBaseShape.ShapeType()) { + case TopAbs_VERTEX: + aShapeTypeToExp = TopAbs_VERTEX; + break; + case TopAbs_EDGE: + case TopAbs_WIRE: + aShapeTypeToExp = TopAbs_EDGE; + break; + case TopAbs_FACE: + case TopAbs_SHELL: + aShapeTypeToExp = TopAbs_FACE; + break; + case TopAbs_COMPOUND: + aShapeTypeToExp = TopAbs_COMPOUND; + break; + default: + return; } - aBoundingBuilder.MakeSolid(aSolid); - aBoundingBuilder.Add(aSolid, aShell); - return aSolid; -} + // Getting axis. + gp_Ax1 anAxis = theAxis->impl(); -//================================================================================================= -TopoDS_Shape GeomAlgoAPI_Revolution::findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint) -{ - TopoDS_Shape aResult = theShape; + // Getting base plane. + Handle(Geom_Plane) aBasePlane; + BRepBuilderAPI_FindPlane aFindPlane(aBaseShape); + if(aShapeTypeToExp == TopAbs_FACE && aFindPlane.Found() == Standard_True) { + aBasePlane = aFindPlane.Plane(); + } else { + gp_Pnt aPnt1 = anAxis.Location(); - if(theShape.ShapeType() == TopAbs_COMPOUND) { - double aMinDistance = Precision::Infinite(); - double aCurDistance; - GProp_GProps aGProps; - gp_Pnt aCentr; + TopExp_Explorer anExp(aBaseShape, TopAbs_VERTEX); + gp_Pnt aPnt2 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current())); + gp_Pnt aPnt3 = aPnt1; - for (TopoDS_Iterator anItr(theShape); anItr.More(); anItr.Next()) { - TopoDS_Shape aValue = anItr.Value(); - BRepGProp::VolumeProperties(aValue, aGProps); - aCentr = aGProps.CentreOfMass(); - aCurDistance = aCentr.Distance(thePoint); - - if(aCurDistance < aMinDistance) { - aMinDistance = aCurDistance; - aResult = aValue; - } + for (anExp.Next(); anExp.More() && aBasePlane.IsNull(); anExp.Next()) { + aPnt3 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current())); + aBasePlane = makePlane(aPnt1, aPnt2, aPnt3); } - } - - return aResult; -} -//================================================================================================= -void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBaseShape, - const std::shared_ptr& theAxis, - const std::shared_ptr& theToShape, - double theToAngle, - const std::shared_ptr& theFromShape, - double theFromAngle) -{ - if(!theBaseShape || !theAxis || - (((!theFromShape && !theToShape) || (theFromShape && theToShape && theFromShape->isEqual(theToShape))) - && (theFromAngle == -theToAngle))) { - return; + if(aBasePlane.IsNull()) { + gp_Pnt aPossiblePoints[] = { aPnt1.Translated(anAxis.Direction()), centreOfMass(aBaseShape) }; + for (auto it = std::begin(aPossiblePoints); + it != std::end(aPossiblePoints) && aBasePlane.IsNull(); ++it) + aBasePlane = makePlane(aPnt1, aPnt2, *it); + } } - // Geting base plane. - const TopoDS_Shape& aBaseShape = theBaseShape->impl(); - TopoDS_Face aBaseFace; - if(theBaseShape->shapeType() == GeomAPI_Shape::FACE) { - aBaseFace = TopoDS::Face(theBaseShape->impl()); - } else if(theBaseShape->shapeType() == GeomAPI_Shape::SHELL) { - GeomAPI_ShapeExplorer anExp(theBaseShape, GeomAPI_Shape::FACE); - if(anExp.more()) { - std::shared_ptr aFaceOnShell = anExp.current(); - aBaseFace = TopoDS::Face(aFaceOnShell->impl()); + if(aShapeTypeToExp == TopAbs_FACE) { + if(aBasePlane->Axis().Angle(anAxis) < Precision::Confusion()) { + return; } } - if(aBaseFace.IsNull()) { - return; - } - GeomLib_IsPlanarSurface isBasePlanar(BRep_Tool::Surface(aBaseFace)); - gp_Pln aBasePln = isBasePlanar.Plan(); - Geom_Plane aBasePlane(aBasePln); - gp_Ax1 anAxis = theAxis->impl(); - if(aBasePlane.Axis().Angle(anAxis) < Precision::Confusion()) { - return; - } gp_Pnt aBaseCentre = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape)->impl(); TopoDS_Shape aResult; - ListOfMakeShape aListOfMakeShape; if(!theFromShape && !theToShape) { // Case 1: When only angles was set. // Rotating base face with the negative value of "from angle". gp_Trsf aBaseTrsf; @@ -160,7 +186,8 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase if(!aBaseTransform) { return; } - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aBaseTransform))); + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aBaseTransform))); if(!aBaseTransform->IsDone()) { return; } @@ -168,34 +195,35 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase // Making revolution to the angle equal to the sum of "from angle" and "to angle". BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aRotatedBase, - anAxis, - (theFromAngle + theToAngle) / 180 * M_PI, - Standard_True); + anAxis, + (theFromAngle + theToAngle) / 180 * M_PI, + Standard_True); if(!aRevolBuilder) { return; } - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aRevolBuilder))); + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aRevolBuilder))); if(!aRevolBuilder->IsDone()) { return; } aResult = aRevolBuilder->Shape(); // Setting naming. - for(TopExp_Explorer anExp(aRotatedBase, TopAbs_FACE); anExp.More(); anExp.Next()) { - const TopoDS_Shape& aFace = anExp.Current(); - std::shared_ptr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape); - aFromShape->setImpl(new TopoDS_Shape(aRevolBuilder->FirstShape(aFace))); - aToShape->setImpl(new TopoDS_Shape(aRevolBuilder->LastShape(aFace))); - myFromFaces.push_back(aFromShape); - myToFaces.push_back(aToShape); + if(aShapeTypeToExp == TopAbs_COMPOUND) { + storeGenerationHistory(this, aRotatedBase, TopAbs_EDGE, aRevolBuilder); + storeGenerationHistory(this, aRotatedBase, TopAbs_FACE, aRevolBuilder); + } else { + storeGenerationHistory(this, aRotatedBase, aShapeTypeToExp, aRevolBuilder); } } else if(theFromShape && theToShape) { // Case 2: When both bounding planes were set. // Making revolution to the 360 angle. - BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True); + BRepPrimAPI_MakeRevol* aRevolBuilder = + new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True); if(!aRevolBuilder) { return; } - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aRevolBuilder))); + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aRevolBuilder))); if(!aRevolBuilder->IsDone()) { return; } @@ -208,11 +236,16 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase // Getting planes from bounding face. GeomLib_IsPlanarSurface isFromPlanar(BRep_Tool::Surface(aFromFace)); GeomLib_IsPlanarSurface isToPlanar(BRep_Tool::Surface(aToFace)); - if(!isFromPlanar.IsPlanar() || !isToPlanar.IsPlanar()) {// non-planar shapes is not supported for revolution bounding + if(!isFromPlanar.IsPlanar() || !isToPlanar.IsPlanar()) { + // non-planar shapes is not supported for revolution bounding return; } - gp_Pln aFromPln = isFromPlanar.Plan(); - gp_Pln aToPln = isToPlanar.Plan(); + + std::shared_ptr aGeomFromFace(new GeomAPI_Face(theFromShape)); + std::shared_ptr aGeomToFace(new GeomAPI_Face(theToShape)); + + gp_Pln aFromPln = aGeomFromFace->getPlane()->impl(); + gp_Pln aToPln = aGeomToFace->getPlane()->impl(); // Orienting bounding planes properly so that the center of mass of the base face stays // on the result shape after cut. @@ -226,8 +259,12 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase // Rotating bounding planes to the specified angle. gp_Trsf aFromTrsf; gp_Trsf aToTrsf; - double aFromRotAngle = ((aFromPln.Axis().Direction() * aBasePln.Axis().Direction()) > 0) ? -theFromAngle : theFromAngle; - double aToRotAngle = ((aToPln.Axis().Direction() * aBasePln.Axis().Direction()) > 0) ? -theToAngle : theToAngle; + double aFromRotAngle = + ((aFromPln.Axis().Direction() * aBasePlane->Axis().Direction()) > 0) ? -theFromAngle : + theFromAngle; + double aToRotAngle = + ((aToPln.Axis().Direction() * aBasePlane->Axis().Direction()) > 0) ? -theToAngle : + theToAngle; aFromTrsf.SetRotation(anAxis,aFromRotAngle / 180.0 * M_PI); aToTrsf.SetRotation(anAxis, aToRotAngle / 180.0 * M_PI); BRepBuilderAPI_Transform aFromTransform(aFromSolid, aFromTrsf, true); @@ -243,8 +280,12 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase if(!aFromCutBuilder->IsDone()) { return; } - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aFromCutBuilder))); + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aFromCutBuilder))); aResult = aFromCutBuilder->Shape(); + if(aResult.ShapeType() == TopAbs_COMPOUND) { + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + } // Cutting revolution with to plane. BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid); @@ -252,85 +293,69 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase if(!aToCutBuilder->IsDone()) { return; } - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aToCutBuilder))); + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aToCutBuilder))); aResult = aToCutBuilder->Shape(); - - TopExp_Explorer anExp(aResult, TopAbs_SOLID); - if(!anExp.More()) { + TopoDS_Iterator aCheckIt(aResult); + if(!aCheckIt.More()) { return; } if(aResult.ShapeType() == TopAbs_COMPOUND) { aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); } if(aResult.ShapeType() == TopAbs_COMPOUND) { - std::shared_ptr aCompound(new GeomAPI_Shape); - aCompound->setImpl(new TopoDS_Shape(aResult)); - ListOfShape aCompSolids, aFreeSolids; - GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids); - if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) { - aResult = aCompSolids.front()->impl(); - } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) { - TopoDS_Compound aResultComp; - TopoDS_Builder aBuilder; - aBuilder.MakeCompound(aResultComp); - for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) { - aBuilder.Add(aResultComp, (*anIter)->impl()); - } - for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) { - aBuilder.Add(aResultComp, (*anIter)->impl()); - } - aResult = aResultComp; - } + std::shared_ptr aGeomShape(new GeomAPI_Shape); + aGeomShape->setImpl(new TopoDS_Shape(aResult)); + ListOfShape aResults; + aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape, + GeomAPI_Shape::COMPSOLID, + aResults); + aResult = aGeomShape->impl(); } - // If after cut we got more than one solids then take closest to the center of mass of the base face. + // If after cut we got more than one solids then take closest + // to the center of mass of the base face. aResult = findClosest(aResult, aBaseCentre); // Setting naming. - for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) { - const TopoDS_Shape& aFaceOnResult = anExp.Current(); - Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aFaceOnResult)); - Handle(Geom_Surface) aFromSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedFromFace)); - Handle(Geom_Surface) aToSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedToFace)); - if(aFaceSurface == aFromSurface) { - std::shared_ptr aFSHape(new GeomAPI_Shape); - aFSHape->setImpl(new TopoDS_Shape(aFaceOnResult)); - myFromFaces.push_back(aFSHape); - } - if(aFaceSurface == aToSurface) { - std::shared_ptr aTSHape(new GeomAPI_Shape); - aTSHape->setImpl(new TopoDS_Shape(aFaceOnResult)); - myToFaces.push_back(aTSHape); - } + if(aShapeTypeToExp == TopAbs_COMPOUND) { + storeGenerationHistory(this, aResult, TopAbs_EDGE, aRotatedToFace, aRotatedFromFace); + storeGenerationHistory(this, aResult, TopAbs_FACE, aRotatedToFace, aRotatedFromFace); + } else { + storeGenerationHistory(this, aResult, aShapeTypeToExp, aRotatedToFace, aRotatedFromFace); } } else { //Case 3: When only one bounding plane was set. // Making revolution to the 360 angle. - BRepPrimAPI_MakeRevol* aRevolBuilder = new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True); + BRepPrimAPI_MakeRevol* aRevolBuilder = + new BRepPrimAPI_MakeRevol(aBaseShape, anAxis, 2 * M_PI, Standard_True); if(!aRevolBuilder) { return; } - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aRevolBuilder))); + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aRevolBuilder))); if(!aRevolBuilder->IsDone()) { return; } aResult = aRevolBuilder->Shape(); // Getting bounding face. - TopoDS_Face aBoundingFace; bool isFromFaceSet = false; + std::shared_ptr aGeomBoundingFace; if(theFromShape) { - aBoundingFace = TopoDS::Face(theFromShape->impl()); + aGeomBoundingFace.reset(new GeomAPI_Face(theFromShape)); isFromFaceSet = true; } else if(theToShape) { - aBoundingFace = TopoDS::Face(theToShape->impl()); + aGeomBoundingFace.reset(new GeomAPI_Face(theToShape)); } + TopoDS_Face aBoundingFace = TopoDS::Face(aGeomBoundingFace->impl()); // Getting plane from bounding face. GeomLib_IsPlanarSurface isBoundingPlanar(BRep_Tool::Surface(aBoundingFace)); if(!isBoundingPlanar.IsPlanar()) { // non-planar shapes is not supported for revolution bounding return; } - gp_Pln aBoundingPln = isBoundingPlanar.Plan(); + + gp_Pln aBoundingPln = aGeomBoundingFace->getPlane()->impl(); // Orienting bounding plane properly so that the center of mass of the base face stays // on the result shape after cut. @@ -341,10 +366,10 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase // Rotating bounding plane to the specified angle. double aBoundingRotAngle = isFromFaceSet ? theFromAngle : theToAngle; - if(aBoundingPln.Axis().IsParallel(aBasePln.Axis(), Precision::Confusion())) { + if(aBoundingPln.Axis().IsParallel(aBasePlane->Axis(), Precision::Confusion())) { if(isFromFaceSet) aBoundingRotAngle = -aBoundingRotAngle; } else { - double aSign = (aBoundingPln.Axis().Direction() ^ aBasePln.Axis().Direction()) * + double aSign = (aBoundingPln.Axis().Direction() ^ aBasePlane->Axis().Direction()) * anAxis.Direction(); if((aSign <= 0 && !isFromFaceSet) || (aSign > 0 && isFromFaceSet)) { aBoundingRotAngle = -aBoundingRotAngle; @@ -362,25 +387,51 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase if(!aBoundingCutBuilder->IsDone()) { return; } - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aBoundingCutBuilder))); + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aBoundingCutBuilder))); aResult = aBoundingCutBuilder->Shape(); + if(aResult.ShapeType() == TopAbs_COMPOUND) { + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + } // Setting naming. - const TopTools_ListOfShape& aBndShapes = aBoundingCutBuilder->Modified(aBoundingFace); - for(TopTools_ListIteratorOfListOfShape anIt(aBndShapes); anIt.More(); anIt.Next()) { - std::shared_ptr aShape(new GeomAPI_Shape()); - aShape->setImpl(new TopoDS_Shape(anIt.Value())); - isFromFaceSet ? myFromFaces.push_back(aShape) : myToFaces.push_back(aShape); + if(aShapeTypeToExp == TopAbs_FACE || aShapeTypeToExp == TopAbs_COMPOUND) { + const TopTools_ListOfShape& aBndShapes = aBoundingCutBuilder->Modified(aBoundingFace); + for(TopTools_ListIteratorOfListOfShape anIt(aBndShapes); anIt.More(); anIt.Next()) { + GeomShapePtr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(anIt.Value())); + fixOrientation(aShape); + isFromFaceSet ? this->addFromShape(aShape) : this->addToShape(aShape); + } } // Try to cut with base face. If it can not be done then keep result of cut with bounding plane. - TopoDS_Shape aModifiedBaseShape = aBaseShape; + TopoDS_Shape aModifiedBaseShape; + if(aShapeTypeToExp != TopAbs_FACE) { + ListOfShape aList; + GeomShapePtr aSh(new GeomAPI_Shape()); + aSh->setImpl(new TopoDS_Shape(aBaseShape)); + std::shared_ptr theCenter(new GeomAPI_Pnt(aBasePlane->Location().X(), + aBasePlane->Location().Y(), + aBasePlane->Location().Z())); + std::shared_ptr theNormal(new GeomAPI_Dir(aBasePlane->Axis().Direction().X(), + aBasePlane->Axis().Direction().Y(), + aBasePlane->Axis().Direction().Z())); + GeomShapePtr aPln = GeomAlgoAPI_FaceBuilder::planarFace(theCenter, theNormal); + aList.push_back(aSh); + std::list > + aBoundingPoints = GeomAlgoAPI_ShapeTools::getBoundingBox(aList); + aSh = GeomAlgoAPI_ShapeTools::fitPlaneToBox(aPln, aBoundingPoints); + aModifiedBaseShape = aSh->impl(); + } else { + aModifiedBaseShape = aBaseShape; + } if(isFromFaceSet) { if(aModifiedBaseShape.ShapeType() == TopAbs_FACE) { aModifiedBaseShape.Orientation(TopAbs_REVERSED); } else { gp_Trsf aMirrorTrsf; - aMirrorTrsf.SetMirror(aBasePlane.Position().Ax2()); + aMirrorTrsf.SetMirror(aBasePlane->Position().Ax2()); BRepBuilderAPI_Transform aMirrorTransform(aModifiedBaseShape, aMirrorTrsf, true); aModifiedBaseShape = aMirrorTransform.Shape(); } @@ -401,61 +452,49 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase aBaseCutBuilder->Build(); if(aBaseCutBuilder->IsDone()) { TopoDS_Shape aCutResult = aBaseCutBuilder->Shape(); - TopExp_Explorer anExp(aCutResult, TopAbs_SOLID); - if(anExp.More()) { - aListOfMakeShape.push_back(std::shared_ptr(new GeomAlgoAPI_MakeShape(aBaseCutBuilder))); + TopoDS_Iterator aCheckIt(aCutResult); + if(aCheckIt.More()) { + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aBaseCutBuilder))); aResult = aCutResult; + if(aResult.ShapeType() == TopAbs_COMPOUND) { + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + } + if(aShapeTypeToExp == TopAbs_FACE || aShapeTypeToExp == TopAbs_COMPOUND) { + const TopTools_ListOfShape& aBsShapes = aBaseCutBuilder->Modified(aBoundingFace); + for(TopTools_ListIteratorOfListOfShape anIt(aBsShapes); anIt.More(); anIt.Next()) { + GeomShapePtr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(anIt.Value())); + fixOrientation(aShape); + isFromFaceSet ? this->addToShape(aShape) : this->addFromShape(aShape); + } + } } } - const TopTools_ListOfShape& aBsShapes = aBaseCutBuilder->Modified(aBoundingFace); - for(TopTools_ListIteratorOfListOfShape anIt(aBsShapes); anIt.More(); anIt.Next()) { - std::shared_ptr aShape(new GeomAPI_Shape()); - aShape->setImpl(new TopoDS_Shape(anIt.Value())); - isFromFaceSet ? myToFaces.push_back(aShape) : myFromFaces.push_back(aShape); - } - - TopExp_Explorer anExp(aResult, TopAbs_SOLID); - if(!anExp.More()) { - return; - } if(aResult.ShapeType() == TopAbs_COMPOUND) { - aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); - } - if(aResult.ShapeType() == TopAbs_COMPOUND) { - std::shared_ptr aCompound(new GeomAPI_Shape); - aCompound->setImpl(new TopoDS_Shape(aResult)); - ListOfShape aCompSolids, aFreeSolids; - GeomAlgoAPI_ShapeTools::combineShapes(aCompound, GeomAPI_Shape::COMPSOLID, aCompSolids, aFreeSolids); - if(aCompSolids.size() == 1 && aFreeSolids.size() == 0) { - aResult = aCompSolids.front()->impl(); - } else if (aCompSolids.size() > 1 || (aCompSolids.size() >= 1 && aFreeSolids.size() >= 1)) { - TopoDS_Compound aResultComp; - TopoDS_Builder aBuilder; - aBuilder.MakeCompound(aResultComp); - for(ListOfShape::const_iterator anIter = aCompSolids.cbegin(); anIter != aCompSolids.cend(); anIter++) { - aBuilder.Add(aResultComp, (*anIter)->impl()); - } - for(ListOfShape::const_iterator anIter = aFreeSolids.cbegin(); anIter != aFreeSolids.cend(); anIter++) { - aBuilder.Add(aResultComp, (*anIter)->impl()); - } - aResult = aResultComp; - } + std::shared_ptr aGeomShape(new GeomAPI_Shape); + aGeomShape->setImpl(new TopoDS_Shape(aResult)); + ListOfShape aResults; + aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape, + GeomAPI_Shape::COMPSOLID, + aResults); + aResult = aGeomShape->impl(); } - // If after cut we got more than one solids then take closest to the center of mass of the base face. + // If after cut we got more than one solids then take + // closest to the center of mass of the base face. aResult = findClosest(aResult, aBaseCentre); // Setting naming. - for(TopExp_Explorer anExp(aResult, TopAbs_FACE); anExp.More (); anExp.Next ()) { - const TopoDS_Shape& aFaceOnResult = anExp.Current(); - Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aFaceOnResult)); - Handle(Geom_Surface) aBoundingSurface = BRep_Tool::Surface(TopoDS::Face(aRotatedBoundingFace)); - if(aFaceSurface == aBoundingSurface) { - std::shared_ptr aShape(new GeomAPI_Shape()); - aShape->setImpl(new TopoDS_Shape(aFaceOnResult)); - isFromFaceSet ? myFromFaces.push_back(aShape) : myToFaces.push_back(aShape); - } + if(aShapeTypeToExp == TopAbs_COMPOUND) { + storeGenerationHistory(this, aResult, TopAbs_EDGE, + aRotatedBoundingFace, aModifiedBaseShape, isFromFaceSet); + storeGenerationHistory(this, aResult, TopAbs_FACE, + aRotatedBoundingFace, aModifiedBaseShape, isFromFaceSet); + } else { + storeGenerationHistory(this, aResult, aShapeTypeToExp, + aRotatedBoundingFace, aModifiedBaseShape, isFromFaceSet); } } @@ -463,76 +502,237 @@ void GeomAlgoAPI_Revolution::build(const std::shared_ptr& theBase if(aResult.IsNull()) { return; } - myShape.reset(new GeomAPI_Shape); - myShape->setImpl(new TopoDS_Shape(aResult)); - - // Filling data map to keep correct orientation of sub-shapes. - myMap.reset(new GeomAPI_DataMapOfShapeShape); - for (TopExp_Explorer Exp(aResult,TopAbs_FACE); Exp.More(); Exp.Next()) { - std::shared_ptr aCurrentShape(new GeomAPI_Shape); - aCurrentShape->setImpl(new TopoDS_Shape(Exp.Current())); - myMap->bind(aCurrentShape, aCurrentShape); + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + GeomShapePtr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(aResult)); + this->setShape(aShape); + this->setDone(true); +} + +//================================================================================================== +TopoDS_Face makeFaceFromPlane(gp_Pln& thePlane, const gp_Pnt& thePoint) +{ + if(!thePlane.Contains(thePoint, Precision::Confusion())) { + gp_XYZ aVec = thePoint.XYZ() - thePlane.Location().XYZ(); + double aSign = aVec * thePlane.Axis().Direction().XYZ(); + if(aSign < 0) thePlane.SetAxis(thePlane.Axis().Reversed()); } - // Setting list of make shape. - myMkShape.reset(new GeomAlgoAPI_MakeShapeList(aListOfMakeShape)); + BRepBuilderAPI_MakeFace aMakeFace(thePlane); + TopoDS_Face aResultFace = TopoDS::Face(aMakeFace.Shape()); - myDone = true; + return aResultFace; } -//================================================================================================= -const bool GeomAlgoAPI_Revolution::isDone() const +//================================================================================================== +TopoDS_Solid makeSolidFromShape(const TopoDS_Shape& theShape) { - return myDone; -} + TopoDS_Shell aShell; + TopoDS_Solid aSolid; -//================================================================================================= -const bool GeomAlgoAPI_Revolution::isValid() const -{ - BRepCheck_Analyzer aChecker(myShape->impl()); - return (aChecker.IsValid() == Standard_True); + BRep_Builder aBoundingBuilder; + if(theShape.ShapeType() == TopAbs_SHELL) { + aShell = TopoDS::Shell(theShape); + } else { + aBoundingBuilder.MakeShell(aShell); + aBoundingBuilder.Add(aShell, theShape); + } + aBoundingBuilder.MakeSolid(aSolid); + aBoundingBuilder.Add(aSolid, aShell); + + return aSolid; } -//================================================================================================= -const bool GeomAlgoAPI_Revolution::hasVolume() const +//================================================================================================ +gp_Pnt centreOfMass(const TopoDS_Shape& theShape) { - bool hasVolume(false); - if(isValid()) { - const TopoDS_Shape& aRShape = myShape->impl(); - GProp_GProps aGProp; - BRepGProp::VolumeProperties(aRShape, aGProp); - if(aGProp.Mass() > Precision::Confusion()) - hasVolume = true; + TopAbs_ShapeEnum aShType = theShape.ShapeType(); + GProp_GProps aGProps; + + if(aShType == TopAbs_EDGE || aShType == TopAbs_WIRE) { + BRepGProp::LinearProperties(theShape, aGProps); + } else if(aShType == TopAbs_FACE || aShType == TopAbs_SHELL) { + BRepGProp::SurfaceProperties(theShape, aGProps); + } else if(aShType == TopAbs_SOLID || aShType == TopAbs_COMPSOLID) { + BRepGProp::VolumeProperties(theShape, aGProps); } - return hasVolume; + + return aGProps.CentreOfMass(); } -//================================================================================================= -const std::shared_ptr& GeomAlgoAPI_Revolution::shape () const +//================================================================================================ +TopoDS_Shape findClosest(const TopoDS_Shape& theShape, const gp_Pnt& thePoint) { - return myShape; + TopoDS_Shape aResult = theShape; + + if(theShape.ShapeType() == TopAbs_COMPOUND) { + double aMinDistance = Precision::Infinite(); + double aCurDistance; + gp_Pnt aCentr; + for (TopoDS_Iterator anItr(theShape); anItr.More(); anItr.Next()) { + TopoDS_Shape aValue = anItr.Value(); + aCentr = centreOfMass(aValue); + aCurDistance = aCentr.Distance(thePoint); + + if(aCurDistance < aMinDistance) { + aMinDistance = aCurDistance; + aResult = aValue; + } + } + } + + return aResult; } -//================================================================================================= -const ListOfShape& GeomAlgoAPI_Revolution::fromFaces() const +//================================================================================================ +Handle(Geom_Plane) makePlane(const gp_Pnt& theP1, const gp_Pnt& theP2, const gp_Pnt& theP3) { - return myFromFaces; + Handle(Geom_Plane) aPlane; + GC_MakePlane aMkPlane(theP1, theP2, theP3); + if (aMkPlane.IsDone()) + aPlane = aMkPlane.Value(); + return aPlane; } -//================================================================================================= -const ListOfShape& GeomAlgoAPI_Revolution::toFaces() const +//================================================================================================ +void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo, + const TopoDS_Shape& theBase, + const TopAbs_ShapeEnum theType, + BRepPrimAPI_MakeRevol* theRevolBuilder) { - return myToFaces; + for(TopExp_Explorer anExp(theBase, theType); anExp.More(); anExp.Next()) { + const TopoDS_Shape& aShape = anExp.Current(); + GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape); + aFromShape->setImpl(new TopoDS_Shape(theRevolBuilder->FirstShape(aShape))); + aToShape->setImpl(new TopoDS_Shape(theRevolBuilder->LastShape(aShape))); + theRevolutionAlgo->fixOrientation(aFromShape); + theRevolutionAlgo->fixOrientation(aToShape); + theRevolutionAlgo->addFromShape(aFromShape); + theRevolutionAlgo->addToShape(aToShape); + } } -//================================================================================================= -std::shared_ptr GeomAlgoAPI_Revolution::mapOfShapes() const +//================================================================================================ +void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo, + const TopoDS_Shape& theResult, + const TopAbs_ShapeEnum theType, + const TopoDS_Shape& theToFace, + const TopoDS_Shape& theFromFace) { - return myMap; + for(TopExp_Explorer anExp(theResult, theType); anExp.More (); anExp.Next ()) { + const TopoDS_Shape& aShape = anExp.Current(); + GeomShapePtr aGeomSh(new GeomAPI_Shape()); + if(theType == TopAbs_VERTEX) { + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape)); + IntTools_Context anIntTools; + if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theToFace), + Precision::Confusion()) == Standard_True) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theRevolutionAlgo->addToShape(aGeomSh); + } + if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theFromFace), + Precision::Confusion()) == Standard_True) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theRevolutionAlgo->addFromShape(aGeomSh); + } + } else if(theType == TopAbs_EDGE) { + TopoDS_Edge anEdge = TopoDS::Edge(aShape); + BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, TopoDS::Face(theToFace)); + anEdgeCheck.Perform(); + if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theRevolutionAlgo->addToShape(aGeomSh); + } + anEdgeCheck.Init(anEdge, TopoDS::Face(theFromFace)); + anEdgeCheck.Perform(); + if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theRevolutionAlgo->addFromShape(aGeomSh); + } + } else { + Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aShape)); + Handle(Geom_Surface) aFromSurface = BRep_Tool::Surface(TopoDS::Face(theFromFace)); + Handle(Geom_Surface) aToSurface = BRep_Tool::Surface(TopoDS::Face(theToFace)); + if(aFaceSurface == aFromSurface) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theRevolutionAlgo->addFromShape(aGeomSh); + } + if(aFaceSurface == aToSurface) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theRevolutionAlgo->addToShape(aGeomSh); + } + } + } } -//================================================================================================= -std::shared_ptr GeomAlgoAPI_Revolution::makeShape() const +void storeGenerationHistory(GeomAlgoAPI_Revolution* theRevolutionAlgo, + const TopoDS_Shape& theResult, + const TopAbs_ShapeEnum theType, + const TopoDS_Shape& theRotatedBoundingFace, + const TopoDS_Shape& theModifiedBaseShape, + const bool theIsFromFaceSet) { - return myMkShape; + for(TopExp_Explorer anExp(theResult, theType); anExp.More (); anExp.Next ()) { + const TopoDS_Shape& aShape = anExp.Current(); + GeomShapePtr aGeomSh(new GeomAPI_Shape()); + if(theType == TopAbs_VERTEX) { + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape)); + IntTools_Context anIntTools; + if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theRotatedBoundingFace), + Precision::Confusion()) == Standard_True) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theIsFromFaceSet ? theRevolutionAlgo->addFromShape(aGeomSh) : + theRevolutionAlgo->addToShape(aGeomSh); + } + if(anIntTools.IsValidPointForFace(aPnt, TopoDS::Face(theModifiedBaseShape), + Precision::Confusion()) == Standard_True) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theIsFromFaceSet ? theRevolutionAlgo->addToShape(aGeomSh) : + theRevolutionAlgo->addFromShape(aGeomSh); + } + } else if(theType == TopAbs_EDGE) { + TopoDS_Edge anEdge = TopoDS::Edge(aShape); + BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, TopoDS::Face(theRotatedBoundingFace)); + anEdgeCheck.Perform(); + if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theIsFromFaceSet ? theRevolutionAlgo->addFromShape(aGeomSh) : + theRevolutionAlgo->addToShape(aGeomSh); + } + anEdgeCheck.Init(anEdge, TopoDS::Face(theModifiedBaseShape)); + anEdgeCheck.Perform(); + if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theIsFromFaceSet ? theRevolutionAlgo->addToShape(aGeomSh) : + theRevolutionAlgo->addFromShape(aGeomSh); + } + } else { + Handle(Geom_Surface) aFaceSurface = BRep_Tool::Surface(TopoDS::Face(aShape)); + Handle(Geom_Surface) aBoundingSurface = + BRep_Tool::Surface(TopoDS::Face(theRotatedBoundingFace)); + Handle(Geom_Surface) aBaseSurface = BRep_Tool::Surface(TopoDS::Face(theModifiedBaseShape)); + if(aFaceSurface == aBoundingSurface) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theIsFromFaceSet ? theRevolutionAlgo->addFromShape(aGeomSh) : + theRevolutionAlgo->addToShape(aGeomSh); + } + if(aFaceSurface == aBaseSurface) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + theRevolutionAlgo->fixOrientation(aGeomSh); + theIsFromFaceSet ? theRevolutionAlgo->addToShape(aGeomSh) : + theRevolutionAlgo->addFromShape(aGeomSh); + } + } + } }