Salome HOME
bos #29469: [EDF] (2022-T1) Advanced geometry features: Detect type of shape
authorvsv <vsv@opencascade.com>
Mon, 20 Jun 2022 09:31:26 +0000 (12:31 +0300)
committerjfa <jfa@opencascade.com>
Thu, 8 Sep 2022 15:48:39 +0000 (18:48 +0300)
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI.i
src/GeomAlgoAPI/GeomAlgoAPI_CanonicalRecognition.cpp [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_CanonicalRecognition.h [new file with mode: 0644]
src/GeomAlgoAPI/GeomAlgoAPI_swig.h
src/PythonAPI/Test/TestCR.py [new file with mode: 0644]
src/PythonAPI/geom/CanonicalRecognition.py [new file with mode: 0644]
src/PythonAPI/geom/__init__.py
src/PythonAPI/tests.set

index fef2d06fc794554f4a3898a4f96a830571f1e029..eec42e1bd193f8dd46c46c780ae498a57d6a56fe 100644 (file)
@@ -96,6 +96,7 @@ SET(PROJECT_HEADERS
     GeomAlgoAPI_NormalToFace.h
     GeomAlgoAPI_Tube.h
     GeomAlgoAPI_ShapeInfo.h
+       GeomAlgoAPI_CanonicalRecognition.h
 )
 
 SET(PROJECT_SOURCES
@@ -171,6 +172,7 @@ SET(PROJECT_SOURCES
     GeomAlgoAPI_NormalToFace.cpp
     GeomAlgoAPI_Tube.cpp
     GeomAlgoAPI_ShapeInfo.cpp
+       GeomAlgoAPI_CanonicalRecognition.cpp
 )
 
 SET(PROJECT_LIBRARIES
index 153bf5b89c040f6c15cde0a3a96062a9916de508..2524c6ce824671ec8a925c06a54f5af1ca0a5075 100644 (file)
@@ -34,6 +34,7 @@
 %include "std_string.i"
 %include "std_list.i"
 %include "std_shared_ptr.i"
+%include "std_vector.i"
 
 %exceptionclass GeomAlgoAPI_Exception;
 
   }
 }
 
+%typemap(out) std::list< std::shared_ptr< GeomAPI_Shape > >::value_type & {
+  $result = SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<GeomAPI_Shape>(*$1)), $descriptor(std::shared_ptr<GeomAPI_Shape> *), SWIG_POINTER_OWN | 0 );
+}
+
+%template(ShapeList) std::list<std::shared_ptr<GeomAPI_Shape> >;
+%template(ValuesList) std::list<GeomAlgoAPI_InfoValue>;
+%template(VectorOfDouble) std::vector<double>;
+
+%typemap(in) std::vector<double>& (std::vector<double> temp) {
+  if (PyList_Check($input)) {
+    for (Py_ssize_t i = 0; i < PyList_Size($input); ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      if (PyNumber_Check(item)) {
+        temp.push_back(PyFloat_AsDouble(item));
+      } else {
+        PyErr_SetString(PyExc_TypeError, "argument must be double value.");
+        return NULL;
+      }
+      Py_DECREF(item);
+    }
+    $1 = &temp;
+  } else {
+    PyErr_SetString(PyExc_ValueError, "argument must be a list of double values.");
+    return NULL;
+  }
+}
+
+%typemap(argout) std::vector<double>& {
+    PyObject* outList = PyList_New(0);
+    int error;
+    std::vector<double>::iterator it;
+    for ( it=$1->begin() ; it != $1->end(); it++ )
+    {
+        error = PyList_Append(outList, PyFloat_FromDouble(*it));
+        if (error)
+            SWIG_fail;
+    }
+    if ((!$result) || ($result == Py_None)) {
+        $result = outList;
+    } else {
+        PyObject *aObj1, *aObj2;
+        if (!PyTuple_Check($result)) {
+            PyObject* aObj = $result;
+            $result = PyTuple_New(1);
+            PyTuple_SetItem($result,0,aObj);
+        }
+        aObj2 = PyTuple_New(1);
+        PyTuple_SetItem(aObj2,0,outList);
+        aObj1 = $result;
+        $result = PySequence_Concat(aObj1,aObj2);
+        Py_DECREF(aObj1);
+        Py_DECREF(aObj2);
+    }
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) std::vector<double>, const std::vector<double>& {
+  if (PyTuple_Check($input)) {
+    for (Py_ssize_t i = 0; i < PyTuple_Size($input); ++i) {
+      PyObject * item = PySequence_GetItem($input, i);
+      if (PyNumber_Check(item)) {
+        $1 = 1;
+      } else {
+        $1 = 0;
+        break;
+      }
+      Py_DECREF(item);
+    }
+  } else {
+    $1 = 0;
+  }
+}
+
+%typemap(in) double& (double temp) {
+  if (PyFloat_Check($input)) {
+    temp = PyFloat_AsDouble($input);
+    $1 = &temp;
+  } else {
+    PyErr_SetString(PyExc_ValueError, "argument must be a double value.");
+    return NULL;
+  }
+}
+
+%typemap(argout) double& {
+    if ((!$result) || ($result == Py_None)) {
+        $result = PyFloat_FromDouble(*$1);
+    } else {
+        PyObject *aObj1, *aObj2;
+        if (!PyTuple_Check($result)) {
+            PyObject* aObj = $result;
+            $result = PyTuple_New(1);
+            PyTuple_SetItem($result,0,aObj);
+        }
+        aObj2 = PyTuple_New(1);
+        PyTuple_SetItem(aObj2,0,PyFloat_FromDouble(*$1));
+        aObj1 = $result;
+        $result = PySequence_Concat(aObj1,aObj2);
+        Py_DECREF(aObj1);
+        Py_DECREF(aObj2);
+    }
+}
+
 // shared pointers
 %shared_ptr(GeomAlgoAPI_Boolean)
 %shared_ptr(GeomAlgoAPI_Intersection)
 %include "GeomAlgoAPI_Box.h"
 %include "GeomAlgoAPI_MapShapesAndAncestors.h"
 %include "GeomAlgoAPI_ShapeInfo.h"
