Salome HOME
bos #29468: Advanced geometry features: distance Edge-Edge & Face-Face
authorazv <azv@opencascade.com>
Fri, 17 Jun 2022 14:19:17 +0000 (17:19 +0300)
committerjfa <jfa@opencascade.com>
Thu, 16 Mar 2023 15:50:52 +0000 (15:50 +0000)
25 files changed:
doc/salome/examples/shape_proximity.py [new file with mode: 0644]
doc/salome/examples/tests.set
doc/salome/gui/GEOM/images/Shape_proximity_0.png [new file with mode: 0644]
doc/salome/gui/GEOM/images/Shape_proximity_1.png [new file with mode: 0644]
doc/salome/gui/GEOM/input/shape_proximity.doc [new file with mode: 0644]
doc/salome/gui/GEOM/input/tui_measurement_tools.doc
doc/salome/gui/GEOM/input/tui_shape_proximity.doc [new file with mode: 0644]
doc/salome/gui/GEOM/input/using_measurement_tools.doc
idl/GEOM_Gen.idl
src/GEOMImpl/CMakeLists.txt
src/GEOMImpl/GEOMImpl_Gen.cxx
src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx
src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx
src/GEOMImpl/GEOMImpl_IProximity.hxx [new file with mode: 0644]
src/GEOMImpl/GEOMImpl_ShapeProximityDriver.cxx [new file with mode: 0644]
src/GEOMImpl/GEOMImpl_ShapeProximityDriver.hxx [new file with mode: 0644]
src/GEOMImpl/GEOMImpl_Types.hxx
src/GEOM_I/GEOM_IMeasureOperations_i.cc
src/GEOM_I/GEOM_IMeasureOperations_i.hh
src/GEOM_SWIG/CMakeLists.txt
src/GEOM_SWIG/geomBuilder.py
src/GEOM_SWIG/proximity.py [new file with mode: 0644]
test/test_proximity_edge_edge.py [new file with mode: 0644]
test/test_proximity_face_face.py [new file with mode: 0644]
test/tests.set

diff --git a/doc/salome/examples/shape_proximity.py b/doc/salome/examples/shape_proximity.py
new file mode 100644 (file)
index 0000000..4e634fd
--- /dev/null
@@ -0,0 +1,40 @@
+# Shape Proximity
+
+import math
+import salome
+salome.salome_init_without_session()
+import GEOM
+from salome.geom import geomBuilder
+geompy = geomBuilder.New()
+
+# create conical and planar faces
+O = geompy.MakeVertex(0, 0, 0)
+OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
+OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
+OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
+Cone_1 = geompy.MakeConeR1R2H(100, 0, 300)
+Cone_1_face_3 = geompy.GetSubShape(Cone_1, [3])
+Cone_1_wire_4 = geompy.GetSubShape(Cone_1, [4])
+Face_1 = geompy.MakeFaceFromSurface(Cone_1_face_3, Cone_1_wire_4)
+Face_1_edge_5 = geompy.GetSubShape(Face_1, [5])
+Face_2 = geompy.MakeFaceObjHW(Face_1_edge_5, 200, 200)
+geompy.Rotate(Face_2, OY, 90*math.pi/180.0)
+Face_2_vertex_7 = geompy.GetSubShape(Face_2, [7])
+Translation_1 = geompy.MakeTranslationTwoPoints(Face_2, Face_2_vertex_7, O)
+
+shape1 = Face_1
+shape2 = Translation_1
+
+# perform proximity calculation with the default parameters
+p1 = geompy.ShapeProximity()
+proximity1 = p1.proximity(shape1, shape2)
+print("Proximity with default parameters: ", proximity1)
+
+# perform proximity calculation with custom parameters
+p2 = geompy.ShapeProximity()
+p2.setShapes(shape1, shape2)
+p2.setSampling(shape1, 100) # number of sample points for the first shape
+p2.setSampling(shape2, 40)  # number of sample points for the second shape
+proximity2_coarse = p2.coarseProximity()
+proximity2_fine = p2.preciseProximity()
+print("Proximity with custom parameters: coarse = ", proximity2_coarse, "; precise = ", proximity2_fine)
index 327d640702071744a253f19894115f65d019fa94..c2c8eb81ee7115c973bffcf39ee88956f31ff439 100644 (file)
@@ -135,4 +135,5 @@ SET(GOOD_TESTS
   working_with_groups_ex06.py
   GEOM_Field.py
   check_self_intersections_fast.py # OCC > 6.9.0
+  shape_proximity.py
 )
diff --git a/doc/salome/gui/GEOM/images/Shape_proximity_0.png b/doc/salome/gui/GEOM/images/Shape_proximity_0.png
new file mode 100644 (file)
index 0000000..196b764
Binary files /dev/null and b/doc/salome/gui/GEOM/images/Shape_proximity_0.png differ
diff --git a/doc/salome/gui/GEOM/images/Shape_proximity_1.png b/doc/salome/gui/GEOM/images/Shape_proximity_1.png
new file mode 100644 (file)
index 0000000..1217989
Binary files /dev/null and b/doc/salome/gui/GEOM/images/Shape_proximity_1.png differ
diff --git a/doc/salome/gui/GEOM/input/shape_proximity.doc b/doc/salome/gui/GEOM/input/shape_proximity.doc
new file mode 100644 (file)
index 0000000..fc82ece
--- /dev/null
@@ -0,0 +1,52 @@
+/*! 
+
+\page shape_proximity_page Shape Proximity
+
+The Shape Proximity operation calculates maximal of all possible distances between two shapes.
+Considering this case :
+
+\image html Shape_proximity_0.png
+
+The proximity of blue shape to the red one is computed like this :
+For each point of blue the distance to the red is computed using perpendicular projection. The proximity value returned is equal to maximal value of all of this distances.
+To do that the implemented algorithm
+
+1 - sampling shapes by points then calculating the distance from each sample point from one shape to another
+
+2 - find the position which gives the maximal distance
+
+3 - improve the proximity value basing on the exact shapes using the points found on step 2 as a start position
+
+It may happen that for some point of blue shape no distance to red shape exist using perpendicular projection.
+This is typically the case here :
+
+\image html Shape_proximity_1.png
+
+In the case of no perpendicular projection of a point on blue shape exists, instead of perpendicular projection the minimal distance to border point of red shape is considered.
+The distance from EndBlue Point is taken using EndRed Point (black line represents the distance for EndBlue).
+
+This is just a TUI functionality. The provided class
+<pre>
+geompy.ShapeProximity()
+</pre>
+has an interface to compute proximity value with default parameters
+<pre>
+p = geompy.ShapeProximity()
+value = p.proximity(shape1, shape2)
+</pre>
+
+Moreover, it also provides the functionality to customize the calculation. 
+For example, compute coarse proximity value basing on the number of sampling points for each shape, 
+or compute the precise value as a refining operation after the coarse value calculation.
+<pre>
+p = geompy.ShapeProximity()
+p.setShapes(shape1, shape2) # customize calculator with input shapes
+p.setSampling(shape1, 100)  # assign number of sample points for the first shape
+p.setSampling(shape2, 25)   # assign number of sample points for the second shape
+coarse_proximity = p.coarseProximity() # rough proximity value basing on the shape sampling and tessellation
+fine_proximity = p.preciseProximity()  # more precise proximity value using exact shapes
+</pre>
+
+See also a \ref tui_shape_proximity_page "TUI example".
+
+*/
index 3966c9c0feb209d4941ee806860a4576566515f1..a4e7f5c9df5d46e06c623869e31098022803bf39 100644 (file)
@@ -22,6 +22,7 @@
 <li>\subpage tui_check_self_intersections_fast_page</li>
 <li>\subpage tui_fast_intersection_page</li>
 <li>\subpage tui_check_conformity_page</li>
