/*************************************************************************** * Copyright (c) 2023 David Friedli * * Copyright (c) 2008 Werner Mayer * * * * This file is part of FreeCAD. * * * * FreeCAD 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. * * * * FreeCAD 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 FreeCAD. If not, see * * . * * * **************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include # include # include # include # include # include # include # include # include #endif #include #include #include #include #include #include "Mod/Measure/App/MeasureDistance.h" #include #include "ViewProviderMeasureDistance.h" #include "Gui/Application.h" #include #include "Gui/Document.h" #include "Gui/ViewParams.h" using namespace Gui; using namespace MeasureGui; using namespace Measure; PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureDistance, MeasureGui::ViewProviderMeasureBase) SbMatrix ViewProviderMeasureDistance::getMatrix() { auto object = dynamic_cast(getObject()); auto vec1 = object->Position1.getValue(); auto vec2 = object->Position2.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(); // X and Y axis have to be 90° to eachother 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, // 0,0,0,1 origin[0], origin[1], origin[2], 1 ); return matrix; } //! calculate a good direction from the elements being measured to the annotation text based on the layout //! of the elements and its relationship with the cardinal axes and the view direction. elementDirection //! is expected to be a normalized vector. //! an example of an elementDirection would be the vector from the start of a line to the end. 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 = "umf-measurement"; // vert indexes used to create the annotation lines const size_t lineCount(3); static const int32_t lines[lineCount] = { 2,3,-1 // dimension line }; const size_t lineCountSecondary(9); static const int32_t linesSecondary[lineCountSecondary] = { 0,2,-1, // extension line 1 1,3,-1, // extension line 2 2,4,-1 // label helper line }; // Line Coordinates // 0-1 points on shape (dimension points) // 2-3 ends of extension lines/dimension line // 4 label position 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); // Secondary Lines 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); } ViewProviderMeasureDistance::~ViewProviderMeasureDistance() { pCoords->unref(); pLines->unref(); } Measure::MeasureDistance* ViewProviderMeasureDistance::getMeasureDistance() { Measure::MeasureDistance* feature = dynamic_cast(pcObject); if (!feature) { throw Base::RuntimeError("Feature not found for ViewProviderMeasureDistance"); } return feature; } //! repaint the annotation void ViewProviderMeasureDistance::redrawAnnotation() { auto object = dynamic_cast(getObject()); auto vec1 = object->Position1.getValue(); auto vec2 = object->Position2.getValue(); // Set the distance fieldDistance = (vec2 - vec1).Length(); setLabelValue(object->Distance.getQuantityValue().getUserString()); // Set matrix SbMatrix matrix = getMatrix(); pcTransform->setMatrix(matrix); ViewProviderMeasureBase::redrawAnnotation(); updateView(); } void ViewProviderMeasureDistance::positionAnno(const Measure::MeasureBase* measureObject) { (void)measureObject; setLabelTranslation(SbVec3f(0, 10, 0)); }