X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGeomAlgoAPI%2FGeomAlgoAPI_Prism.cpp;h=1072405de1323bf1bd7f22a7e8e57642b32e4343;hb=d1bf96e37f50cceb9a4c225addf693d2460334ba;hp=d8599e7675406d5728d8532664929d3c6ebb0bd8;hpb=01cfaed78e7e3a720c5363ca5ba5465fe3840376;p=modules%2Fshaper.git diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp index d8599e767..1072405de 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Prism.cpp @@ -1,19 +1,39 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: GeomAlgoAPI_Prism.cpp -// Created: 5 May 2015 -// Author: Dmitry Bobylev +// Copyright (C) 2014-2022 CEA/DEN, EDF R&D +// +// 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_Prism.h" +#include +#include #include #include #include #include #include + +#include #include #include +#include +#include #include +#include #include #include @@ -21,11 +41,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -37,386 +59,839 @@ #include #include -#include -//================================================================================================= -GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape, - const double theToSize, - const double theFromSize) +/// Expand planar face to cover the bounding box if theOriginalShape is planar. +/// Otherwise, return the same shape; +static GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape, + const Bnd_Box& theBaseShapeBB); + +/// Build offset for the given shape. +/// If the offset algorithm failed, translate the shape along the direction. +static GeomShapePtr buildOffset(const GeomShapePtr& theShape, + const double theOffset, + const GeomDirPtr theDirection, + GeomAlgoAPI_MakeShapeList& theMakeShapeList); + +/// Collect base faces of the prism. +static void collectPrismBases(const TopoDS_Shape& theBaseShape, + BRepPrimAPI_MakePrism& thePrismAlgo, + ListOfShape& theBoundaries, + const GeomAPI_Shape::ShapeType theTypeToExp); + +/// Collect all solids which contain boundaries but do not contain bases of prism. +static GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation, + const ListOfShape& theBoundaries, + const ListOfShape& theShapesToExclude, + const GeomAPI_Shape::ShapeType theTypeToExp); + +static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo, + const TopoDS_Shape& theBase, + const TopAbs_ShapeEnum theType, + BRepPrimAPI_MakePrism* thePrismBuilder); + +static void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo, + const TopoDS_Shape& theResult, + const TopAbs_ShapeEnum theType, + const TopoDS_Face& theToFace, + const TopoDS_Face& theFromFace); + +static GeomShapePtr toShape(const TopoDS_Shape& theShape) { - build(theBaseShape, std::shared_ptr(), GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize); + GeomShapePtr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(theShape)); + return aShape; } -//================================================================================================= -GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape, - const std::shared_ptr theDirection, - const double theToSize, - const double theFromSize) +static void changeOrientationIfNeeded(const TopoDS_Shape& theShape, gp_Vec& theNormal) { - build(theBaseShape, theDirection, GeomShapePtr(), theToSize, GeomShapePtr(), theFromSize); + TopExp_Explorer anExp(theShape, TopAbs_VERTEX); + gp_Pnt aPnt0 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current())); + gp_Dir aDir01; + for (anExp.Next(); anExp.More(); anExp.Next()) { + gp_Pnt aPnt1 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current())); + if (aPnt1.SquareDistance(aPnt0) > Precision::SquareConfusion()) { + aDir01 = gp_Dir(gp_Vec(aPnt0, aPnt1)); + break; + } + } + gp_Vec aNormal; + for (; anExp.More(); anExp.Next()) { + gp_Pnt aPnt2 = BRep_Tool::Pnt(TopoDS::Vertex(anExp.Current())); + if (aPnt2.SquareDistance(aPnt0) > Precision::SquareConfusion()) { + aNormal = gp_Vec(aDir01) ^ gp_Vec(aPnt0, aPnt2); + if (aNormal.SquareMagnitude() > Precision::SquareConfusion()) + break; + } + } + if (anExp.More() && aNormal.XYZ().Dot(theNormal.XYZ()) < -Precision::Confusion()) { + // directions differ, reverse the normal + theNormal.Reverse(); + } } -//================================================================================================= +//================================================================================================== GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape, + const GeomDirPtr theDirection, const GeomShapePtr theToShape, const double theToSize, const GeomShapePtr theFromShape, const double theFromSize) -{ - build(theBaseShape, std::shared_ptr(), theToShape, theToSize, theFromShape, theFromSize); -} - -//================================================================================================= -GeomAlgoAPI_Prism::GeomAlgoAPI_Prism(const GeomShapePtr theBaseShape, - const std::shared_ptr theDirection, - const GeomShapePtr theToShape, - const double theToSize, - const GeomShapePtr theFromShape, - const double theFromSize) -{ - build(theBaseShape, theDirection, theToShape, theToSize, theFromShape, theFromSize); -} - -//================================================================================================= -void GeomAlgoAPI_Prism::build(const GeomShapePtr& theBaseShape, - const std::shared_ptr theDirection, - const GeomShapePtr& theToShape, - const double theToSize, - const GeomShapePtr& theFromShape, - const double theFromSize) { if(!theBaseShape.get() || - (((!theFromShape.get() && !theToShape.get()) || (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape))) + (((!theFromShape.get() && !theToShape.get()) || + (theFromShape.get() && theToShape.get() && theFromShape->isEqual(theToShape))) && (theFromSize == -theToSize))) { return; } // Getting base shape. const TopoDS_Shape& aBaseShape = theBaseShape->impl(); - TopAbs_ShapeEnum aShapeTypeToExp; + GeomAPI_Shape::ShapeType aShapeTypeToExp; switch(aBaseShape.ShapeType()) { case TopAbs_VERTEX: - aShapeTypeToExp = TopAbs_VERTEX; + aShapeTypeToExp = GeomAPI_Shape::VERTEX; break; case TopAbs_EDGE: case TopAbs_WIRE: - aShapeTypeToExp = TopAbs_EDGE; + aShapeTypeToExp = GeomAPI_Shape::EDGE; break; case TopAbs_FACE: case TopAbs_SHELL: - aShapeTypeToExp = TopAbs_FACE; + aShapeTypeToExp = GeomAPI_Shape::FACE; + break; + case TopAbs_COMPOUND: + aShapeTypeToExp = GeomAPI_Shape::COMPOUND; break; default: return; } // Getting direction. - gp_Vec aDirVec; + gp_Vec aBaseVec; std::shared_ptr aBaseLoc; std::shared_ptr aBaseDir; - GeomShapePtr aBasePlane; - const bool isBoundingShapesSet = theFromShape.get() || theToShape.get(); BRepBuilderAPI_FindPlane aFindPlane(aBaseShape); - if(aBaseShape.ShapeType() == TopAbs_VERTEX || aBaseShape.ShapeType() == TopAbs_EDGE || - aFindPlane.Found() != Standard_True) { - // Direction and both bounding planes should be set or empty. - if(!theDirection.get() || (isBoundingShapesSet && (!theToShape.get() || !theFromShape.get()))) { - return; + if(aFindPlane.Found() == Standard_True) + { + bool checkOrientation = false; + Handle(Geom_Plane) aPlane; + if(aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) { + TopExp_Explorer anExp(aBaseShape, TopAbs_FACE); + const TopoDS_Shape& aFace = anExp.Current(); + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace)); + if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) { + Handle(Geom_RectangularTrimmedSurface) aTrimSurface = + Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface); + aSurface = aTrimSurface->BasisSurface(); + } + if (aSurface->DynamicType() == STANDARD_TYPE(Geom_Plane)) + aPlane = Handle(Geom_Plane)::DownCast(aSurface); } - aBaseDir = theDirection; - aDirVec = theDirection->impl(); - } else { - Handle(Geom_Plane) aPlane = aFindPlane.Plane(); + if (aPlane.IsNull()) { + aPlane = aFindPlane.Plane(); + checkOrientation = true; + } gp_Pnt aLoc = aPlane->Axis().Location(); - aDirVec = aPlane->Axis().Direction(); + aBaseVec = aPlane->Axis().Direction(); + + if (checkOrientation) { + // to stabilize the result of algorithm, if base shape is a wire, compare the orientation + // of calculated plane with the normal vector got iterating on vertices + changeOrientationIfNeeded(aBaseShape, aBaseVec); + } aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z())); - aBaseDir.reset(new GeomAPI_Dir(aDirVec.X(), aDirVec.Y(), aDirVec.Z())); - aBasePlane = GeomAlgoAPI_FaceBuilder::planarFace(aBaseLoc, aBaseDir); + aBaseDir.reset(new GeomAPI_Dir(aBaseVec.X(), aBaseVec.Y(), aBaseVec.Z())); + } + else if (theDirection.get()) + { + aBaseDir = theDirection; + aBaseVec = theDirection->impl(); + } + else + { + return; } - TopoDS_Shape aResult; - if(!isBoundingShapesSet) { - // Moving base shape. - gp_Trsf aTrsf; - aTrsf.SetTranslation(aDirVec * -theFromSize); - BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf); - if(!aTransformBuilder) { - return; - } - this->appendAlgo(std::shared_ptr(new GeomAlgoAPI_MakeShape(aTransformBuilder))); - if(!aTransformBuilder->IsDone()) { - return; + if(!aBaseLoc.get()) { + gp_Pnt aLoc; + gp_XYZ aDirXYZ = aBaseVec.XYZ(); + Standard_Real aMinParam = Precision::Infinite(); + for(TopExp_Explorer anExp(aBaseShape, TopAbs_VERTEX); anExp.More(); anExp.Next()) { + const TopoDS_Shape& aVertex = anExp.Current(); + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex)); + double aParam = aDirXYZ.Dot(aPnt.XYZ()); + if(aParam < aMinParam) { + aMinParam = aParam; + aLoc = aPnt; + } } - TopoDS_Shape aMovedBase = aTransformBuilder->Shape(); + aBaseLoc.reset(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z())); + } - // Making prism. - BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * (theFromSize + theToSize)); - if(!aPrismBuilder) { - return; - } - this->appendAlgo(std::shared_ptr(new GeomAlgoAPI_MakeShape(aPrismBuilder))); - if(!aPrismBuilder->IsDone()) { - return; - } - aResult = aPrismBuilder->Shape(); - - // Setting naming. - for(TopExp_Explorer anExp(aMovedBase, aShapeTypeToExp); anExp.More(); anExp.Next()) { - const TopoDS_Shape& aShape = anExp.Current(); - GeomShapePtr aFromShape(new GeomAPI_Shape), aToShape(new GeomAPI_Shape); - aFromShape->setImpl(new TopoDS_Shape(aPrismBuilder->FirstShape(aShape))); - aToShape->setImpl(new TopoDS_Shape(aPrismBuilder->LastShape(aShape))); - this->addFromShape(aFromShape); - this->addToShape(aToShape); - } + gp_Vec anExtVec; + std::shared_ptr anExtDir; + if (theDirection.get()) + { + anExtDir = theDirection; + anExtVec = theDirection->impl(); + } + else + { + anExtDir = aBaseDir; + anExtVec = aBaseDir->impl(); + } + + + TopoDS_Shape aResult; + const bool isBoundingShapesSet = theFromShape.get() || theToShape.get(); + if(!isBoundingShapesSet) { + buildBySizes(theBaseShape, anExtDir, theToSize, theFromSize, aShapeTypeToExp); } else { + GeomShapePtr aBasePlane = GeomAlgoAPI_FaceBuilder::squareFace(aBaseLoc, aBaseDir, 100.0); + GeomShapePtr aBoundingFromShape = theFromShape ? theFromShape : aBasePlane; GeomShapePtr aBoundingToShape = theToShape ? theToShape : aBasePlane; - // Moving prism bounding faces according to "from" and "to" sizes. - std::shared_ptr aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane(); - std::shared_ptr aFromLoc = aFromPln->location(); - std::shared_ptr aFromDir = aFromPln->direction(); - - std::shared_ptr aToPln = GeomAPI_Face(aBoundingToShape).getPlane(); - std::shared_ptr aToLoc = aToPln->location(); - std::shared_ptr aToDir = aToPln->direction(); - - bool aSign = aFromLoc->xyz()->dot(aBaseDir->xyz()) > aToLoc->xyz()->dot(aBaseDir->xyz()); - - std::shared_ptr aFromPnt(new GeomAPI_Pnt(aFromLoc->xyz()->added(aBaseDir->xyz()->multiplied( - aSign ? theFromSize : -theFromSize)))); - aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir); - - std::shared_ptr aToPnt(new GeomAPI_Pnt(aToLoc->xyz()->added(aBaseDir->xyz()->multiplied( - aSign ? -theToSize : theToSize)))); - aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir); - - // Getting bounding box for base shape. - Bnd_Box aBndBox; - BRepBndLib::Add(aBaseShape, aBndBox); - Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()}; - Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()}; - Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()}; - gp_Pnt aPoints[8]; - int aNum = 0; - for(int i = 0; i < 2; i++) { - for(int j = 0; j < 2; j++) { - for(int k = 0; k < 2; k++) { - aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]); - aNum++; - } - } + bool isFromShapePlanar = aBoundingFromShape->isPlanar(); + bool isToShapePlanar = aBoundingToShape->isPlanar(); + + // Set signs of offsets if both bounding shapes are planar + if (isFromShapePlanar && isToShapePlanar) { + std::shared_ptr aFromPln = GeomAPI_Face(aBoundingFromShape).getPlane(); + std::shared_ptr aToPln = GeomAPI_Face(aBoundingToShape).getPlane(); + buildByPlanes(theBaseShape, anExtDir, + aToPln, theToSize, + aFromPln, theFromSize, + aShapeTypeToExp); } - - // Project points to bounding planes. Search max distance to them. - IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl(), aToDir->impl())); - IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl(), aFromDir->impl())); - Standard_Real aMaxToDist = 0, aMaxFromDist = 0; - for(int i = 0; i < 8; i++) { - gp_Lin aLine(aPoints[i], aDirVec); - IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric); - IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric); - if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) { - return; - } - const gp_Pnt& aPntOnToFace = aToIntAna.Point(1); - const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1); - if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) { - aMaxToDist = aPoints[i].Distance(aPntOnToFace); - } - if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) { - aMaxFromDist = aPoints[i].Distance(aPntOnFromFace); - } + else { + buildByFaces(theBaseShape, anExtDir, + aBoundingToShape, theToSize, isToShapePlanar, + aBoundingFromShape, theFromSize, isFromShapePlanar, + aShapeTypeToExp); } + } +} - // We added 1 just to be sure that prism is long enough for boolean operation. - double aPrismLength = aMaxToDist + aMaxFromDist + 1; +//================================================================================================== +void GeomAlgoAPI_Prism::buildBySizes(const GeomShapePtr theBaseShape, + const GeomDirPtr theDirection, + const double theToSize, + const double theFromSize, + const GeomAPI_Shape::ShapeType theTypeToExp) +{ + const TopoDS_Shape& aBaseShape = theBaseShape->impl(); + gp_Vec anExtVec = theDirection->impl(); + + // Moving base shape. + gp_Trsf aTrsf; + aTrsf.SetTranslation(anExtVec * -theFromSize); + BRepBuilderAPI_Transform* aTransformBuilder = + new BRepBuilderAPI_Transform(aBaseShape, aTrsf); + if (!aTransformBuilder || !aTransformBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aTransformBuilder))); + TopoDS_Shape aMovedBase = aTransformBuilder->Shape(); + + // Making prism. + BRepPrimAPI_MakePrism* aPrismBuilder = + new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * (theFromSize + theToSize)); + if (!aPrismBuilder || !aPrismBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aPrismBuilder))); + TopoDS_Shape aResult = aPrismBuilder->Shape(); + + // Setting naming. + if(theTypeToExp == GeomAPI_Shape::COMPOUND) { + storeGenerationHistory(this, aMovedBase, TopAbs_EDGE, aPrismBuilder); + storeGenerationHistory(this, aMovedBase, TopAbs_FACE, aPrismBuilder); + } else { + storeGenerationHistory(this, aMovedBase, (TopAbs_ShapeEnum)theTypeToExp, aPrismBuilder); + } - // Moving base shape. - gp_Trsf aTrsf; - aTrsf.SetTranslation(aDirVec * -aPrismLength); - BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf); - if(!aTransformBuilder) { - return; - } - this->appendAlgo(std::shared_ptr(new GeomAlgoAPI_MakeShape(aTransformBuilder))); - if(!aTransformBuilder->IsDone()) { - return; - } - TopoDS_Shape aMovedBase = aTransformBuilder->Shape(); + // Setting result. + if (!aResult.IsNull()) { + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + this->setShape(toShape(aResult)); + this->setDone(true); + } +} - // Making prism. - BRepPrimAPI_MakePrism* aPrismBuilder = new BRepPrimAPI_MakePrism(aMovedBase, aDirVec * 2 * aPrismLength); - if(!aPrismBuilder) { - return; - } - this->appendAlgo(std::shared_ptr(new GeomAlgoAPI_MakeShape(aPrismBuilder))); - if(!aPrismBuilder->IsDone()) { - return; +//================================================================================================== +void GeomAlgoAPI_Prism::buildByPlanes(const GeomShapePtr theBaseShape, + const GeomDirPtr theDirection, + const GeomPlanePtr theToPlane, + const double theToSize, + const GeomPlanePtr theFromPlane, + const double theFromSize, + const GeomAPI_Shape::ShapeType theTypeToExp) +{ + const TopoDS_Shape& aBaseShape = theBaseShape->impl(); + gp_Vec anExtVec = theDirection->impl(); + + // Moving prism bounding faces according to "from" and "to" sizes. + std::shared_ptr aFromLoc = theFromPlane->location(); + std::shared_ptr aFromDir = theFromPlane->direction(); + + std::shared_ptr aToLoc = theToPlane->location(); + std::shared_ptr aToDir = theToPlane->direction(); + + std::shared_ptr anExtDir = theDirection->xyz(); + bool aSign = aFromLoc->xyz()->dot(anExtDir) > aToLoc->xyz()->dot(anExtDir); + + std::shared_ptr aFromPnt( + new GeomAPI_Pnt(aFromLoc->xyz()->added(anExtDir->multiplied( + aSign ? theFromSize : -theFromSize)))); + + std::shared_ptr aToPnt( + new GeomAPI_Pnt(aToLoc->xyz()->added(anExtDir->multiplied( + aSign ? -theToSize : theToSize)))); + + // Getting bounding box for base shape. + Bnd_Box aBndBox; + BRepBndLib::Add(aBaseShape, aBndBox); + Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()}; + Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()}; + Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()}; + gp_Pnt aPoints[8]; + int aNum = 0; + for(int i = 0; i < 2; i++) { + for(int j = 0; j < 2; j++) { + for(int k = 0; k < 2; k++) { + aPoints[aNum] = gp_Pnt(aXArr[i], aYArr[j], aZArr[k]); + aNum++; + } } - aResult = aPrismBuilder->Shape(); + } - // Orienting bounding planes. - std::shared_ptr aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape); - const gp_Pnt& aCentrePnt = aCentreOfMass->impl(); - gp_Lin aLine(aCentrePnt, aDirVec); + // Project points to bounding planes. Search max distance to them. + IntAna_Quadric aBndToQuadric(gp_Pln(aToPnt->impl(), aToDir->impl())); + IntAna_Quadric aBndFromQuadric(gp_Pln(aFromPnt->impl(), aFromDir->impl())); + Standard_Real aMaxToDist = 0, aMaxFromDist = 0; + for(int i = 0; i < 8; i++) { + gp_Lin aLine(aPoints[i], anExtVec); IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric); IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric); - Standard_Real aToParameter = aToIntAna.ParamOnConic(1); - Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1); - if(aToParameter > aFromParameter) { - gp_Vec aVec = aToDir->impl(); - if((aVec * aDirVec) > 0) { - aToDir->setImpl(new gp_Dir(aVec.Reversed())); - aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir); - } - aVec = aFromDir->impl(); - if((aVec * aDirVec) < 0) { - aFromDir->setImpl(new gp_Dir(aVec.Reversed())); - aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir); - } - } else { - gp_Vec aVec = aToDir->impl(); - if((aVec * aDirVec) < 0) { - aToDir->setImpl(new gp_Dir(aVec.Reversed())); - aBoundingToShape = GeomAlgoAPI_FaceBuilder::planarFace(aToPnt, aToDir); - } - aVec = aFromDir->impl(); - if((aVec * aDirVec) > 0) { - aFromDir->setImpl(new gp_Dir(aVec.Reversed())); - aBoundingFromShape = GeomAlgoAPI_FaceBuilder::planarFace(aFromPnt, aFromDir); - } - } - - // Making solids from bounding planes. - TopoDS_Shell aToShell, aFromShell; - TopoDS_Solid aToSolid, aFromSolid; - const TopoDS_Shape& aToShape = aBoundingToShape->impl(); - const TopoDS_Shape& aFromShape = aBoundingFromShape->impl(); - TopoDS_Face aToFace = TopoDS::Face(aToShape); - TopoDS_Face aFromFace = TopoDS::Face(aFromShape); - BRep_Builder aBoundingBuilder; - aBoundingBuilder.MakeShell(aToShell); - aBoundingBuilder.Add(aToShell, aToShape); - aBoundingBuilder.MakeShell(aFromShell); - aBoundingBuilder.Add(aFromShell, aFromShape); - aBoundingBuilder.MakeSolid(aToSolid); - aBoundingBuilder.Add(aToSolid, aToShell); - aBoundingBuilder.MakeSolid(aFromSolid); - aBoundingBuilder.Add(aFromSolid, aFromShell); - - // Cutting with to plane. - BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid); - aToCutBuilder->Build(); - if(!aToCutBuilder->IsDone()) { + if(aToIntAna.NbPoints() == 0 || aFromIntAna.NbPoints() == 0) { return; } - this->appendAlgo(std::shared_ptr(new GeomAlgoAPI_MakeShape(aToCutBuilder))); - aResult = aToCutBuilder->Shape(); - if(aResult.ShapeType() == TopAbs_COMPOUND) { - aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + const gp_Pnt& aPntOnToFace = aToIntAna.Point(1); + const gp_Pnt& aPntOnFromFace = aFromIntAna.Point(1); + if(aPoints[i].Distance(aPntOnToFace) > aMaxToDist) { + aMaxToDist = aPoints[i].Distance(aPntOnToFace); + } + if(aPoints[i].Distance(aPntOnFromFace) > aMaxFromDist) { + aMaxFromDist = aPoints[i].Distance(aPntOnFromFace); } - if(aShapeTypeToExp == TopAbs_FACE) { - const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(aToShape); - for(TopTools_ListIteratorOfListOfShape anIt(aToShapes); anIt.More(); anIt.Next()) { - GeomShapePtr aGeomSh(new GeomAPI_Shape()); - aGeomSh->setImpl(new TopoDS_Shape(anIt.Value())); + } + + // We added 1 just to be sure that prism is long enough for boolean operation. + double aPrismLength = aMaxToDist + aMaxFromDist + 1; + + // Moving base shape. + gp_Trsf aTrsf; + aTrsf.SetTranslation(anExtVec * -aPrismLength); + BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf); + if(!aTransformBuilder || !aTransformBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aTransformBuilder))); + TopoDS_Shape aMovedBase = aTransformBuilder->Shape(); + + // Making prism. + BRepPrimAPI_MakePrism* aPrismBuilder = + new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength); + if(!aPrismBuilder || !aPrismBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aPrismBuilder))); + TopoDS_Shape aResult = aPrismBuilder->Shape(); + + BRepBndLib::Add(aResult, aBndBox); + aBndBox.Add(aFromPnt->impl()); + aBndBox.Add(aToPnt->impl()); + Standard_Real aBndBoxSize = aBndBox.CornerMin().Distance(aBndBox.CornerMax()); + + // Orienting bounding planes. + std::shared_ptr aCentreOfMass = GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape); + const gp_Pnt& aCentrePnt = aCentreOfMass->impl(); + gp_Lin aLine(aCentrePnt, anExtVec); + IntAna_IntConicQuad aToIntAna(aLine, aBndToQuadric); + IntAna_IntConicQuad aFromIntAna(aLine, aBndFromQuadric); + Standard_Real aToParameter = aToIntAna.ParamOnConic(1); + Standard_Real aFromParameter = aFromIntAna.ParamOnConic(1); + if(aToParameter > aFromParameter) { + gp_Vec aVec = aToDir->impl(); + if((aVec * anExtVec) > 0) + aToDir->setImpl(new gp_Dir(aVec.Reversed())); + aVec = aFromDir->impl(); + if((aVec * anExtVec) < 0) + aFromDir->setImpl(new gp_Dir(aVec.Reversed())); + } else { + gp_Vec aVec = aToDir->impl(); + if((aVec * anExtVec) < 0) + aToDir->setImpl(new gp_Dir(aVec.Reversed())); + aVec = aFromDir->impl(); + if((aVec * anExtVec) > 0) + aFromDir->setImpl(new gp_Dir(aVec.Reversed())); + } + + static const double THE_FACE_SIZE_COEFF = 10.0; + GeomShapePtr aBoundingFromShape = + GeomAlgoAPI_FaceBuilder::squareFace(aFromPnt, aFromDir, THE_FACE_SIZE_COEFF * aBndBoxSize); + GeomShapePtr aBoundingToShape = + GeomAlgoAPI_FaceBuilder::squareFace(aToPnt, aToDir, THE_FACE_SIZE_COEFF * aBndBoxSize); + + // bounding planes + const TopoDS_Shape& aToShape = aBoundingToShape->impl(); + const TopoDS_Shape& aFromShape = aBoundingFromShape->impl(); + TopoDS_Face aToFace = TopoDS::Face(aToShape); + TopoDS_Face aFromFace = TopoDS::Face(aFromShape); + + // Solid based on "To" bounding plane + gp_Vec aNormal = aToDir->impl(); + BRepPrimAPI_MakePrism* aToPrismBuilder = + new BRepPrimAPI_MakePrism(aToShape, aNormal * (-2.0 * aBndBoxSize)); + if (!aToPrismBuilder || !aToPrismBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aToPrismBuilder))); + TopoDS_Shape aToSolid = aToPrismBuilder->Shape(); + + // Cutting with to plane. + BRepAlgoAPI_Cut* aToCutBuilder = new BRepAlgoAPI_Cut(aResult, aToSolid); + aToCutBuilder->Build(); + if(!aToCutBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aToCutBuilder))); + aResult = aToCutBuilder->Shape(); + if(aResult.ShapeType() == TopAbs_COMPOUND) { + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + } + if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) { + TopTools_ListOfShape aPrismShapes = aToPrismBuilder->Modified(aToShape); + if (aPrismShapes.IsEmpty()) + aPrismShapes.Append(aToShape); + for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) { + const TopTools_ListOfShape& aToShapes = aToCutBuilder->Modified(anIt1.Value()); + for (TopTools_ListIteratorOfListOfShape anIt2(aToShapes); anIt2.More(); anIt2.Next()) { + GeomShapePtr aGeomSh = toShape(anIt2.Value()); + fixOrientation(aGeomSh); this->addToShape(aGeomSh); } } + } - // Cutting with from plane. - BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid); - aFromCutBuilder->Build(); - if(!aFromCutBuilder->IsDone()) { - return; - } - this->appendAlgo(std::shared_ptr(new GeomAlgoAPI_MakeShape(aFromCutBuilder))); - aResult = aFromCutBuilder->Shape(); - TopoDS_Iterator aCheckIt(aResult); - if(!aCheckIt.More()) { - return; - } - if(aResult.ShapeType() == TopAbs_COMPOUND) { - aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); - } - if(aShapeTypeToExp == TopAbs_FACE) { - const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(aFromShape); - for(TopTools_ListIteratorOfListOfShape anIt(aFromShapes); anIt.More(); anIt.Next()) { - GeomShapePtr aGeomSh(new GeomAPI_Shape()); - aGeomSh->setImpl(new TopoDS_Shape(anIt.Value())); + // Solid based on "From" bounding plane + aNormal = aFromDir->impl(); + BRepPrimAPI_MakePrism* aFromPrismBuilder = + new BRepPrimAPI_MakePrism(aFromShape, aNormal * (-2.0 * aBndBoxSize)); + if (!aFromPrismBuilder || !aFromPrismBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aFromPrismBuilder))); + TopoDS_Shape aFromSolid = aFromPrismBuilder->Shape(); + + // Cutting with from plane. + BRepAlgoAPI_Cut* aFromCutBuilder = new BRepAlgoAPI_Cut(aResult, aFromSolid); + aFromCutBuilder->Build(); + if(!aFromCutBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aFromCutBuilder))); + aResult = aFromCutBuilder->Shape(); + TopoDS_Iterator aCheckIt(aResult); + if(!aCheckIt.More()) { + return; + } + if(aResult.ShapeType() == TopAbs_COMPOUND) { + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + } + if (theTypeToExp == GeomAPI_Shape::FACE || theTypeToExp == GeomAPI_Shape::COMPOUND) { + TopTools_ListOfShape aPrismShapes = aFromPrismBuilder->Modified(aFromShape); + if (aPrismShapes.IsEmpty()) + aPrismShapes.Append(aFromShape); + for (TopTools_ListIteratorOfListOfShape anIt1(aPrismShapes); anIt1.More(); anIt1.Next()) { + const TopTools_ListOfShape& aFromShapes = aFromCutBuilder->Modified(anIt1.Value()); + for (TopTools_ListIteratorOfListOfShape anIt2(aFromShapes); anIt2.More(); anIt2.Next()) { + GeomShapePtr aGeomSh = toShape(anIt2.Value()); + fixOrientation(aGeomSh); this->addFromShape(aGeomSh); } } + } - // Naming for extrusion from vertex, edge. - for(TopExp_Explorer anExp(aResult, aShapeTypeToExp); anExp.More(); anExp.Next()) { - const TopoDS_Shape& aShape = anExp.Current(); - if(aShapeTypeToExp == TopAbs_VERTEX) { - gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aShape)); - IntTools_Context anIntTools; - if(anIntTools.IsValidPointForFace(aPnt, aToFace, Precision::Confusion()) == Standard_True) { - GeomShapePtr aGeomSh(new GeomAPI_Shape()); - aGeomSh->setImpl(new TopoDS_Shape(aShape)); - this->addToShape(aGeomSh); - } - if(anIntTools.IsValidPointForFace(aPnt, aFromFace, Precision::Confusion()) == Standard_True) { - GeomShapePtr aGeomSh(new GeomAPI_Shape()); - aGeomSh->setImpl(new TopoDS_Shape(aShape)); - this->addFromShape(aGeomSh); - } - } else if(aShapeTypeToExp == TopAbs_EDGE) { - TopoDS_Edge anEdge = TopoDS::Edge(aShape); - BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, aToFace); - anEdgeCheck.Perform(); - if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { - GeomShapePtr aGeomSh(new GeomAPI_Shape()); - aGeomSh->setImpl(new TopoDS_Shape(aShape)); - this->addToShape(aGeomSh); - } - anEdgeCheck.Init(anEdge, aFromFace); - anEdgeCheck.Perform(); - if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { - GeomShapePtr aGeomSh(new GeomAPI_Shape()); - aGeomSh->setImpl(new TopoDS_Shape(aShape)); - this->addFromShape(aGeomSh); - } - } else { - break; - } + // Naming for extrusion from vertex, edge. + if(theTypeToExp == GeomAPI_Shape::COMPOUND) { + storeGenerationHistory(this, aResult, TopAbs_EDGE, aToFace, aFromFace); + storeGenerationHistory(this, aResult, TopAbs_FACE, aToFace, aFromFace); + } else { + storeGenerationHistory(this, aResult, (TopAbs_ShapeEnum)theTypeToExp, aToFace, aFromFace); + } + + if(aResult.ShapeType() == TopAbs_COMPOUND) { + GeomShapePtr aGeomShape = toShape(aResult); + ListOfShape aResults; + aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape, + GeomAPI_Shape::COMPSOLID, + aResults); + aResult = aGeomShape->impl(); + } + + // Setting result. + if (!aResult.IsNull()) { + aResult = GeomAlgoAPI_DFLoader::refineResult(aResult); + this->setShape(toShape(aResult)); + this->setDone(true); + } +} + +//================================================================================================== +void GeomAlgoAPI_Prism::buildByFaces(const GeomShapePtr theBaseShape, + const GeomDirPtr theDirection, + const GeomShapePtr theToShape, + const double theToSize, + const bool theToIsPlanar, + const GeomShapePtr theFromShape, + const double theFromSize, + const bool theFromIsPlanar, + const GeomAPI_Shape::ShapeType theTypeToExp) +{ + const TopoDS_Shape& aBaseShape = theBaseShape->impl(); + gp_Vec anExtVec = theDirection->impl(); + + // Moving prism bounding faces according to "from" and "to" sizes. + GeomShapePtr aBoundingFromShape = buildOffset(theFromShape, -theFromSize, theDirection, *this); + GeomShapePtr aBoundingToShape = buildOffset(theToShape, theToSize, theDirection, *this); + + // Bounding box for shapes used in prism building. + Bnd_Box aBndBox; + BRepBndLib::Add(aBaseShape, aBndBox); + BRepBndLib::Add(aBoundingFromShape->impl(), aBndBox); + BRepBndLib::Add(aBoundingToShape->impl(), aBndBox); + double aPrismLength = 2.0 * aBndBox.CornerMin().Distance(aBndBox.CornerMax()); + + // Prism building. + gp_Trsf aTrsf; + aTrsf.SetTranslation(anExtVec * -aPrismLength); + BRepBuilderAPI_Transform* aTransformBuilder = new BRepBuilderAPI_Transform(aBaseShape, aTrsf); + if (!aTransformBuilder || !aTransformBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aTransformBuilder))); + TopoDS_Shape aMovedBase = aTransformBuilder->Shape(); + + // Making prism. + BRepPrimAPI_MakePrism* aPrismBuilder = + new BRepPrimAPI_MakePrism(aMovedBase, anExtVec * 2 * aPrismLength); + if (!aPrismBuilder || !aPrismBuilder->IsDone()) { + return; + } + this->appendAlgo(std::shared_ptr( + new GeomAlgoAPI_MakeShape(aPrismBuilder))); + + GeomShapePtr aResult = toShape(aPrismBuilder->Shape()); + + // Prism generatrix + ListOfShape aPrismBaseFaces; + collectPrismBases(aMovedBase, *aPrismBuilder, aPrismBaseFaces, theTypeToExp); + + // Build planar faces intersecting the prism fully. + BRepBndLib::Add(aResult->impl(), aBndBox); + aBoundingFromShape = buildPlanarFace(aBoundingFromShape, aBndBox); + aBoundingToShape = buildPlanarFace(aBoundingToShape, aBndBox); + + // Perform partition. + ListOfShape anObjects, aTools; + anObjects.push_back(aResult); + aTools.push_back(aBoundingFromShape); + aTools.push_back(aBoundingToShape); + + GeomMakeShapePtr aPartition(new GeomAlgoAPI_Partition(anObjects, aTools)); + if (!aPartition->isDone()) + return; + + this->appendAlgo(aPartition); + + // Collect pieces of boundary shapes, split by Partition. + if (theFromIsPlanar) { + ListOfShape anImagesFrom; + aPartition->modified(aBoundingFromShape, anImagesFrom); + for (ListOfShape::iterator anIt = anImagesFrom.begin(); anIt != anImagesFrom.end(); ++anIt) + addFromShape(*anIt); + } + + if (theToIsPlanar) { + ListOfShape anImagesTo; + aPartition->modified(aBoundingToShape, anImagesTo); + for (ListOfShape::iterator anIt = anImagesTo.begin(); anIt != anImagesTo.end(); ++anIt) + addToShape(*anIt); + } + + // Collect results which have both boundaries, selected for extrusion, + // but which do not contain top and bottom faces of the prism + // (these faces are treated as infinitely distant). + aResult = collectResults(aPartition, aTools, aPrismBaseFaces, theTypeToExp); + if (aResult && aResult->shapeType() == GeomAPI_Shape::COMPOUND) { + ListOfShape aResults; + aResult = GeomAlgoAPI_ShapeTools::combineShapes(aResult, + theTypeToExp == GeomAPI_Shape::EDGE ? GeomAPI_Shape::SHELL : GeomAPI_Shape::COMPSOLID, + aResults); + + if (aResults.size() > 1 && + (GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::EDGE) || + GeomAlgoAPI_ShapeTools::hasSharedTopology(aResults, GeomAPI_Shape::VERTEX))) { + // results shuold not have shared topology + aResult = GeomShapePtr(); } + } - if(aResult.ShapeType() == TopAbs_COMPOUND) { - GeomShapePtr 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; + if (aResult) { + this->setShape(aResult); + this->setDone(true); + } +} + + +// Auxilary functions: +//================================================================================================== +GeomShapePtr buildPlanarFace(const GeomShapePtr& theOriginalShape, + const Bnd_Box& theBaseShapeBB) +{ + GeomPlanePtr aPlane = GeomAPI_Face(theOriginalShape).getPlane(); + if (!aPlane) + return theOriginalShape; + + gp_Pnt aCornerMin = theBaseShapeBB.CornerMin(); + gp_Pnt aCornerMax = theBaseShapeBB.CornerMax(); + double aSize = aCornerMin.SquareDistance(aCornerMax); + + gp_Pnt aLocation = aPlane->location()->impl(); + + gp_Pnt aCurPnt; + for (int x = 0; x < 2; ++x) { + aCurPnt.SetX(x == 0 ? aCornerMin.X() : aCornerMax.X()); + for (int y = 0; y < 2; ++y) { + aCurPnt.SetY(y == 0 ? aCornerMin.Y() : aCornerMax.Y()); + for (int z = 0; z < 2; ++z) { + aCurPnt.SetZ(z == 0 ? aCornerMin.Z() : aCornerMax.Z()); + double aDist = aCurPnt.SquareDistance(aLocation); + if (aDist > aSize) + aSize = aDist; } } } - // Setting result. - if(aResult.IsNull()) { - return; + aSize = Sqrt(aSize); + return GeomAlgoAPI_FaceBuilder::squareFace(aPlane, 2.0 * aSize); +} + +//================================================================================================== +GeomShapePtr buildOffset(const GeomShapePtr& theShape, + const double theOffset, + const GeomDirPtr theDirection, + GeomAlgoAPI_MakeShapeList& theMakeShapeList) +{ + if (Abs(theOffset) < Precision::Confusion()) + return theShape; // no need zero offset + + GeomMakeShapePtr anAlgo(new GeomAlgoAPI_Offset(theShape, theOffset)); + if (!anAlgo->isDone()) { + // offset not done, perform translation + std::shared_ptr anAxis(new GeomAPI_Ax1()); + anAxis->setDir(theDirection); + anAlgo.reset(new GeomAlgoAPI_Translation(theShape, anAxis, theOffset)); + } + + GeomShapePtr aResult = theShape; + if (anAlgo->isDone()) { + theMakeShapeList.appendAlgo(anAlgo); + aResult = anAlgo->shape(); + } + return aResult; +} + +//================================================================================================== +void collectPrismBases(const TopoDS_Shape& theBaseShape, + BRepPrimAPI_MakePrism& thePrismAlgo, + ListOfShape& theBoundaries, + const GeomAPI_Shape::ShapeType theTypeToExp) +{ + for (TopExp_Explorer anExp(theBaseShape, (TopAbs_ShapeEnum)theTypeToExp); + anExp.More(); anExp.Next()) { + theBoundaries.push_back(toShape(thePrismAlgo.FirstShape(anExp.Current()))); + theBoundaries.push_back(toShape(thePrismAlgo.LastShape(anExp.Current()))); + } +} + +//================================================================================================== +typedef std::set SetOfShape; + +bool isShapeApplicable(const GeomShapePtr& theSolid, + const std::list& theShapesToExist, + const SetOfShape& theShapesToExclude, + const GeomAPI_Shape::ShapeType theTypeToExp) +{ + SetOfShape aFaces; + for (GeomAPI_ShapeExplorer aFExp(theSolid, theTypeToExp); + aFExp.more(); aFExp.next()) { + GeomShapePtr aCurrent = aFExp.current(); + if (theShapesToExclude.find(aCurrent) != theShapesToExclude.end()) + return false; + aFaces.insert(aCurrent); + } + + // check all faces are in solid + bool isApplicable = true; + for (std::list::const_iterator it1 = theShapesToExist.begin(); + it1 != theShapesToExist.end() && isApplicable; ++it1) { + ListOfShape::const_iterator it2 = it1->begin(); + for (; it2 != it1->end(); ++it2) + if (aFaces.find(*it2) != aFaces.end()) + break; + isApplicable = it2 != it1->end(); + } + return isApplicable; +} + +void collectModified(const GeomMakeShapePtr& theOperation, + const ListOfShape& theShapes, + std::list& theModified) +{ + for (ListOfShape::const_iterator anIt = theShapes.begin(); + anIt != theShapes.end(); ++anIt) { + theModified.push_back(ListOfShape()); + theOperation->modified(*anIt, theModified.back()); + theOperation->generated(*anIt, theModified.back()); + theModified.back().push_back(*anIt); + } +} + +GeomShapePtr collectResults(const GeomMakeShapePtr& theOperation, + const ListOfShape& theBoundaries, + const ListOfShape& theShapesToExclude, + const GeomAPI_Shape::ShapeType theTypeToExp) +{ + ListOfShape aResults; + + // collect modified shapes + std::list aModifiedBoundaries; + collectModified(theOperation, theBoundaries, aModifiedBoundaries); + + std::list aModifiedExclude; + collectModified(theOperation, theShapesToExclude, aModifiedExclude); + SetOfShape aTabooShapes; + for (std::list::iterator anIt = aModifiedExclude.begin(); + anIt != aModifiedExclude.end(); ++anIt) + aTabooShapes.insert(anIt->begin(), anIt->end()); + + // type of sub-shapes to explode + GeomAPI_Shape::ShapeType aSubshapeType; + switch (theTypeToExp) { + case GeomAPI_Shape::VERTEX: + aSubshapeType = GeomAPI_Shape::EDGE; + break; + case GeomAPI_Shape::EDGE: + aSubshapeType = GeomAPI_Shape::FACE; + break; + case GeomAPI_Shape::FACE: + aSubshapeType = GeomAPI_Shape::SOLID; + break; + default: + aSubshapeType = GeomAPI_Shape::COMPOUND; + } + + // search applicable solids + GeomShapePtr anOperationResult = theOperation->shape(); + for (GeomAPI_ShapeExplorer anExp(anOperationResult, aSubshapeType); + anExp.more(); anExp.next()) { + if (isShapeApplicable(anExp.current(), aModifiedBoundaries, aTabooShapes, theTypeToExp)) + aResults.push_back(anExp.current()); + } + + GeomShapePtr aResult; + if (aResults.size() == 1) + aResult = aResults.front(); + else if (!aResults.empty()) + aResult = GeomAlgoAPI_CompoundBuilder::compound(aResults); + return aResult; +} + +//================================================================================================== +void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo, + const TopoDS_Shape& theBase, + const TopAbs_ShapeEnum theType, + BRepPrimAPI_MakePrism* thePrismBuilder) +{ + 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(thePrismBuilder->FirstShape(aShape))); + aToShape->setImpl(new TopoDS_Shape(thePrismBuilder->LastShape(aShape))); + thePrismAlgo->fixOrientation(aFromShape); + thePrismAlgo->fixOrientation(aToShape); + thePrismAlgo->addFromShape(aFromShape); + thePrismAlgo->addToShape(aToShape); + } +} + +//================================================================================================== +void storeGenerationHistory(GeomAlgoAPI_Prism* thePrismAlgo, + const TopoDS_Shape& theResult, + const TopAbs_ShapeEnum theType, + const TopoDS_Face& theToFace, + const TopoDS_Face& theFromFace) +{ + 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, + theToFace, Precision::Confusion()) == Standard_True) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + thePrismAlgo->fixOrientation(aGeomSh); + thePrismAlgo->addToShape(aGeomSh); + } + if(anIntTools.IsValidPointForFace(aPnt, + theFromFace, Precision::Confusion()) == Standard_True) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + thePrismAlgo->fixOrientation(aGeomSh); + thePrismAlgo->addFromShape(aGeomSh); + } + } else if(theType == TopAbs_EDGE) { + TopoDS_Edge anEdge = TopoDS::Edge(aShape); + BRepLib_CheckCurveOnSurface anEdgeCheck(anEdge, theToFace); + anEdgeCheck.Perform(); + if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + thePrismAlgo->fixOrientation(aGeomSh); + thePrismAlgo->addToShape(aGeomSh); + } + anEdgeCheck.Init(anEdge, theFromFace); + anEdgeCheck.Perform(); + if(anEdgeCheck.MaxDistance() < Precision::Confusion()) { + aGeomSh->setImpl(new TopoDS_Shape(aShape)); + thePrismAlgo->fixOrientation(aGeomSh); + thePrismAlgo->addFromShape(aGeomSh); + } + } else { + break; + } } - GeomShapePtr aGeomSh(new GeomAPI_Shape()); - aGeomSh->setImpl(new TopoDS_Shape(aResult)); - this->setShape(aGeomSh); - this->setDone(true); }