+<li>\subpage tui_shape_proximity_page</li>
 </ul>
 
 */
diff --git a/doc/salome/gui/GEOM/input/tui_shape_proximity.doc b/doc/salome/gui/GEOM/input/tui_shape_proximity.doc
new file mode 100644 (file)
index 0000000..34efab4
--- /dev/null
@@ -0,0 +1,6 @@
+/*!
+
+\page tui_shape_proximity_page Compute Proximity between Shapes
+\tui_script{shape_proximity.py}
+
+*/
index 11803eec225f0245527a067d7ab4f6a70f53d4a9..c30850fd319458bebd6d7fcecf99707559770b64 100644 (file)
@@ -21,6 +21,7 @@
 <li>\subpage whatis_page "WhatIs"</li>
 <li>\subpage inspect_object_operation_page "Inspect Object"</li>
 <li>\subpage shape_statistics_operation_page "Shape Statistics"</li>
+<li>\subpage shape_proximity_page "Shapes Proximity"</li>
 </ul>
 
 \n To check their integrity:
index 89a1e777950838776ea50635979880ba45957b67..d33bc140dcb1be63fc7cbb9afcf3ec5f11cbd583 100644 (file)
@@ -4833,6 +4833,38 @@ module GEOM
     *  \param theShape Shape for update.
     */
     double UpdateTolerance(in GEOM_Object theShape);
+
+    /*!
+     *  \brief Get the calculator for the proximity value between the given shapes.
+     *  \param theShape1,theShape2 Shapes to find proximity.
+     *  \return The calculator object.
+     */
+    GEOM_Object ShapeProximityCalculator(in GEOM_Object theShape1, in GEOM_Object theShape2);
+
+    /*!
+     *  \brief Set number sample points to compute the coarse proximity.
+     *  \param theCalculator Proximity calculator.
+     *  \param theShape      Shape to be samples.
+     *  \param theNbSamples  Number of samples points.
+     */
+    void SetShapeSampling(in GEOM_Object theCalculator,
+                          in GEOM_Object theShape,
+                          in long theNbSamples);
+
+    /*!
+     *  \brief Compute coarse value of the proximity basing on the polygonal representation of shapes.
+     *  \param theCalculator Proximity calculator.
+     *  \return Proximity value.
+     */
+    double GetCoarseProximity(in GEOM_Object theCalculator);
+
+    /*!
+     *  \brief Compute precise value of the proximity basing on the exact shapes.
+     *  \param theCalculator Proximity calculator.
+     *  \return Proximity value.
+     */
+    double GetPreciseProximity(in GEOM_Object theCalculator);
+
   };
 
  // # GEOM_IGroupOperations:
