Salome HOME
Non planar faces 35156
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_NonPlanarFace.cpp
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_NonPlanarFace.cpp
new file mode 100644 (file)
index 0000000..59b07da
--- /dev/null
@@ -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 <GeomAlgoAPI_NonPlanarFace.h>
+
+#include <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+#include <BRepTools_WireExplorer.hxx>
+#include <BRepBuilderAPI_Copy.hxx>
+#include <BRepOffsetAPI_MakeFilling.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
+#include <BOPTools_AlgoTools.hxx>
+
+#include <GeomAPI_Shape.h>
+#include <Geom_Surface.hxx>
+
+#include <ShapeFix_Face.hxx>
+#include <ShapeAnalysis_FreeBounds.hxx>
+#include <ShapeFix_ShapeTolerance.hxx>
+#include <TopTools_HSequenceOfShape.hxx>
+#include <TColStd_IndexedDataMapOfTransientTransient.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Wire.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+
+//==================================================================================================
+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<TopoDS_Edge>();
+        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<GeomAPI_Shape> 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);
+}