-// Copyright (C) 2018-20xx CEA/DEN, EDF R&D
+// Copyright (C) 2018-2023 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
//
// 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
+// 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>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
#include "FeaturesPlugin_Measurement.h"
#include <GeomAlgoAPI_ShapeTools.h>
+#include <Config_PropManager.h>
+
+#include <TopoDS.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Shape.hxx>
+#include <PrsDim_Dimension.hxx>
+#include <PrsDim_LengthDimension.hxx>
+#include <PrsDim_RadiusDimension.hxx>
+#include <PrsDim_AngleDimension.hxx>
+#include <BRepExtrema_DistShapeShape.hxx>
+
+#include <Basics_OCCTVersion.hxx>
+
#include <iomanip>
#include <sstream>
+#include <array>
-FeaturesPlugin_Measurement::FeaturesPlugin_Measurement()
+FeaturesPlugin_Measurement::FeaturesPlugin_Measurement() : mySceenScale(1)
{
}
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();
- selection(ANGLE_POINT1_ID())->reset();
- selection(ANGLE_POINT2_ID())->reset();
- selection(ANGLE_POINT3_ID())->reset();
+ // clear results
string(RESULT_ID())->setValue("");
std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(
- attribute(RESULT_VALUES_ID()))->setSize(0);
+ attribute(RESULT_VALUES_ID()))->setSize(0);
}
- else if (theID != RESULT_ID()) {
+ else if (theID != RESULT_ID() &&
+ theID != RESULT_VALUES_ID()) {
std::string aKind = string(MEASURE_KIND())->value();
if (aKind == MEASURE_LENGTH())
computeLength();
else if (aKind == MEASURE_DISTANCE())
computeDistance();
+ else if (aKind == MEASURE_PROXIMITY())
+ computeProximity();
else if (aKind == MEASURE_RADIUS())
computeRadius();
else if (aKind == MEASURE_ANGLE())
std::ostringstream anOutput;
anOutput << "Length = " << std::setprecision(10) << anEdge->length();
+ if(anEdge->isLine())
+ {
+ auto point1 = anEdge->firstPoint();
+ auto point2 = anEdge->lastPoint();
+
+ anOutput <<"\n|dx| = " << std::setprecision(10) << std::abs(point2->x() - point1->x())
+ <<"\n|dy| = " << std::setprecision(10) << std::abs(point2->y() - point1->y())
+ <<"\n|dz| = " << std::setprecision(10) << std::abs(point2->z() - point1->z());
+ }
string(RESULT_ID())->setValue(anOutput.str());
AttributeDoubleArrayPtr aValues =
return;
}
- double aDistance = GeomAlgoAPI_ShapeTools::minimalDistance(aShape1, aShape2);
+ std::array<double, 3> fromShape1To2;
+ double aDistance = GeomAlgoAPI_ShapeTools::minimalDistance(aShape1, aShape2, fromShape1To2);
std::ostringstream anOutput;
- anOutput << "Distance = " << std::setprecision(10) << aDistance;
+ anOutput << "Distance = " << std::setprecision(10) << aDistance
+ <<"\n|dx| = " << std::setprecision(10) << std::abs(fromShape1To2[0])
+ <<"\n|dy| = " << std::setprecision(10) << std::abs(fromShape1To2[1])
+ <<"\n|dz| = " << std::setprecision(10) << std::abs(fromShape1To2[2]);
+ 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::computeProximity()
+{
+ AttributeSelectionPtr aFirstFeature = selection(DISTANCE_FROM_OBJECT_ID());
+ GeomShapePtr aShape1;
+ if (aFirstFeature && aFirstFeature->isInitialized()) {
+ aShape1 = aFirstFeature->value();
+ if (!aShape1 && aFirstFeature->context())
+ aShape1 = aFirstFeature->context()->shape();
+ }
+
+ AttributeSelectionPtr aSecondFeature = selection(DISTANCE_TO_OBJECT_ID());
+ GeomShapePtr aShape2;
+ if (aSecondFeature && aSecondFeature->isInitialized()) {
+ aShape2 = aSecondFeature->value();
+ if (!aShape2 && aSecondFeature->context())
+ aShape2 = aSecondFeature->context()->shape();
+ }
+
+ if (!aShape1 || !aShape2) {
+ string(RESULT_ID())->setValue("");
+ return;
+ }
+
+ double aDistance = GeomAlgoAPI_ShapeTools::shapeProximity(aShape1, aShape2);
+
+ std::ostringstream anOutput;
+ anOutput << "Proximity = " << std::setprecision(10) << aDistance;
string(RESULT_ID())->setValue(anOutput.str());
AttributeDoubleArrayPtr aValues =
aValues->setValue(anIndex++, *anIt);
}
-static GeomVertexPtr selectionToVertex(AttributeSelectionPtr& aSelection)
+static GeomVertexPtr selectionToVertex(const AttributeSelectionPtr& aSelection)
{
GeomShapePtr aShape;
GeomVertexPtr aVertex;
aValues->setSize(1);
aValues->setValue(0, anAngleValue);
}
+
+AISObjectPtr FeaturesPlugin_Measurement::getAISObject(AISObjectPtr thePrevious)
+{
+ AttributeDoubleArrayPtr aValues =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(attribute(RESULT_VALUES_ID()));
+ if ((aValues->size() == 0) || (aValues->value(0) <= Precision::Confusion()))
+ return AISObjectPtr();
+
+ if (!myScreenPlane) {
+ // initialize a default plane for dimension
+ GeomPointPtr anOrigin(new GeomAPI_Pnt(0., 0., 0.));
+ GeomDirPtr aNormal(new GeomAPI_Dir(0., 0., 1.));
+ myScreenPlane = GeomPlanePtr(new GeomAPI_Pln(anOrigin, aNormal));
+ }
+
+ AISObjectPtr anAIS;
+ std::string aKind = string(MEASURE_KIND())->value();
+ if (aKind == MEASURE_LENGTH())
+ anAIS = lengthDimension(thePrevious);
+ else if (aKind == MEASURE_DISTANCE())
+ anAIS = distanceDimension(thePrevious);
+ else if (aKind == MEASURE_RADIUS())
+ anAIS = radiusDimension(thePrevious);
+ else if (aKind == MEASURE_ANGLE())
+ anAIS = angleDimension(thePrevious);
+ else if (aKind == MEASURE_ANGLE_POINTS())
+ anAIS = angleByPointsDimension(thePrevious);
+ setupDimension(anAIS);
+ return anAIS;
+}
+
+AISObjectPtr FeaturesPlugin_Measurement::lengthDimension(AISObjectPtr thePrevious)
+{
+ AISObjectPtr aAISObj;
+
+ AttributeSelectionPtr aSelectedFeature = selection(EDGE_FOR_LENGTH_ID());
+
+ GeomShapePtr aShape;
+ GeomEdgePtr anEdge;
+ if (aSelectedFeature && aSelectedFeature->isInitialized()) {
+ aShape = aSelectedFeature->value();
+ if (!aShape && aSelectedFeature->context())
+ aShape = aSelectedFeature->context()->shape();
+ }
+ if (aShape && aShape->isEdge())
+ anEdge = GeomEdgePtr(new GeomAPI_Edge(aShape));
+ if (anEdge) {
+ TopoDS_Edge aTEdge = TopoDS::Edge(anEdge->impl<TopoDS_Shape>());
+ GeomPointPtr aPoint1 = anEdge->firstPoint();
+ GeomPointPtr aPoint2 = anEdge->lastPoint();
+
+ gp_Pnt aPnt1(aPoint1->impl<gp_Pnt>());
+ gp_Pnt aPnt2(aPoint2->impl<gp_Pnt>());
+
+ double aLength = aPnt1.Distance(aPnt2);
+ if (aLength > 0) {
+ gp_Pln aPlane = myScreenPlane->impl<gp_Pln>(); // gce_MP.Value();
+ aPlane.SetLocation(aPnt1);
+
+ gp_XYZ aNormal = aPlane.Axis().Direction().XYZ();
+ gp_XYZ aVec(aPnt2.X() - aPnt1.X(), aPnt2.Y() - aPnt1.Y(), aPnt2.Z() - aPnt1.Z());
+ double aDot = aNormal.Dot(aVec);
+ if (fabs(aDot - aLength) <= Precision::Confusion()) {
+ aPlane = gp_Pln(aPnt1, aPlane.XAxis().Direction());
+ }
+
+ Handle(PrsDim_LengthDimension) aDim;
+ if (thePrevious.get()) {
+ aAISObj = thePrevious;
+ Handle(AIS_InteractiveObject) aAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+ aDim = Handle(PrsDim_LengthDimension)::DownCast(aAIS);
+ if (aDim.IsNull()) {
+ aDim = new PrsDim_LengthDimension(aTEdge, aPlane);
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ }
+ else {
+ aDim->SetMeasuredGeometry(aTEdge, aPlane);
+ }
+ }
+ else {
+ aDim = new PrsDim_LengthDimension(aTEdge, aPlane);
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ }
+ aDim->SetFlyout(aLength / 3.);
+ }
+ }
+ return aAISObj;
+}
+
+AISObjectPtr FeaturesPlugin_Measurement::distanceDimension(AISObjectPtr thePrevious)
+{
+ AISObjectPtr aAISObj;
+
+ AttributeSelectionPtr aFirstFeature = selection(DISTANCE_FROM_OBJECT_ID());
+ AttributeSelectionPtr aSecondFeature = selection(DISTANCE_TO_OBJECT_ID());
+ if (aFirstFeature.get() && aSecondFeature.get()) {
+ GeomShapePtr aShape1;
+ GeomShapePtr aShape2;
+ if (aFirstFeature->isInitialized() && aSecondFeature->isInitialized()) {
+ aShape1 = aFirstFeature->value();
+ if (!aShape1 && aFirstFeature->context())
+ aShape1 = aFirstFeature->context()->shape();
+ aShape2 = aSecondFeature->value();
+ if (!aShape2 && aSecondFeature->context())
+ aShape2 = aSecondFeature->context()->shape();
+ }
+
+ if (aShape1 && aShape2) {
+ const TopoDS_Shape& aShp1 = aShape1->impl<TopoDS_Shape>();
+ const TopoDS_Shape& aShp2 = aShape2->impl<TopoDS_Shape>();
+ BRepExtrema_DistShapeShape aDist(aShp1, aShp2);
+ aDist.Perform();
+ if (aDist.IsDone()) {
+ gp_Pnt aPnt1 = aDist.PointOnShape1(1);
+ gp_Pnt aPnt2 = aDist.PointOnShape2(1);
+ double aDistance = aDist.Value();
+ if (aDistance > 0) {
+ gp_Pln aPlane = myScreenPlane->impl<gp_Pln>();
+ aPlane.SetLocation(aPnt1);
+
+ gp_XYZ aNormal = aPlane.Axis().Direction().XYZ();
+ gp_XYZ aVec(aPnt2.X() - aPnt1.X(), aPnt2.Y() - aPnt1.Y(), aPnt2.Z() - aPnt1.Z());
+ double aDot = aNormal.Dot(aVec);
+ if (fabs(aDot - aDistance) <= Precision::Confusion()) {
+ aPlane = gp_Pln(aPnt1, aPlane.XAxis().Direction());
+ }
+
+ Handle(PrsDim_LengthDimension) aDim;
+ if (thePrevious.get()) {
+ aAISObj = thePrevious;
+ Handle(AIS_InteractiveObject) aAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+ aDim = Handle(PrsDim_LengthDimension)::DownCast(aAIS);
+ if (aDim.IsNull()) {
+ aDim = new PrsDim_LengthDimension(aPnt1, aPnt2, aPlane);
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ }
+ else {
+ aDim->SetMeasuredGeometry(aPnt1, aPnt2, aPlane);
+ aDim->SetFlyout(aDistance / 3.);
+ }
+ }
+ else {
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aDim = new PrsDim_LengthDimension(aPnt1, aPnt2, aPlane);
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ }
+ aDim->SetFlyout(aDistance / 3.);
+ }
+ }
+ }
+ }
+ return aAISObj;
+}
+
+AISObjectPtr FeaturesPlugin_Measurement::radiusDimension(AISObjectPtr thePrevious)
+{
+ AISObjectPtr aAISObj;
+ AttributeSelectionPtr aSelectedFeature = selection(CIRCULAR_OBJECT_ID());
+
+ GeomShapePtr aShape;
+ if (aSelectedFeature && aSelectedFeature->isInitialized()) {
+ aShape = aSelectedFeature->value();
+ if (!aShape && aSelectedFeature->context())
+ aShape = aSelectedFeature->context()->shape();
+ }
+ if (aShape.get()) {
+ TopoDS_Shape aShp = aShape->impl<TopoDS_Shape>();
+ if (thePrevious.get()) {
+ aAISObj = thePrevious;
+ Handle(AIS_InteractiveObject) aAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+ Handle(PrsDim_RadiusDimension) aDim = Handle(PrsDim_RadiusDimension)::DownCast(aAIS);
+ if (aDim.IsNull()) {
+ aDim = new PrsDim_RadiusDimension(aShp);
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ } else
+ aDim->SetMeasuredGeometry(aShp);
+ } else {
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ Handle(PrsDim_RadiusDimension) aDim = new PrsDim_RadiusDimension(aShp);
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ }
+ }
+ return aAISObj;
+}
+
+AISObjectPtr FeaturesPlugin_Measurement::angleDimension(AISObjectPtr thePrevious)
+{
+ AISObjectPtr aAISObj;
+ AttributeSelectionPtr aFirstFeature = selection(ANGLE_FROM_EDGE_ID());
+ GeomShapePtr aShape1;
+ GeomEdgePtr anEdge1;
+ if (aFirstFeature && aFirstFeature->isInitialized()) {
+ 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 && aSecondFeature->isInitialized()) {
+ aShape2 = aSecondFeature->value();
+ if (!aShape2 && aSecondFeature->context())
+ aShape2 = aSecondFeature->context()->shape();
+ }
+ if (aShape2 && aShape2->isEdge())
+ anEdge2 = GeomEdgePtr(new GeomAPI_Edge(aShape2));
+
+ if (anEdge1.get() && anEdge2.get()) {
+ TopoDS_Edge aTEdge1 = TopoDS::Edge(anEdge1->impl<TopoDS_Shape>());
+ TopoDS_Edge aTEdge2 = TopoDS::Edge(anEdge2->impl<TopoDS_Shape>());
+
+ Handle(PrsDim_AngleDimension) aDim;
+ if (thePrevious.get()) {
+ aAISObj = thePrevious;
+ Handle(AIS_InteractiveObject) aAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+ aDim = Handle(PrsDim_AngleDimension)::DownCast(aAIS);
+ if (aDim.IsNull()) {
+ aDim = new PrsDim_AngleDimension(aTEdge1, aTEdge2);
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ } else
+ aDim->SetMeasuredGeometry(aTEdge1, aTEdge2);
+ } else {
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aDim = new PrsDim_AngleDimension(aTEdge1, aTEdge2);
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ }
+ }
+ return aAISObj;
+}
+
+AISObjectPtr FeaturesPlugin_Measurement::angleByPointsDimension(AISObjectPtr thePrevious)
+{
+ AISObjectPtr aAISObj;
+ GeomVertexPtr aVertex1 = selectionToVertex(selection(ANGLE_POINT1_ID()));
+ GeomVertexPtr aVertex2 = selectionToVertex(selection(ANGLE_POINT2_ID()));
+ GeomVertexPtr aVertex3 = selectionToVertex(selection(ANGLE_POINT3_ID()));
+
+ if (aVertex1.get() && aVertex2.get() && aVertex3.get()) {
+ GeomPointPtr aPoint1 = aVertex1->point();
+ GeomPointPtr aPoint2 = aVertex2->point();
+ GeomPointPtr aPoint3 = aVertex3->point();
+ gp_Pnt aPnt1(aPoint1->impl<gp_Pnt>());
+ gp_Pnt aPnt2(aPoint2->impl<gp_Pnt>());
+ gp_Pnt aPnt3(aPoint3->impl<gp_Pnt>());
+
+ if (aPnt1.IsEqual(aPnt2, Precision::Confusion()) ||
+ aPnt1.IsEqual(aPnt3, Precision::Confusion()) ||
+ aPnt2.IsEqual(aPnt3, Precision::Confusion()))
+ return thePrevious;
+
+ if (thePrevious.get()) {
+ aAISObj = thePrevious;
+ Handle(AIS_InteractiveObject) aAIS = aAISObj->impl<Handle(AIS_InteractiveObject)>();
+ Handle(PrsDim_AngleDimension) aDim = Handle(PrsDim_AngleDimension)::DownCast(aAIS);
+ if (aDim.IsNull()) {
+ aDim = new PrsDim_AngleDimension(aPnt1, aPnt2, aPnt3);
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ } else
+ aDim->SetMeasuredGeometry(aPnt1, aPnt2, aPnt3);
+ } else {
+ Handle(PrsDim_AngleDimension) aDim = new PrsDim_AngleDimension(aPnt1, aPnt2, aPnt3);
+ aAISObj = AISObjectPtr(new GeomAPI_AISObject());
+ aAISObj->setImpl(new Handle(AIS_InteractiveObject)(aDim));
+ }
+ }
+ return aAISObj;
+}
+
+
+void FeaturesPlugin_Measurement::setupDimension(AISObjectPtr theDim)
+{
+ if (theDim.get()) {
+ Handle(AIS_InteractiveObject) aAIS = theDim->impl<Handle(AIS_InteractiveObject)>();
+ Handle(PrsDim_Dimension) aDim = Handle(PrsDim_Dimension)::DownCast(aAIS);
+ int aSize = Config_PropManager::integer("Visualization", "dimension_arrow_size");
+ int aTextSize = Config_PropManager::integer("Visualization", "dimension_value_size");
+ std::string aFont = Config_PropManager::string("Visualization", "dimension_font");
+
+ Handle(Prs3d_DimensionAspect) anAspect = aDim->DimensionAspect();
+#if OCC_VERSION_LARGE >= 0x07070000
+ if (anAspect.IsNull()) {
+ aDim->Attributes()->SetupOwnDefaults();
+ anAspect = aDim->DimensionAspect();
+ }
+#endif
+ anAspect->MakeArrows3d(false);
+ anAspect->MakeText3d(false);
+ anAspect->MakeTextShaded(false);
+ anAspect->MakeUnitsDisplayed(false);
+ anAspect->MakeUnitsDisplayed(false);
+ anAspect->TextAspect()->SetFont(aFont.c_str());
+ anAspect->TextAspect()->SetHeight(aTextSize);
+ anAspect->ArrowAspect()->SetLength(aSize / mySceenScale);
+ anAspect->SetExtensionSize((aTextSize / mySceenScale + aSize) / 2.0);
+ aDim->SetDimensionAspect(anAspect);
+
+ aDim->SetZLayer(Graphic3d_ZLayerId_Top);
+ std::vector<int> aColor = Config_PropManager::color("Visualization", "sketch_dimension_color");
+ theDim->setColor(aColor[0], aColor[1], aColor[2]);
+ }
+}