index 6dbbae81ed19136ec63e2e9be83fafebe878ad65..f79a186a535388cff09ac3063e13cfc037a5e895 100644 (file)
@@ -95,6 +95,7 @@ SET(GEOMImpl_HEADERS
   GEOMImpl_ILine.hxx
   GEOMImpl_IPatchFace.hxx
   GEOMImpl_IPlane.hxx
+  GEOMImpl_IProximity.hxx
   GEOMImpl_IMarker.hxx
   GEOMImpl_ITranslate.hxx
   GEOMImpl_IMirror.hxx
@@ -182,6 +183,7 @@ SET(GEOMImpl_HEADERS
   GEOMImpl_FillingDriver.hxx
   GEOMImpl_GlueDriver.hxx
   GEOMImpl_PatchFaceDriver.hxx
+  GEOMImpl_ShapeProximityDriver.hxx
   GEOMImpl_Types.hxx
   GEOM_GEOMImpl.hxx
   GEOMImpl_ICanonicalRecognition.hxx
@@ -261,6 +263,7 @@ SET(GEOMImpl_SOURCES
   GEOMImpl_FillingDriver.cxx
   GEOMImpl_GlueDriver.cxx
   GEOMImpl_PatchFaceDriver.cxx
+  GEOMImpl_ShapeProximityDriver.cxx
   GEOMImpl_FieldDriver.cxx
   GEOMImpl_ICanonicalRecognition.cxx
   )
index 7df117c33a0cf95055e099ae18427c9cd69df65b..e1d7d3a28f89a913acdd06b4b3075a67871904cd 100644 (file)
@@ -84,6 +84,7 @@
 #include <GEOMImpl_MeasureDriver.hxx>
 #include <GEOMImpl_FieldDriver.hxx>
 #include <GEOMImpl_ConformityDriver.hxx>
+#include <GEOMImpl_ShapeProximityDriver.hxx>
 
 //=============================================================================
 /*!
@@ -165,6 +166,7 @@ GEOMImpl_Gen::GEOMImpl_Gen()
    TFunction_DriverTable::Get()->AddDriver(GEOMImpl_MeasureDriver::GetID(), new GEOMImpl_MeasureDriver());
    TFunction_DriverTable::Get()->AddDriver(GEOMImpl_PatchFaceDriver::GetID(), new GEOMImpl_PatchFaceDriver());
    TFunction_DriverTable::Get()->AddDriver(GEOMImpl_ConformityDriver::GetID(), new GEOMImpl_ConformityDriver());
+   TFunction_DriverTable::Get()->AddDriver(GEOMImpl_ShapeProximityDriver::GetID(), new GEOMImpl_ShapeProximityDriver());
 
    // Field
    TFunction_DriverTable::Get()->AddDriver(GEOMImpl_FieldDriver::GetID(), new GEOMImpl_FieldDriver());
index 1c8c7add37667c3ecbc3179336a1e8b890cb29c8..7bfc35b5f19243ae780e2a1823a8ec67b8d441a0 100644 (file)
@@ -25,7 +25,9 @@
 #include <GEOMImpl_MeasureDriver.hxx>
 
 #include <GEOMImpl_IPatchFace.hxx>
+#include <GEOMImpl_IProximity.hxx>
 #include <GEOMImpl_PatchFaceDriver.hxx>
+#include <GEOMImpl_ShapeProximityDriver.hxx>
 
 #include <GEOMImpl_Types.hxx>
 
@@ -3278,3 +3280,191 @@ void GEOMImpl_IMeasureOperations::FillErrors
     }
   }
 }
+
+//=======================================================================
+//function : ShapeProximityCalculator
+//purpose  : returns an object to compute the proximity value
+//=======================================================================
+Handle(GEOM_Object) GEOMImpl_IMeasureOperations::ShapeProximityCalculator
+                                          (Handle(GEOM_Object) theShape1,
+                                           Handle(GEOM_Object) theShape2)
+{
+  SetErrorCode(KO);
+
+  if (theShape1.IsNull() || theShape2.IsNull())
+    return NULL;
+
+  Handle(GEOM_Function) aShapeFunc1 = theShape1->GetLastFunction();
+  Handle(GEOM_Function) aShapeFunc2 = theShape2->GetLastFunction();
+  if (aShapeFunc1.IsNull() || aShapeFunc2.IsNull())
+    return NULL;
+
+  Handle(GEOM_Object) aProximityCalc = GetEngine()->AddObject(GEOM_SHAPE_PROXIMITY);
+  if (aProximityCalc.IsNull())
+    return NULL;
+
+  Handle(GEOM_Function) aProximityFuncCoarse =
+      aProximityCalc->AddFunction(GEOMImpl_ShapeProximityDriver::GetID(), PROXIMITY_COARSE);
+  //Check if the function is set correctly
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID())
+    return NULL;
+
+  GEOMImpl_IProximity aProximity (aProximityFuncCoarse);
+  aProximity.SetShapes(aShapeFunc1, aShapeFunc2);
+
+  //Make a Python command
+  GEOM::TPythonDump pd (aProximityFuncCoarse);
+  pd << "p = geompy.ShapeProximity()\n";
+  pd << "p.setShapes(" << theShape1 << ", " << theShape2 << ")";
+
+  SetErrorCode(OK);
+  return aProximityCalc;
+}
+
+//=======================================================================
+//function : SetShapeSampling
+//purpose  : set number sample points to compute the coarse proximity
+//=======================================================================
+void GEOMImpl_IMeasureOperations::SetShapeSampling(Handle(GEOM_Object) theCalculator,
+                                                   Handle(GEOM_Object) theShape,
+                                                   const Standard_Integer theNbSamples)
+{
+  SetErrorCode(KO);
+  if (theShape.IsNull() ||
+      theCalculator.IsNull() ||
+      theCalculator->GetNbFunctions() <= 0 ||
+      theNbSamples <= 0)
+    return ;
+
+  Handle(GEOM_Function) aProximityFuncCoarse = theCalculator->GetFunction(1);
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID())
+    return ;
+
+  Handle(GEOM_Function) aShapeFunc = theShape->GetLastFunction();
+  if (aShapeFunc.IsNull())
+    return ;
+
+  GEOMImpl_IProximity aProximity(aProximityFuncCoarse);
+  Handle(GEOM_Function) aShape1, aShape2;
+  aProximity.GetShapes(aShape1, aShape2);
+  if (aShape1->GetValue() == aShapeFunc->GetValue())
+    aProximity.SetNbSamples(PROXIMITY_ARG_SAMPLES1, theNbSamples);
+  else if (aShape2->GetValue() == aShapeFunc->GetValue())
+    aProximity.SetNbSamples(PROXIMITY_ARG_SAMPLES2, theNbSamples);
+
+  //Make a Python command
+  GEOM::TPythonDump(aProximityFuncCoarse, /*append=*/true) <<
+    "p.setSampling(" << theShape << ", " << theNbSamples << ")";
+
+  SetErrorCode(OK);
+}
+
+//=======================================================================
+//function : GetCoarseProximity
+//purpose  : compute coarse proximity
+//=======================================================================
+Standard_Real GEOMImpl_IMeasureOperations::GetCoarseProximity(Handle(GEOM_Object) theCalculator,
+                                                              bool doPythonDump)
+{
+  SetErrorCode(KO);
+  if (theCalculator.IsNull())
+    return -1;
+
+  Handle(GEOM_Function) aProximityFuncCoarse = theCalculator->GetFunction(1);
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID() ||
+      aProximityFuncCoarse->GetType() != PROXIMITY_COARSE)
+    return -1;
+
+  // Perform
+  // We have to recompute the function each time,
+  // because the number of samples can be changed
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aProximityFuncCoarse)) {
+      SetErrorCode("shape proximity driver failed");
+      return -1;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return -1;
+  }
+
+  //Make a Python command
+  if (doPythonDump)
+    GEOM::TPythonDump(aProximityFuncCoarse, /*append=*/true) << "value = p.coarseProximity()";
+
+  SetErrorCode(OK);
+  GEOMImpl_IProximity aProximity (aProximityFuncCoarse);
+  return aProximity.GetValue();
+}
+
+//=======================================================================
+//function : GetPreciseProximity
+//purpose  : compute precise proximity
+//=======================================================================
+Standard_Real GEOMImpl_IMeasureOperations::GetPreciseProximity(Handle(GEOM_Object) theCalculator)
+{
+  SetErrorCode(KO);
+  if (theCalculator.IsNull())
+    return -1;
+
+  Handle(GEOM_Function) aProximityFuncCoarse = theCalculator->GetFunction(1);
+  Handle(GEOM_Function) aProximityFuncFine = theCalculator->GetFunction(2);
+  if (aProximityFuncFine.IsNull())
+    aProximityFuncFine = theCalculator->AddFunction
+      (GEOMImpl_ShapeProximityDriver::GetID(), PROXIMITY_PRECISE);
+
+  //Check if the functions are set correctly
+  if (aProximityFuncCoarse.IsNull() ||
+      aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID() ||
+      aProximityFuncFine.IsNull() ||
+      aProximityFuncFine->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID())
+    return -1;
+
+  // perform coarse computation beforehand
+  GetCoarseProximity(theCalculator, /*doPythonDump=*/false);
+
+  // transfer parameters from the coarse to precise calculator
+  GEOMImpl_IProximity aCoarseProximity (aProximityFuncCoarse);
+  Handle(GEOM_Function) aShape1, aShape2;
+  aCoarseProximity.GetShapes(aShape1, aShape2);
+  if (aShape1.IsNull() || aShape2.IsNull())
+    return -1;
+  gp_Pnt aProxPnt1, aProxPnt2;
+  Standard_Integer intStatus1, intStatus2;
+  aCoarseProximity.GetProximityPoints(aProxPnt1, aProxPnt2);
+  aCoarseProximity.GetStatusOfPoints(intStatus1, intStatus2);
+  Standard_Real aResultValue = aCoarseProximity.GetValue();
+
+  GEOMImpl_IProximity aFineProximity (aProximityFuncFine);
+  aFineProximity.SetShapes(aShape1, aShape2);
+  aFineProximity.SetProximityPoints(aProxPnt1, aProxPnt2);
+  aFineProximity.SetStatusOfPoints(intStatus1, intStatus2);
+  aFineProximity.SetValue(aResultValue); // in some cases this value cannot be precised
+
+  // Perform
+  try {
+    OCC_CATCH_SIGNALS;
+    if (!GetSolver()->ComputeFunction(aProximityFuncFine)) {
+      SetErrorCode("shape proximity driver failed");
+      return -1;
+    }
+  }
+  catch (Standard_Failure& aFail) {
+    SetErrorCode(aFail.GetMessageString());
+    return -1;
+  }
+
+  aResultValue = aFineProximity.GetValue();
+  aFineProximity.GetProximityPoints(aProxPnt1, aProxPnt2);
+
+  //Make a Python command
+  GEOM::TPythonDump(aProximityFuncCoarse, /*append=*/true) << "value = p.preciseProximity()";
+
+  SetErrorCode(OK);
+  return aResultValue;
+}
index d896b5da1adcd036b8d520c268e6dc8f379c58eb..3e96a329568d3ffbcbfa6e79d11e25a4838d0187 100644 (file)
@@ -244,6 +244,16 @@ class GEOMImpl_IMeasureOperations : public GEOM_IOperations {
                                        Handle(GEOM_Object) thePoint,
                                        Handle(GEOM_Object) theDirection);
 
+  // Methods to compute proximity between two shapes
+  Standard_EXPORT Handle(GEOM_Object) ShapeProximityCalculator(Handle(GEOM_Object) theShape1,
+                                                               Handle(GEOM_Object) theShape2);
+  Standard_EXPORT Standard_Real GetCoarseProximity(Handle(GEOM_Object) theCalculator,
+                                                   bool doPythonDump = true);
+  Standard_EXPORT Standard_Real GetPreciseProximity(Handle(GEOM_Object) theCalculator);
+  Standard_EXPORT void SetShapeSampling(Handle(GEOM_Object) theCalculator,
+                                        Handle(GEOM_Object) theShape,
+                                        const Standard_Integer theNbSamples);
+
  private:
 
    void FillErrorsSub