-
-%typemap(out) std::list< std::shared_ptr< GeomAPI_Shape > >::value_type & {
-  $result = SWIG_NewPointerObj(SWIG_as_voidptr(new std::shared_ptr<GeomAPI_Shape>(*$1)), $descriptor(std::shared_ptr<GeomAPI_Shape> *), SWIG_POINTER_OWN | 0 );
-}
-%template(ShapeList) std::list<std::shared_ptr<GeomAPI_Shape> >;
-%template(ValuesList) std::list<GeomAlgoAPI_InfoValue>;
+%include "GeomAlgoAPI_CanonicalRecognition.h"
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_CanonicalRecognition.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_CanonicalRecognition.cpp
new file mode 100644 (file)
index 0000000..dc93558
--- /dev/null
@@ -0,0 +1,441 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "GeomAlgoAPI_CanonicalRecognition.h"
+
+#include <Standard_Version.hxx>
+// code from KERNEL_SRC/src/Basics/Basics_OCCTVersion.hxx
+#ifdef OCC_VERSION_SERVICEPACK
+#  define OCC_VERSION_LARGE (OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8 | OCC_VERSION_SERVICEPACK)
+#else
+#  ifdef OCC_VERSION_DEVELOPMENT
+#    define OCC_VERSION_LARGE ((OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8)-1)
+#  else
+#    define OCC_VERSION_LARGE (OCC_VERSION_MAJOR << 24 | OCC_VERSION_MINOR << 16 | OCC_VERSION_MAINTENANCE << 8)
+#  endif
+#endif
+
+#if OCC_VERSION_LARGE > 0x07050303
+#include <ShapeAnalysis_CanonicalRecognition.hxx>
+#endif
+
+#include <TopoDS_Shape.hxx>
+
+#include <gp_Pln.hxx>
+#include <gp_Sphere.hxx>
+#include <gp_Cone.hxx>
+#include <gp_Cylinder.hxx>
+#include <gp_Circ.hxx>
+#include <gp_Elips.hxx>
+
+static bool isValidDirection(const std::vector<double>& theDir)
+{
+  return (theDir.size() == 3) && (gp_Vec(theDir[0], theDir[1], theDir[2]).Magnitude() > 0.);
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isPlane(const GeomShapePtr& theShape, double theTolerance,
+  std::vector<double>& theNormal, std::vector<double>& theOrigin)
+{
+  if (!theShape.get())
+    return false;
+
+  const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  bool aIsValidNormal = isValidDirection(theNormal);
+  bool aIsValidOrigin = theOrigin.size() == 3;
+  gp_Pln aPln;
+  if (aIsValidNormal && aIsValidOrigin) {
+    aPln = gp_Pln(gp_Pnt(theOrigin[0], theOrigin[1], theOrigin[2]),
+      gp_Dir(theNormal[0], theNormal[1], theNormal[2]));
+  }
+
+  bool aResult = false;
+
+#if OCC_VERSION_LARGE > 0x07050303
+  ShapeAnalysis_CanonicalRecognition aRecognition(aShape);
+  try {
+    if (aRecognition.GetStatus() == 0)
+      aResult = aRecognition.IsPlane(theTolerance, aPln);
+  }
+  catch (...) {
+    return false;
+  }
+#endif
+
+  gp_Pnt aOrig = aPln.Location();
+  if (theOrigin.size() != 3)
+    theOrigin.resize(3);
+  theOrigin[0] = aOrig.X();
+  theOrigin[1] = aOrig.Y();
+  theOrigin[2] = aOrig.Z();
+
+  gp_Dir aNorm = aPln.Axis().Direction();
+  if (theNormal.size() != 3)
+    theNormal.resize(3);
+  theNormal[0] = aNorm.X();
+  theNormal[1] = aNorm.Y();
+  theNormal[2] = aNorm.Z();
+
+  return aResult;
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isSphere(const GeomShapePtr& theShape, double theTolerance,
+  std::vector<double>& theOrigin, double& theRadius)
+{
+  if (!theShape.get())
+    return false;
+
+  const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  bool aIsValidOrigin = theOrigin.size() == 3;
+  bool aIsValidRadius = theRadius > 0;
+  gp_Sphere aSphere;
+  if (aIsValidOrigin && aIsValidRadius)
+  {
+    aSphere.SetLocation(gp_Pnt(theOrigin[0], theOrigin[1], theOrigin[2]));
+    aSphere.SetRadius(theRadius);
+  }
+  else
+    aSphere.SetRadius(1.0);
+
+  bool aResult = false;
+
+#if OCC_VERSION_LARGE > 0x07050303
+  ShapeAnalysis_CanonicalRecognition aRecognition(aShape);
+  try {
+    if (aRecognition.GetStatus() == 0)
+      aResult = aRecognition.IsSphere(theTolerance, aSphere);
+  }
+  catch (...) {
+    return false;
+  }
+#endif
+
+  gp_Pnt aLoc = aSphere.Location();
+  if (theOrigin.size() != 3)
+    theOrigin.resize(3);
+  theOrigin[0] = aLoc.X();
+  theOrigin[1] = aLoc.Y();
+  theOrigin[2] = aLoc.Z();
+  theRadius = aSphere.Radius();
+
+  return aResult;
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isCone(const GeomShapePtr& theShape, double theTolerance,
+  std::vector<double>& theAxis, std::vector<double>& theApex,
+  double& theHalfAngle)
+{
+  if (!theShape.get())
+    return false;
+
+  const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  bool aIsValidAxis = isValidDirection(theAxis);
+  bool aIsValidApex = theApex.size() == 3;
+  bool aIsValidAngle = theHalfAngle > 0;
+  gp_Cone aCone;
+  if (aIsValidAxis && aIsValidApex && aIsValidAngle)
+  {
+    gp_Pnt aLoc(theApex[0], theApex[1], theApex[2]);
+    gp_Ax3 aAx3(aLoc, gp_Dir(theAxis[0], theAxis[1], theAxis[2]));
+    aCone.SetPosition(aAx3);
+  }
+  else
+    aCone.SetRadius(1.0);
+
+  bool aResult = false;
+
+#if OCC_VERSION_LARGE > 0x07050303
+  ShapeAnalysis_CanonicalRecognition aRecognition(aShape);
+  try {
+    if (aRecognition.GetStatus() == 0)
+      aResult = aRecognition.IsCone(theTolerance, aCone);
+  }
+  catch (...) {
+    return false;
+  }
+#endif
+
+  gp_Dir aDir = aCone.Axis().Direction();
+  if (theAxis.size() != 3)
+    theAxis.resize(3);
+  theAxis[0] = aDir.X();
+  theAxis[1] = aDir.Y();
+  theAxis[2] = aDir.Z();
+
+  gp_Pnt aApex = aCone.Apex();
+  if (theApex.size() != 3)
+    theApex.resize(3);
+  theApex[0] = aApex.X();
+  theApex[1] = aApex.Y();
+  theApex[2] = aApex.Z();
+
+  theHalfAngle = aCone.SemiAngle();
+
+  return aResult;
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isCylinder(const GeomShapePtr& theShape, double theTolerance,
+  std::vector<double>& theAxis, std::vector<double>& theOrigin,
+  double& theRadius)
+{
+  if (!theShape.get())
+    return false;
+
+  const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  bool aIsValidAxis = isValidDirection(theAxis);
+  bool aIsValidOrigin = theOrigin.size() == 3;
+  bool aIsValidRadius = theRadius > 0;
+  gp_Cylinder aCylinder;
+  if (aIsValidAxis && aIsValidOrigin && aIsValidRadius)
+  {
+    gp_Pnt aLoc(theOrigin[0], theOrigin[0], theOrigin[0]);
+    gp_Ax3 aAx3(aLoc, gp_Dir(theAxis[0], theAxis[1], theAxis[2]));
+    aCylinder.SetPosition(aAx3);
+    aCylinder.SetRadius(theRadius);
+  }
+  else
+    aCylinder.SetRadius(1.0);
+
+  bool aResult = false;
+
+#if OCC_VERSION_LARGE > 0x07050303
+  ShapeAnalysis_CanonicalRecognition aRecognition(aShape);
+  try {
+    if (aRecognition.GetStatus() == 0)
+      aResult = aRecognition.IsCylinder(theTolerance, aCylinder);
+  }
+  catch (...) {
+    return false;
+  }
+#endif
+
+  gp_Dir aDir = aCylinder.Axis().Direction();
+  if (theAxis.size() != 3)
+    theAxis.resize(3);
+  theAxis[0] = aDir.X();
+  theAxis[1] = aDir.Y();
+  theAxis[2] = aDir.Z();
+
+  gp_Pnt aLoc = aCylinder.Location();
+  if (theOrigin.size() != 3)
+    theOrigin.resize(3);
+  theOrigin[0] = aLoc.X();
+  theOrigin[1] = aLoc.Y();
+  theOrigin[2] = aLoc.Z();
+
+  theRadius = aCylinder.Radius();
+
+  return aResult;
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isLine(const GeomShapePtr& theEdge, double theTolerance,
+  std::vector<double>& theDir, std::vector<double>& theOrigin)
+{
+  if (!theEdge.get())
+    return false;
+
+  const TopoDS_Shape& aShape = theEdge->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  bool aIsValidDir = isValidDirection(theDir);
+  bool aIsValidOrigin = theOrigin.size() == 3;
+  gp_Lin aLine;
+  if (aIsValidDir && aIsValidOrigin)
+  {
+    aLine.SetLocation(gp_Pnt(theOrigin[0], theOrigin[1], theOrigin[2]));
+    aLine.SetDirection(gp_Dir(theDir[0], theDir[1], theDir[2]));
+  }
+
+  bool aResult = false;
+
+#if OCC_VERSION_LARGE > 0x07050303
+  ShapeAnalysis_CanonicalRecognition aRecognition(aShape);
+  try {
+    if (aRecognition.GetStatus() == 0)
+      aResult = aRecognition.IsLine(theTolerance, aLine);
+  }
+  catch (...) {
+    return false;
+  }
+#endif
+
+  gp_Pnt aLoc = aLine.Location();
+  if (theOrigin.size() != 3)
+    theOrigin.resize(3);
+  theOrigin[0] = aLoc.X();
+  theOrigin[1] = aLoc.Y();
+  theOrigin[2] = aLoc.Z();
+
+  gp_Dir aDir = aLine.Direction();
+  if (theDir.size() != 3)
+    theDir.resize(3);
+  theDir[0] = aDir.X();
+  theDir[1] = aDir.Y();
+  theDir[2] = aDir.Z();
+
+  return aResult;
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isCircle(const GeomShapePtr& theEdge, double theTolerance,
+  std::vector<double>& theNormal, std::vector<double>& theOrigin,
+  double& theRadius)
+{
+  if (!theEdge.get())
+    return false;
+
+  const TopoDS_Shape& aShape = theEdge->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  bool aIsValidNormal = isValidDirection(theNormal);
+  bool aIsValidOrigin = theOrigin.size() == 3;
+  bool aIsValidRadius = theRadius > 0;
+  gp_Circ aCircle;
+  if (aIsValidNormal && aIsValidOrigin && aIsValidRadius)
+  {
+    gp_Ax2 aAx2(gp_Pnt(theOrigin[0], theOrigin[1], theOrigin[2]),
+      gp_Dir(theNormal[0], theNormal[1], theNormal[2]));
+    aCircle.SetPosition(aAx2);
+    aCircle.SetRadius(theRadius);
+  }
+  else
+    aCircle.SetRadius(1.0);
+
+  bool aResult = false;
+
+#if OCC_VERSION_LARGE > 0x07050303
+  ShapeAnalysis_CanonicalRecognition aRecognition(aShape);
+  try {
+    if (aRecognition.GetStatus() == 0)
+      aResult = aRecognition.IsCircle(theTolerance, aCircle);
+  }
+  catch (...) {
+    return false;
+  }
+#endif
+
+  gp_Pnt aLoc = aCircle.Location();
+  if (theOrigin.size() != 3)
+    theOrigin.resize(3);
+  theOrigin[0] = aLoc.X();
+  theOrigin[1] = aLoc.Y();
+  theOrigin[2] = aLoc.Z();
+
+  gp_Dir aDir = aCircle.Axis().Direction();
+  if (theNormal.size() != 3)
+    theNormal.resize(3);
+  theNormal[0] = aDir.X();
+  theNormal[1] = aDir.Y();
+  theNormal[2] = aDir.Z();
+  theRadius = aCircle.Radius();
+  return aResult;
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isEllipse(const GeomShapePtr& theEdge, double theTolerance,
+  std::vector<double>& theNormal, std::vector<double>& theDirX,
+  std::vector<double>& theOrigin,
+  double& theMajorRadius, double& theMinorRadius)
+{
+  if (!theEdge.get())
+    return false;
+
+  const TopoDS_Shape& aShape = theEdge->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  bool aIsValidNormal = isValidDirection(theNormal);
+  bool aIsValidOrigin = theOrigin.size() == 3;
+  bool aIsValidDirX = isValidDirection(theDirX);
+  bool aIsValidRad1 = (theMajorRadius > 0) && (theMajorRadius > theMinorRadius);
+  bool aIsValidRad2 = (theMinorRadius > 0) && (theMajorRadius > theMinorRadius);
+
+  gp_Elips aElips;
+  if (aIsValidNormal && aIsValidOrigin && aIsValidDirX && aIsValidRad1 && aIsValidRad2)
+  {
+    gp_Pnt anOrigin(theOrigin[0], theOrigin[1], theOrigin[2]);
+    gp_XYZ aNormal(theNormal[0], theNormal[1], theNormal[2]);
+    gp_XYZ aDirX(theDirX[0], theDirX[1], theDirX[2]);
+    Standard_Boolean isCollinear =
+        aNormal.CrossSquareMagnitude(aDirX) < Precision::SquareConfusion();
+    gp_Ax2 aAx2 = isCollinear ? gp_Ax2(anOrigin, aNormal) : gp_Ax2(anOrigin, aNormal, aDirX);
+    aElips = gp_Elips(aAx2, theMajorRadius, theMinorRadius);
+  }
+  else
+    aElips.SetMajorRadius(1.0);
+
+  bool aResult = false;
+
+#if OCC_VERSION_LARGE > 0x07050303
+  ShapeAnalysis_CanonicalRecognition aRecognition(aShape);
+  try {
+    if (aRecognition.GetStatus() == 0)
+      aResult = aRecognition.IsEllipse(theTolerance, aElips);
+  }
+  catch (...) {
+    return false;
+  }
+#endif
+
+  gp_Pnt aLoc = aElips.Position().Location();
+  if (theOrigin.size() != 3)
+    theOrigin.resize(3);
+  theOrigin[0] = aLoc.X();
+  theOrigin[1] = aLoc.Y();
+  theOrigin[2] = aLoc.Z();
+
+  gp_Dir aNorm = aElips.Position().Direction();
+  if (theNormal.size() != 3)
+    theNormal.resize(3);
+  theNormal[0] = aNorm.X();
+  theNormal[1] = aNorm.Y();
+  theNormal[2] = aNorm.Z();
+
+  gp_Dir aDirX = aElips.Position().XDirection();
+  if (theDirX.size() != 3)
+    theDirX.resize(3);
+  theDirX[0] = aDirX.X();
+  theDirX[1] = aDirX.Y();
+  theDirX[2] = aDirX.Z();
+
+  theMajorRadius = aElips.MajorRadius();
+  theMinorRadius = aElips.MinorRadius();
+
+  return aResult;
+}
+
+bool GeomAlgoAPI_CanonicalRecognition::isImplemented()
+{
+#if OCC_VERSION_LARGE > 0x07050303
+  return true;
+#else
+  return false;
+#endif
+}
diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_CanonicalRecognition.h b/src/GeomAlgoAPI/GeomAlgoAPI_CanonicalRecognition.h
new file mode 100644 (file)
index 0000000..6efddfa
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifndef GeomAlgoAPI_CanonicalRecognition_H_
+#define GeomAlgoAPI_CanonicalRecognition_H_
+
+#include "GeomAlgoAPI.h"
+#include <GeomAPI_Shape.h>
+
+#include <vector>
+
+class GeomAlgoAPI_CanonicalRecognition
+{
+public:
+  /*!
+   *  \brief Check if the shape is planar
+   */
+  GEOMALGOAPI_EXPORT static bool isPlane(const GeomShapePtr& theShape, double theTolerance,
+    std::vector<double>& theNormal, std::vector<double>& theOrigin);
+
+  /*!
+   * \brief Check if shape is spherical
+   */
+  GEOMALGOAPI_EXPORT static bool isSphere(const GeomShapePtr& theShape, double theTolerance,
+    std::vector<double>& theOrigin, double& theRadius);
+
+  /*!
+   * \brief Check if shape is conical
+   */
+  GEOMALGOAPI_EXPORT static bool isCone(const GeomShapePtr& theShape, double theTolerance,
+    std::vector<double>& theAxis, std::vector<double>& theApex,
+    double& theHalfAngle);
+
+  /*!
+   * \brief Check if shape is cylinder
+   */
+  GEOMALGOAPI_EXPORT static bool isCylinder(const GeomShapePtr& theShape, double theTolerance,
+    std::vector<double>& theAxis, std::vector<double>& theOrigin,
+    double& theRadius);
+
+  /*!
+   * \brief Check if edge / wire is line
+   */
+  GEOMALGOAPI_EXPORT static bool isLine(const GeomShapePtr& theEdge, double theTolerance,
+    std::vector<double>& theDir, std::vector<double>& theOrigin);
+
+  /*!
+   * \brief Check if edge / wire is circle
+   */
+  GEOMALGOAPI_EXPORT static bool isCircle(const GeomShapePtr& theEdge, double theTolerance,
+    std::vector<double>& theNormal, std::vector<double>& theOrigin,
+    double& theRadius);
+
+  /*!
+   * \brief Check if edge / wire is ellipse
+   */
+  GEOMALGOAPI_EXPORT static bool isEllipse(const GeomShapePtr& theEdge, double theTolerance,
+    std::vector<double>& theNormal, std::vector<double>& theDirX,
+    std::vector<double>& theOrigin,
+    double& theMajorRadius, double& theMinorRadius);
+
+  /*!
+   * \brief Check if the algorithm is implemented (Shaper is built with appropriate OCCT version)
+   */
+  GEOMALGOAPI_EXPORT static bool isImplemented();
+
+};
+
+#endif
index a3be80588ab9a909a6603235ed2f4dc0a689458c..d628b267a41b3e57947199ce1319b3cd7019ce32 100644 (file)
@@ -64,6 +64,7 @@
   #include "GeomAlgoAPI_Symmetry.h"
   #include "GeomAlgoAPI_MapShapesAndAncestors.h"
   #include "GeomAlgoAPI_ShapeInfo.h"
+  #include "GeomAlgoAPI_CanonicalRecognition.h"
 
   #include <memory>
   #include <string>
diff --git a/src/PythonAPI/Test/TestCR.py b/src/PythonAPI/Test/TestCR.py
new file mode 100644 (file)
index 0000000..634275b
--- /dev/null
@@ -0,0 +1,118 @@
+# Copyright (C) 2014-2022  CEA/DEN, EDF R&D
+#
+# 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
+#
+
+from salome.shaper import model, geom
+
+def isCRImplemented():
+    CR = geom.CanonicalRecognition()
+    return CR.isImplemented()
+
+def GetShapeType(theShape):
+    CR = geom.CanonicalRecognition()
+    if CR.isLine(theShape, 0.1)[0]:
+        return "Line"
+    if CR.isPlane(theShape, 0.1)[0]:
+        if CR.isCircle(theShape, 0.1)[0]:
+            return ("Plane","Circle")
+        if CR.isEllipse(theShape, 0.1)[0]:
+            return ("Plane","Ellipse")
+        return "Plane"
+    if CR.isSphere(theShape, 0.1)[0]:
+        return "Sphere"
+    if CR.isCone(theShape, 0.1)[0]:
+        return "Cone"
+    if CR.isCylinder(theShape, 0.1)[0]:
+        return "Cylinder"
+    return "Not defined"
+
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create Cylinder
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+
+### Create Shell
+Plane_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Cylinder_1_1/Face_2")])
+
+### Create Recover
+Recover_1 = model.addRecover(Part_1_doc, Plane_1, [Cylinder_1.result()])
+
+### Create Shell
+Shell_2 = model.addShell(Part_1_doc, [model.selection("FACE", "Recover_1_1/Modified_Face&Cylinder_1_1/Face_1")])
+
+### Create Wire
+Circle_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "[Recover_1_1/Modified_Face&Cylinder_1_1/Face_1][new_weak_name_2]")], False)
+
+### Create Recover
+Recover_2 = model.addRecover(Part_1_doc, Circle_1, [Shell_2.result()])
+
+### Create Edge
+Line_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "(Recover_2_1/Modified_Edge&Wire_1_1/Edge)")], False)
+
+### Create Recover
+Cylinder_3 = model.addRecover(Part_1_doc, Line_1, [Recover_2.result()])
+
+### Create Sphere
+Sphere_1 = model.addSphere(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), 10)
+SphereShell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Sphere_1_1/Face_1")])
+
+### Create Cone
+Cone_1 = model.addCone(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 10, 0, 10)
+ConeShell_1 = model.addShell(Part_1_doc, [model.selection("FACE", "Cone_1_1/Face_1")])
+
+### Create Sketch
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+
+### Create SketchProjection
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+
+### Create SketchEllipse
+SketchEllipse_1 = Sketch_1.addEllipse(-37.39690313669599, -52.92905511857006, 61.08141071866921, -16.40734649833807, 41.5747486523393)
+[SketchPoint_2, SketchPoint_3, SketchPoint_4, SketchPoint_5, SketchPoint_6, SketchPoint_7, SketchPoint_8, SketchLine_1, SketchLine_2] = SketchEllipse_1.construction(center = "aux", firstFocus = "aux", secondFocus = "aux", majorAxisStart = "aux", majorAxisEnd = "aux", minorAxisStart = "aux", minorAxisEnd = "aux", majorAxis = "aux", minorAxis = "aux")
+model.do()
+
+### Create Wire
+EllipseWire_1 = model.addWire(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchEllipse_1")], False)
+
+model.end()
+
+### Get shapes for tests
+aPlaneShape = Plane_1.defaultResult().shape()
+aCircleShape = Circle_1.defaultResult().shape()
+aLineShape = Line_1.defaultResult().shape()
+aCylinderShape = Cylinder_3.defaultResult().shape()
+aSphereShape = SphereShell_1.defaultResult().shape()
+aConeShape = ConeShell_1.defaultResult().shape()
+aEllipseShape = EllipseWire_1.defaultResult().shape()
+
+### Check shapes types
+if isCRImplemented():
+    assert (GetShapeType(aPlaneShape) == "Plane")
+    assert (GetShapeType(aCircleShape)[1] == "Circle")
+    assert (GetShapeType(aLineShape) == "Line")
+    assert (GetShapeType(aCylinderShape) == "Cylinder")
+    assert (GetShapeType(aSphereShape) == "Sphere")
+    assert (GetShapeType(aConeShape) == "Cone")
+    assert (GetShapeType(aEllipseShape)[1] == "Ellipse")
diff --git a/src/PythonAPI/geom/CanonicalRecognition.py b/src/PythonAPI/geom/CanonicalRecognition.py
new file mode 100644 (file)
index 0000000..44b0255
--- /dev/null
@@ -0,0 +1,85 @@
+# 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
+#
+
+from GeomAlgoAPI import GeomAlgoAPI_CanonicalRecognition
+
+class CanonicalRecognition:
+    "The class provides recognition of canonical shapes"
+
+    def isPlane(self, shape, tolerance, normal = [], origin = []):
+        """
+        Check if shape is planar
+        Usage:
+        > CR.isPlane(shape, tolerance, normal, origin)
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isPlane(shape, tolerance, normal, origin)
+
+    def isSphere(self, shape, tolerance, origin = [], radius = 0.0):
+        """
+        Check if shape is spherical
+        Usage:
+        > CR.isSphere(shape, tolerance, origin, radius)
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isSphere(shape, tolerance, origin, radius)
+
+    def isCone(self, shape, tolerance, axis = [], apex = [], halfAngle = 0.0):
+        """
+        Check if shape is conical
+        Usage:
+        > CR.isCone(shape, tolerance, axis, apex, halfAngle)
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isCone(shape, tolerance, axis, apex, halfAngle)
+
+    def isCylinder(self, shape, tolerance, axis = [], origin = [], radius = 0.0):
+        """
+        Check if shape is cylinder
+        Usage:
+        > CR.isCylinder(shape, tolerance, axis, origin, radius)
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isCylinder(shape, tolerance, axis, origin, radius)
+
+    def isLine(self, edge, tolerance, direction = [], origin = []):
+        """
+        Check if edge/wire is line
+        Usage:
+        > CR.isLine(edge, tolerance, direction, origin)
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isLine(edge, tolerance, direction, origin)
+
+    def isCircle(self, edge, tolerance, normal = [], origin = [], radius = 0.0):
+        """
+        Check if edge/wire is circle
+        Usage:
+        > CR.isCircle(edge, tolerance, normal, origin, radius)
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isCircle(edge, tolerance, normal, origin, radius)
+
+    def isEllipse(self, edge, tolerance, normal = [], dirX = [], origin = [], majorRadius = 0.0, minorRadius = 0.0):
+        """
+        Check if edge/wire is ellipse
+        Usage:
+        > CR.isEllipse(edge, tolerance, normal, dirX, origin, majorRadius, minorRadius)
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isEllipse(edge, tolerance, normal, dirX, origin, majorRadius, minorRadius)
+
+    def isImplemented(self):
+        """
+        Check if the CanonicalRecognition is implemented (built with appropriate OCCT version)
+        Usage:
+        > CR.isImplemented()
+        """
+        return GeomAlgoAPI_CanonicalRecognition.isImplemented()
index 00475f940a049733c995cd31ae151ced76935383..ef2c426fa176e71976ad7a410ffa489046270d56 100644 (file)
@@ -39,3 +39,4 @@ from GeomAPI import GeomAPI_Shape  as Shape
 from GeomAlgoAPI import GeomAlgoAPI_Boolean   as Boolean
 
 from .ShapeInfo import *
+from .CanonicalRecognition import *
index 510f66d07532ec560fc8126d63d60e28fff0bfbc..d877f34f2e06229237b4abcd5a17def6a8f68df6 100644 (file)
@@ -52,4 +52,6 @@ SET(TEST_NAMES
   TestShapeInfo.py
 
   Test2044.py
+
+  TestCR.py
 )