From 9bf1f80e4bad2dc98d36cb798a373f48cf6f147a Mon Sep 17 00:00:00 2001 From: Ekaterina Sukhareva Date: Fri, 25 Aug 2023 16:52:12 +0100 Subject: [PATCH] Non planar faces 35156 --- src/BuildPlugin/BuildPlugin_Face.cpp | 58 ++++++- src/BuildPlugin/BuildPlugin_Face.h | 4 + src/BuildPlugin/BuildPlugin_Validators.cpp | 46 ++++-- src/BuildPlugin/Test/TestNonPlanarFace.py | 67 ++++++++ .../Test/TestNonPlanarFace_Edges.py | 78 +++++++++ src/BuildPlugin/doc/faceFeature.rst | 2 + src/BuildPlugin/tests.set | 4 +- src/GeomAPI/GeomAPI_Shape.cpp | 59 +++++-- src/GeomAlgoAPI/CMakeLists.txt | 2 + src/GeomAlgoAPI/GeomAlgoAPI.i | 2 + src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.cpp | 153 ++++++++++++++++++ src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.h | 51 ++++++ src/GeomAlgoAPI/GeomAlgoAPI_swig.h | 1 + 13 files changed, 490 insertions(+), 37 deletions(-) create mode 100755 src/BuildPlugin/Test/TestNonPlanarFace.py create mode 100644 src/BuildPlugin/Test/TestNonPlanarFace_Edges.py create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.cpp create mode 100644 src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.h diff --git a/src/BuildPlugin/BuildPlugin_Face.cpp b/src/BuildPlugin/BuildPlugin_Face.cpp index ba39fe3be..874ff58f3 100644 --- a/src/BuildPlugin/BuildPlugin_Face.cpp +++ b/src/BuildPlugin/BuildPlugin_Face.cpp @@ -32,6 +32,7 @@ #include #include #include +#include //================================================================================================= BuildPlugin_Face::BuildPlugin_Face() @@ -60,8 +61,10 @@ void BuildPlugin_Face::execute() // Collect base shapes. ListOfShape anEdges; + ListOfShape aNonPlanarEdges; ListOfShape anOriginalFaces; ListOfShape aContexts; + getOriginalShapesAndContexts(BASE_OBJECTS_ID(), anOriginalFaces, aContexts); anOriginalFaces.clear(); std::list< std::shared_ptr > aListOfNormals; @@ -88,16 +91,29 @@ void BuildPlugin_Face::execute() } } - for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { - GeomShapePtr anEdge = anExp.current(); - anEdges.push_back(anEdge); - } - // check whether the context is a sketch, in this case store its normal for further needs std::shared_ptr aSketch = std::dynamic_pointer_cast(aContext); if (aSketch) aListOfNormals.push_back(aSketch->norm()); + + bool isPlanar(aShape->isPlanar() || aSketch); + + for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { + GeomShapePtr anEdge = anExp.current(); + isPlanar? anEdges.push_back(anEdge) : aNonPlanarEdges.push_back(anEdge); + } + } + + if (!anEdges.empty()) + { + //check is planar objects belong to nke + std::shared_ptr aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges); + if(!aPln.get()) + { + aNonPlanarEdges.insert(aNonPlanarEdges.end(), anEdges.begin(), anEdges.end()); + anEdges.clear(); + } } // Build faces by edges. @@ -107,6 +123,18 @@ void BuildPlugin_Face::execute() buildFacesByEdges(anEdges, aListOfNormals, aFaces, aFaceBuilder); int aNbFacesFromEdges = (int)aFaces.size(); + // Build non-planar faces by edges. + GeomMakeShapePtr aNonPlanarFaceBuilder; + int aNbNonPlanarFaces = (int)aFaces.size(); + if(!aNonPlanarEdges.empty()) + { + ListOfShape aNonPlanarFaces; + buildNonPlanarFacesByEdges(aNonPlanarEdges, aNonPlanarFaces, aNonPlanarFaceBuilder); + // Add non-planar faces to common faces list. + aFaces.insert(aFaces.end(), aNonPlanarFaces.begin(), aNonPlanarFaces.end()); + aNbNonPlanarFaces += (int)aNonPlanarFaces.size(); + } + // Add faces selected by user. aFaces.insert(aFaces.end(), anOriginalFaces.begin(), anOriginalFaces.end()); @@ -116,6 +144,8 @@ void BuildPlugin_Face::execute() std::shared_ptr aMakeShapeList(new GeomAlgoAPI_MakeShapeList); if (anIndex < aNbFacesFromEdges) aMakeShapeList->appendAlgo(aFaceBuilder); + else if(anIndex < aNbNonPlanarFaces) + aMakeShapeList->appendAlgo(aNonPlanarFaceBuilder); GeomShapePtr aShape = *anIt; GeomMakeShapePtr aCopy(new GeomAlgoAPI_Copy(aShape)); @@ -124,6 +154,8 @@ void BuildPlugin_Face::execute() ListOfShape aBaseShapes; if (anIndex < aNbFacesFromEdges) aBaseShapes = anEdges; + else if(anIndex < aNbNonPlanarFaces) + aBaseShapes = aNonPlanarEdges; else aBaseShapes.push_back(aShape); storeResult(aMakeShapeList, aBaseShapes, aContexts, aCopy->shape(), anIndex++); @@ -132,6 +164,7 @@ void BuildPlugin_Face::execute() removeResults(anIndex); } +//================================================================================================== void BuildPlugin_Face::buildFacesByEdges( const ListOfShape& theEdges, const std::list< std::shared_ptr >& theNormals, @@ -167,3 +200,18 @@ void BuildPlugin_Face::buildFacesByEdges( GeomAlgoAPI_ShapeTools::makeFacesWithHoles(aPln->location(), aPln->direction(), aWires, theFaces); } + +//================================================================================================== +void BuildPlugin_Face::buildNonPlanarFacesByEdges( + const ListOfShape& theShapes, + ListOfShape& theFaces, + std::shared_ptr& theBuilderAlgo) const +{ + + // Get faces. + std::shared_ptr aNonPlanarFaceBuilder + (new GeomAlgoAPI_NonPlanarFace(theShapes)); + theFaces = aNonPlanarFaceBuilder->faces(); + theBuilderAlgo = aNonPlanarFaceBuilder; + +} diff --git a/src/BuildPlugin/BuildPlugin_Face.h b/src/BuildPlugin/BuildPlugin_Face.h index cbb4e9cbf..4653845f7 100644 --- a/src/BuildPlugin/BuildPlugin_Face.h +++ b/src/BuildPlugin/BuildPlugin_Face.h @@ -69,6 +69,10 @@ private: const std::list< std::shared_ptr >& theNormals, std::list< std::shared_ptr >& theFaces, std::shared_ptr& theBuilderAlgo) const; + + void buildNonPlanarFacesByEdges(const ListOfShape& theShapes, + ListOfShape& theFaces, + std::shared_ptr& theBuilderAlgo) const; }; #endif diff --git a/src/BuildPlugin/BuildPlugin_Validators.cpp b/src/BuildPlugin/BuildPlugin_Validators.cpp index 13063fa03..81c16c770 100644 --- a/src/BuildPlugin/BuildPlugin_Validators.cpp +++ b/src/BuildPlugin/BuildPlugin_Validators.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -292,7 +293,9 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptrsize(); ++anIndex) { AttributeSelectionPtr aSelection = aSelectionList->value(anIndex); GeomShapePtr aShape = aSelection->value(); @@ -313,24 +316,26 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptrisPlanar()); for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::EDGE); anExp.more(); anExp.next()) { hasEdgesOrWires = true; GeomShapePtr anEdge = anExp.current(); - anEdges.push_back(anEdge); + anAllEdges.push_back(anEdge); + isPlanar? aPlanarEdges.push_back(anEdge): aNonPlanarEdges.push_back(anEdge); } } if (hasFaces && hasEdgesOrWires) { theError = "Faces and edges/wires should be selected together."; return false; - } else if (hasEdgesOrWires && anEdges.empty()) { + } else if (hasEdgesOrWires && anAllEdges.empty()) { theError = "Objects are not selected."; return false; } // Check that edges does not have intersections. - if(anEdges.size() > 1) { - GeomAlgoAPI_PaveFiller aPaveFiller(anEdges, false); + if(anAllEdges.size() > 1) { + GeomAlgoAPI_PaveFiller aPaveFiller(anAllEdges, false); if(!aPaveFiller.isDone()) { theError = "Error while checking if edges intersects."; return false; @@ -342,25 +347,36 @@ bool BuildPlugin_ValidatorBaseForFace::isValid(const std::shared_ptr aPln = GeomAlgoAPI_ShapeTools::findPlane(anEdges); - if(!aPln.get()) { - theError = "Selected object(s) should belong to only one plane."; - return false; + std::shared_ptr aPln = GeomAlgoAPI_ShapeTools::findPlane(aPlanarEdges); + if(aPln.get()) { + // Check that selected objects have closed contours. + isPlanarBelongToOnePlane = true; + GeomAlgoAPI_SketchBuilder aBuilder(aPln, aPlanarEdges); + const ListOfShape& aFaces = aBuilder.faces(); + if(aFaces.empty()) { + theError = "Selected planar objects do not generate closed contour."; + return false; + } } + } - // Check that selected objects have closed contours. - GeomAlgoAPI_SketchBuilder aBuilder(aPln, anEdges); - const ListOfShape& aFaces = aBuilder.faces(); + //check non planar objects + if(!aNonPlanarEdges.empty() || (!aPlanarEdges.empty() && !isPlanarBelongToOnePlane)) + { + GeomAlgoAPI_NonPlanarFace aNonPlanarFaceBuilder(isPlanarBelongToOnePlane? aNonPlanarEdges : anAllEdges); + const ListOfShape& aFaces = aNonPlanarFaceBuilder.faces(); if(aFaces.empty()) { - theError = "Selected objects do not generate closed contour."; + theError = "Selected non-planar objects do not generate closed contour."; return false; } } diff --git a/src/BuildPlugin/Test/TestNonPlanarFace.py b/src/BuildPlugin/Test/TestNonPlanarFace.py new file mode 100755 index 000000000..f0ffbe570 --- /dev/null +++ b/src/BuildPlugin/Test/TestNonPlanarFace.py @@ -0,0 +1,67 @@ +# Copyright (C) 2017-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 +# + +"""Test de la création de faces gauches""" + +import salome + +salome.salome_init() + +from SketchAPI import * + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() + +### Create Part +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +### Create Point +l_noms = list() +l_coo = list() +l_coo.append((0, 0, 0)) +l_coo.append((1, 8, 0)) +l_coo.append((3, 10, 4)) +l_coo.append((5, 5, 5)) +l_coo.append((2, 3, 1)) +for iaux, (coo_x,coo_y,coo_z) in enumerate(l_coo): + point = model.addPoint(Part_1_doc, coo_x,coo_y,coo_z) + nom = "P_{}".format(iaux) + point.setName(nom) + point.result().setName(nom) + l_noms.append(nom) + +### Create Interpolation +Interpolation_1_objects = list() +for nom in l_noms: + Interpolation_1_objects.append(model.selection("VERTEX", "all-in-{}".format(nom))) +Interpolation_1 = model.addInterpolation(Part_1_doc, Interpolation_1_objects, True, False) + +### Create Wire +Wire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Interpolation_1_1")], False) + +### Create Face +Face_1 = model.addFace(Part_1_doc, [model.selection("WIRE", "Wire_1_1")]) + +model.end() + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/src/BuildPlugin/Test/TestNonPlanarFace_Edges.py b/src/BuildPlugin/Test/TestNonPlanarFace_Edges.py new file mode 100644 index 000000000..12090f50c --- /dev/null +++ b/src/BuildPlugin/Test/TestNonPlanarFace_Edges.py @@ -0,0 +1,78 @@ +# Copyright (C) 2017-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 +# + +import sys +import salome + +salome.salome_init() +import salome_notebook +notebook = salome_notebook.NoteBook() +sys.path.insert(0, r'/home/eksu/S2') + +### +### SHAPER component +### + +from salome.shaper import model + +model.begin() +partSet = model.moduleDocument() + +### Create Part +Part_1 = model.addPart(partSet) +Part_1_doc = Part_1.document() + +### Create Points +Point_2 = model.addPoint(Part_1_doc, 0, 0, 0) +Point_3 = model.addPoint(Part_1_doc, 10, 0, 0) +Point_4 = model.addPoint(Part_1_doc, 0, 10, 0) +Point_5 = model.addPoint(Part_1_doc, 10, 10, 3) + +### Create Edges +Edge_1 = model.addEdge(Part_1_doc, model.selection("VERTEX", "Point_1"), model.selection("VERTEX", "Point_2")) +Edge_2 = model.addEdge(Part_1_doc, model.selection("VERTEX", "Edge_1_1/Modified_Vertex&Point_2/Point_2"), model.selection("VERTEX", "Point_4")) +Edge_3 = model.addEdge(Part_1_doc, model.selection("VERTEX", "Edge_2_1/Modified_Vertex&Point_4/Point_4"), model.selection("VERTEX", "Point_3")) +Edge_4 = model.addEdge(Part_1_doc, model.selection("VERTEX", "Point_3"), model.selection("VERTEX", "Point_1")) + +### Create Wire +Wire_1_objects = [model.selection("EDGE", "Edge_1_1"), + model.selection("EDGE", "Edge_2_1"), + model.selection("EDGE", "Edge_4_1"), + model.selection("EDGE", "Edge_3_1")] +Wire_1 = model.addWire(Part_1_doc, Wire_1_objects, False) + +### Create Face +Face_1_objects = [model.selection("EDGE", "Wire_1_1/Modified_Edge&Edge_1_1/Edge_1_1"), + model.selection("EDGE", "Wire_1_1/Modified_Edge&Edge_2_1/Edge_2_1"), + model.selection("EDGE", "Wire_1_1/Modified_Edge&Edge_4_1/Edge_4_1"), + model.selection("EDGE", "Wire_1_1/Modified_Edge&Edge_3_1/Edge_3_1")] +Face_1 = model.addFace(Part_1_doc, Face_1_objects) + +model.end() + +### +### SHAPERSTUDY component +### + +model.publishToShaperStudy() +import SHAPERSTUDY +Face_1_1, = SHAPERSTUDY.shape(model.featureStringId(Face_1)) + +if salome.sg.hasDesktop(): + salome.sg.updateObjBrowser() diff --git a/src/BuildPlugin/doc/faceFeature.rst b/src/BuildPlugin/doc/faceFeature.rst index 57f37737b..b37ee7deb 100644 --- a/src/BuildPlugin/doc/faceFeature.rst +++ b/src/BuildPlugin/doc/faceFeature.rst @@ -20,6 +20,8 @@ The following property panel will be opened: Select one or several faces in viewer. Additionally, a face can be build by a closed wire or a set of edges composing a closed wire. +It is possible to build a non-planar face by selecting non-planar wire or set of edges composing a closed wire, which do not belong to only one plane. + It is also possible to select a whole sketch result from the object browser. In this case, the smallest closed contour of the sketch will be transformed to the planar face. **Apply** button creates faces. diff --git a/src/BuildPlugin/tests.set b/src/BuildPlugin/tests.set index 32ff7447b..c4b39ebc0 100644 --- a/src/BuildPlugin/tests.set +++ b/src/BuildPlugin/tests.set @@ -71,4 +71,6 @@ SET(TEST_NAMES Test20469.py Test20513_1.py Test20513_2.py -) \ No newline at end of file + TestNonPlanarFace.py + TestNonPlanarFace_Edges.py +) diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index c03fd9d7a..5fe8500d0 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -326,23 +326,50 @@ bool GeomAPI_Shape::isPlanar() const BRepBuilderAPI_FindPlane aFindPlane(aShape); bool isFound = aFindPlane.Found() == Standard_True; - if(!isFound && aShapeType == TopAbs_EDGE) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(aShape), aFirst, aLast); - Handle(Standard_Type) aType = aCurve->DynamicType(); - - if(aType == STANDARD_TYPE(Geom_TrimmedCurve)) { - Handle(Geom_TrimmedCurve) aTrimCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve); - aType = aTrimCurve->BasisCurve()->DynamicType(); - } + if(!isFound) { + + auto checkEdge = [](const TopoDS_Shape& theShape){ + if(theShape.ShapeType()!= TopAbs_EDGE) + return false; + + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(theShape), aFirst, aLast); + Handle(Standard_Type) aType = aCurve->DynamicType(); + if(aType == STANDARD_TYPE(Geom_TrimmedCurve)) { + Handle(Geom_TrimmedCurve) aTrimCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve); + aType = aTrimCurve->BasisCurve()->DynamicType(); + } - if(aType == STANDARD_TYPE(Geom_Line) - || aType == STANDARD_TYPE(Geom_Conic) - || aType == STANDARD_TYPE(Geom_Circle) - || aType == STANDARD_TYPE(Geom_Ellipse) - || aType == STANDARD_TYPE(Geom_Hyperbola) - || aType == STANDARD_TYPE(Geom_Parabola)) { - isFound = true; + if(aType == STANDARD_TYPE(Geom_Line) + || aType == STANDARD_TYPE(Geom_Conic) + || aType == STANDARD_TYPE(Geom_Circle) + || aType == STANDARD_TYPE(Geom_Ellipse) + || aType == STANDARD_TYPE(Geom_Hyperbola) + || aType == STANDARD_TYPE(Geom_Parabola)) { + return true; + } + return false; + }; + + if(aShapeType == TopAbs_WIRE){ + //check if wire consist of only one edge + int aNbEdges = 0; + TopExp_Explorer anExp(aShape, TopAbs_EDGE); + for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) { + aNbEdges++; + if(aNbEdges == 1){ + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + isFound = checkEdge(anEdge); + } + else{ + //if more than one edge, check is not valid + isFound = false; + break; + } + } + } + else if(aShapeType == TopAbs_EDGE){ + isFound = checkEdge(aShape); } } diff --git a/src/GeomAlgoAPI/CMakeLists.txt b/src/GeomAlgoAPI/CMakeLists.txt index ea051707f..815f52f3d 100644 --- a/src/GeomAlgoAPI/CMakeLists.txt +++ b/src/GeomAlgoAPI/CMakeLists.txt @@ -101,6 +101,7 @@ SET(PROJECT_HEADERS GeomAlgoAPI_GlueFaces.h GeomAlgoAPI_LimitTolerance.h GeomAlgoAPI_Utils.h + GeomAlgoAPI_NonPlanarFace.h ) SET(PROJECT_SOURCES @@ -182,6 +183,7 @@ SET(PROJECT_SOURCES GeomAlgoAPI_CanonicalRecognition.cpp GeomAlgoAPI_LimitTolerance.cpp GeomAlgoAPI_Utils.cpp + GeomAlgoAPI_NonPlanarFace.cpp ) SET(PROJECT_LIBRARIES diff --git a/src/GeomAlgoAPI/GeomAlgoAPI.i b/src/GeomAlgoAPI/GeomAlgoAPI.i index 4eb97f979..2dc9bded0 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI.i +++ b/src/GeomAlgoAPI/GeomAlgoAPI.i @@ -175,6 +175,7 @@ %shared_ptr(GeomAlgoAPI_Rotation) %shared_ptr(GeomAlgoAPI_Sewing) %shared_ptr(GeomAlgoAPI_SketchBuilder) +%shared_ptr(GeomAlgoAPI_NonPlanarFace) %shared_ptr(GeomAlgoAPI_ShapeBuilder) %shared_ptr(GeomAlgoAPI_Translation) %shared_ptr(GeomAlgoAPI_Transform) @@ -219,6 +220,7 @@ %include "GeomAlgoAPI_WireBuilder.h" %include "GeomAlgoAPI_Sewing.h" %include "GeomAlgoAPI_ShapeBuilder.h" +%include "GeomAlgoAPI_NonPlanarFace.h" %include "GeomAlgoAPI_Exception.h" %include "GeomAlgoAPI_ShapeAPI.h" %include "GeomAlgoAPI_Copy.h" diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.cpp new file mode 100644 index 000000000..59b07da86 --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.cpp @@ -0,0 +1,153 @@ +// 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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//================================================================================================== +GeomAlgoAPI_NonPlanarFace::GeomAlgoAPI_NonPlanarFace( + const ListOfShape& theEdges) +{ + build(theEdges); +} + +//================================================================================================== +void GeomAlgoAPI_NonPlanarFace::build + (const ListOfShape& theEdges) +{ + myResultFaces.clear(); + setDone(false); + if (theEdges.empty()) + { + return; + } + + //prepare edges + Handle(TopTools_HSequenceOfShape) aSeqEdgesIn = new TopTools_HSequenceOfShape; + TColStd_IndexedDataMapOfTransientTransient aMapTShapes; + TopTools_MapOfShape aMapEdges; + for (auto anEdge: theEdges) + { + const TopoDS_Edge& aTEdge = anEdge->impl(); + if (aMapEdges.Add(aTEdge)) + { + BRepBuilderAPI_Copy aCopy(aTEdge, Standard_False, Standard_False); + const TopoDS_Shape& aCopyEdge = aCopy.Shape(); + aSeqEdgesIn->Append(aCopyEdge); + } + } + + // no edges + if (aSeqEdgesIn->IsEmpty()) + { + return; + } + + // Connect edges to wires of maximum length + Handle(TopTools_HSequenceOfShape) aSeqWiresOut; + ShapeAnalysis_FreeBounds::ConnectEdgesToWires(aSeqEdgesIn, Precision::Confusion(), Standard_False, aSeqWiresOut); + + // prepare compound result + BRep_Builder aBuilder; + TopoDS_Compound aResult; + aBuilder.MakeCompound(aResult); + + // try to construct face for each non-planar wire + for(int ind = 1; ind <= aSeqWiresOut->Length(); ind++) + { + if(!aSeqWiresOut->Value(ind).Closed()) + { + continue; + } + TopoDS_Wire aWire = TopoDS::Wire(aSeqWiresOut->Value(ind)); + + // try to construct filling surface + BRepOffsetAPI_MakeFilling aMF; + BRepTools_WireExplorer aWExp(aWire); + for (; aWExp.More(); aWExp.Next()) + { + aMF.Add(TopoDS::Edge(aWExp.Current()), GeomAbs_C0); + } + aMF.Build(); + if (!aMF.IsDone()) + { + return; + } + // Result of filling + TopoDS_Shape aFillRes = aMF.Shape(); + Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(aFillRes)); + BRepBuilderAPI_MakeFace aMakeFace(aGS, aWire); + if (aMakeFace.IsDone()) + { + TopoDS_Face aNewFace = aMakeFace.Face(); + Handle(ShapeFix_Face) aFix = new ShapeFix_Face(aNewFace); + aFix->Perform(); + aFix->FixOrientation(); + aNewFace = aFix->Face(); + + //check and fix pcurves, if necessary + TopExp_Explorer aExpE; + Standard_Real aT, aTolE, aDMax; + ShapeFix_ShapeTolerance sat; + aExpE.Init(aNewFace, TopAbs_EDGE); + for (; aExpE.More(); aExpE.Next()) + { + const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current(); + if (!BOPTools_AlgoTools::ComputeTolerance(aNewFace, aE, aDMax, aT)) continue; + aTolE = BRep_Tool::Tolerance(aE); + if (aDMax < aTolE) continue; + + sat.LimitTolerance(aE, aDMax); + } + + // store face + aBuilder.Add(aResult, aNewFace); + std::shared_ptr aResFace(new GeomAPI_Shape); + aResFace->setImpl(new TopoDS_Face(aNewFace)); + myResultFaces.push_back(aResFace); + } + } + + // update results + GeomShapePtr aResShape(new GeomAPI_Shape); + aResShape->setImpl(new TopoDS_Shape(aResult)); + setShape(aResShape); + setDone(true); +} diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.h b/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.h new file mode 100644 index 000000000..0ffb5e25a --- /dev/null +++ b/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.h @@ -0,0 +1,51 @@ +// 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 +// + +#ifndef GeomAlgoAPI_NonPlanarFace_H_ +#define GeomAlgoAPI_NonPlanarFace_H_ + +#include +#include + +/** \class GeomAlgoAPI_NonPlanarFace + * \ingroup DataAlgo + * \brief Creates non planar faces + */ +class GeomAlgoAPI_NonPlanarFace : public GeomAlgoAPI_MakeShape +{ +public: + + /// Creates list of faces based on the non-planar wires + /// \param theEdges list of input non-planar edges. + GEOMALGOAPI_EXPORT + GeomAlgoAPI_NonPlanarFace(const ListOfShape& theEdges); + + /// Return list of created faces + GEOMALGOAPI_EXPORT const ListOfShape& faces() const + { return myResultFaces; } + +private: + /// \brief Perform operation + /// \param theEdges list of selected wires. + GEOMALGOAPI_EXPORT void build(const ListOfShape& theEdges); + + std::list > myResultFaces; +}; + +#endif diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_swig.h b/src/GeomAlgoAPI/GeomAlgoAPI_swig.h index d9776dea9..7a708573b 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_swig.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_swig.h @@ -43,6 +43,7 @@ #include "GeomAlgoAPI_Rotation.h" #include "GeomAlgoAPI_ShapeTools.h" #include "GeomAlgoAPI_SketchBuilder.h" + #include "GeomAlgoAPI_NonPlanarFace.h" #include "GeomAlgoAPI_BREPExport.h" #include "GeomAlgoAPI_IGESExport.h" #include "GeomAlgoAPI_STEPExport.h" -- 2.39.2