diff --git a/src/GEOMImpl/GEOMImpl_IProximity.hxx b/src/GEOMImpl/GEOMImpl_IProximity.hxx
new file mode 100644 (file)
index 0000000..c32a5fd
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright (C) 2022-2022  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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 <GEOM_Function.hxx>
+
+#define PROXIMITY_ARG_SHAPE1   1
+#define PROXIMITY_ARG_SHAPE2   2
+#define PROXIMITY_ARG_SAMPLES1 3
+#define PROXIMITY_ARG_SAMPLES2 4
+#define PROXIMITY_ARG_POINT1   5
+#define PROXIMITY_ARG_POINT2   6
+#define PROXIMITY_ARG_VALUE    7
+#define PROXIMITY_ARG_STATUS1  8
+#define PROXIMITY_ARG_STATUS2  9
+
+class GEOMImpl_IProximity
+{
+public:
+
+  GEOMImpl_IProximity(Handle(GEOM_Function) theFunction) : _func(theFunction) {}
+
+  void SetShapes(Handle(GEOM_Function) theShape1, Handle(GEOM_Function) theShape2)
+  {
+    _func->SetReference(PROXIMITY_ARG_SHAPE1, theShape1);
+    _func->SetReference(PROXIMITY_ARG_SHAPE2, theShape2);
+  }
+
+  void GetShapes(Handle(GEOM_Function)& theShape1, Handle(GEOM_Function)& theShape2) const
+  {
+    theShape1 = _func->GetReference(PROXIMITY_ARG_SHAPE1);
+    theShape2 = _func->GetReference(PROXIMITY_ARG_SHAPE2);
+  }
+
+  void SetNbSamples(const Standard_Integer thePosition, const Standard_Integer theNbSamples) const
+  {
+    _func->SetInteger(thePosition, theNbSamples);
+  }
+
+  Standard_Integer GetNbSamples(const Standard_Integer thePosition) const
+  {
+    return _func->GetInteger(thePosition);
+  }
+
+  void SetProximityPoints(const gp_Pnt& thePoint1, const gp_Pnt& thePoint2)
+  {
+    setPoint(PROXIMITY_ARG_POINT1, thePoint1);
+    setPoint(PROXIMITY_ARG_POINT2, thePoint2);
+  }
+
+  void SetStatusOfPoints(const Standard_Integer theStatus1, const Standard_Integer theStatus2)
+  {
+    setStatus(PROXIMITY_ARG_STATUS1, theStatus1);
+    setStatus(PROXIMITY_ARG_STATUS2, theStatus2);
+  }
+
+  void GetProximityPoints(gp_Pnt& thePoint1, gp_Pnt& thePoint2)
+  {
+    thePoint1 = getPoint(PROXIMITY_ARG_POINT1);
+    thePoint2 = getPoint(PROXIMITY_ARG_POINT2);
+  }
+
+  void GetStatusOfPoints(Standard_Integer& theStatus1, Standard_Integer& theStatus2)
+  {
+    theStatus1 = getStatus(PROXIMITY_ARG_STATUS1);
+    theStatus2 = getStatus(PROXIMITY_ARG_STATUS2);
+  }
+
+  void SetValue(const Standard_Real theValue)
+  {
+    _func->SetReal(PROXIMITY_ARG_VALUE, theValue);
+  }
+
+  Standard_Real GetValue() const
+  {
+    return _func->GetReal(PROXIMITY_ARG_VALUE);
+  }
+
+private:
+  void setPoint(const Standard_Integer thePosition, const gp_Pnt& thePoint)
+  {
+    Handle(TColStd_HArray1OfReal) aCoords = new TColStd_HArray1OfReal(1, 3);
+    aCoords->SetValue(1, thePoint.X());
+    aCoords->SetValue(2, thePoint.Y());
+    aCoords->SetValue(3, thePoint.Z());
+    _func->SetRealArray(thePosition, aCoords);
+  }
+
+  void setStatus(const Standard_Integer thePosition, const Standard_Integer theStatus)
+  {
+    _func->SetInteger(thePosition, theStatus);
+  }
+
+  gp_Pnt getPoint(const Standard_Integer thePosition)
+  {
+    Handle(TColStd_HArray1OfReal) aCoords = _func->GetRealArray(thePosition);
+    return gp_Pnt(aCoords->Value(1), aCoords->Value(2), aCoords->Value(3));
+  }
+
+  Standard_Integer getStatus(const Standard_Integer thePosition)
+  {
+    return _func->GetInteger(thePosition);
+  }
+
+private:
+  Handle(GEOM_Function) _func;
+};
diff --git a/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.cxx b/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.cxx
new file mode 100644 (file)
index 0000000..e1397ef
--- /dev/null
@@ -0,0 +1,457 @@
+// Copyright (C) 2022-2022  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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 <GEOMImpl_ShapeProximityDriver.hxx>
+#include <GEOMImpl_IProximity.hxx>
+#include <GEOMImpl_Types.hxx>
+
+#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepExtrema_ShapeProximity.hxx>
+#include <BRepMesh_IncrementalMesh.hxx>
+#include <Extrema_ExtPC.hxx>
+#include <Extrema_ExtPS.hxx>
+#include <Extrema_GenLocateExtCS.hxx>
+#include <Extrema_GenLocateExtSS.hxx>
+#include <Extrema_GenLocateExtPS.hxx>
+#include <Extrema_LocateExtCC.hxx>
+#include <Extrema_LocateExtPC.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+
+namespace {
+  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,
+                                 gp_Pnt& thePoint1, gp_Pnt& thePoint2)
+  {
+    BRepAdaptor_Curve aCurve1(theEdge1);
+    BRepAdaptor_Curve aCurve2(theEdge2);
+
+    TopLoc_Location aLoc;
+    Standard_Real aTol1 = BRep_Tool::Tolerance(theEdge1);
+    Handle(Poly_Polygon3D) aPoly1 = BRep_Tool::Polygon3D (theEdge1, aLoc);
+    if (!aPoly1.IsNull())
+      aTol1 = Max (aTol1, aPoly1->Deflection());
+    Standard_Real aTol2 = BRep_Tool::Tolerance(theEdge2);
+    Handle(Poly_Polygon3D) aPoly2 = BRep_Tool::Polygon3D (theEdge2, aLoc);
+    if (!aPoly2.IsNull())
+      aTol2 = Max (aTol2, aPoly2->Deflection());
+  
+    Standard_Real aU1 = paramOnCurve(aCurve1, thePoint1, 2*aTol1);
+    Standard_Real aU2 = paramOnCurve(aCurve2, thePoint2, 2*aTol2);
+
+    Standard_Real aValue = -1.0;
+    Extrema_LocateExtCC anExtr(aCurve1, aCurve2, aU1, aU2);
+    if (anExtr.IsDone())
+    {
+      aValue = Sqrt(anExtr.SquareDistance());
+
+      Extrema_POnCurv aP1, aP2;
+      anExtr.Point(aP1, aP2);
+      thePoint1 = aP1.Value();
+      thePoint2 = aP2.Value();
+    }
+    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,
+                                 gp_Pnt& thePonE, gp_Pnt& thePonF)
+  {
+    BRepAdaptor_Curve aCurve(theEdge);
+    BRepAdaptor_Surface aSurf(theFace);
+
+    TopLoc_Location aLoc;
+    Standard_Real aTolEdge = BRep_Tool::Tolerance(theEdge);
+    Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc);
+    if (!aPoly.IsNull())
+      aTolEdge = Max (aTolEdge, aPoly->Deflection());
+    Standard_Real aTolFace = BRep_Tool::Tolerance(theFace);
+    Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc);
+    if (!aTria.IsNull())
+      aTolFace = Max (aTolFace, aTria->Deflection());
+  
+    Standard_Real aP = paramOnCurve(aCurve, thePonE, 2*aTolEdge);
+    Standard_Real aU, aV;
+    paramsOnSurf(aSurf, thePonF, 2*aTolFace, aU, aV);
+
+    Standard_Real aValue = -1.0;
+    Extrema_GenLocateExtCS anExtr(aCurve, aSurf, aP, aU, aV, Precision::PConfusion(), Precision::PConfusion());
+    if (anExtr.IsDone())
+    {
+      aValue = Sqrt(anExtr.SquareDistance());
+      thePonE = anExtr.PointOnCurve().Value();
+      thePonF = anExtr.PointOnSurface().Value();
+    }
+    return aValue;
+  }
+
+  static Standard_Real extremaFF(const TopoDS_Face& theFace1, const TopoDS_Face& theFace2,
+                                 gp_Pnt& thePoint1, gp_Pnt& thePoint2)
+  {
+    BRepAdaptor_Surface aSurf1(theFace1);
+    BRepAdaptor_Surface aSurf2(theFace2);
+
+    TopLoc_Location aLoc;
+    Standard_Real aTol1 = BRep_Tool::Tolerance(theFace1);
+    Handle(Poly_Triangulation) aTria1 = BRep_Tool::Triangulation (theFace1, aLoc);
+    if (!aTria1.IsNull())
+      aTol1 = Max (aTol1, aTria1->Deflection());
+    Standard_Real aTol2 = BRep_Tool::Tolerance(theFace2);
+    Handle(Poly_Triangulation) aTria2 = BRep_Tool::Triangulation (theFace2, aLoc);
+    if (!aTria2.IsNull())
+      aTol2 = Max (aTol2, aTria2->Deflection());
+  
+    Standard_Real aU1, aV1;
+    paramsOnSurf(aSurf1, thePoint1, 2*aTol1, aU1, aV1);
+    Standard_Real aU2, aV2;
+    paramsOnSurf(aSurf2, thePoint2, 2*aTol2, aU2, aV2);
+
+    Standard_Real aValue = -1.0;
+    Extrema_GenLocateExtSS anExtr(aSurf1, aSurf2, aU1, aV1, aU2, aV2, Precision::PConfusion(), Precision::PConfusion());
+    if (anExtr.IsDone())
+    {
+      aValue = Sqrt(anExtr.SquareDistance());
+      thePoint1 = anExtr.PointOnS1().Value();
+      thePoint2 = anExtr.PointOnS2().Value();
+    }
+    return aValue;
+  }
+}
+
+//=======================================================================
+//function : GetID
+//purpose  :
+//=======================================================================
+const Standard_GUID& GEOMImpl_ShapeProximityDriver::GetID()
+{
+  static Standard_GUID aShapeProximityDriver("1C3449A6-E4EB-407D-B623-89261C4BA785");
+  return aShapeProximityDriver;
+}
+
+//=======================================================================
+//function : Execute
+//purpose  :
+//=======================================================================
+Standard_Integer GEOMImpl_ShapeProximityDriver::Execute(Handle(TFunction_Logbook)& log) const
+{
+  if (Label().IsNull())
+    return 0;
+
+  Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
+  GEOMImpl_IProximity aProximity (aFunction);
+
+  Handle(GEOM_Function) aShapeFunc1, aShapeFunc2;
+  aProximity.GetShapes(aShapeFunc1, aShapeFunc2);
+  if (aShapeFunc1.IsNull() || aShapeFunc2.IsNull())
+    return 0;
+
+  TopoDS_Shape aShape1 = aShapeFunc1->GetValue();
+  TopoDS_Shape aShape2 = aShapeFunc2->GetValue();
+
+  Standard_Real aValue = -1.0;
+
+  if (aFunction->GetType() == PROXIMITY_COARSE)
+  {
+    // tessellate shapes if there is no mesh exists
+    tessellateShape(aShape1);
+    tessellateShape(aShape2);
+
+    // compute proximity basing on the tessellation
+    BRepExtrema_ShapeProximity aCalcProx;
+    aCalcProx.LoadShape1(aShape1);
+    aCalcProx.LoadShape2(aShape2);
+    aCalcProx.SetNbSamples1(aProximity.GetNbSamples(PROXIMITY_ARG_SAMPLES1));
+    aCalcProx.SetNbSamples2(aProximity.GetNbSamples(PROXIMITY_ARG_SAMPLES2));
+    aCalcProx.Perform();
+
+    if (aCalcProx.IsDone())
+    {
+      aValue = aCalcProx.Proximity();
+      aProximity.SetProximityPoints(aCalcProx.ProximityPoint1(),
+                                    aCalcProx.ProximityPoint2());
+      aProximity.SetStatusOfPoints((Standard_Integer)aCalcProx.ProxPntStatus1(),
+                                   (Standard_Integer)aCalcProx.ProxPntStatus2());
+    }
+    else
+      Standard_ConstructionError::Raise("Failed to compute coarse proximity");
+  }
+  else if (aFunction->GetType() == PROXIMITY_PRECISE)
+  {
+    // coarse proximity value
+    // in some cases this value cannot be precised
+    // it can be precised only if at least one point is in the middle of the shape
+    aValue = aProximity.GetValue();
+
+    TopAbs_ShapeEnum aType1 = aShape1.ShapeType();
+    TopAbs_ShapeEnum aType2 = aShape2.ShapeType();
+
+    gp_Pnt aPnt1, aPnt2;
+    BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus1, aStatus2;
+    Standard_Integer intStatus1, intStatus2;
+    aProximity.GetProximityPoints(aPnt1, aPnt2);
+    aProximity.GetStatusOfPoints(intStatus1, intStatus2);
+    aStatus1 = (BRepExtrema_ProximityDistTool::ProxPnt_Status)intStatus1;
+    aStatus2 = (BRepExtrema_ProximityDistTool::ProxPnt_Status)intStatus2;
+
+    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)
+      aProximity.SetProximityPoints(aPnt1, aPnt2);
+    else
+      Standard_ConstructionError::Raise("Failed to compute precise proximity");
+  }
+  else
+  {
+    Standard_ConstructionError::Raise("incorrect algorithm");
+  }
+
+  aProximity.SetValue(aValue);
+  log->SetTouched(Label());
+  return 1;
+}
+
+//=======================================================================
+//function : GetCreationInformation
+//purpose  : Returns a name of creation operation and names and values of creation parameters
+//=======================================================================
+bool GEOMImpl_ShapeProximityDriver::GetCreationInformation(
+    std::string&             theOperationName,
+    std::vector<GEOM_Param>& theParams)
+{
+  if (Label().IsNull())
+    return false;
+
+  Handle(GEOM_Function) aFunc = GEOM_Function::GetFunction(Label());
+  GEOMImpl_IProximity aProxFunc(aFunc);
+  Handle(GEOM_Function) aShape1, aShape2;
+  aProxFunc.GetShapes(aShape1, aShape2);
+
+  if (aFunc->GetType() == PROXIMITY_COARSE)
+    theOperationName = "PROXIMITY_COARSE";
+  else if (aFunc->GetType() == PROXIMITY_PRECISE)
+    theOperationName = "PROXIMITY_PRECISE";
+
+  AddParam(theParams, "Shape1", aShape1);
+  AddParam(theParams, "Shape2", aShape2);
+
+  return false;
+}
+
+IMPLEMENT_STANDARD_RTTIEXT(GEOMImpl_ShapeProximityDriver, GEOM_BaseDriver)
diff --git a/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.hxx b/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.hxx
new file mode 100644 (file)
index 0000000..3a1312e
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (C) 2022-2022  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// 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 _GEOMImpl_ShapeProximityDriver_HeaderFile
+#define _GEOMImpl_ShapeProximityDriver_HeaderFile
+
+#include <GEOM_BaseDriver.hxx>
+
+DEFINE_STANDARD_HANDLE(GEOMImpl_ShapeProximityDriver, GEOM_BaseDriver)
+
+class GEOMImpl_ShapeProximityDriver : public GEOM_BaseDriver {
+
+public:
+
+  Standard_EXPORT GEOMImpl_ShapeProximityDriver() {}
+  Standard_EXPORT virtual Standard_Integer Execute(Handle(TFunction_Logbook)& log) const;
+  Standard_EXPORT virtual void Validate(Handle(TFunction_Logbook)&) const {}
+  Standard_EXPORT Standard_Boolean MustExecute(const Handle(TFunction_Logbook)&) const { return Standard_True; }
+
+  Standard_EXPORT static const Standard_GUID& GetID();
+  Standard_EXPORT ~GEOMImpl_ShapeProximityDriver() {}
+
+  Standard_EXPORT virtual
+  bool GetCreationInformation(std::string&             theOperationName,
+                              std::vector<GEOM_Param>& params);
+
+  DEFINE_STANDARD_RTTIEXT(GEOMImpl_ShapeProximityDriver, GEOM_BaseDriver)
+};
+
+#endif
index fec26368a732588a3dff19d0357b939420ab84a9..8984fe9397b334a35d541a7af95b11c665e625cc 100644 (file)
 
 #define GEOM_PATCH_FACE 60
 
