]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Task 2.8. Measurement functions
authorazv <azv@opencascade.com>
Tue, 29 May 2018 10:32:34 +0000 (13:32 +0300)
committerazv <azv@opencascade.com>
Tue, 29 May 2018 11:22:47 +0000 (14:22 +0300)
Implement feature to compute length, distance, radius or angle.

32 files changed:
src/FeaturesAPI/CMakeLists.txt
src/FeaturesAPI/FeaturesAPI.i
src/FeaturesAPI/FeaturesAPI_Measurement.cpp [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_Measurement.h [new file with mode: 0644]
src/FeaturesAPI/FeaturesAPI_swig.h
src/FeaturesPlugin/CMakeLists.txt
src/FeaturesPlugin/FeaturesPlugin_Measurement.cpp [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Measurement.h [new file with mode: 0644]
src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.h
src/FeaturesPlugin/Test/TestMeasurementAngle.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestMeasurementDistance.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestMeasurementLength.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestMeasurementRadius.py [new file with mode: 0644]
src/FeaturesPlugin/icons/edge.png [new file with mode: 0644]
src/FeaturesPlugin/icons/meas_angle_32x32.png [new file with mode: 0644]
src/FeaturesPlugin/icons/meas_distance_32x32.png [new file with mode: 0644]
src/FeaturesPlugin/icons/meas_length_32x32.png [new file with mode: 0644]
src/FeaturesPlugin/icons/meas_radius_32x32.png [new file with mode: 0644]
src/FeaturesPlugin/icons/measurement.png [new file with mode: 0644]
src/FeaturesPlugin/measurement_widget.xml [new file with mode: 0644]
src/FeaturesPlugin/plugin-Features.xml
src/GeomAPI/CMakeLists.txt
src/GeomAPI/GeomAPI_Angle.cpp [new file with mode: 0644]
src/GeomAPI/GeomAPI_Angle.h [new file with mode: 0644]
src/GeomAPI/GeomAPI_Angle2d.h
src/GeomAPI/GeomAPI_Edge.h
src/GeomAPI/GeomAPI_Face.h
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.h
src/PythonAPI/model/features/__init__.py

index 1c549224202d4f881ecb6d847c8bad37a59ac8b4..83e853688b8a54f2efe19def56dfe5c474a0c7a4 100644 (file)
@@ -27,6 +27,7 @@ SET(PROJECT_HEADERS
   FeaturesAPI_ExtrusionBoolean.h
   FeaturesAPI_Fillet.h
   FeaturesAPI_Intersection.h
+  FeaturesAPI_Measurement.h
   FeaturesAPI_MultiRotation.h
   FeaturesAPI_MultiTranslation.h
   FeaturesAPI_Partition.h
@@ -49,6 +50,7 @@ SET(PROJECT_SOURCES
   FeaturesAPI_ExtrusionBoolean.cpp
   FeaturesAPI_Fillet.cpp
   FeaturesAPI_Intersection.cpp
+  FeaturesAPI_Measurement.cpp
   FeaturesAPI_MultiRotation.cpp
   FeaturesAPI_MultiTranslation.cpp
   FeaturesAPI_Partition.cpp
index 62afc3e4889829499a60f6e0870b7319d3ffee73..01d1c9197b4239835df6ef0ef6ea6b9a706dfc53 100644 (file)
@@ -69,6 +69,7 @@
 %include "FeaturesAPI_ExtrusionBoolean.h"
 %include "FeaturesAPI_Fillet.h"
 %include "FeaturesAPI_Intersection.h"
+%include "FeaturesAPI_Measurement.h"
 %include "FeaturesAPI_MultiRotation.h"
 %include "FeaturesAPI_MultiTranslation.h"
 %include "FeaturesAPI_Partition.h"
diff --git a/src/FeaturesAPI/FeaturesAPI_Measurement.cpp b/src/FeaturesAPI/FeaturesAPI_Measurement.cpp
new file mode 100644 (file)
index 0000000..466aa01
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "FeaturesAPI_Measurement.h"
+
+#include <FeaturesPlugin_Measurement.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelHighAPI_Services.h>
+#include <ModelHighAPI_Tools.h>
+
+double measureLength(const std::shared_ptr<ModelAPI_Document>& thePart,
+                     const ModelHighAPI_Selection& theEdge)
+{
+  FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+  fillAttribute(FeaturesPlugin_Measurement::MEASURE_LENGTH(),
+                aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+  fillAttribute(theEdge, aMeasure->selection(FeaturesPlugin_Measurement::EDGE_FOR_LENGTH_ID()));
+  aMeasure->execute();
+
+  // obtain result
+  AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+      aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+  double aValue = aResult->size() ? aResult->value(0) : -1.0;
+
+  // perform removing macro feature Measurement
+  thePart->removeFeature(aMeasure);
+  apply();
+
+  return aValue;
+}
+
+double measureDistance(const std::shared_ptr<ModelAPI_Document>& thePart,
+                       const ModelHighAPI_Selection& theFrom,
+                       const ModelHighAPI_Selection& theTo)
+{
+  FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+  fillAttribute(FeaturesPlugin_Measurement::MEASURE_DISTANCE(),
+                aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+  fillAttribute(theFrom,
+                aMeasure->selection(FeaturesPlugin_Measurement::DISTANCE_FROM_OBJECT_ID()));
+  fillAttribute(theTo, aMeasure->selection(FeaturesPlugin_Measurement::DISTANCE_TO_OBJECT_ID()));
+  aMeasure->execute();
+
+  // obtain result
+  AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+      aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+  double aValue = aResult->size() ? aResult->value(0) : -1.0;
+
+  // perform removing macro feature Measurement
+  thePart->removeFeature(aMeasure);
+  apply();
+
+  return aValue;
+}
+
+double measureRadius(const std::shared_ptr<ModelAPI_Document>& thePart,
+                     const ModelHighAPI_Selection& theObject)
+{
+  FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+  fillAttribute(FeaturesPlugin_Measurement::MEASURE_RADIUS(),
+                aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+  fillAttribute(theObject, aMeasure->selection(FeaturesPlugin_Measurement::CIRCULAR_OBJECT_ID()));
+  aMeasure->execute();
+
+  // obtain result
+  AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+      aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+  double aValue = aResult->size() ? aResult->value(0) : -1.0;
+
+  // perform removing macro feature Measurement
+  thePart->removeFeature(aMeasure);
+  apply();
+
+  return aValue;
+}
+
+std::list<double> measureAngle(const std::shared_ptr<ModelAPI_Document>& thePart,
+                               const ModelHighAPI_Selection& theFrom,
+                               const ModelHighAPI_Selection& theTo)
+{
+  FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+  fillAttribute(FeaturesPlugin_Measurement::MEASURE_ANGLE(),
+                aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+  fillAttribute(theFrom, aMeasure->selection(FeaturesPlugin_Measurement::ANGLE_FROM_EDGE_ID()));
+  fillAttribute(theTo, aMeasure->selection(FeaturesPlugin_Measurement::ANGLE_TO_EDGE_ID()));
+  aMeasure->execute();
+
+  // obtain result
+  AttributeDoubleArrayPtr aResult = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+      aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID()));
+  std::list<double> aValues;
+  for (int i = 0, n = aResult->size(); i < n; ++i)
+    aValues.push_back(aResult->value(i));
+
+  // perform removing macro feature Measurement
+  thePart->removeFeature(aMeasure);
+  apply();
+
+  return aValues;
+}
diff --git a/src/FeaturesAPI/FeaturesAPI_Measurement.h b/src/FeaturesAPI/FeaturesAPI_Measurement.h
new file mode 100644 (file)
index 0000000..2712018
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef FeaturesAPI_Measurement_H_
+#define FeaturesAPI_Measurement_H_
+
+#include "FeaturesAPI.h"
+
+#include <list>
+#include <memory>
+
+class ModelAPI_Document;
+class ModelHighAPI_Selection;
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate length of the edge.
+FEATURESAPI_EXPORT
+double measureLength(const std::shared_ptr<ModelAPI_Document>& thePart,
+                     const ModelHighAPI_Selection& theEdge);
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate distance between objects.
+FEATURESAPI_EXPORT
+double measureDistance(const std::shared_ptr<ModelAPI_Document>& thePart,
+                       const ModelHighAPI_Selection& theFrom,
+                       const ModelHighAPI_Selection& theTo);
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate radius of circular.
+FEATURESAPI_EXPORT
+double measureRadius(const std::shared_ptr<ModelAPI_Document>& thePart,
+                     const ModelHighAPI_Selection& theObject);
+
+/// \ingroup CPPHighAPI
+/// \brief Calculate angle(s) between edges.
+FEATURESAPI_EXPORT
+std::list<double> measureAngle(const std::shared_ptr<ModelAPI_Document>& thePart,
+                               const ModelHighAPI_Selection& theFrom,
+                               const ModelHighAPI_Selection& theTo);
+
+#endif // FeaturesAPI_Measurement_H_
index 8b6ce0005d468d1366028a17764a6ba9a7fea3cd..a45b780ca99321045a6d45a2881e6da57641a75c 100644 (file)
@@ -29,6 +29,7 @@
   #include "FeaturesAPI_ExtrusionBoolean.h"
   #include "FeaturesAPI_Fillet.h"
   #include "FeaturesAPI_Intersection.h"
+  #include "FeaturesAPI_Measurement.h"
   #include "FeaturesAPI_MultiRotation.h"
   #include "FeaturesAPI_MultiTranslation.h"
   #include "FeaturesAPI_Partition.h"
index b0be8b41278ecdeba343131e49998b7b0d07c41d..ed5523231db41dedb98db313a44fbdac26acb69c 100644 (file)
@@ -52,6 +52,7 @@ SET(PROJECT_HEADERS
     FeaturesPlugin_MultiTranslation.h
     FeaturesPlugin_MultiRotation.h
     FeaturesPlugin_Fillet.h
+    FeaturesPlugin_Measurement.h
 )
 
 SET(PROJECT_SOURCES
@@ -84,6 +85,7 @@ SET(PROJECT_SOURCES
     FeaturesPlugin_MultiTranslation.cpp
     FeaturesPlugin_MultiRotation.cpp
     FeaturesPlugin_Fillet.cpp
+    FeaturesPlugin_Measurement.cpp
 )
 
 SET(XML_RESOURCES
@@ -109,6 +111,7 @@ SET(XML_RESOURCES
   multitranslation_widget.xml
   multirotation_widget.xml
   fillet_widget.xml
+  measurement_widget.xml
 )
 
 SET(TEXT_RESOURCES
@@ -219,6 +222,10 @@ ADD_UNIT_TESTS(TestExtrusion.py
                TestUnion4CurvedFaces.py
                TestUnion4Faces.py
                TestUnionOfUnion.py
+               TestMeasurementLength.py
+               TestMeasurementDistance.py
+               TestMeasurementRadius.py
+               TestMeasurementAngle.py
                Test1922.py
                Test1942.py
                Test1915.py
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Measurement.cpp b/src/FeaturesPlugin/FeaturesPlugin_Measurement.cpp
new file mode 100644 (file)
index 0000000..0082c2f
--- /dev/null
@@ -0,0 +1,253 @@
+// Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+//
+
+#include "FeaturesPlugin_Measurement.h"
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeSelection.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Session.h>
+
+#include <GeomAPI_Angle.h>
+#include <GeomAPI_Circ.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Face.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Shape.h>
+#include <GeomAPI_ShapeIterator.h>
+
+#include <GeomAlgoAPI_ShapeTools.h>
+
+#include <iomanip>
+#include <sstream>
+
+FeaturesPlugin_Measurement::FeaturesPlugin_Measurement()
+{
+}
+
+void FeaturesPlugin_Measurement::initAttributes()
+{
+  data()->addAttribute(FeaturesPlugin_Measurement::MEASURE_KIND(),
+                       ModelAPI_AttributeString::typeId());
+
+  // attribute for length
+  data()->addAttribute(EDGE_FOR_LENGTH_ID(), ModelAPI_AttributeSelection::typeId());
+  // attributes for distance
+  data()->addAttribute(DISTANCE_FROM_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+  data()->addAttribute(DISTANCE_TO_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+  // attribute for radius
+  data()->addAttribute(CIRCULAR_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
+  // attribute for angle
+  data()->addAttribute(ANGLE_FROM_EDGE_ID(), ModelAPI_AttributeSelection::typeId());
+  data()->addAttribute(ANGLE_TO_EDGE_ID(), ModelAPI_AttributeSelection::typeId());
+  // attribute for result message and values
+  data()->addAttribute(RESULT_ID(), ModelAPI_AttributeString::typeId());
+  data()->addAttribute(RESULT_VALUES_ID(), ModelAPI_AttributeDoubleArray::typeId());
+}
+
+void FeaturesPlugin_Measurement::execute()
+{
+}
+
+void FeaturesPlugin_Measurement::attributeChanged(const std::string& theID)
+{
+  if (theID == MEASURE_KIND()) {
+    // clear selected objects
+    selection(EDGE_FOR_LENGTH_ID())->reset();
+    selection(DISTANCE_FROM_OBJECT_ID())->reset();
+    selection(DISTANCE_TO_OBJECT_ID())->reset();
+    selection(CIRCULAR_OBJECT_ID())->reset();
+    selection(ANGLE_FROM_EDGE_ID())->reset();
+    selection(ANGLE_TO_EDGE_ID())->reset();
+    string(RESULT_ID())->setValue("");
+    std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
+        attribute(RESULT_VALUES_ID()))->setSize(0);
+  }
+  else if (theID != RESULT_ID()) {
+    std::string aKind = string(MEASURE_KIND())->value();
+    if (aKind == MEASURE_LENGTH())
+      computeLength();
+    else if (aKind == MEASURE_DISTANCE())
+      computeDistance();
+    else if (aKind == MEASURE_RADIUS())
+      computeRadius();
+    else if (aKind == MEASURE_ANGLE())
+      computeAngle();
+  }
+}
+
+void FeaturesPlugin_Measurement::computeLength()
+{
+  AttributeSelectionPtr aSelectedFeature = selection(EDGE_FOR_LENGTH_ID());
+
+  GeomShapePtr aShape;
+  GeomEdgePtr anEdge;
+  if (aSelectedFeature)
+    aShape = aSelectedFeature->value();
+  if (!aShape && aSelectedFeature->context())
+    aShape = aSelectedFeature->context()->shape();
+  if (aShape && aShape->isEdge())
+    anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
+  if (!anEdge)
+    return;
+
+  std::ostringstream anOutput;
+  anOutput << "Length = " << std::setprecision(10) << anEdge->length();
+  string(RESULT_ID())->setValue(anOutput.str());
+
+  AttributeDoubleArrayPtr aValues =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+  aValues->setSize(1);
+  aValues->setValue(0, anEdge->length());
+}
+
+void FeaturesPlugin_Measurement::computeDistance()
+{
+  AttributeSelectionPtr aFirstFeature = selection(DISTANCE_FROM_OBJECT_ID());
+  GeomShapePtr aShape1;
+  if (aFirstFeature)
+    aShape1 = aFirstFeature->value();
+  if (!aShape1 && aFirstFeature->context())
+    aShape1 = aFirstFeature->context()->shape();
+
+  AttributeSelectionPtr aSecondFeature = selection(DISTANCE_TO_OBJECT_ID());
+  GeomShapePtr aShape2;
+  if (aSecondFeature)
+    aShape2 = aSecondFeature->value();
+  if (!aShape2 && aSecondFeature->context())
+    aShape2 = aSecondFeature->context()->shape();
+
+  if (!aShape1 || !aShape2)
+    return;
+
+  double aDistance = GeomAlgoAPI_ShapeTools::minimalDistance(aShape1, aShape2);
+
+  std::ostringstream anOutput;
+  anOutput << "Distance = " << std::setprecision(10) << aDistance;
+  string(RESULT_ID())->setValue(anOutput.str());
+
+  AttributeDoubleArrayPtr aValues =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+  aValues->setSize(1);
+  aValues->setValue(0, aDistance);
+}
+
+void FeaturesPlugin_Measurement::computeRadius()
+{
+  AttributeSelectionPtr aSelectedFeature = selection(CIRCULAR_OBJECT_ID());
+
+  GeomShapePtr aShape;
+  if (aSelectedFeature)
+    aShape = aSelectedFeature->value();
+  if (!aShape && aSelectedFeature->context())
+    aShape = aSelectedFeature->context()->shape();
+
+  double aRadius = -1.0;
+  if (aShape) {
+    if (aShape->isEdge()) {
+      GeomEdgePtr anEdge(new GeomAPI_Edge(aShape));
+      if (anEdge->isCircle()) {
+        aRadius = anEdge->circle()->radius();
+      }
+    } else if (aShape->isFace()) {
+      GeomFacePtr aFace(new GeomAPI_Face(aShape));
+      aRadius = GeomAlgoAPI_ShapeTools::radius(aFace);
+    }
+  }
+
+  if (aRadius < 0.0)
+    return;
+
+  std::ostringstream anOutput;
+  anOutput << "Radius = " << std::setprecision(10) << aRadius;
+  string(RESULT_ID())->setValue(anOutput.str());
+
+  AttributeDoubleArrayPtr aValues =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+  aValues->setSize(1);
+  aValues->setValue(0, aRadius);
+}
+
+void FeaturesPlugin_Measurement::computeAngle()
+{
+  AttributeSelectionPtr aFirstFeature = selection(ANGLE_FROM_EDGE_ID());
+  GeomShapePtr aShape1;
+  GeomEdgePtr anEdge1;
+  if (aFirstFeature)
+    aShape1 = aFirstFeature->value();
+  if (!aShape1 && aFirstFeature->context())
+    aShape1 = aFirstFeature->context()->shape();
+  if (aShape1 && aShape1->isEdge())
+    anEdge1 = GeomEdgePtr(new GeomAPI_Edge(aShape1));
+
+
+  AttributeSelectionPtr aSecondFeature = selection(ANGLE_TO_EDGE_ID());
+  GeomShapePtr aShape2;
+  GeomEdgePtr anEdge2;
+  if (aSecondFeature)
+    aShape2 = aSecondFeature->value();
+  if (!aShape2 && aSecondFeature->context())
+    aShape2 = aSecondFeature->context()->shape();
+  if (aShape2 && aShape2->isEdge())
+    anEdge2 = GeomEdgePtr(new GeomAPI_Edge(aShape2));
+
+  if (!anEdge1 || !anEdge2)
+    return;
+
+  GeomShapePtr anInter = anEdge1->intersect(anEdge2);
+
+  std::ostringstream anOutput;
+  anOutput << std::setprecision(10);
+  std::list<double> aValuesList;
+  if (anInter) {
+    if (anInter->isVertex()) {
+      std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex(anInter));
+      std::shared_ptr<GeomAPI_Angle> anAngle(
+          new GeomAPI_Angle(anEdge1, anEdge2, aVertex->point()));
+      double anAngleValue = anAngle->angleDegree();
+      anOutput << "Angle = " << anAngleValue << std::endl;
+      aValuesList.push_back(anAngleValue);
+    }
+    else {
+      GeomAPI_ShapeIterator anIt(anInter);
+      for (int anIndex = 1; anIt.more(); anIt.next(), ++anIndex) {
+        GeomShapePtr aCurrent = anIt.current();
+        if (!aCurrent->isVertex())
+          continue;
+        std::shared_ptr<GeomAPI_Vertex> aVertex(new GeomAPI_Vertex(aCurrent));
+        std::shared_ptr<GeomAPI_Angle> anAngle(
+            new GeomAPI_Angle(anEdge1, anEdge2, aVertex->point()));
+        double anAngleValue = anAngle->angleDegree();
+        anOutput << "Angle" << anIndex << " = " << anAngleValue << std::endl;
+        aValuesList.push_back(anAngleValue);
+      }
+    }
+  }
+
+  string(RESULT_ID())->setValue(anOutput.str());
+
+  AttributeDoubleArrayPtr aValues =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+  aValues->setSize((int)aValuesList.size());
+  int anIndex = 0;
+  for (std::list<double>::iterator anIt = aValuesList.begin(); anIt != aValuesList.end(); ++anIt)
+    aValues->setValue(anIndex++, *anIt);
+}
diff --git a/src/FeaturesPlugin/FeaturesPlugin_Measurement.h b/src/FeaturesPlugin/FeaturesPlugin_Measurement.h
new file mode 100644 (file)
index 0000000..a358155
--- /dev/null
@@ -0,0 +1,171 @@
+// Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef FeaturesPlugin_Measurement_H_
+#define FeaturesPlugin_Measurement_H_
+
+#include "FeaturesPlugin.h"
+#include <ModelAPI_Feature.h>
+
+/// \class FeaturesPlugin_Measurement
+/// \ingroup Plugins
+/// \brief Feature for calculation metrics.
+///
+/// Supported following metrics:
+/// * length of edge,
+/// * distance between shapes,
+/// * radius of arc or cylindrical faces,
+/// * angle between edges.
+class FeaturesPlugin_Measurement : public ModelAPI_Feature
+{
+public:
+  /// Feature kind.
+  inline static const std::string& ID()
+  {
+    static const std::string MY_ID("Measurement");
+    return MY_ID;
+  }
+
+  /// \return the kind of a feature.
+  virtual const std::string& getKind()
+  {
+    return ID();
+  }
+
+  /// Attribute name for measurement method.
+  inline static const std::string& MEASURE_KIND()
+  {
+    static const std::string MY_MEASURE_KIND_ID("MeasureKind");
+    return MY_MEASURE_KIND_ID;
+  }
+
+  /// Attribute name for length measure.
+  inline static const std::string& MEASURE_LENGTH()
+  {
+    static const std::string MY_MEASURE_ID("Length");
+    return MY_MEASURE_ID;
+  }
+
+  /// Attribute name for distance measure.
+  inline static const std::string& MEASURE_DISTANCE()
+  {
+    static const std::string MY_MEASURE_ID("Distance");
+    return MY_MEASURE_ID;
+  }
+
+  /// Attribute name for radius measure.
+  inline static const std::string& MEASURE_RADIUS()
+  {
+    static const std::string MY_MEASURE_ID("Radius");
+    return MY_MEASURE_ID;
+  }
+
+  /// Attribute name for angle measure.
+  inline static const std::string& MEASURE_ANGLE()
+  {
+    static const std::string MY_MEASURE_ID("Angle");
+    return MY_MEASURE_ID;
+  }
+
+
+  /// Attribute name of edge selected for length calculation.
+  inline static const std::string& EDGE_FOR_LENGTH_ID()
+  {
+    static const std::string MY_EDGE_FOR_LENGTH_ID("edge_for_length");
+    return MY_EDGE_FOR_LENGTH_ID;
+  }
+
+  /// Attribute name of first shape selected for distance calculation.
+  inline static const std::string& DISTANCE_FROM_OBJECT_ID()
+  {
+    static const std::string MY_DISTANCE_FROM_OBJECT_ID("distance_from");
+    return MY_DISTANCE_FROM_OBJECT_ID;
+  }
+
+  /// Attribute name of second shape selected for distance calculation.
+  inline static const std::string& DISTANCE_TO_OBJECT_ID()
+  {
+    static const std::string MY_DISTANCE_TO_OBJECT_ID("distance_to");
+    return MY_DISTANCE_TO_OBJECT_ID;
+  }
+
+  // Attribute name of edge or face selected to calculate radius.
+  inline static const std::string& CIRCULAR_OBJECT_ID()
+  {
+    static const std::string MY_CIRCULAR_OBJECT_ID("circular");
+    return MY_CIRCULAR_OBJECT_ID;
+  }
+
+  /// Attribute name of first edge selected for angle calculation.
+  inline static const std::string& ANGLE_FROM_EDGE_ID()
+  {
+    static const std::string MY_ANGLE_FROM_EDGE_ID("angle_from");
+    return MY_ANGLE_FROM_EDGE_ID;
+  }
+
+  /// Attribute name of second shape selected for distance calculation.
+  inline static const std::string& ANGLE_TO_EDGE_ID()
+  {
+    static const std::string MY_ANGLE_TO_EDGE_ID("angle_to");
+    return MY_ANGLE_TO_EDGE_ID;
+  }
+
+  /// Attribute name for result.
+  inline static const std::string& RESULT_ID()
+  {
+    static const std::string MY_RESULT_ID("result");
+    return MY_RESULT_ID;
+  }
+
+  /// Attribute name for values of result.
+  inline static const std::string& RESULT_VALUES_ID()
+  {
+    static const std::string MY_RESULT_VALUES_ID("result_values");
+    return MY_RESULT_VALUES_ID;
+  }
+
+  /// Creates a new part document if needed
+  FEATURESPLUGIN_EXPORT virtual void execute();
+
+  /// Request for initialization of data model of the feature: adding all attributes
+  FEATURESPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Called on change of any argument-attribute of this object
+  /// \param theID identifier of changed attribute
+  FEATURESPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Reimplemented from ModelAPI_Feature::isMacro(). Returns true.
+  virtual bool isMacro() const { return true; }
+
+  /// Use plugin manager for features creation
+  FeaturesPlugin_Measurement();
+
+private:
+  /// Compute length of the edge
+  void computeLength();
+  /// Compute minimal distance between pair of shapes
+  void computeDistance();
+  /// Compute radius of circular edge or cylindrical face
+  void computeRadius();
+  /// Compute angle(s) between pair of edges if they are intersected
+  void computeAngle();
+};
+
+#endif
index b9760dc07027ad7c55a7d4a85171ae343ad62659..2a8023433c763f1f06c3752987da571887980439 100644 (file)
@@ -26,6 +26,7 @@
 #include <FeaturesPlugin_ExtrusionFuse.h>
 #include <FeaturesPlugin_Fillet.h>
 #include <FeaturesPlugin_Intersection.h>
+#include <FeaturesPlugin_Measurement.h>
 #include <FeaturesPlugin_MultiRotation.h>
 #include <FeaturesPlugin_MultiTranslation.h>
 #include <FeaturesPlugin_Partition.h>
@@ -87,6 +88,8 @@ FeaturesPlugin_Plugin::FeaturesPlugin_Plugin()
                               new FeaturesPlugin_ValidatorConcealedResult);
   aFactory->registerValidator("FeaturesPlugin_ValidatorFilletSelection",
                               new FeaturesPlugin_ValidatorFilletSelection);
+  aFactory->registerValidator("FeaturesPlugin_ValidatorCircular",
+                              new FeaturesPlugin_ValidatorCircular);
 
   // register this plugin
   ModelAPI_Session::get()->registerPlugin(this);
@@ -136,6 +139,8 @@ FeaturePtr FeaturesPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new FeaturesPlugin_MultiRotation);
   } else if (theFeatureID == FeaturesPlugin_Fillet::ID()) {
     return FeaturePtr(new FeaturesPlugin_Fillet);
+  } else if (theFeatureID == FeaturesPlugin_Measurement::ID()) {
+    return FeaturePtr(new FeaturesPlugin_Measurement);
   }
 
   // feature of such kind is not found
index b4ca4332fd22bd0347be0ffe5f115e1ed28a2f90..5a06ceaaccb7c195ec89a83c589203d4162ca55a 100644 (file)
@@ -37,6 +37,7 @@
 #include <ModelAPI_Tools.h>
 
 #include <GeomValidators_BodyShapes.h>
+#include <GeomValidators_Face.h>
 #include <GeomValidators_FeatureKind.h>
 #include <GeomValidators_ShapeType.h>
 
@@ -998,3 +999,20 @@ bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAtt
 
   return theError.empty();
 }
+
+bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
+                                               const std::list<std::string>& theArguments,
+                                               Events_InfoMessage& theError) const
+{
+  static std::list<std::string> aEdgeArg(1, "circle");
+  static std::list<std::string> aFaceArg(1, "cylinder");
+
+  Events_InfoMessage aError;
+  bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
+  if (!isValid) {
+    isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
+    if (!isValid)
+      theError = "The shape neither circle nor cylinder";
+  }
+  return isValid;
+}
index b54b3f0be54992f8d699d2c322e82c6a0cd72905..5824ce9dc08753ffb46219711eae7e46bee418ff 100644 (file)
@@ -252,4 +252,19 @@ class FeaturesPlugin_ValidatorConcealedResult: public ModelAPI_AttributeValidato
                         Events_InfoMessage& theError) const;
 };
 
+/// \class FeaturesPlugin_ValidatorCircular
+/// \ingroup Validators
+/// \brief Verifies the selected object is circular edge or cylindrical face
+class FeaturesPlugin_ValidatorCircular : public ModelAPI_AttributeValidator
+{
+public:
+  //! \return True if the attribute is valid.
+  //! \param[in] theAttribute the checked attribute.
+  //! \param[in] theArguments arguments of the attribute.
+  //! \param[out] theError error message.
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 #endif
diff --git a/src/FeaturesPlugin/Test/TestMeasurementAngle.py b/src/FeaturesPlugin/Test/TestMeasurementAngle.py
new file mode 100644 (file)
index 0000000..d00f1c8
--- /dev/null
@@ -0,0 +1,95 @@
+## Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+##
+
+from SketchAPI import *
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"))
+SketchLine_7 = Sketch_2.addLine(119.1454520140253, 130.0744845530344, 10, 0)
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_8 = SketchProjection_3.createdFeature()
+SketchConstraintAngle_1 = Sketch_2.setAngle(SketchLine_8.result(), SketchLine_7.result(), 50)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchLine_8.result())
+SketchConstraintDistanceHorizontal_2 = Sketch_2.setHorizontalDistance(SketchAPI_Line(SketchLine_8).startPoint(), SketchLine_7.endPoint(), 10)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [("Sketch_1/Edge-SketchLine_3", "Sketch_1/Edge-SketchLine_6", [90]),
+            ("Extrusion_1_1/Generated_Face_5", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", [45]),
+            ("Sketch_1/Edge-SketchCircle_1_2", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", [0]),
+            ("Sketch_1/Edge-SketchLine_3", "Sketch_1/Edge-SketchCircle_1_2", []),
+            ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", []),
+            ("Sketch_2/Edge-SketchLine_7", "Extrusion_1_1/To_Face_1&Extrusion_1_1/Generated_Face_4", [130]),
+            ("Sketch_2/Edge-SketchLine_7", "Extrusion_1_1/To_Face_1&Extrusion_1_1/Generated_Face_1", [140]),
+            ("Sketch_2/Edge-SketchLine_7", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", [85.95645561, 95.19768874])
+           ]
+
+for ref in REF_DATA:
+    angle = model.measureAngle(Part_1_doc, model.selection("EDGE", ref[0]), model.selection("EDGE", ref[1]))
+    assert(angle.size() == len(ref[2]))
+    for a, r in zip(angle, ref[2]):
+        assert(math.fabs(a - r) < TOLERANCE), "Angle {} differs from expected value {}".format(a, r)
+
+# select incorrect data
+angle = model.measureAngle(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"), model.selection("EDGE", "Sketch_2/Edge-SketchLine_7"))
+assert(angle.size() == 0)
+
+model.end()
diff --git a/src/FeaturesPlugin/Test/TestMeasurementDistance.py b/src/FeaturesPlugin/Test/TestMeasurementDistance.py
new file mode 100644 (file)
index 0000000..c2b7d0a
--- /dev/null
@@ -0,0 +1,131 @@
+## Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+Sketch_2 = model.addSketch(Part_1_doc, model.standardPlane("YOZ"))
+SketchArc_1 = Sketch_2.addArc(100, 48.41229182762603, 87.5, 0, 87.5, 96.82458365525073, False)
+SketchArc_2 = Sketch_2.addArc(0, 48.41229182762603, 87.5, 0, 87.5, 96.82458365525073, False)
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchArc_1.startPoint(), SketchArc_2.startPoint())
+SketchConstraintCoincidence_6 = Sketch_2.setCoincident(SketchArc_2.endPoint(), SketchArc_1.endPoint())
+SketchConstraintRadius_2 = Sketch_2.setRadius(SketchArc_1.results()[1], "R")
+SketchConstraintRadius_3 = Sketch_2.setRadius(SketchArc_2.results()[1], "2*R")
+SketchLine_7 = Sketch_2.addLine(0, 48.41229182762603, 100, 48.41229182762603)
+SketchLine_7.setAuxiliary(True)
+SketchConstraintCoincidence_7 = Sketch_2.setCoincident(SketchArc_2.center(), SketchLine_7.startPoint())
+SketchConstraintCoincidence_8 = Sketch_2.setCoincident(SketchArc_1.center(), SketchLine_7.endPoint())
+SketchConstraintHorizontal_3 = Sketch_2.setHorizontal(SketchLine_7.result())
+SketchProjection_3 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_8 = SketchProjection_3.createdFeature()
+SketchConstraintCoincidence_9 = Sketch_2.setCoincident(SketchArc_1.startPoint(), SketchLine_8.result())
+SketchProjection_4 = Sketch_2.addProjection(model.selection("EDGE", "PartSet/OZ"), False)
+SketchLine_9 = SketchProjection_4.createdFeature()
+SketchConstraintCoincidence_10 = Sketch_2.setCoincident(SketchLine_7.startPoint(), SketchLine_9.result())
+SketchConstraintCoincidence_11 = Sketch_2.setCoincident(SketchLine_7.endPoint(), SketchArc_2.results()[1])
+SketchConstraintMirror_1 = Sketch_2.addMirror(SketchLine_9.result(), [SketchArc_2.results()[1], SketchArc_1.results()[1]])
+[SketchArc_3, SketchArc_4] = SketchConstraintMirror_1.mirrored()
+model.do()
+Extrusion_2 = model.addExtrusion(Part_1_doc, [model.selection("COMPOUND", "Sketch_2")], model.selection(), 100, 0)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [(model.selection("VERTEX", "PartSet/Origin"),
+             model.selection("VERTEX", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1"),
+             122.4744871),
+            (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1"),
+             model.selection("VERTEX", "Sketch_2/Vertex-SketchArc_1-SketchLine_7e"),
+             36.94403089),
+            (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"),
+             model.selection("EDGE", "Extrusion_1_1/Generated_Face_5"),
+             0),
+            (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"),
+             model.selection("EDGE", "Extrusion_2_1/Generated_Face_2&Extrusion_2_1/To_Face_1"),
+             16.00781059),
+            (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"),
+             model.selection("FACE", "Extrusion_2_1/Generated_Face_2"),
+             8.412291828),
+            (model.selection("VERTEX", "Sketch_1/Vertex-SketchCircle_1"),
+             model.selection("FACE", "Plane_1"),
+             35.35533906),
+            (model.selection("FACE", "Extrusion_2_2/From_Face_1"),
+             model.selection("FACE", "Extrusion_2_2/To_Face_1"),
+             100),
+            (model.selection("FACE", "Extrusion_1_1/Generated_Face_5"),
+             model.selection("FACE", "Extrusion_2_1/Generated_Face_2"),
+             0),
+            (model.selection("FACE", "Extrusion_1_1/Generated_Face_5"),
+             model.selection("FACE", "Extrusion_1_1/Generated_Face_2"),
+             27.63932023),
+            (model.selection("SOLID", "Extrusion_1_1"),
+             model.selection("FACE", "Extrusion_2_1/To_Face_1"),
+             12.5),
+            (model.selection("SOLID", "Extrusion_1_1"),
+             model.selection("SOLID", "Extrusion_2_1"),
+             0),
+            (model.selection("SOLID", "Extrusion_1_1"),
+             model.selection("SOLID", "Extrusion_2_2"),
+             87.5)
+           ]
+
+for ref in REF_DATA:
+    dist = model.measureDistance(Part_1_doc, ref[0], ref[1])
+    assert(math.fabs(dist - ref[2]) < TOLERANCE), "Distance {} differs from expected value {}".format(dist, ref[2])
+
+model.end()
diff --git a/src/FeaturesPlugin/Test/TestMeasurementLength.py b/src/FeaturesPlugin/Test/TestMeasurementLength.py
new file mode 100644 (file)
index 0000000..f557f8f
--- /dev/null
@@ -0,0 +1,84 @@
+## Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [("Extrusion_1_1/From_Face_1&Extrusion_1_1/Generated_Face_1", ParamH.value()),
+            ("Extrusion_1_1/From_Face_1&Extrusion_1_1/Generated_Face_4", ParamL.value()),
+            ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1", ParamR.value() * 2.0 * math.pi),
+            ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1", 381.981436664),
+            ("Extrusion_1_1/Generated_Face_5", 60),
+            ("Sketch_1/Edge-SketchLine_3", ParamL.value()),
+            ("Sketch_1/Edge-SketchLine_4", ParamH.value()),
+            ("Sketch_1/Edge-SketchCircle_1_2", ParamR.value() * 2.0 * math.pi)
+           ]
+
+for ref in REF_DATA:
+    length = model.measureLength(Part_1_doc, model.selection("EDGE", ref[0]))
+    assert(math.fabs(length - ref[1]) < TOLERANCE), "Length {} differs from expected value {}".format(length, ref[1])
+
+# select incorrect data
+length = model.measureLength(Part_1_doc, model.selection("FACE", "Extrusion_1_1/Generated_Face_5"))
+assert(length == -1)
+
+model.end()
diff --git a/src/FeaturesPlugin/Test/TestMeasurementRadius.py b/src/FeaturesPlugin/Test/TestMeasurementRadius.py
new file mode 100644 (file)
index 0000000..a39927d
--- /dev/null
@@ -0,0 +1,79 @@
+## Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+##
+
+from salome.shaper import model
+
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+ParamR = model.addParameter(Part_1_doc, "R", "50")
+ParamL = model.addParameter(Part_1_doc, "L", "40")
+ParamH = model.addParameter(Part_1_doc, "H", "20")
+Point_2 = model.addPoint(Part_1_doc, 0, 100, 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("EDGE", "PartSet/OX"), model.selection("VERTEX", "Point_1"), False)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchCircle_1 = Sketch_1.addCircle(50, 50, 50)
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], "R")
+SketchProjection_1 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OX"), False)
+SketchLine_1 = SketchProjection_1.createdFeature()
+SketchConstraintTangent_1 = Sketch_1.setTangent(SketchLine_1.result(), SketchCircle_1.results()[1])
+SketchProjection_2 = Sketch_1.addProjection(model.selection("EDGE", "PartSet/OY"), False)
+SketchLine_2 = SketchProjection_2.createdFeature()
+SketchConstraintTangent_2 = Sketch_1.setTangent(SketchLine_2.result(), SketchCircle_1.results()[1])
+SketchLine_3 = Sketch_1.addLine(70, 40, 30, 40)
+SketchLine_4 = Sketch_1.addLine(30, 40, 30, 60)
+SketchLine_5 = Sketch_1.addLine(30, 60, 70, 60)
+SketchLine_6 = Sketch_1.addLine(70, 60, 70, 40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_5.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_6.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_3.result(), "L")
+SketchConstraintLength_2 = Sketch_1.setLength(SketchLine_4.result(), "H")
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "L/2")
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_4.startPoint(), SketchCircle_1.center(), "H/2")
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), model.selection("FACE", "Plane_1"), 0, model.selection(), 10)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [(model.selection("EDGE", "Sketch_1/Edge-SketchCircle_1_2"), ParamR.value()),
+            (model.selection("EDGE", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"), ParamR.value()),
+            (model.selection("FACE", "Extrusion_1_1/Generated_Face_5"), ParamR.value())
+           ]
+
+for ref in REF_DATA:
+    radius = model.measureRadius(Part_1_doc, ref[0])
+    assert(math.fabs(radius - ref[1]) < TOLERANCE), "Radius {} differs from expected value {}".format(radius, ref[1])
+
+# select incorrect data
+radius = model.measureRadius(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"))
+assert(radius == -1)
+
+model.end()
diff --git a/src/FeaturesPlugin/icons/edge.png b/src/FeaturesPlugin/icons/edge.png
new file mode 100644 (file)
index 0000000..53dbb08
Binary files /dev/null and b/src/FeaturesPlugin/icons/edge.png differ
diff --git a/src/FeaturesPlugin/icons/meas_angle_32x32.png b/src/FeaturesPlugin/icons/meas_angle_32x32.png
new file mode 100644 (file)
index 0000000..800536f
Binary files /dev/null and b/src/FeaturesPlugin/icons/meas_angle_32x32.png differ
diff --git a/src/FeaturesPlugin/icons/meas_distance_32x32.png b/src/FeaturesPlugin/icons/meas_distance_32x32.png
new file mode 100644 (file)
index 0000000..d9a6d5b
Binary files /dev/null and b/src/FeaturesPlugin/icons/meas_distance_32x32.png differ
diff --git a/src/FeaturesPlugin/icons/meas_length_32x32.png b/src/FeaturesPlugin/icons/meas_length_32x32.png
new file mode 100644 (file)
index 0000000..37ebd09
Binary files /dev/null and b/src/FeaturesPlugin/icons/meas_length_32x32.png differ
diff --git a/src/FeaturesPlugin/icons/meas_radius_32x32.png b/src/FeaturesPlugin/icons/meas_radius_32x32.png
new file mode 100644 (file)
index 0000000..a3c70fc
Binary files /dev/null and b/src/FeaturesPlugin/icons/meas_radius_32x32.png differ
diff --git a/src/FeaturesPlugin/icons/measurement.png b/src/FeaturesPlugin/icons/measurement.png
new file mode 100644 (file)
index 0000000..c93fa62
Binary files /dev/null and b/src/FeaturesPlugin/icons/measurement.png differ
diff --git a/src/FeaturesPlugin/measurement_widget.xml b/src/FeaturesPlugin/measurement_widget.xml
new file mode 100644 (file)
index 0000000..22c557b
--- /dev/null
@@ -0,0 +1,80 @@
+<!--
+Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+-->
+
+<source>
+  <toolbox id="MeasureKind">
+    <box id="Length" title="Edge length" icon="icons/Features/meas_length_32x32.png">
+      <shape_selector id="edge_for_length"
+                      icon="icons/Features/edge.png"
+                      label="Edge"
+                      tooltip="Select an edge"
+                      shape_types="edge"
+                      default="">
+        <validator id="GeomValidators_ShapeType" parameters="edge"/>
+      </shape_selector>
+    </box>
+    <box id="Distance" title="Distance between objects" icon="icons/Features/meas_distance_32x32.png">
+      <shape_selector id="distance_from"
+                      icon=""
+                      label="From"
+                      tooltip="Select a shape"
+                      shape_types="vertex edge wire face shell solid objects"
+                      default="">
+      </shape_selector>
+      <shape_selector id="distance_to"
+                      icon=""
+                      label="To"
+                      tooltip="Select a shape"
+                      shape_types="vertex edge wire face shell solid objects"
+                      default="">
+      </shape_selector>
+    </box>
+    <box id="Radius" title="Radius of circular" icon="icons/Features/meas_radius_32x32.png">
+      <shape_selector id="circular"
+                      icon=""
+                      label="Object"
+                      tooltip="Select an edge or face"
+                      shape_types="edge face"
+                      default="">
+        <validator id="FeaturesPlugin_ValidatorCircular"/>
+      </shape_selector>
+    </box>
+    <box id="Angle" title="Angle between edges" icon="icons/Features/meas_angle_32x32.png">
+      <shape_selector id="angle_from"
+                      icon="icons/Features/edge.png"
+                      label="First edge"
+                      tooltip="Select an edge"
+                      shape_types="edge"
+                      default="">
+        <validator id="GeomValidators_ShapeType" parameters="edge"/>
+      </shape_selector>
+      <shape_selector id="angle_to"
+                      icon="icons/Features/edge.png"
+                      label="Second edge"
+                      tooltip="Select an edge"
+                      shape_types="edge"
+                      default="">
+        <validator id="GeomValidators_ShapeType" parameters="edge"/>
+      </shape_selector>
+    </box>
+  </toolbox>
+  <label id="result"/>
+</source>
index 31d9e290331f6f9bb1d6961a04d37e0c29d30ad6..5a4ac2f526988d246b6aabdc8b5d399e16203bfa 100644 (file)
@@ -107,5 +107,10 @@ email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com
         <source path="multirotation_widget.xml"/>
       </feature>
     </group>
+    <group id="Measurement">
+      <feature id="Measurement" title="Measurement" tooltip="Calculate properties of objects" icon="icons/Features/measurement.png">
+        <source path="measurement_widget.xml"/>
+      </feature>
+    </group>
   </workbench>
 </plugin>
index 325e5055d15213afea642371172db3df3879a03a..b75212b547336fce43aa271dd167dd3c54a3f2ab 100644 (file)
@@ -55,6 +55,7 @@ SET(PROJECT_HEADERS
     GeomAPI_Ax3.h
     GeomAPI_Trsf.h
     GeomAPI_Angle2d.h
+    GeomAPI_Angle.h
     GeomAPI_Wire.h
     GeomAPI_Ellipse.h
     GeomAPI_Ellipse2d.h
@@ -91,6 +92,7 @@ SET(PROJECT_SOURCES
     GeomAPI_IPresentable.cpp
     GeomAPI_Trsf.cpp
     GeomAPI_Angle2d.cpp
+    GeomAPI_Angle.cpp
     GeomAPI_Wire.cpp
     GeomAPI_Ellipse.cpp
     GeomAPI_Ellipse2d.cpp
diff --git a/src/GeomAPI/GeomAPI_Angle.cpp b/src/GeomAPI/GeomAPI_Angle.cpp
new file mode 100644 (file)
index 0000000..97d45ee
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+//
+
+#include <GeomAPI_Angle.h>
+
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Pnt.h>
+
+#include <BRep_Tool.hxx>
+#include <ElCLib.hxx>
+#include <Geom_Curve.hxx>
+#include <GeomAPI_ProjectPointOnCurve.hxx>
+#include <Precision.hxx>
+#include <TopoDS_Edge.hxx>
+
+/// \struct AngleDirections
+/// \brief Used to store info about angle.
+struct AngleDirections {
+  gp_Vec myDir1;
+  gp_Vec myDir2;
+};
+
+#define MY_ANGLE implPtr<AngleDirections>()
+#define PI 3.1415926535897932
+
+
+GeomAPI_Angle::GeomAPI_Angle(const std::shared_ptr<GeomAPI_Edge>& theEdge1,
+                             const std::shared_ptr<GeomAPI_Edge>& theEdge2,
+                             const std::shared_ptr<GeomAPI_Pnt>&  thePoint)
+{
+  gp_Pnt aPoint = thePoint->impl<gp_Pnt>();
+  const TopoDS_Edge& anEdge1 = theEdge1->impl<TopoDS_Edge>();
+  const TopoDS_Edge& anEdge2 = theEdge2->impl<TopoDS_Edge>();
+
+  double aF1, aL1;
+  Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aF1, aL1);
+  double aF2, aL2;
+  Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aF2, aL2);
+
+  AngleDirections* anAngle = new AngleDirections;
+  gp_Pnt aP;
+
+  GeomAPI_ProjectPointOnCurve aProj1(aPoint, aCurve1);
+  if (aProj1.NbPoints() > 0)
+    aCurve1->D1(aProj1.Parameter(1), aP, anAngle->myDir1);
+
+  GeomAPI_ProjectPointOnCurve aProj2(aPoint, aCurve2);
+  if (aProj2.NbPoints() > 0)
+    aCurve2->D1(aProj2.Parameter(1), aP, anAngle->myDir2);
+
+  setImpl(anAngle);
+}
+
+double GeomAPI_Angle::angleDegree()
+{
+  return angleRadian() * 180.0 / PI;
+}
+
+double GeomAPI_Angle::angleRadian()
+{
+  AngleDirections* anAngle = MY_ANGLE;
+  if (anAngle->myDir1.SquareMagnitude() < Precision::SquareConfusion() ||
+      anAngle->myDir2.SquareMagnitude() < Precision::SquareConfusion())
+    return 0.0;
+
+  gp_Dir aDir1(anAngle->myDir1);
+  gp_Dir aDir2(anAngle->myDir2);
+  double aRes = aDir1.Angle(aDir2);
+  aRes = ElCLib::InPeriod(aRes, 0.0, 2.0 * PI);
+  if (Abs(aRes) < 1.e-12)
+    aRes = 0.0;
+  return aRes;
+}
diff --git a/src/GeomAPI/GeomAPI_Angle.h b/src/GeomAPI/GeomAPI_Angle.h
new file mode 100644 (file)
index 0000000..e0c2eec
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) 2018-20xx  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<mailto:webmaster.salome@opencascade.com>
+//
+
+#ifndef GeomAPI_Angle_H_
+#define GeomAPI_Angle_H_
+
+#include <GeomAPI_Interface.h>
+
+class GeomAPI_Edge;
+class GeomAPI_Pnt;
+
+/// \class GeomAPI_Angle
+/// \ingroup DataModel
+/// \brief Build an angle
+class GeomAPI_Angle : public GeomAPI_Interface
+{
+public:
+  /// Creation of an angle defined by two edges in the given intersection point.
+  GEOMAPI_EXPORT
+  GeomAPI_Angle(const std::shared_ptr<GeomAPI_Edge>& theEdge1,
+                const std::shared_ptr<GeomAPI_Edge>& theEdge2,
+                const std::shared_ptr<GeomAPI_Pnt>&  thePoint);
+
+  /// Returns value of the angle in degrees
+  GEOMAPI_EXPORT double angleDegree();
+  /// Returns value of the angle in radians
+  GEOMAPI_EXPORT double angleRadian();
+};
+
+#endif
index ca84924c08a79d4735c1cef3cd0ed9892e6721d3..78846df72ad53277d4962d1bb5f01e982201cd17 100644 (file)
@@ -18,8 +18,8 @@
 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
 //
 
-#ifndef GeomAPI_Angle_H_
-#define GeomAPI_Angle_H_
+#ifndef GeomAPI_Angle2d_H_
+#define GeomAPI_Angle2d_H_
 
 #include <GeomAPI_Interface.h>
 
index e165279f2488d25d08ede3ad5a2bee4486483a86..ac5973d9bca882b6e7e8c63ca22981321b907460 100644 (file)
@@ -97,7 +97,8 @@ public:
   /// Returns list of intersection points if the edge has intersections with the given plane
   /// \param thePlane a plane for intersection
   GEOMAPI_EXPORT
-  void intersectWithPlane(const std::shared_ptr<GeomAPI_Pln> thePlane, std::list<std::shared_ptr<GeomAPI_Pnt> >& theResult) const;
+  void intersectWithPlane(const std::shared_ptr<GeomAPI_Pln> thePlane,
+                          std::list<std::shared_ptr<GeomAPI_Pnt> >& theResult) const;
 
   /// Returns edge length.
   GEOMAPI_EXPORT
index 4d1250d9cb4ac2b7698d41e6d333bfc69e6ca0c0..477b91b9007c52a6674ddfab2bab306afae58ff3 100644 (file)
@@ -53,5 +53,8 @@ public:
   std::shared_ptr<GeomAPI_Pln> getPlane() const;
 };
 
+//! Pointer on attribute object
+typedef std::shared_ptr<GeomAPI_Face> GeomFacePtr;
+
 #endif
 
index a8df94d7dbd49d0fcbae3da17db9a159078a9fb2..32384bf25021c13c6191deb79e34a5ae931a021c 100644 (file)
@@ -51,6 +51,7 @@
 #include <Geom2d_Curve.hxx>
 #include <BRepLib_CheckCurveOnSurface.hxx>
 #include <BRep_Tool.hxx>
+#include  <Geom_CylindricalSurface.hxx>
 #include <Geom_Line.hxx>
 #include <Geom_Plane.hxx>
 #include <GeomAPI_ProjectPointOnCurve.hxx>
@@ -142,6 +143,32 @@ std::shared_ptr<GeomAPI_Pnt>
   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aCentre.X(), aCentre.Y(), aCentre.Z()));
 }
 
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::radius(const std::shared_ptr<GeomAPI_Face>& theCylinder)
+{
+  double aRadius = -1.0;
+  if (theCylinder->isCylindrical()) {
+    const TopoDS_Shape& aShape = theCylinder->impl<TopoDS_Shape>();
+    Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aShape));
+    Handle(Geom_CylindricalSurface) aCyl = Handle(Geom_CylindricalSurface)::DownCast(aSurf);
+    if (!aCyl.IsNull())
+      aRadius = aCyl->Radius();
+  }
+  return aRadius;
+}
+
+//==================================================================================================
+double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1,
+                                               const GeomShapePtr& theShape2)
+{
+  const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+  const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+  BRepExtrema_DistShapeShape aDist(aShape1, aShape2);
+  aDist.Perform();
+  return aDist.IsDone() ? aDist.Value() : Precision::Infinite();
+}
+
 //==================================================================================================
 std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::combineShapes(
   const std::shared_ptr<GeomAPI_Shape> theCompound,
index 42f87c8626ce40d8725329917da8a7305cc5d41c..a9211e397b16dc03423c39544ba9ca5dfc32c4cf 100644 (file)
@@ -59,6 +59,14 @@ public:
   GEOMALGOAPI_EXPORT static std::shared_ptr<GeomAPI_Pnt>
     centreOfMass(const std::shared_ptr<GeomAPI_Shape> theShape);
 
+  /// \brief Obtain radius of cylindrical face.
+  ///        Return negative value if the face is not a cylinder
+  GEOMALGOAPI_EXPORT static double radius(const std::shared_ptr<GeomAPI_Face>& theCylinder);
+
+  /// \brief Calculate minimal distance between shapes
+  GEOMALGOAPI_EXPORT static double minimalDistance(const GeomShapePtr& theShape1,
+                                                   const GeomShapePtr& theShape2);
+
   /// \brief Combines faces with common edges to shells, or solids to compsolids.
   /// \param[in] theCompound compound of shapes.
   /// \param[in] theType type of combine.
index fb5939d5f972519a16e78016905bb2270d06e705..266e7ee8855d3fe3d3624570d07cd4b981b80791 100644 (file)
@@ -10,3 +10,4 @@ from FeaturesAPI import addCut, addFuse, addCommon, addSmash, addFill
 from FeaturesAPI import addIntersection, addPartition, addUnion, addRemoveSubShapes
 from FeaturesAPI import addRecover
 from FeaturesAPI import addFillet
+from FeaturesAPI import measureLength, measureDistance, measureRadius, measureAngle