Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_ShapeTools.cpp
index d6baade6e733544a5ae4135770cd4e1669930085..3d0c3c65b0f0fa1ab7a2efe51c9e0929629f5da2 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+// 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
@@ -21,6 +21,8 @@
 
 #include "GeomAlgoAPI_SketchBuilder.h"
 
+#include <Basics_OCCTVersion.hxx>
+
 #include <GeomAPI_Ax1.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Dir.h>
@@ -48,7 +50,9 @@
 #include <BRepCheck_Analyzer.hxx>
 #include <BRepExtrema_DistShapeShape.hxx>
 #include <BRepExtrema_ExtCF.hxx>
+#include <BRepExtrema_ShapeProximity.hxx>
 #include <BRepGProp.hxx>
+#include <BRepMesh_IncrementalMesh.hxx>
 #include <BRepTools.hxx>
 #include <BRepTools_WireExplorer.hxx>
 #include <BRepTopAdaptor_FClass2d.hxx>
 
 #include <BOPAlgo_Builder.hxx>
 
+#include <Extrema_GenLocateExtCS.hxx>
+#include <Extrema_GenLocateExtSS.hxx>
+#include <Extrema_GenLocateExtPS.hxx>
+#include <Extrema_LocateExtCC.hxx>
+#include <Extrema_LocateExtPC.hxx>
+
 #include <Geom2d_Curve.hxx>
 #include <Geom2d_Curve.hxx>
 
 #include <Geom_Plane.hxx>
 #include <Geom_RectangularTrimmedSurface.hxx>
 
+#if OCC_VERSION_LARGE < 0x07070000
 #include <GeomAdaptor_HCurve.hxx>
+#else
+#include <GeomAdaptor_Curve.hxx>
+#endif
 
 #include <GeomAPI_ProjectPointOnCurve.hxx>
 #include <GeomAPI_ShapeIterator.h>
@@ -334,8 +348,185 @@ auto getExtemaDistShape = [](const GeomShapePtr& theShape1,
   aDist.Perform();
   return aDist;
 };