+#define GEOM_SHAPE_PROXIMITY 61
 #define GEOM_CHECKCONFORMITY 62
 
 //GEOM_Function types
 #define VERTEX_BY_INDEX 5
 #define CURVATURE_VEC_MEASURE 6
 
+// Proximity algorithms
+#define PROXIMITY_COARSE  1
+#define PROXIMITY_PRECISE 2
+
 #define GROUP_FUNCTION 1
 
 // Curve constructor type
index c2bffa8e9a4a12abe774b1140662db441c0f3b64..e829aceabec2103f9a95aacade55111c6424349b 100644 (file)
@@ -1443,3 +1443,97 @@ void GEOM_IMeasureOperations_i::ConvertToList(const GEOM::GEOM_IMeasureOperation
     theListOfResults.push_back(aCheck);
   }
 }
+
+//=============================================================================
+/*!
+ *  ShapeProximityCalculator
+ */
+//=============================================================================
+GEOM::GEOM_Object_ptr GEOM_IMeasureOperations_i::ShapeProximityCalculator(GEOM::GEOM_Object_ptr theShape1,
+                                                                          GEOM::GEOM_Object_ptr theShape2)
+{
+  GEOM::GEOM_Object_var anEmptyCalc;
+
+  //Set a not done flag
+  GetOperations()->SetNotDone();
+
+  //Get the reference shape
+  Handle(::GEOM_Object) aShape1 = GetObjectImpl(theShape1);
+  Handle(::GEOM_Object) aShape2 = GetObjectImpl(theShape2);
+  if (aShape1.IsNull() || aShape2.IsNull())
+    return anEmptyCalc._retn();
+
+  Handle(::GEOM_Object) aCalculator = GetOperations()->ShapeProximityCalculator(aShape1, aShape2);
+  if (!GetOperations()->IsDone() || aCalculator.IsNull())
+    return anEmptyCalc._retn();
+
+  return GetObject(aCalculator);
+}
+
+//=============================================================================
+/*!
+ *  SetShapeSampling
+ */
+ //=============================================================================
+void GEOM_IMeasureOperations_i::SetShapeSampling(GEOM::GEOM_Object_ptr theCalculator,
+                                                 GEOM::GEOM_Object_ptr theShape,
+                                                 CORBA::Long theNbSamples)
+{
+  //Set a not done flag
+  GetOperations()->SetNotDone();
+
+  //Get the proximity calculator
+  Handle(::GEOM_Object) aCalc = GetObjectImpl(theCalculator);
+  if (aCalc.IsNull())
+    return ;
+  //Get the reference shape
+  Handle(::GEOM_Object) aShape = GetObjectImpl(theShape);
+  if (aShape.IsNull())
+    return ;
+
+  GetOperations()->SetShapeSampling(aCalc, aShape, theNbSamples);
+}
+
+//=============================================================================
+/*!
+ *  GetCoarseProximity
+ */
+ //=============================================================================
+CORBA::Double GEOM_IMeasureOperations_i::GetCoarseProximity(GEOM::GEOM_Object_ptr theCalculator)
+{
+  //Set a not done flag
+  GetOperations()->SetNotDone();
+
+  //Get the reference shape
+  Handle(::GEOM_Object) aCalc = GetObjectImpl(theCalculator);
+  if (aCalc.IsNull())
+    return -1.0;
+
+  Standard_Real aProximity = GetOperations()->GetCoarseProximity(aCalc);
+  if (!GetOperations()->IsDone())
+    return -1.0;
+
+  return aProximity;
+}
+
+//=============================================================================
+/*!
+ *  GetPreciseProximity
+ */
+ //=============================================================================
+CORBA::Double GEOM_IMeasureOperations_i::GetPreciseProximity(GEOM::GEOM_Object_ptr theCalculator)
+{
+  //Set a not done flag
+  GetOperations()->SetNotDone();
+
+  //Get the reference shape
+  Handle(::GEOM_Object) aCalc = GetObjectImpl(theCalculator);
+  if (aCalc.IsNull())
+    return -1.0;
+
+  Standard_Real aProximity = GetOperations()->GetPreciseProximity(aCalc);
+  if (!GetOperations()->IsDone())
+    return -1.0;
+
+  return aProximity;
+}
index 630218c04624399bbf9bc2bb90d71b4af0d49e4b..ded2f9c4122e45132d67ff728d43475315f14a24 100644 (file)
@@ -191,6 +191,15 @@ class GEOM_I_EXPORT GEOM_IMeasureOperations_i :
 
   CORBA::Double UpdateTolerance(GEOM::GEOM_Object_ptr theShape);
 
