| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| |
|
| | #include <sstream>
|
| | #include <QApplication>
|
| | #include <Inventor/engines/SoCalculator.h>
|
| | #include <Inventor/engines/SoConcatenate.h>
|
| | #include <Inventor/engines/SoComposeRotation.h>
|
| | #include <Inventor/engines/SoComposeRotationFromTo.h>
|
| | #include <Inventor/engines/SoComposeVec3f.h>
|
| | #include <Inventor/engines/SoDecomposeVec3f.h>
|
| | #include <Inventor/nodes/SoAnnotation.h>
|
| | #include <Inventor/nodes/SoBaseColor.h>
|
| | #include <Inventor/nodes/SoCoordinate3.h>
|
| | #include <Inventor/nodes/SoDrawStyle.h>
|
| | #include <Inventor/nodes/SoFontStyle.h>
|
| | #include <Inventor/nodes/SoIndexedLineSet.h>
|
| | #include <Inventor/nodes/SoMarkerSet.h>
|
| | #include <Inventor/nodes/SoPickStyle.h>
|
| | #include <Inventor/nodes/SoText2.h>
|
| | #include <Inventor/nodes/SoTranslation.h>
|
| | #include <Inventor/nodes/SoMaterial.h>
|
| | #include <Inventor/nodes/SoSwitch.h>
|
| | #include <Inventor/nodes/SoCone.h>
|
| | #include <Inventor/nodes/SoResetTransform.h>
|
| | #include <Inventor/nodes/SoNodes.h>
|
| |
|
| |
|
| | #include <Gui/Inventor/MarkerBitmaps.h>
|
| |
|
| | #include <App/Document.h>
|
| | #include <Base/BaseClass.h>
|
| | #include <Base/Console.h>
|
| | #include <Base/Quantity.h>
|
| | #include <Mod/Measure/App/Preferences.h>
|
| |
|
| | #include "ViewProviderMeasureDistance.h"
|
| | #include "Gui/Application.h"
|
| | #include <Gui/Command.h>
|
| | #include "Gui/Document.h"
|
| | #include "Gui/ViewParams.h"
|
| |
|
| |
|
| | using namespace Gui;
|
| | using namespace MeasureGui;
|
| | using namespace Measure;
|
| |
|
| | PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureDistance, MeasureGui::ViewProviderMeasureBase)
|
| |
|
| | SO_KIT_SOURCE(MeasureGui::DimensionLinear)
|
| |
|
| | void MeasureGui::DimensionLinear::initClass()
|
| | {
|
| | SO_KIT_INIT_CLASS(DimensionLinear, SoSeparatorKit, "SeparatorKit");
|
| | }
|
| |
|
| | MeasureGui::DimensionLinear::DimensionLinear()
|
| | {
|
| | SO_KIT_CONSTRUCTOR(MeasureGui::DimensionLinear);
|
| |
|
| | SO_KIT_ADD_CATALOG_ENTRY(transformation, SoTransform, true, topSeparator, "", true);
|
| | SO_KIT_ADD_CATALOG_ENTRY(annotate, SoAnnotation, true, topSeparator, "", true);
|
| | SO_KIT_ADD_CATALOG_ENTRY(leftArrow, SoShapeKit, true, topSeparator, "", true);
|
| | SO_KIT_ADD_CATALOG_ENTRY(rightArrow, SoShapeKit, true, topSeparator, "", true);
|
| | SO_KIT_ADD_CATALOG_ENTRY(line, SoShapeKit, true, annotate, "", true);
|
| | SO_KIT_ADD_CATALOG_ENTRY(textSep, SoSeparator, true, annotate, "", true);
|
| |
|
| | SO_KIT_INIT_INSTANCE();
|
| |
|
| | SO_NODE_ADD_FIELD(rotate, (1.0, 0.0, 0.0, 0.0));
|
| | SO_NODE_ADD_FIELD(length, (1.0));
|
| | SO_NODE_ADD_FIELD(origin, (0.0, 0.0, 0.0));
|
| | SO_NODE_ADD_FIELD(text, ("test"));
|
| | SO_NODE_ADD_FIELD(dColor, (1.0, 0.0, 0.0));
|
| | SO_NODE_ADD_FIELD(backgroundColor, (1.0, 1.0, 1.0));
|
| | SO_NODE_ADD_FIELD(showArrows, (false));
|
| | SO_NODE_ADD_FIELD(fontSize, (12.0));
|
| | }
|
| |
|
| | MeasureGui::DimensionLinear::~DimensionLinear()
|
| | {}
|
| |
|
| | SbBool MeasureGui::DimensionLinear::affectsState() const
|
| | {
|
| | return false;
|
| | }
|
| |
|
| | void MeasureGui::DimensionLinear::setupDimension()
|
| | {
|
| |
|
| | SoPickStyle* ps = static_cast<SoPickStyle*>(getPart("pickStyle", true));
|
| | if (ps) {
|
| | ps->style = SoPickStyle::UNPICKABLE;
|
| | }
|
| |
|
| |
|
| | SoTransform* trans = static_cast<SoTransform*>(getPart("transformation", true));
|
| | trans->translation.connectFrom(&point1);
|
| |
|
| | SoCalculator* hyp = new SoCalculator();
|
| | hyp->A.connectFrom(&point1);
|
| | hyp->B.connectFrom(&point2);
|
| | hyp->expression.set1Value(0, "oA = B-A");
|
| | hyp->expression.set1Value(1, "oB = normalize(oA)");
|
| | hyp->expression.set1Value(2, "oa = length(oA)");
|
| | length.connectFrom(&hyp->oa);
|
| |
|
| |
|
| | SoComposeRotationFromTo* rotationEngine = new SoComposeRotationFromTo();
|
| | rotationEngine->from.setValue(SbVec3f(1.0, 0.0, 0.0));
|
| | rotationEngine->to.connectFrom(&hyp->oB);
|
| | trans->rotation.connectFrom(&rotationEngine->rotation);
|
| |
|
| |
|
| | SoMaterial* material = new SoMaterial;
|
| | material->diffuseColor.connectFrom(&dColor);
|
| |
|
| |
|
| | float dimLength = (point2.getValue() - point1.getValue()).length();
|
| | float coneHeight = dimLength * 0.06;
|
| | float coneRadius = coneHeight * 0.5;
|
| |
|
| | SoComposeVec3f* vec = new SoComposeVec3f;
|
| | vec->x.connectFrom(&length);
|
| | vec->y.setValue(0.0);
|
| | vec->z.setValue(0.0);
|
| |
|
| |
|
| | if (showArrows.getValue()) {
|
| | SoCone* cone = new SoCone();
|
| | cone->bottomRadius.setValue(coneRadius);
|
| | cone->height.setValue(coneHeight);
|
| |
|
| | char lStr[100];
|
| | char rStr[100];
|
| | snprintf(lStr, sizeof(lStr), "translation %.6f 0.0 0.0", coneHeight * 0.5);
|
| | snprintf(rStr, sizeof(rStr), "translation 0.0 -%.6f 0.0", coneHeight * 0.5);
|
| |
|
| | setPart("leftArrow.shape", cone);
|
| | set("leftArrow.transform", "rotation 0.0 0.0 1.0 1.5707963");
|
| | set("leftArrow.transform", lStr);
|
| | setPart("rightArrow.shape", cone);
|
| | set("rightArrow.transform", "rotation 0.0 0.0 -1.0 1.5707963");
|
| |
|
| | set("rightArrow.localTransform", rStr);
|
| |
|
| | SoTransform* transform = static_cast<SoTransform*>(getPart("rightArrow.transform", false));
|
| | if (!transform) {
|
| | return;
|
| | }
|
| | transform->translation.connectFrom(&vec->vector);
|
| |
|
| | setPart("leftArrow.material", material);
|
| | setPart("rightArrow.material", material);
|
| | }
|
| |
|
| |
|
| | SoConcatenate* catEngine = new SoConcatenate(SoMFVec3f::getClassTypeId());
|
| |
|
| | catEngine->input[0]->connectFrom(&origin);
|
| | catEngine->input[1]->connectFrom(&vec->vector);
|
| |
|
| | SoVertexProperty* lineVerts = new SoVertexProperty;
|
| | lineVerts->vertex.connectFrom(catEngine->output);
|
| |
|
| | int lineVertexMap[] = {0, 1};
|
| | int lineVertexMapSize(sizeof(lineVertexMap) / sizeof(int));
|
| | SoIndexedLineSet* line = new SoIndexedLineSet;
|
| | line->vertexProperty = lineVerts;
|
| | line->coordIndex.setValues(0, lineVertexMapSize, lineVertexMap);
|
| |
|
| | setPart("line.shape", line);
|
| | setPart("line.material", material);
|
| |
|
| |
|
| | SoSeparator* textSep = static_cast<SoSeparator*>(getPart("textSep", true));
|
| | if (!textSep) {
|
| | return;
|
| | }
|
| |
|
| | textSep->addChild(material);
|
| |
|
| | SoCalculator* textVecCalc = new SoCalculator();
|
| | textVecCalc->A.connectFrom(&vec->vector);
|
| | textVecCalc->B.set1Value(0, 0.0, 0.250, 0.0);
|
| | textVecCalc->expression.set1Value(0, "oA = (A / 2) + B");
|
| |
|
| | SoTransform* textTransform = new SoTransform();
|
| | textTransform->translation.connectFrom(&textVecCalc->oA);
|
| | textSep->addChild(textTransform);
|
| |
|
| | auto textNode = new SoFrameLabel();
|
| | textNode->justification = SoText2::CENTER;
|
| | textNode->string.connectFrom(&text);
|
| | textNode->textColor.connectFrom(&dColor);
|
| | textNode->backgroundColor.connectFrom(&backgroundColor);
|
| | textNode->size.connectFrom(&fontSize);
|
| | textNode->name.setValue("Helvetica");
|
| | textSep->addChild(textNode);
|
| |
|
| |
|
| | SoResetTransform* rTrans = new SoResetTransform;
|
| | rTrans->whatToReset = SoResetTransform::BBOX;
|
| | textSep->addChild(rTrans);
|
| | }
|
| |
|
| |
|
| | SbMatrix ViewProviderMeasureDistance::getMatrix()
|
| | {
|
| | if (!pcObject) {
|
| | return {};
|
| | }
|
| |
|
| | auto prop1 = freecad_cast<App::PropertyVector*>(pcObject->getPropertyByName("Position1"));
|
| | auto prop2 = freecad_cast<App::PropertyVector*>(pcObject->getPropertyByName("Position2"));
|
| |
|
| | if (!prop1 || !prop2) {
|
| | return {};
|
| | }
|
| |
|
| | auto vec1 = prop1->getValue();
|
| | auto vec2 = prop2->getValue();
|
| |
|
| | const double tolerance(10.0e-6);
|
| | SbVec3f origin = toSbVec3f((vec2 + vec1) / 2);
|
| | Base::Vector3d localXAxis = (vec2 - vec1).Normalize();
|
| | Base::Vector3d localYAxis = getTextDirection(localXAxis, tolerance).Normalize();
|
| |
|
| |
|
| | assert(fabs(localYAxis.Dot(localXAxis)) < tolerance);
|
| | Base::Vector3d localZAxis = localYAxis.Cross(localXAxis).Normalize();
|
| |
|
| | SbMatrix matrix = SbMatrix(
|
| | localXAxis.x,
|
| | localXAxis.y,
|
| | localXAxis.z,
|
| | 0,
|
| | localYAxis.x,
|
| | localYAxis.y,
|
| | localYAxis.z,
|
| | 0,
|
| | localZAxis.x,
|
| | localZAxis.y,
|
| | localZAxis.z,
|
| | 0,
|
| |
|
| | origin[0],
|
| | origin[1],
|
| | origin[2],
|
| | 1
|
| | );
|
| |
|
| | return matrix;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | Base::Vector3d ViewProviderMeasureDistance::getTextDirection(
|
| | Base::Vector3d elementDirection,
|
| | double tolerance
|
| | )
|
| | {
|
| | const Base::Vector3d stdX(1.0, 0.0, 0.0);
|
| | const Base::Vector3d stdY(0.0, 1.0, 0.0);
|
| | const Base::Vector3d stdZ(0.0, 0.0, 1.0);
|
| |
|
| | Base::Vector3d textDirection = elementDirection.Cross(stdX);
|
| | if (textDirection.Length() < tolerance) {
|
| | textDirection = elementDirection.Cross(stdY);
|
| | }
|
| | if (textDirection.Length() < tolerance) {
|
| | textDirection = elementDirection.Cross(stdZ);
|
| | }
|
| | textDirection.Normalize();
|
| | if (textDirection.Dot(stdZ) < 0.0) {
|
| | textDirection = textDirection * -1.0;
|
| | }
|
| |
|
| | return textDirection.Normalize();
|
| | }
|
| |
|
| |
|
| | ViewProviderMeasureDistance::ViewProviderMeasureDistance()
|
| | {
|
| | sPixmap = "Measurement-Distance";
|
| |
|
| | ADD_PROPERTY_TYPE(
|
| | ShowDelta,
|
| | (false),
|
| | "Appearance",
|
| | App::Prop_None,
|
| | "Display the X, Y and Z components of the distance"
|
| | );
|
| |
|
| |
|
| | const size_t lineCount(3);
|
| | static const int32_t lines[lineCount] = {
|
| | 2,
|
| | 3,
|
| | -1
|
| | };
|
| |
|
| | const size_t lineCountSecondary(9);
|
| | static const int32_t linesSecondary[lineCountSecondary] = {
|
| | 0,
|
| | 2,
|
| | -1,
|
| | 1,
|
| | 3,
|
| | -1,
|
| | 2,
|
| | 4,
|
| | -1
|
| | };
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | pCoords = new SoCoordinate3();
|
| | pCoords->ref();
|
| |
|
| | auto engineCoords = new SoCalculator();
|
| | engineCoords->a.connectFrom(&fieldDistance);
|
| | engineCoords->A.connectFrom(&pLabelTranslation->translation);
|
| | engineCoords->expression.setValue(
|
| | "ta=a/2; tb=A[1]; oA=vec3f(ta, 0, 0); oB=vec3f(-ta, 0, 0); "
|
| | "oC=vec3f(ta, tb, 0); oD=vec3f(-ta, tb, 0)"
|
| | );
|
| |
|
| | auto engineCat = new SoConcatenate(SoMFVec3f::getClassTypeId());
|
| | engineCat->input[0]->connectFrom(&engineCoords->oA);
|
| | engineCat->input[1]->connectFrom(&engineCoords->oB);
|
| | engineCat->input[2]->connectFrom(&engineCoords->oC);
|
| | engineCat->input[3]->connectFrom(&engineCoords->oD);
|
| | engineCat->input[4]->connectFrom(&pLabelTranslation->translation);
|
| |
|
| | pCoords->point.connectFrom(engineCat->output);
|
| | pCoords->point.setNum(engineCat->output->getNumConnections());
|
| |
|
| | pLines = new SoIndexedLineSet();
|
| | pLines->ref();
|
| | pLines->coordIndex.setNum(lineCount);
|
| | pLines->coordIndex.setValues(0, lineCount, lines);
|
| |
|
| | pLineSeparator->addChild(pCoords);
|
| | pLineSeparator->addChild(pLines);
|
| |
|
| |
|
| |
|
| | auto lineSetSecondary = new SoIndexedLineSet();
|
| | lineSetSecondary->coordIndex.setNum(lineCountSecondary);
|
| | lineSetSecondary->coordIndex.setValues(0, lineCountSecondary, linesSecondary);
|
| |
|
| | pLineSeparatorSecondary->addChild(pCoords);
|
| | pLineSeparatorSecondary->addChild(lineSetSecondary);
|
| |
|
| | auto points = new SoMarkerSet();
|
| | points->markerIndex = Gui::Inventor::MarkerBitmaps::getMarkerIndex(
|
| | "CROSS",
|
| | ViewParams::instance()->getMarkerSize()
|
| | );
|
| | points->numPoints = 2;
|
| | pLineSeparator->addChild(points);
|
| |
|
| |
|
| |
|
| | auto decomposedPosition1 = new SoDecomposeVec3f();
|
| | decomposedPosition1->vector.connectFrom(&fieldPosition1);
|
| | auto decomposedPosition2 = new SoDecomposeVec3f();
|
| | decomposedPosition2->vector.connectFrom(&fieldPosition2);
|
| |
|
| |
|
| | auto composeVecDelta1 = new SoComposeVec3f();
|
| | composeVecDelta1->x.connectFrom(&decomposedPosition2->x);
|
| | composeVecDelta1->y.connectFrom(&decomposedPosition1->y);
|
| | composeVecDelta1->z.connectFrom(&decomposedPosition1->z);
|
| |
|
| | auto composeVecDelta2 = new SoComposeVec3f();
|
| | composeVecDelta2->x.connectFrom(&decomposedPosition2->x);
|
| | composeVecDelta2->y.connectFrom(&decomposedPosition2->y);
|
| | composeVecDelta2->z.connectFrom(&decomposedPosition1->z);
|
| |
|
| |
|
| | SbColor colorX;
|
| | SbColor colorY;
|
| | SbColor colorZ;
|
| |
|
| | float t = 0.0f;
|
| | colorX.setPackedValue(ViewParams::instance()->getAxisXColor(), t);
|
| | colorY.setPackedValue(ViewParams::instance()->getAxisYColor(), t);
|
| | colorZ.setPackedValue(ViewParams::instance()->getAxisZColor(), t);
|
| |
|
| | auto dimDeltaX = new MeasureGui::DimensionLinear();
|
| | dimDeltaX->point1.connectFrom(&fieldPosition1);
|
| | dimDeltaX->point2.connectFrom(&composeVecDelta1->vector);
|
| | dimDeltaX->setupDimension();
|
| | dimDeltaX->dColor.setValue(colorX);
|
| | dimDeltaX->fontSize.connectFrom(&fieldFontSize);
|
| |
|
| | auto dimDeltaY = new MeasureGui::DimensionLinear();
|
| | dimDeltaY->point1.connectFrom(&composeVecDelta1->vector);
|
| | dimDeltaY->point2.connectFrom(&composeVecDelta2->vector);
|
| | dimDeltaY->setupDimension();
|
| | dimDeltaY->dColor.setValue(colorY);
|
| | dimDeltaY->fontSize.connectFrom(&fieldFontSize);
|
| |
|
| | auto dimDeltaZ = new MeasureGui::DimensionLinear();
|
| | dimDeltaZ->point2.connectFrom(&composeVecDelta2->vector);
|
| | dimDeltaZ->point1.connectFrom(&fieldPosition2);
|
| | dimDeltaZ->setupDimension();
|
| | dimDeltaZ->dColor.setValue(colorZ);
|
| | dimDeltaZ->fontSize.connectFrom(&fieldFontSize);
|
| |
|
| | pDeltaDimensionSwitch = new SoSwitch();
|
| | pDeltaDimensionSwitch->ref();
|
| | pGlobalSeparator->addChild(pDeltaDimensionSwitch);
|
| |
|
| | pDeltaDimensionSwitch->addChild(dimDeltaX);
|
| | pDeltaDimensionSwitch->addChild(dimDeltaY);
|
| | pDeltaDimensionSwitch->addChild(dimDeltaZ);
|
| |
|
| |
|
| | FontSize.touch();
|
| | }
|
| |
|
| | ViewProviderMeasureDistance::~ViewProviderMeasureDistance()
|
| | {
|
| | pCoords->unref();
|
| | pLines->unref();
|
| | pDeltaDimensionSwitch->unref();
|
| | }
|
| |
|
| |
|
| |
|
| | void ViewProviderMeasureDistance::redrawAnnotation()
|
| | {
|
| | if (!pcObject) {
|
| | return;
|
| | }
|
| |
|
| | auto prop1 = freecad_cast<App::PropertyVector*>(pcObject->getPropertyByName("Position1"));
|
| | auto prop2 = freecad_cast<App::PropertyVector*>(pcObject->getPropertyByName("Position2"));
|
| |
|
| | if (!prop1 || !prop2) {
|
| | return;
|
| | }
|
| |
|
| | auto vec1 = prop1->getValue();
|
| | auto vec2 = prop2->getValue();
|
| |
|
| | fieldPosition1.setValue(SbVec3f(vec1.x, vec1.y, vec1.z));
|
| | fieldPosition2.setValue(SbVec3f(vec2.x, vec2.y, vec2.z));
|
| |
|
| |
|
| | fieldDistance = (vec2 - vec1).Length();
|
| |
|
| | auto propDistance = dynamic_cast<App::PropertyDistance*>(pcObject->getPropertyByName("Distance"));
|
| | setLabelValue(QString::fromStdString(propDistance->getQuantityValue().getUserString()));
|
| |
|
| |
|
| | auto propDistanceX = static_cast<App::PropertyDistance*>(
|
| | getMeasureObject()->getPropertyByName("DistanceX")
|
| | );
|
| | static_cast<DimensionLinear*>(pDeltaDimensionSwitch->getChild(0))
|
| | ->text.setValue(("Δx: " + propDistanceX->getQuantityValue().getUserString()).c_str());
|
| |
|
| | auto propDistanceY = static_cast<App::PropertyDistance*>(
|
| | getMeasureObject()->getPropertyByName("DistanceY")
|
| | );
|
| | static_cast<DimensionLinear*>(pDeltaDimensionSwitch->getChild(1))
|
| | ->text.setValue(("Δy: " + propDistanceY->getQuantityValue().getUserString()).c_str());
|
| |
|
| | auto propDistanceZ = static_cast<App::PropertyDistance*>(
|
| | getMeasureObject()->getPropertyByName("DistanceZ")
|
| | );
|
| | static_cast<DimensionLinear*>(pDeltaDimensionSwitch->getChild(2))
|
| | ->text.setValue(("Δz: " + propDistanceZ->getQuantityValue().getUserString()).c_str());
|
| |
|
| |
|
| | SbMatrix matrix = getMatrix();
|
| | pcTransform->setMatrix(matrix);
|
| |
|
| | ViewProviderMeasureBase::redrawAnnotation();
|
| | updateView();
|
| | }
|
| |
|
| | void ViewProviderMeasureDistance::onChanged(const App::Property* prop)
|
| | {
|
| |
|
| | if (prop == &ShowDelta) {
|
| | pDeltaDimensionSwitch->whichChild.setValue(
|
| | ShowDelta.getValue() ? SO_SWITCH_ALL : SO_SWITCH_NONE
|
| | );
|
| | }
|
| | else if (prop == &TextBackgroundColor) {
|
| | auto bColor = TextBackgroundColor.getValue();
|
| | static_cast<DimensionLinear*>(pDeltaDimensionSwitch->getChild(0))
|
| | ->backgroundColor.setValue(bColor.r, bColor.g, bColor.g);
|
| | static_cast<DimensionLinear*>(pDeltaDimensionSwitch->getChild(1))
|
| | ->backgroundColor.setValue(bColor.r, bColor.g, bColor.g);
|
| | static_cast<DimensionLinear*>(pDeltaDimensionSwitch->getChild(2))
|
| | ->backgroundColor.setValue(bColor.r, bColor.g, bColor.g);
|
| | }
|
| |
|
| | ViewProviderMeasureBase::onChanged(prop);
|
| | }
|
| |
|
| |
|
| | void ViewProviderMeasureDistance::positionAnno(const Measure::MeasureBase* measureObject)
|
| | {
|
| | (void)measureObject;
|
| | setLabelTranslation(SbVec3f(0, 0.1 * getViewScale(), 0));
|
| | }
|
| |
|