+
+static void tessellateShape(const TopoDS_Shape& theShape)
+{
+  Standard_Boolean isTessellate = Standard_False;
+  TopLoc_Location aLoc;
+  for (TopExp_Explorer anExp(theShape, TopAbs_FACE); anExp.More() && !isTessellate; anExp.Next()) {
+    Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation(TopoDS::Face(anExp.Value()), aLoc);
+    isTessellate = aTria.IsNull();
+  }
+  for (TopExp_Explorer anExp(theShape, TopAbs_EDGE); anExp.More() && !isTessellate; anExp.Next()) {
+    Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(TopoDS::Edge(anExp.Value()), aLoc);
+    isTessellate = aPoly.IsNull();
+  }
+
+  if (isTessellate) {
+    BRepMesh_IncrementalMesh aMesher(theShape, 0.1);
+    Standard_ProgramError_Raise_if(!aMesher.IsDone(), "Meshing failed");
+  }
+}
+
+static Standard_Real paramOnCurve(const BRepAdaptor_Curve& theCurve,
+                                  const gp_Pnt&            thePoint,
+                                  const Standard_Real      theTol)
+{
+  Extrema_ExtPC aParamSearch(thePoint,
+                             theCurve,
+                             theCurve.FirstParameter(),
+                             theCurve.LastParameter());
+  if (aParamSearch.IsDone()) {
+    Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
+    Standard_Real aSqDistMin = RealLast();
+    for (Standard_Integer i = 1; i <= aNbExt; ++i) {
+      if (aParamSearch.SquareDistance(i) < aSqDistMin) {
+        anIndMin = i;
+        aSqDistMin = aParamSearch.SquareDistance(i);
+      }
+    }
+    if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
+      return aParamSearch.Point(anIndMin).Parameter();
+  }
+  return 0.5 * (theCurve.FirstParameter() + theCurve.LastParameter());
+}
+
+static void paramsOnSurf(const BRepAdaptor_Surface& theSurf,
+                         const gp_Pnt&              thePoint,
+                         const Standard_Real        theTol,
+                         Standard_Real&             theU,
+                         Standard_Real&             theV)
+{
+  Extrema_ExtPS aParamSearch(thePoint, theSurf, Precision::PConfusion(), Precision::PConfusion());
+  if (aParamSearch.IsDone()) {
+    Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt();
+    Standard_Real aSqDistMin = RealLast();
+    for (Standard_Integer i = 1; i <= aNbExt; ++i) {
+      if (aParamSearch.SquareDistance(i) < aSqDistMin) {
+        anIndMin = i;
+        aSqDistMin = aParamSearch.SquareDistance(i);
+      }
+    }
+    if (anIndMin != 0 && aSqDistMin <= theTol * theTol)
+      return aParamSearch.Point(anIndMin).Parameter(theU, theV);
+  }
+  theU = 0.5 * (theSurf.FirstUParameter() + theSurf.LastUParameter());
+  theV = 0.5 * (theSurf.FirstVParameter() + theSurf.LastVParameter());
+}
+
+static Standard_Real extremaEE(const TopoDS_Edge& theEdge1,
+                               const TopoDS_Edge& theEdge2,
+                               const gp_Pnt&      thePoint1,
+                               const gp_Pnt&      thePoint2)
+{
+  BRepAdaptor_Curve aCurve1(theEdge1);
+  BRepAdaptor_Curve aCurve2(theEdge2);
+
+  Standard_Real aU1 = paramOnCurve(aCurve1, thePoint1, BRep_Tool::Tolerance(theEdge1));
+  Standard_Real aU2 = paramOnCurve(aCurve2, thePoint2, BRep_Tool::Tolerance(theEdge2));
+
+  Standard_Real aValue = -1.0;
+  Extrema_LocateExtCC anExtr(aCurve1, aCurve2, aU1, aU2);
+  if (anExtr.IsDone() && aValue > Precision::Confusion())
+    aValue = Sqrt(anExtr.SquareDistance());
+  return aValue;
+}
+
+static Standard_Real extremaPE(const gp_Pnt&      thePoint,
+                               const TopoDS_Edge& theEdge,
+                               gp_Pnt&            thePointOnEdge)
+{
+  BRepAdaptor_Curve aCurve (theEdge);
+
+  TopLoc_Location aLoc;
+  Standard_Real aTol = BRep_Tool::Tolerance(theEdge);
+  Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc);
+  if (!aPoly.IsNull())
+    aTol = Max (aTol, aPoly->Deflection());
+
+  Standard_Real aParam = paramOnCurve (aCurve, thePointOnEdge, 2*aTol);
+
+  Standard_Real aValue = -1.0;
+  Extrema_LocateExtPC anExtr (thePoint, aCurve, aParam, Precision::PConfusion());
+  if (anExtr.IsDone())
+  {
+    aValue = Sqrt(anExtr.SquareDistance());
+
+    Extrema_POnCurv aPointOnCurve = anExtr.Point();
+    thePointOnEdge = aPointOnCurve.Value();
+  }
+  return aValue;
+}
+  
+static Standard_Real extremaPF(const gp_Pnt&      thePoint,
+                               const TopoDS_Face& theFace,
+                               gp_Pnt&            thePointOnFace)
+{
+  BRepAdaptor_Surface aSurf (theFace);
+
+  TopLoc_Location aLoc;
+  Standard_Real aTol = BRep_Tool::Tolerance(theFace);
+  Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc);
+  if (!aTria.IsNull())
+    aTol = Max (aTol, aTria->Deflection());
+
+  Standard_Real aU, aV;
+  paramsOnSurf(aSurf, thePointOnFace, 2*aTol, aU, aV);
+
+  Standard_Real aValue = -1.0;
+  Extrema_GenLocateExtPS anExtr (aSurf);
+  anExtr.Perform (thePoint, aU, aV);
+  if (anExtr.IsDone())
+  {
+    aValue = Sqrt(anExtr.SquareDistance());
+
+    Extrema_POnSurf aPointOnSurf = anExtr.Point();
+    thePointOnFace = aPointOnSurf.Value();
+  }
+  return aValue;
+}
+
+static Standard_Real extremaEF(const TopoDS_Edge& theEdge,
+                               const TopoDS_Face& theFace,
+                               const gp_Pnt&      thePonE,
+                               const gp_Pnt&      thePonF)
+{
+  BRepAdaptor_Curve aCurve(theEdge);
+  BRepAdaptor_Surface aSurf(theFace);
+
+  Standard_Real aP = paramOnCurve(aCurve, thePonE, BRep_Tool::Tolerance(theEdge));
+  Standard_Real aU, aV;
+  paramsOnSurf(aSurf, thePonF, BRep_Tool::Tolerance(theFace), aU, aV);
+
+  Standard_Real aValue = -1.0;
+  Extrema_GenLocateExtCS anExtr(aCurve, aSurf, aP, aU, aV, Precision::PConfusion(), Precision::PConfusion());
+  if (anExtr.IsDone() && aValue > Precision::Confusion())
+    aValue = Sqrt(anExtr.SquareDistance());
+  return aValue;
 }
 
