From f43834312777d2cf3d5e9c2260398f899c1d6dde Mon Sep 17 00:00:00 2001 From: Anthony Geay Date: Thu, 9 Jun 2022 14:44:53 +0300 Subject: [PATCH] Correct defining tolerances for edges and faces in static functions extrema** Add some doc after iteration [tuleap29468] : For Acceptance, fix compilation error bos #29468: Advanced geometry features: distance Edge-Edge & Face-Face [bos #29472] [EDF] (2022-T1) Advanced geometry features: curvature vector on a point of a face [bos #29471] [EDF] (2022-T1) Advanced geometry features: iterate through holes of a face - Added python command PatchFace - Add description for function into GEOM_Gen.idl - Method PatchFace was added into Geom_Superv_i and Geom_Superv MakeFaceWires and MakeFace can raise RuntimeError in case of a non planar detected --- doc/salome/examples/shape_proximity.py | 39 +++ doc/salome/examples/tests.set | 1 + .../gui/GEOM/images/Shape_proximity_0.png | Bin 0 -> 9214 bytes .../gui/GEOM/images/Shape_proximity_1.png | Bin 0 -> 10746 bytes doc/salome/gui/GEOM/input/shape_proximity.doc | 52 +++ .../gui/GEOM/input/tui_measurement_tools.doc | 1 + .../gui/GEOM/input/tui_shape_proximity.doc | 6 + .../GEOM/input/using_measurement_tools.doc | 1 + idl/GEOM_Gen.idl | 31 ++ src/GEOMImpl/CMakeLists.txt | 3 + src/GEOMImpl/GEOMImpl_Gen.cxx | 2 + src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx | 192 +++++++++++ src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx | 9 + src/GEOMImpl/GEOMImpl_IProximity.hxx | 98 ++++++ .../GEOMImpl_ShapeProximityDriver.cxx | 325 ++++++++++++++++++ .../GEOMImpl_ShapeProximityDriver.hxx | 45 +++ src/GEOMImpl/GEOMImpl_Types.hxx | 10 +- src/GEOM_I/GEOM_IMeasureOperations_i.cc | 94 +++++ src/GEOM_I/GEOM_IMeasureOperations_i.hh | 9 + src/GEOM_SWIG/CMakeLists.txt | 1 + src/GEOM_SWIG/geomBuilder.py | 17 + src/GEOM_SWIG/proximity.py | 91 +++++ test/test_proximity_edge_edge.py | 60 ++++ test/test_proximity_face_face.py | 43 +++ test/tests.set | 2 + 25 files changed, 1130 insertions(+), 2 deletions(-) create mode 100644 doc/salome/examples/shape_proximity.py create mode 100644 doc/salome/gui/GEOM/images/Shape_proximity_0.png create mode 100644 doc/salome/gui/GEOM/images/Shape_proximity_1.png create mode 100644 doc/salome/gui/GEOM/input/shape_proximity.doc create mode 100644 doc/salome/gui/GEOM/input/tui_shape_proximity.doc create mode 100644 src/GEOMImpl/GEOMImpl_IProximity.hxx create mode 100644 src/GEOMImpl/GEOMImpl_ShapeProximityDriver.cxx create mode 100644 src/GEOMImpl/GEOMImpl_ShapeProximityDriver.hxx create mode 100644 src/GEOM_SWIG/proximity.py create mode 100644 test/test_proximity_edge_edge.py create mode 100644 test/test_proximity_face_face.py diff --git a/doc/salome/examples/shape_proximity.py b/doc/salome/examples/shape_proximity.py new file mode 100644 index 000000000..997730e93 --- /dev/null +++ b/doc/salome/examples/shape_proximity.py @@ -0,0 +1,39 @@ +# Shape Proximity + +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) diff --git a/doc/salome/examples/tests.set b/doc/salome/examples/tests.set index 327d64070..c2c8eb81e 100644 --- a/doc/salome/examples/tests.set +++ b/doc/salome/examples/tests.set @@ -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 index 0000000000000000000000000000000000000000..196b764c7181d8d6c05f40e0f2b16b1aa305a8c8 GIT binary patch literal 9214 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 Q{4<>6dM9<$v`K#d1L5)wHUIzs literal 0 HcmV?d00001 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 index 0000000000000000000000000000000000000000..1217989e093ad0ca60008d05149d57670d8e163c GIT binary patch literal 10746 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 G3i*Gk1Nv0} literal 0 HcmV?d00001 diff --git a/doc/salome/gui/GEOM/input/shape_proximity.doc b/doc/salome/gui/GEOM/input/shape_proximity.doc new file mode 100644 index 000000000..fc82ece1e --- /dev/null +++ b/doc/salome/gui/GEOM/input/shape_proximity.doc @@ -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 +
+geompy.ShapeProximity()
+
+has an interface to compute proximity value with default parameters +
+p = geompy.ShapeProximity()
+value = p.proximity(shape1, shape2)
+
+ +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. +
+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
+
+ +See also a \ref tui_shape_proximity_page "TUI example". + +*/ diff --git a/doc/salome/gui/GEOM/input/tui_measurement_tools.doc b/doc/salome/gui/GEOM/input/tui_measurement_tools.doc index be111dbb1..d9b3fbf6c 100644 --- a/doc/salome/gui/GEOM/input/tui_measurement_tools.doc +++ b/doc/salome/gui/GEOM/input/tui_measurement_tools.doc @@ -21,6 +21,7 @@
  • \subpage tui_check_self_intersections_page
  • \subpage tui_check_self_intersections_fast_page
  • \subpage tui_fast_intersection_page
  • +
  • \subpage tui_shape_proximity_page
  • */ 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 index 000000000..34efab45d --- /dev/null +++ b/doc/salome/gui/GEOM/input/tui_shape_proximity.doc @@ -0,0 +1,6 @@ +/*! + +\page tui_shape_proximity_page Compute Proximity between Shapes +\tui_script{shape_proximity.py} + +*/ diff --git a/doc/salome/gui/GEOM/input/using_measurement_tools.doc b/doc/salome/gui/GEOM/input/using_measurement_tools.doc index feca9e24f..a688499c4 100644 --- a/doc/salome/gui/GEOM/input/using_measurement_tools.doc +++ b/doc/salome/gui/GEOM/input/using_measurement_tools.doc @@ -21,6 +21,7 @@
  • \subpage whatis_page "WhatIs"
  • \subpage inspect_object_operation_page "Inspect Object"
  • \subpage shape_statistics_operation_page "Shape Statistics"
  • +
  • \subpage shape_proximity_page "Shapes Proximity"
  • \n To check their integrity: diff --git a/idl/GEOM_Gen.idl b/idl/GEOM_Gen.idl index 7423266a4..03bae141d 100644 --- a/idl/GEOM_Gen.idl +++ b/idl/GEOM_Gen.idl @@ -4745,6 +4745,37 @@ module GEOM in GEOM_Object thePoint, in GEOM_Object theDirection); + /*! + * \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: diff --git a/src/GEOMImpl/CMakeLists.txt b/src/GEOMImpl/CMakeLists.txt index 98e47cea3..5aa6e29a5 100644 --- a/src/GEOMImpl/CMakeLists.txt +++ b/src/GEOMImpl/CMakeLists.txt @@ -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 @@ -180,6 +181,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 @@ -257,6 +259,7 @@ SET(GEOMImpl_SOURCES GEOMImpl_FillingDriver.cxx GEOMImpl_GlueDriver.cxx GEOMImpl_PatchFaceDriver.cxx + GEOMImpl_ShapeProximityDriver.cxx GEOMImpl_FieldDriver.cxx GEOMImpl_ICanonicalRecognition.cxx ) diff --git a/src/GEOMImpl/GEOMImpl_Gen.cxx b/src/GEOMImpl/GEOMImpl_Gen.cxx index 74aceaf12..a589f3cc6 100644 --- a/src/GEOMImpl/GEOMImpl_Gen.cxx +++ b/src/GEOMImpl/GEOMImpl_Gen.cxx @@ -83,6 +83,7 @@ #include #include #include +#include //============================================================================= /*! @@ -163,6 +164,7 @@ GEOMImpl_Gen::GEOMImpl_Gen() // Measurements 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_ShapeProximityDriver::GetID(), new GEOMImpl_ShapeProximityDriver()); // Field TFunction_DriverTable::Get()->AddDriver(GEOMImpl_FieldDriver::GetID(), new GEOMImpl_FieldDriver()); diff --git a/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx b/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx index aa141c288..3b9652146 100644 --- a/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx +++ b/src/GEOMImpl/GEOMImpl_IMeasureOperations.cxx @@ -25,7 +25,9 @@ #include #include +#include #include +#include #include @@ -2941,3 +2943,193 @@ 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_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); + Handle(GEOM_Function) aShapeFunc1 = theShape1->GetLastFunction(); + Handle(GEOM_Function) aShapeFunc2 = theShape2->GetLastFunction(); + if (aShapeFunc1.IsNull() || aShapeFunc2.IsNull()) + return NULL; + + aProximity.SetShapes(aShapeFunc1, aShapeFunc2); + + // Perform + try + { + OCC_CATCH_SIGNALS; + if (!GetSolver()->ComputeFunction(aProximityFuncCoarse)) + { + SetErrorCode("shape proximity driver failed"); + return NULL; + } + } + catch (Standard_Failure& aFail) + { + SetErrorCode(aFail.GetMessageString()); + return NULL; + } + + //Make a Python command + GEOM::TPythonDump(aProximityFuncCoarse) << "p = geompy.ShapeProximity()"; + GEOM::TPythonDump(aProximityFuncCoarse) << "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 == aShapeFunc) + aProximity.SetNbSamples(PROXIMITY_ARG_SAMPLES1, theNbSamples); + else if (aShape2 == aShapeFunc) + aProximity.SetNbSamples(PROXIMITY_ARG_SAMPLES2, theNbSamples); + + //Make a Python command + GEOM::TPythonDump(aProximityFuncCoarse) << "p.setSampling(" << theShape << ", " << theNbSamples << ")"; + + SetErrorCode(OK); +} + +//======================================================================= +//function : GetCoarseProximity +//purpose : compute coarse proximity +//======================================================================= +Standard_Real GEOMImpl_IMeasureOperations::GetCoarseProximity(Handle(GEOM_Object) theCalculator) +{ + SetErrorCode(KO); + if (theCalculator.IsNull()) + return NULL; + + Handle(GEOM_Function) aProximityFuncCoarse; + for (int i = 1; i <= theCalculator->GetNbFunctions() && aProximityFuncCoarse.IsNull(); ++i) + { + Handle(GEOM_Function) aFunc = theCalculator->GetFunction(i); + if (!aFunc.IsNull() && aFunc->GetType() == PROXIMITY_COARSE) + aProximityFuncCoarse = aFunc; + } + //Check if the function is set correctly + if (aProximityFuncCoarse.IsNull() || + aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID()) + return NULL; + + GEOMImpl_IProximity aProximity(aProximityFuncCoarse); + + //Make a Python command + GEOM::TPythonDump(aProximityFuncCoarse) << "value = p.coarseProximity()"; + + SetErrorCode(OK); + return aProximity.GetValue(); +} + +//======================================================================= +//function : GetPreciseProximity +//purpose : compute precise proximity +//======================================================================= +Standard_Real GEOMImpl_IMeasureOperations::GetPreciseProximity(Handle(GEOM_Object) theCalculator) +{ + SetErrorCode(KO); + if (theCalculator.IsNull()) + return NULL; + + Handle(GEOM_Function) aProximityFuncFine = theCalculator->GetLastFunction(); + if (aProximityFuncFine.IsNull()) + { + // perform coarse computatiuon beforehand + GetCoarseProximity(theCalculator); + aProximityFuncFine = theCalculator->GetLastFunction(); + } + if (aProximityFuncFine->GetType() != PROXIMITY_PRECISE) + aProximityFuncFine = theCalculator->AddFunction(GEOMImpl_ShapeProximityDriver::GetID(), PROXIMITY_PRECISE); + Handle(GEOM_Function) aProximityFuncCoarse = theCalculator->GetFunction(1); + //Check if the functions are set correctly + if (aProximityFuncCoarse.IsNull() || + aProximityFuncCoarse->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID() || + aProximityFuncFine.IsNull() || + aProximityFuncFine->GetDriverGUID() != GEOMImpl_ShapeProximityDriver::GetID()) + return NULL; + + // 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 NULL; + gp_Pnt aProxPnt1, aProxPnt2; + aCoarseProximity.GetProximityPoints(aProxPnt1, aProxPnt2); + + GEOMImpl_IProximity aFineProximity(aProximityFuncFine); + aFineProximity.SetShapes(aShape1, aShape2); + aFineProximity.SetProximityPoints(aProxPnt1, aProxPnt2); + + // Perform + try + { + OCC_CATCH_SIGNALS; + if (!GetSolver()->ComputeFunction(aProximityFuncFine)) + { + SetErrorCode("shape proximity driver failed"); + return NULL; + } + } + catch (Standard_Failure& aFail) + { + SetErrorCode(aFail.GetMessageString()); + return NULL; + } + + //Make a Python command + GEOM::TPythonDump(aProximityFuncCoarse) << "value = p.preciseProximity()"; + + SetErrorCode(OK); + return aFineProximity.GetValue(); +} diff --git a/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx b/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx index 827f695ff..5bb63aab2 100644 --- a/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx +++ b/src/GEOMImpl/GEOMImpl_IMeasureOperations.hxx @@ -222,6 +222,15 @@ 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); + 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 index 000000000..48b0854e8 --- /dev/null +++ b/src/GEOMImpl/GEOMImpl_IProximity.hxx @@ -0,0 +1,98 @@ +// 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 + +#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 + +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 GetProximityPoints(gp_Pnt& thePoint1, gp_Pnt& thePoint2) + { + thePoint1 = getPoint(PROXIMITY_ARG_POINT1); + thePoint2 = getPoint(PROXIMITY_ARG_POINT2); + } + + 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); + } + + 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)); + } + +private: + Handle(GEOM_Function) _func; +}; diff --git a/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.cxx b/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.cxx new file mode 100644 index 000000000..c8cd2e459 --- /dev/null +++ b/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.cxx @@ -0,0 +1,325 @@ +// 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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 of 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()); + } + else + Standard_ConstructionError::Raise("Failed to compute coarse proximity"); + } + else if (aFunction->GetType() == PROXIMITY_PRECISE) + { + TopAbs_ShapeEnum aType1 = aShape1.ShapeType(); + TopAbs_ShapeEnum aType2 = aShape2.ShapeType(); + + gp_Pnt aP1, aP2; + aProximity.GetProximityPoints(aP1, aP2); + + if (aType1 == TopAbs_EDGE) + { + if (aType2 == TopAbs_EDGE) + aValue = extremaEE(TopoDS::Edge(aShape1), TopoDS::Edge(aShape2), aP1, aP2); + else if (aType2 == TopAbs_FACE) + aValue = extremaEF(TopoDS::Edge(aShape1), TopoDS::Face(aShape2), aP1, aP2); + } + else if (aType1 == TopAbs_FACE) + { + if (aType2 == TopAbs_EDGE) + aValue = extremaEF(TopoDS::Edge(aShape2), TopoDS::Face(aShape1), aP2, aP1); + else if (aType2 == TopAbs_FACE) + aValue = extremaFF(TopoDS::Face(aShape1), TopoDS::Face(aShape2), aP1, aP2); + } + + if (aValue >= 0) + aProximity.SetProximityPoints(aP1, aP2); + 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& 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 index 000000000..3a1312e2f --- /dev/null +++ b/src/GEOMImpl/GEOMImpl_ShapeProximityDriver.hxx @@ -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 + +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& params); + + DEFINE_STANDARD_RTTIEXT(GEOMImpl_ShapeProximityDriver, GEOM_BaseDriver) +}; + +#endif diff --git a/src/GEOMImpl/GEOMImpl_Types.hxx b/src/GEOMImpl/GEOMImpl_Types.hxx index af37b6dcf..808ca4b86 100644 --- a/src/GEOMImpl/GEOMImpl_Types.hxx +++ b/src/GEOMImpl/GEOMImpl_Types.hxx @@ -121,9 +121,11 @@ #define GEOM_EXTRACTION 58 -#define GEOM_CURVATURE_VEC 59 +#define GEOM_PATCH_FACE 59 -#define GEOM_PATCH_FACE 60 +#define GEOM_CURVATURE_VEC 60 + +#define GEOM_SHAPE_PROXIMITY 61 //GEOM_Function types @@ -363,6 +365,10 @@ #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 diff --git a/src/GEOM_I/GEOM_IMeasureOperations_i.cc b/src/GEOM_I/GEOM_IMeasureOperations_i.cc index 0c09e09c4..735929134 100644 --- a/src/GEOM_I/GEOM_IMeasureOperations_i.cc +++ b/src/GEOM_I/GEOM_IMeasureOperations_i.cc @@ -1243,3 +1243,97 @@ GEOM::GEOM_Object_ptr GEOM_IMeasureOperations_i::SurfaceCurvatureByPointAndDirec return GetObject(anObject); } + +//============================================================================= +/*! + * 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; +} diff --git a/src/GEOM_I/GEOM_IMeasureOperations_i.hh b/src/GEOM_I/GEOM_IMeasureOperations_i.hh index 6a5aa39ee..4f9551989 100644 --- a/src/GEOM_I/GEOM_IMeasureOperations_i.hh +++ b/src/GEOM_I/GEOM_IMeasureOperations_i.hh @@ -170,6 +170,15 @@ class GEOM_I_EXPORT GEOM_IMeasureOperations_i : GEOM::GEOM_Object_ptr thePoint, GEOM::GEOM_Object_ptr theDirection); + // 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(); } }; diff --git a/src/GEOM_SWIG/CMakeLists.txt b/src/GEOM_SWIG/CMakeLists.txt index 39f3ac6af..9c390544e 100644 --- a/src/GEOM_SWIG/CMakeLists.txt +++ b/src/GEOM_SWIG/CMakeLists.txt @@ -72,6 +72,7 @@ SET(_python_SCRIPTS geomBuilder.py gsketcher.py canonicalrecognition.py + proximity.py ) # Advanced scripts diff --git a/src/GEOM_SWIG/geomBuilder.py b/src/GEOM_SWIG/geomBuilder.py index 49115d58a..e7e8c5431 100644 --- a/src/GEOM_SWIG/geomBuilder.py +++ b/src/GEOM_SWIG/geomBuilder.py @@ -261,6 +261,7 @@ import functools from salome.geom.gsketcher import Sketcher3D, Sketcher2D, Polyline2D from salome.geom.canonicalrecognition import CanonicalRecognition +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 @@ -14036,6 +14037,22 @@ class geomBuilder(GEOM._objref_GEOM_Gen): RaiseIfFailed("Tesselate", self.TestOp) return r + + ## 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 index 000000000..d2296e120 --- /dev/null +++ b/src/GEOM_SWIG/proximity.py @@ -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 index 000000000..562310764 --- /dev/null +++ b/test/test_proximity_edge_edge.py @@ -0,0 +1,60 @@ +# 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) + +# create 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.9974949866) < 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 index 000000000..08e71d2b4 --- /dev/null +++ b/test/test_proximity_face_face.py @@ -0,0 +1,43 @@ +# 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) + +# create 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_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) + +# 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) diff --git a/test/tests.set b/test/tests.set index b87d630e2..5524eacbb 100644 --- a/test/tests.set +++ b/test/tests.set @@ -19,6 +19,8 @@ SET(ALL_TESTS test_perf_01.py + test_proximity_edge_edge.py + test_proximity_face_face.py ) IF(${OpenCASCADE_VERSION}.${OpenCASCADE_SP_VERSION} VERSION_GREATER "7.5.3.3") -- 2.39.2