+  // Methods to compute proximity between two shapes
+  GEOM::GEOM_Object_ptr ShapeProximityCalculator (GEOM::GEOM_Object_ptr theShape1,
+                                                  GEOM::GEOM_Object_ptr theShape2);
+  void SetShapeSampling(GEOM::GEOM_Object_ptr theCalculator,
+                        GEOM::GEOM_Object_ptr theShape,
+                        CORBA::Long theNbSamples);
+  CORBA::Double GetCoarseProximity(GEOM::GEOM_Object_ptr theCalculator);
+  CORBA::Double GetPreciseProximity(GEOM::GEOM_Object_ptr theCalculator);
+
   ::GEOMImpl_IMeasureOperations* GetOperations()
   { return (::GEOMImpl_IMeasureOperations*)GetImpl(); }
 
index e9b78cadcecd64a14ae20b6fe1180e7e9d4cc1b0..5735fa949da12fe87a8274dd355fe1ebbe2ae27a 100644 (file)
@@ -73,6 +73,7 @@ SET(_python_SCRIPTS
   gsketcher.py
   canonicalrecognition.py
   conformity.py
+  proximity.py
   )
 
 # Advanced scripts
index cf5a9dba0bcd519c8477c7212a46ac2387486ec8..d28107781165ebaaaa4e471a27bab5f4b06882c8 100644 (file)
@@ -262,6 +262,7 @@ import functools
 from salome.geom.gsketcher import Sketcher3D, Sketcher2D, Polyline2D
 from salome.geom.canonicalrecognition import CanonicalRecognition
 from salome.geom.conformity import CheckConformity
+from salome.geom.proximity import ShapeProximity
 
 # In case the omniORBpy EnumItem class does not fully support Python 3
 # (for instance in version 4.2.1-2), the comparison ordering methods must be
@@ -14056,6 +14057,21 @@ class geomBuilder(GEOM._objref_GEOM_Gen):
             conf = CheckConformity (shape, self)
             return conf
 
+        ## Obtain a shape proximity calculator
+        #  @return An instance of @ref proximity.ShapeProximity "ShapeProximity" interface
+        #
+        #  @ref tui_proximity_page "Example"
+        def ShapeProximity (self):
+            """
+            Obtain a shape proximity calculator.
+
+            Example of usage:
+                prox = geompy.ShapeProximity()
+                value = prox.proximity(shape1, shape2)
+            """
+            prox = ShapeProximity (self)
+            return prox
+
         # end of l2_testing
         ## @}
 