+static Standard_Real extremaFF(const TopoDS_Face& theFace1,
+                               const TopoDS_Face& theFace2,
+                               const gp_Pnt&      thePoint1,
+                               const gp_Pnt&      thePoint2)
+{
+  BRepAdaptor_Surface aSurf1(theFace1);
+  BRepAdaptor_Surface aSurf2(theFace2);
+
+  Standard_Real aU1, aV1;
+  paramsOnSurf(aSurf1, thePoint1, BRep_Tool::Tolerance(theFace1), aU1, aV1);
+  Standard_Real aU2, aV2;
+  paramsOnSurf(aSurf2, thePoint2, BRep_Tool::Tolerance(theFace2), aU2, aV2);
+
+  Standard_Real aValue = -1.0;
+  Extrema_GenLocateExtSS anExtr(aSurf1, aSurf2, aU1, aV1, aU2, aV2, Precision::PConfusion(), Precision::PConfusion());
+  if (anExtr.IsDone() && aValue > Precision::Confusion())
+    aValue = Sqrt(anExtr.SquareDistance());
+  return aValue;
+}
+
+} // namespace
+
 double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
                                                const GeomShapePtr& theShape2)
 {
@@ -356,6 +547,123 @@ double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
   return aDist.IsDone() ? aDist.Value() : Precision::Infinite();
 }
 
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::shapeProximity(const GeomShapePtr& theShape1,
+                                              const GeomShapePtr& theShape2)
+{
+  double aResult = -1.0;
+  if (!theShape1.get() || !theShape2.get())
+    return aResult;
+
+  const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+  const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+  TopAbs_ShapeEnum aType1 = aShape1.ShapeType();
+  TopAbs_ShapeEnum aType2 = aShape2.ShapeType();
+
+  // tessellate shapes if there is no mesh exists
+  tessellateShape(aShape1);
+  tessellateShape(aShape2);
+
+  BRepExtrema_ShapeProximity aDist (aShape1, aShape2);
+  aDist.Perform();
+  if (aDist.IsDone()) {
+    aResult = aDist.Proximity();
+
+    // refine the result
+    gp_Pnt aPnt1 = aDist.ProximityPoint1();
+    gp_Pnt aPnt2 = aDist.ProximityPoint2();
+
+    BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus1 = aDist.ProxPntStatus1();
+    BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus2 = aDist.ProxPntStatus2();
+
+    double aValue = -1.0;
+
+    if (aType1 == TopAbs_EDGE)
+    {
+      if (aType2 == TopAbs_EDGE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaEE(TopoDS::Edge(aShape1), TopoDS::Edge(aShape2), aPnt1, aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
+        }
+      }
+      else if (aType2 == TopAbs_FACE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaEF(TopoDS::Edge(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1);
+        }
+      }
+    }
+    else if (aType1 == TopAbs_FACE)
+    {
+      if (aType2 == TopAbs_EDGE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaEF(TopoDS::Edge(aShape2), TopoDS::Face(aShape1), aPnt2, aPnt1);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
+        }
+      }
+      else if (aType2 == TopAbs_FACE)
+      {
+        if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+            aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaFF(TopoDS::Face(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE)
+        {
+          aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2);
+        }
+        else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE &&
+                 aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER)
+        {
+          aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1);
+        }
+      }
+    }
+
+    if (aValue > 0.0)
+      aResult = aValue;
+  }
+  return aResult;
+}
+
 //==================================================================================================
 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   const std::shared_ptr<GeomAPI_Shape> theCompound,
@@ -1303,7 +1611,11 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_ShapeTools::wireToEdge(
       static const int THE_MAX_INTERVALS = 32;
       double aFirst, aLast;
       Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aNewEdge, aFirst, aLast);
+#if OCC_VERSION_LARGE < 0x07070000
       Handle(GeomAdaptor_HCurve) aHCurve = new GeomAdaptor_HCurve(aCurve);
+#else
+      Handle(GeomAdaptor_Curve) aHCurve = new GeomAdaptor_Curve(aCurve);
+#endif
       Approx_CurvilinearParameter anApprox(aHCurve, Precision::Confusion(), aCurve->Continuity(),
                                            THE_MAX_DEGREE, THE_MAX_INTERVALS);
       if (anApprox.HasResult()) {
@@ -1469,3 +1781,20 @@ void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects,
     }
   }
 }
+
+ListOfShape GeomAlgoAPI_ShapeTools::getSharedFaces(const GeomShapePtr& theShape)
+{
+  ListOfShape aSharedFaces;
+  TopTools_IndexedDataMapOfShapeListOfShape aMapFS;
+  TopExp::MapShapesAndUniqueAncestors(theShape->impl<TopoDS_Shape>(),
+                                      TopAbs_FACE, TopAbs_SOLID, aMapFS);
+  for (Standard_Integer i = 1; i <= aMapFS.Extent(); i++) {
+    const TopTools_ListOfShape& ancestors = aMapFS.FindFromIndex(i);
+    if (ancestors.Size() > 1) {
+      GeomShapePtr aFace(new GeomAPI_Shape);
+      aFace->setImpl<TopoDS_Shape>(new TopoDS_Shape(aMapFS.FindKey(i)));
+      aSharedFaces.push_back(aFace);
+    }
+  }
+  return aSharedFaces;
+}