Add new measurement type: angle by three points.
return aValues;
}
+
+double measureAngle(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& thePoint1,
+ const ModelHighAPI_Selection& thePoint2,
+ const ModelHighAPI_Selection& thePoint3)
+{
+ FeaturePtr aMeasure = thePart->addFeature(FeaturesPlugin_Measurement::ID());
+ fillAttribute(FeaturesPlugin_Measurement::MEASURE_ANGLE_POINTS(),
+ aMeasure->string(FeaturesPlugin_Measurement::MEASURE_KIND()));
+ fillAttribute(thePoint1, aMeasure->selection(FeaturesPlugin_Measurement::ANGLE_POINT1_ID()));
+ fillAttribute(thePoint2, aMeasure->selection(FeaturesPlugin_Measurement::ANGLE_POINT2_ID()));
+ fillAttribute(thePoint3, aMeasure->selection(FeaturesPlugin_Measurement::ANGLE_POINT3_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;
+}
const ModelHighAPI_Selection& theFrom,
const ModelHighAPI_Selection& theTo);
+/// \ingroup CPPHighAPI
+/// \brief Calculate angle by 3 points.
+FEATURESAPI_EXPORT
+double measureAngle(const std::shared_ptr<ModelAPI_Document>& thePart,
+ const ModelHighAPI_Selection& thePoint1,
+ const ModelHighAPI_Selection& thePoint2,
+ const ModelHighAPI_Selection& thePoint3);
+
#endif // FeaturesAPI_Measurement_H_
#include <GeomAPI_Pnt.h>
#include <GeomAPI_Shape.h>
#include <GeomAPI_ShapeIterator.h>
+#include <GeomAPI_Vertex.h>
#include <GeomAlgoAPI_ShapeTools.h>
data()->addAttribute(DISTANCE_TO_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
// attribute for radius
data()->addAttribute(CIRCULAR_OBJECT_ID(), ModelAPI_AttributeSelection::typeId());
- // attribute for angle
+ // attributes 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
+ // attributes for angle by 3 points
+ data()->addAttribute(ANGLE_POINT1_ID(), ModelAPI_AttributeSelection::typeId());
+ data()->addAttribute(ANGLE_POINT2_ID(), ModelAPI_AttributeSelection::typeId());
+ data()->addAttribute(ANGLE_POINT3_ID(), ModelAPI_AttributeSelection::typeId());
+ // attributes for result message and values
data()->addAttribute(RESULT_ID(), ModelAPI_AttributeString::typeId());
data()->addAttribute(RESULT_VALUES_ID(), ModelAPI_AttributeDoubleArray::typeId());
}
selection(CIRCULAR_OBJECT_ID())->reset();
selection(ANGLE_FROM_EDGE_ID())->reset();
selection(ANGLE_TO_EDGE_ID())->reset();
+ selection(ANGLE_POINT1_ID())->reset();
+ selection(ANGLE_POINT2_ID())->reset();
+ selection(ANGLE_POINT3_ID())->reset();
string(RESULT_ID())->setValue("");
std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
attribute(RESULT_VALUES_ID()))->setSize(0);
computeRadius();
else if (aKind == MEASURE_ANGLE())
computeAngle();
+ else if (aKind == MEASURE_ANGLE_POINTS())
+ computeAngleByPoints();
}
}
std::shared_ptr<GeomAPI_Angle> anAngle(
new GeomAPI_Angle(anEdge1, anEdge2, aVertex->point()));
double anAngleValue = anAngle->angleDegree();
- anOutput << "Angle = " << anAngleValue << std::endl;
+ anOutput << "Angle = " << std::setprecision(10) << anAngleValue << std::endl;
aValuesList.push_back(anAngleValue);
}
else {
std::shared_ptr<GeomAPI_Angle> anAngle(
new GeomAPI_Angle(anEdge1, anEdge2, aVertex->point()));
double anAngleValue = anAngle->angleDegree();
- anOutput << "Angle" << anIndex << " = " << anAngleValue << std::endl;
+ anOutput << "Angle" << anIndex << " = "
+ << std::setprecision(10) << anAngleValue << std::endl;
aValuesList.push_back(anAngleValue);
}
}
for (std::list<double>::iterator anIt = aValuesList.begin(); anIt != aValuesList.end(); ++anIt)
aValues->setValue(anIndex++, *anIt);
}
+
+static GeomVertexPtr selectionToVertex(AttributeSelectionPtr& aSelection)
+{
+ GeomShapePtr aShape;
+ GeomVertexPtr aVertex;
+ if (aSelection && aSelection->isInitialized()) {
+ aShape = aSelection->value();
+ if (!aShape && aSelection->context())
+ aShape = aSelection->context()->shape();
+ }
+ if (aShape && aShape->isVertex())
+ aVertex = GeomVertexPtr(new GeomAPI_Vertex(aShape));
+ return aVertex;
+}
+
+void FeaturesPlugin_Measurement::computeAngleByPoints()
+{
+ GeomVertexPtr aVertex1 = selectionToVertex(selection(ANGLE_POINT1_ID()));
+ GeomVertexPtr aVertex2 = selectionToVertex(selection(ANGLE_POINT2_ID()));
+ GeomVertexPtr aVertex3 = selectionToVertex(selection(ANGLE_POINT3_ID()));
+
+ if (!aVertex1 || !aVertex2 || ! aVertex3) {
+ string(RESULT_ID())->setValue("");
+ return;
+ }
+
+ std::shared_ptr<GeomAPI_Angle> anAngle(
+ new GeomAPI_Angle(aVertex1->point(), aVertex2->point(), aVertex3->point()));
+ double anAngleValue = anAngle->angleDegree();
+
+ std::ostringstream anOutput;
+ anOutput << "Angle = " << std::setprecision(10) << anAngleValue;
+ string(RESULT_ID())->setValue(anOutput.str());
+
+ AttributeDoubleArrayPtr aValues =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+ aValues->setSize(1);
+ aValues->setValue(0, anAngleValue);
+}
return MY_MEASURE_ID;
}
+ /// Attribute name for angle measurement by 3 points.
+ inline static const std::string& MEASURE_ANGLE_POINTS()
+ {
+ static const std::string MY_MEASURE_ID("AngleBy3Points");
+ return MY_MEASURE_ID;
+ }
+
/// Attribute name of edge selected for length calculation.
inline static const std::string& EDGE_FOR_LENGTH_ID()
return MY_ANGLE_FROM_EDGE_ID;
}
- /// Attribute name of second shape selected for distance calculation.
+ /// Attribute name of second shape selected for angle 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 of first point selected for angle calculation.
+ inline static const std::string& ANGLE_POINT1_ID()
+ {
+ static const std::string MY_ANGLE_POINT1_ID("angle_point_1");
+ return MY_ANGLE_POINT1_ID;
+ }
+
+ /// Attribute name of second point (apex) selected for angle calculation.
+ inline static const std::string& ANGLE_POINT2_ID()
+ {
+ static const std::string MY_ANGLE_POINT2_ID("angle_point_2");
+ return MY_ANGLE_POINT2_ID;
+ }
+
+ /// Attribute name of third point selected for angle calculation.
+ inline static const std::string& ANGLE_POINT3_ID()
+ {
+ static const std::string MY_ANGLE_POINT3_ID("angle_point_3");
+ return MY_ANGLE_POINT3_ID;
+ }
+
/// Attribute name for result.
inline static const std::string& RESULT_ID()
{
void computeRadius();
/// Compute angle(s) between pair of edges if they are intersected
void computeAngle();
+ /// Compute angle by three points
+ void computeAngleByPoints();
};
#endif
--- /dev/null
+## 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()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(0, 0, 30, -51.96152422706629)
+SketchLine_2 = Sketch_1.addLine(30, -51.96152422706629, 90, -51.96152422706629)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_1.addLine(90, -51.96152422706629, 120, 0)
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchLine_4 = Sketch_1.addLine(120, 0, 90, 51.96152422706636)
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchLine_5 = Sketch_1.addLine(90, 51.96152422706636, 30, 51.96152422706631)
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_5.startPoint())
+SketchLine_6 = Sketch_1.addLine(30, 51.96152422706631, 0, 0)
+SketchConstraintCoincidence_5 = Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint())
+SketchConstraintCoincidence_6 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_6.endPoint())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_2.result(), SketchLine_1.result())
+SketchConstraintEqual_2 = Sketch_1.setEqual(SketchLine_3.result(), SketchLine_1.result())
+SketchConstraintEqual_3 = Sketch_1.setEqual(SketchLine_4.result(), SketchLine_1.result())
+SketchConstraintEqual_4 = Sketch_1.setEqual(SketchLine_5.result(), SketchLine_1.result())
+SketchConstraintEqual_5 = Sketch_1.setEqual(SketchLine_6.result(), SketchLine_1.result())
+SketchConstraintAngle_1 = Sketch_1.setAngleBackward(SketchLine_1.result(), SketchLine_2.result(), 120)
+SketchConstraintAngle_2 = Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), 120)
+SketchConstraintAngle_3 = Sketch_1.setAngleBackward(SketchLine_3.result(), SketchLine_4.result(), 120)
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_5.result(), 60)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintCoincidence_7 = Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchAPI_Point(SketchPoint_1).coordinates())
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_1f-SketchLine_2f-SketchLine_3f-SketchLine_4f-SketchLine_5f-SketchLine_6f")], model.selection(), 100, 0)
+model.do()
+
+TOLERANCE = 1.e-6
+
+# reference data
+REF_DATA = [("Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/From_Face_1",
+ 120),
+ ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1",
+ 120),
+ ("Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_2&Extrusion_1_1/Generated_Face_1&Extrusion_1_1/From_Face_1",
+ 60),
+ ("Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/To_Face_1",
+ "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1",
+ "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1",
+ 120),
+ ("Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1",
+ 104.9068234),
+ ("Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/To_Face_1",
+ 90),
+ ("Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1",
+ "Extrusion_1_1/Generated_Face_4&Extrusion_1_1/Generated_Face_3&Extrusion_1_1/From_Face_1",
+ 52.91916441),
+ ("Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1",
+ "Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1",
+ "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1",
+ 0)
+ ]
+
+for ref in REF_DATA:
+ angle = model.measureAngle(Part_1_doc, model.selection("VERTEX", ref[0]), model.selection("VERTEX", ref[1]), model.selection("VERTEX", ref[2]))
+ assert(math.fabs(angle - ref[3]) < TOLERANCE), "Angle {} differs from expected value {}".format(angle, ref[3])
+
+# select incorrect data
+angle = model.measureAngle(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face_1"), model.selection("VERTEX", "Extrusion_1_1/Generated_Face_5&Extrusion_1_1/Generated_Face_4&Extrusion_1_1/To_Face_1"), model.selection("VERTEX", "Extrusion_1_1/Generated_Face_6&Extrusion_1_1/Generated_Face_5&Extrusion_1_1/From_Face_1"))
+assert(angle == -1.0)
+
+angle = model.measureAngle(Part_1_doc, model.selection("VERTEX", ""), model.selection("VERTEX", ""), model.selection("VERTEX", ""))
+assert(angle == -1.0)
+
+model.end()
<validator id="GeomValidators_Intersected" parameters="angle_from"/>
</shape_selector>
</box>
+ <box id="AngleBy3Points" title="Angle by 3 points" icon="icons/Features/meas_angle3p_32x32.png">
+ <shape_selector id="angle_point_1"
+ icon="icons/Features/point.png"
+ label="Start point"
+ tooltip="Select a point"
+ shape_types="vertex"
+ default="">
+ <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+ </shape_selector>
+ <shape_selector id="angle_point_2"
+ icon="icons/Features/point.png"
+ label="Angle apex"
+ tooltip="Select a point"
+ shape_types="vertex"
+ default="">
+ <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+ </shape_selector>
+ <shape_selector id="angle_point_3"
+ icon="icons/Features/point.png"
+ label="End point"
+ tooltip="Select a point"
+ shape_types="vertex"
+ default="">
+ <validator id="GeomValidators_ShapeType" parameters="vertex"/>
+ </shape_selector>
+ </box>
</toolbox>
<label id="result"/>
</source>
setImpl(anAngle);
}
+GeomAPI_Angle::GeomAPI_Angle(const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint2,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint3)
+{
+ gp_Pnt aPoint1 = thePoint1->impl<gp_Pnt>();
+ gp_Pnt aPoint2 = thePoint2->impl<gp_Pnt>();
+ gp_Pnt aPoint3 = thePoint3->impl<gp_Pnt>();
+
+ AngleDirections* anAngle = new AngleDirections;
+ anAngle->myDir1.SetXYZ(aPoint1.XYZ() - aPoint2.XYZ());
+ anAngle->myDir2.SetXYZ(aPoint3.XYZ() - aPoint2.XYZ());
+ setImpl(anAngle);
+}
+
double GeomAPI_Angle::angleDegree()
{
return angleRadian() * 180.0 / PI;
const std::shared_ptr<GeomAPI_Edge>& theEdge2,
const std::shared_ptr<GeomAPI_Pnt>& thePoint);
+ /// Creation of an angle defined by 3 points (the second point is an apex of an angle).
+ GEOMAPI_EXPORT
+ GeomAPI_Angle(const std::shared_ptr<GeomAPI_Pnt>& thePoint1,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint2,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint3);
+
/// Returns value of the angle in degrees
GEOMAPI_EXPORT double angleDegree();
/// Returns value of the angle in radians