diff --git a/src/GEOM_SWIG/proximity.py b/src/GEOM_SWIG/proximity.py
new file mode 100644 (file)
index 0000000..ac24fbe
--- /dev/null
@@ -0,0 +1,91 @@
+#  -*- coding: iso-8859-1 -*-
+# Copyright (C) 2022-2022  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+# 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
+
+## @defgroup proximity ShapeProximity - tool to check the proximity distance between two shapes
+#  @{ 
+#  @details
+#  The tool provides the user a possibility to compute the proximity distance between two shapes:
+#  * a minimal diameter of a tube containing both edges (for edge-edge proximity);
+#  * a minimal thickness of a shell containing both faces (for face-face proximity).
+#
+#  In other words, this tool calculate maximal of all possible distances between pair of objects.
+#  It is supported to compute distance between two edges or between two faces.
+#  Other combinations of shapes are prohibited.
+#  @}
+
+"""
+    \namespace geompy
+    \brief ShapeProximity interface
+"""
+
+## A class to compute proximity value between two shapes.
+#  Use geompy.ShapeProximity() method to obtain an instance of this class.
+#
+#  @ref tui_proximity_page "Example"
+#  @ingroup proximity
+class ShapeProximity():
+    """
+    ShapeProximity interface.
+
+    Example of usage:
+        prox = geompy.ShapeProximity()
+        value = prox.proximity(shape1, shape2)
+    """
+
+    def __init__(self, geompyD):
+        self.myCommand = "ShapeProximity"
+        self.myOp = geompyD.GetIMeasureOperations()
+        pass
+
+    ## Computes proximity between two shapes of the same type
+    def proximity(self, shape1, shape2):
+        self.setShapes(shape1, shape2)
+        #self.coarseProximity()
+        return self.preciseProximity()
+        pass
+
+    ## Customize object with the input shapes
+    def setShapes(self, shape1, shape2):
+        self.myProximityValue = None
+        from salome.geom.geomBuilder import RaiseIfFailed
+        self.myCalc = self.myOp.ShapeProximityCalculator(shape1, shape2)
+        RaiseIfFailed(self.myCommand, self.myOp)
+        pass
+
+    ## Define the minimal number of sample points for the given shape,
+    #  which should be used for raw computation of proximity value
+    def setSampling(self, shape, nbSamples):
+        self.myOp.SetShapeSampling(self.myCalc, shape, nbSamples)
+        pass
+
+    ## Find rough proximity value based on polygon/tessellation representation
+    def coarseProximity(self):
+        from salome.geom.geomBuilder import RaiseIfFailed
+        self.myProximityValue = self.myOp.GetCoarseProximity(self.myCalc)
+        RaiseIfFailed(self.myCommand, self.myOp)
+        return self.myProximityValue
+        pass
+
+    ## Find precise proximity value based on exact shapes
+    def preciseProximity(self):
+        from salome.geom.geomBuilder import RaiseIfFailed
+        self.myProximityValue = self.myOp.GetPreciseProximity(self.myCalc)
+        RaiseIfFailed(self.myCommand, self.myOp)
+        return self.myProximityValue
+        pass
diff --git a/test/test_proximity_edge_edge.py b/test/test_proximity_edge_edge.py
new file mode 100644 (file)
index 0000000..9c8e732
--- /dev/null
@@ -0,0 +1,130 @@
+# Shape Proximity between edges
+
+import math
+import salome
+salome.salome_init_without_session()
+import GEOM
+from salome.geom import geomBuilder
+geompy = geomBuilder.New()
+
+O = geompy.MakeVertex(0, 0, 0)
+OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
+OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
+OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
+
+# Case 1: two bezier curves (original Cas2_29468.py)
+from math import sqrt
+
+# 283x384
+szY = 384
+listOfPtsRed_gimp = [(10,84), (54,96),(145,146),(167,167),(185,212),(187,234),(176,302)]
+listOfPtsBlue_gimp = [(120,72),(170,87),(227,118),(238,126),(243,157),(203,216),(134,281),(94,324)]
+#
+listOfPtsRed = [(x,szY-y) for x,y in listOfPtsRed_gimp]
+listOfPtsBlue = [(x,szY-y) for x,y in listOfPtsBlue_gimp]
+#
+verticesRed = [geompy.MakeVertex(x,y,0) for x,y in listOfPtsRed]
+verticesBlue = [geompy.MakeVertex(x,y,0) for x,y in listOfPtsBlue]
+for i,(x,y) in enumerate(listOfPtsRed):
+    geompy.addToStudy(geompy.MakeVertex(x,y,0),"red_pt{}".format(i))
+for i,(x,y) in enumerate(listOfPtsBlue):
+    geompy.addToStudy(geompy.MakeVertex(x,y,0),"blue_pt{}".format(i))
+redEdge = geompy.MakeBezier(verticesRed)
+blueEdge = geompy.MakeBezier(verticesBlue)
+#
+geompy.addToStudy(redEdge,"red")
+geompy.addToStudy(blueEdge,"blue")
+
+XY_red = (152,214)
+XY_blue = (215,260)
+exp_red = geompy.MakeVertex(*XY_red,0)
+exp_blue = geompy.MakeVertex(*XY_blue,0)
+geompy.addToStudy(exp_red,"exp_red")
+geompy.addToStudy(exp_blue,"exp_blue")
+
+p = geompy.ShapeProximity()
+p.setShapes(redEdge, blueEdge)
+p.setSampling(redEdge, 1000)
+p.setSampling(blueEdge, 1000)
+p_coarse  = p.coarseProximity()
+p_precise = p.preciseProximity()
+print( "coarse = {} ; fine = {}".format(p_coarse,p_precise) )
+print( "Manually obtained value = {}".format( sqrt( (XY_red[0]-XY_blue[0])**2 + (XY_red[1]-XY_blue[1])**2 ) ) )
+
+assert(math.fabs(p_coarse - 223.00892775) < 1.e-7)
+
+prev = geompy.ShapeProximity()
+prev.setShapes(blueEdge, redEdge)
+prev.setSampling(redEdge, 1000)
+prev.setSampling(blueEdge, 1000)
+p_coarse  = prev.coarseProximity()
+p_precise = prev.preciseProximity()
+print( "coarse = {} ; fine = {}".format(p_coarse,p_precise) )
+
+assert(math.fabs(p_coarse - 84.89994110) < 1.e-7)
+
+# Case 2: two bezier curves (different coarse and fine proximities)
+V1 = geompy.MakeVertex(10, 10, 0)
+V2 = geompy.MakeVertex(20, -10, 0)
+V3 = geompy.MakeVertex(30, 0, 0)
+V4 = geompy.MakeVertex(0, -3, 0)
+V5 = geompy.MakeVertex(13, -10, 0)
+V6 = geompy.MakeVertex(25, 10, 0)
+V7 = geompy.MakeVertex(30, 5, 0)
+BC1 = geompy.MakeBezier([ O, V1, V2, V3], False, "BC1")
+BC2 = geompy.MakeBezier([V4, V5, V6, V7], False, "BC2")
+
+pcalc = geompy.ShapeProximity()
+pcalc.setShapes(BC1, BC2)
+p_coarse = pcalc.coarseProximity()
+p_fine = pcalc.preciseProximity()
+
+assert(math.fabs(p_coarse - 7.3126564) < 1.e-7)
+assert(math.fabs(p_fine - 7.380468495) < 1.e-7)
+
+# Case 3: arc and segment
+Vertex_1 = geompy.MakeVertex(0, 0, -1)
+Vertex_2 = geompy.MakeVertex(1, 0, 0)
+Vertex_3 = geompy.MakeVertex(0, 0, 1)
+Arc_1 = geompy.MakeArc(Vertex_1, Vertex_2, Vertex_3)
+Arc_1_vertex_2 = geompy.GetSubShape(Arc_1, [2])
+Edge_1 = geompy.MakeEdgeOnCurveByLength(Arc_1, 3, Arc_1_vertex_2)
+Edge_2 = geompy.MakeEdge(Vertex_1, Vertex_3)
+
+shape1 = Edge_1
+shape2 = Edge_2
+
+# perform proximity calculation with the default parameters
+p1 = geompy.ShapeProximity()
+proximity1 = p1.proximity(shape1, shape2)
+
+# perform proximity calculation with custom parameters
+p2 = geompy.ShapeProximity()
+p2.setShapes(shape1, shape2)
+p2.setSampling(shape1, 100) # number of sample points for the first shape
+p2.setSampling(shape2, 40)  # number of sample points for the second shape
+proximity2_coarse = p2.coarseProximity()
+proximity2_fine = p2.preciseProximity()
+
+assert(math.fabs(proximity1 - proximity2_fine) < 1.e-7)
+assert(math.fabs(proximity2_coarse - 0.99998769) < 1.e-7)
+assert(math.fabs(proximity2_fine - 1) < 1.e-7)
+
+# move second edge and check proximity
+Translation_1 = geompy.MakeTranslation(Edge_2, 0.3, 0, 0)
+shape2 = Translation_1
+
+# perform proximity calculation with the default parameters
+p1 = geompy.ShapeProximity()
+proximity1 = p1.proximity(shape1, shape2)
+
+# perform proximity calculation with custom parameters
+p2 = geompy.ShapeProximity()
+p2.setShapes(shape1, shape2)
+p2.setSampling(shape1, 100) # number of sample points for the first shape
+p2.setSampling(shape2, 40)  # number of sample points for the second shape
+proximity2_coarse = p2.coarseProximity()
+proximity2_fine = p2.preciseProximity()
+
+assert(math.fabs(proximity1 - 0.7) < 1.e-7)
+assert(math.fabs(proximity2_fine - 0.7) < 1.e-7)
diff --git a/test/test_proximity_face_face.py b/test/test_proximity_face_face.py
new file mode 100644 (file)
index 0000000..a143709
--- /dev/null
@@ -0,0 +1,87 @@
+# Shape Proximity between faces
+
+import math
+import salome
+salome.salome_init_without_session()
+import GEOM
+from salome.geom import geomBuilder
+geompy = geomBuilder.New()
+
+O = geompy.MakeVertex(0, 0, 0)
+OX = geompy.MakeVectorDXDYDZ(1, 0, 0)
+OY = geompy.MakeVectorDXDYDZ(0, 1, 0)
+OZ = geompy.MakeVectorDXDYDZ(0, 0, 1)
+
+# Case 1: cylinder and sphere (different coarse and fine proximities)
+OCyl = geompy.MakeVertex(0, -5, 15)
+Cyl = geompy.MakeCylinder(OCyl, OY, 3, 10, "Cyl")
+AX1 = geompy.MakeTranslation(OX, 0, 0, 15, "AX1")
+geompy.Rotate(Cyl, AX1, -20.0*math.pi/180.0)
+Cyl_face = geompy.SubShapeAllSortedCentres(Cyl, geompy.ShapeType["FACE"], "Face")[1]
+Sph = geompy.MakeSphereR(10, "Sph")
+Box_1 = geompy.MakeBoxDXDYDZ(40, 40, 27.071067)
+Translation_1 = geompy.MakeTranslation(Box_1, -20, -20, -20)
+Cut_1 = geompy.MakeCutList(Sph, [Translation_1], True, "Cut_1")
+Sph_face = geompy.SubShapeAllSortedCentres(Cut_1, geompy.ShapeType["FACE"], "Face")[1]
+
+pcalc = geompy.ShapeProximity()
+#pcalc.setShapes(Cyl_face, Sph_face)
+pcalc.setShapes(Sph_face, Cyl_face)
+p_coarse = pcalc.coarseProximity()
+p_fine   = pcalc.preciseProximity()
+
+assert(math.fabs(p_coarse - 9.8649933) < 1.e-7)
+assert(math.fabs(p_fine - 7.6984631) < 1.e-7)
+
+geompy.MakeVertex(0, 2.63303, 17.2342, "p1")
+geompy.MakeVertex(0, 0, 10, "p2")
+
+print("With sampling 0: coarse = {} ; fine = {}".format(p_coarse, p_fine))
+
+pcalc.setSampling(Cyl_face, 100) # number of sample points for the first shape
+pcalc.setSampling(Sph_face, 100) # number of sample points for the second shape
+p_coarse = pcalc.coarseProximity()
+p_fine   = pcalc.preciseProximity()
+
+print("With sampling 100: coarse = {} ; fine = {}".format(p_coarse, p_fine))
+
+pcalc.setSampling(Cyl_face, 1000) # number of sample points for the first shape
+pcalc.setSampling(Sph_face, 1000) # number of sample points for the second shape
+p_coarse = pcalc.coarseProximity()
+p_fine   = pcalc.preciseProximity()
+
+print("With sampling 1000: coarse = {} ; fine = {}".format(p_coarse, p_fine))
+
+# Case 2: conical and planar faces
+Cone_1 = geompy.MakeConeR1R2H(100, 0, 300)
+Cone_1_face_3 = geompy.GetSubShape(Cone_1, [3])
+Cone_1_wire_4 = geompy.GetSubShape(Cone_1, [4])
+Face_1 = geompy.MakeFaceFromSurface(Cone_1_face_3, Cone_1_wire_4, "Face_1")
+Face_1_edge_5 = geompy.GetSubShape(Face_1, [5])
+Face_2 = geompy.MakeFaceObjHW(Face_1_edge_5, 200, 200)
+geompy.Rotate(Face_2, OY, 90*math.pi/180.0)
+Face_2_vertex_7 = geompy.GetSubShape(Face_2, [7])
+Translation_1 = geompy.MakeTranslationTwoPoints(Face_2, Face_2_vertex_7, O, "Translation_1")
+
+shape1 = Face_1
+shape2 = Translation_1
+
+# perform proximity calculation with the default parameters
+p1 = geompy.ShapeProximity()
+proximity1 = p1.proximity(shape1, shape2)
+
+# perform proximity calculation with custom parameters
+p2 = geompy.ShapeProximity()
+p2.setShapes(shape1, shape2)
+p2.setSampling(shape1, 100) # number of sample points for the first shape
+p2.setSampling(shape2, 40)  # number of sample points for the second shape
+proximity2_coarse = p2.coarseProximity()
+proximity2_fine = p2.preciseProximity()
+
+assert(math.fabs(proximity1 - proximity2_fine) < 1.e-7)
+assert(math.fabs(proximity2_coarse - 127.1141386) < 1.e-7)
+#assert(math.fabs(proximity2_fine - 94.8683298) < 1.e-7)
+assert(math.fabs(proximity2_fine - 127.1141386) < 1.e-7)
+
+geompy.MakeVertex(0, 0, 300, "p3")
+geompy.MakeVertex(-63.2456, 0, 189.737, "p4")
index 1688ac2c72e03b0c54cc82a93ad0c87459689de2..7a002556f003d589c311481c24672c5a233da1dc 100644 (file)
@@ -27,5 +27,7 @@ IF(${OpenCASCADE_VERSION}.${OpenCASCADE_SP_VERSION} VERSION_GREATER "7.5.3.3")
       test_point_cloud_on_face.py
       test_CR.py
       test_conformity.py
+      test_proximity_edge_edge.py
+      test_proximity_face_face.py
     )
 ENDIF()