From: azv Date: Tue, 29 May 2018 10:32:34 +0000 (+0300) Subject: Task 2.8. Measurement functions X-Git-Tag: EDF_2018-1~33^2~1 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=46d76cd07aec0e520d4179139520c36bd7fb5c95;p=modules%2Fshaper.git Task 2.8. Measurement functions Implement feature to compute length, distance, radius or angle. --- diff --git a/src/FeaturesAPI/CMakeLists.txt b/src/FeaturesAPI/CMakeLists.txt index 1c5492242..83e853688 100644 --- a/src/FeaturesAPI/CMakeLists.txt +++ b/src/FeaturesAPI/CMakeLists.txt @@ -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 diff --git a/src/FeaturesAPI/FeaturesAPI.i b/src/FeaturesAPI/FeaturesAPI.i index 62afc3e48..01d1c9197 100644 --- a/src/FeaturesAPI/FeaturesAPI.i +++ b/src/FeaturesAPI/FeaturesAPI.i @@ -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 index 000000000..466aa0178 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_Measurement.cpp @@ -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 +// + +#include "FeaturesAPI_Measurement.h" + +#include +#include +#include +#include + +double measureLength(const std::shared_ptr& 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( + 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& 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( + 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& 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( + 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 measureAngle(const std::shared_ptr& 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( + aMeasure->attribute(FeaturesPlugin_Measurement::RESULT_VALUES_ID())); + std::list 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 index 000000000..271201821 --- /dev/null +++ b/src/FeaturesAPI/FeaturesAPI_Measurement.h @@ -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 +// + +#ifndef FeaturesAPI_Measurement_H_ +#define FeaturesAPI_Measurement_H_ + +#include "FeaturesAPI.h" + +#include +#include + +class ModelAPI_Document; +class ModelHighAPI_Selection; + +/// \ingroup CPPHighAPI +/// \brief Calculate length of the edge. +FEATURESAPI_EXPORT +double measureLength(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theEdge); + +/// \ingroup CPPHighAPI +/// \brief Calculate distance between objects. +FEATURESAPI_EXPORT +double measureDistance(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theFrom, + const ModelHighAPI_Selection& theTo); + +/// \ingroup CPPHighAPI +/// \brief Calculate radius of circular. +FEATURESAPI_EXPORT +double measureRadius(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theObject); + +/// \ingroup CPPHighAPI +/// \brief Calculate angle(s) between edges. +FEATURESAPI_EXPORT +std::list measureAngle(const std::shared_ptr& thePart, + const ModelHighAPI_Selection& theFrom, + const ModelHighAPI_Selection& theTo); + +#endif // FeaturesAPI_Measurement_H_ diff --git a/src/FeaturesAPI/FeaturesAPI_swig.h b/src/FeaturesAPI/FeaturesAPI_swig.h index 8b6ce0005..a45b780ca 100644 --- a/src/FeaturesAPI/FeaturesAPI_swig.h +++ b/src/FeaturesAPI/FeaturesAPI_swig.h @@ -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" diff --git a/src/FeaturesPlugin/CMakeLists.txt b/src/FeaturesPlugin/CMakeLists.txt index b0be8b412..ed5523231 100644 --- a/src/FeaturesPlugin/CMakeLists.txt +++ b/src/FeaturesPlugin/CMakeLists.txt @@ -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 index 000000000..0082c2ffd --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Measurement.cpp @@ -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 +// + +#include "FeaturesPlugin_Measurement.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +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( + 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(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(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(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 aValuesList; + if (anInter) { + if (anInter->isVertex()) { + std::shared_ptr aVertex(new GeomAPI_Vertex(anInter)); + std::shared_ptr 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 aVertex(new GeomAPI_Vertex(aCurrent)); + std::shared_ptr 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(attribute(RESULT_VALUES_ID())); + aValues->setSize((int)aValuesList.size()); + int anIndex = 0; + for (std::list::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 index 000000000..a358155cf --- /dev/null +++ b/src/FeaturesPlugin/FeaturesPlugin_Measurement.h @@ -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 +// + +#ifndef FeaturesPlugin_Measurement_H_ +#define FeaturesPlugin_Measurement_H_ + +#include "FeaturesPlugin.h" +#include + +/// \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 diff --git a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp index b9760dc07..2a8023433 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Plugin.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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 diff --git a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp index b4ca4332f..5a06ceaac 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp +++ b/src/FeaturesPlugin/FeaturesPlugin_Validators.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -998,3 +999,20 @@ bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAtt return theError.empty(); } + +bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const +{ + static std::list aEdgeArg(1, "circle"); + static std::list 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; +} diff --git a/src/FeaturesPlugin/FeaturesPlugin_Validators.h b/src/FeaturesPlugin/FeaturesPlugin_Validators.h index b54b3f0be..5824ce9dc 100644 --- a/src/FeaturesPlugin/FeaturesPlugin_Validators.h +++ b/src/FeaturesPlugin/FeaturesPlugin_Validators.h @@ -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& theArguments, + Events_InfoMessage& theError) const; +}; + #endif diff --git a/src/FeaturesPlugin/Test/TestMeasurementAngle.py b/src/FeaturesPlugin/Test/TestMeasurementAngle.py new file mode 100644 index 000000000..d00f1c842 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestMeasurementAngle.py @@ -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 +## + +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 index 000000000..c2b7d0a6a --- /dev/null +++ b/src/FeaturesPlugin/Test/TestMeasurementDistance.py @@ -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 +## + +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 index 000000000..f557f8fde --- /dev/null +++ b/src/FeaturesPlugin/Test/TestMeasurementLength.py @@ -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 +## + +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 index 000000000..a39927d46 --- /dev/null +++ b/src/FeaturesPlugin/Test/TestMeasurementRadius.py @@ -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 +## + +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 index 000000000..53dbb0820 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 index 000000000..800536f41 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 index 000000000..d9a6d5b4a 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 index 000000000..37ebd09f4 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 index 000000000..a3c70fca4 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 index 000000000..c93fa62b2 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 index 000000000..22c557b1d --- /dev/null +++ b/src/FeaturesPlugin/measurement_widget.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +