FreeCAD

Форк
0
/
ViewProviderMeasureAngle.cpp 
362 строки · 13.5 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2023 David Friedli <david[at]friedli-be.ch>             *
3
 *   Copyright (c) 2013 Thomas Anderson <blobfish[at]gmx.com>              *
4
 *                                                                         *
5
 *   This file is part of FreeCAD.                                         *
6
 *                                                                         *
7
 *   FreeCAD is free software: you can redistribute it and/or modify it    *
8
 *   under the terms of the GNU Lesser General Public License as           *
9
 *   published by the Free Software Foundation, either version 2.1 of the  *
10
 *   License, or (at your option) any later version.                       *
11
 *                                                                         *
12
 *   FreeCAD is distributed in the hope that it will be useful, but        *
13
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      *
15
 *   Lesser General Public License for more details.                       *
16
 *                                                                         *
17
 *   You should have received a copy of the GNU Lesser General Public      *
18
 *   License along with FreeCAD. If not, see                               *
19
 *   <https://www.gnu.org/licenses/>.                                      *
20
 *                                                                         *
21
 **************************************************************************/
22

23
#include "PreCompiled.h"
24

25
#ifndef _PreComp_
26
#include <sstream>
27
#include <QApplication>
28
#include <Inventor/draggers/SoTranslate2Dragger.h>
29
#include <Inventor/nodes/SoAnnotation.h>
30
#include <Inventor/nodes/SoBaseColor.h>
31
#include <Inventor/nodes/SoCoordinate3.h>
32
#include <Inventor/nodes/SoDrawStyle.h>
33
#include <Inventor/nodes/SoFontStyle.h>
34
#include <Inventor/nodes/SoIndexedLineSet.h>
35
#include <Inventor/nodes/SoPickStyle.h>
36
#include <Inventor/nodes/SoText2.h>
37
#include <Inventor/nodes/SoTranslation.h>
38
#include <Inventor/engines/SoCalculator.h>
39
#include <Inventor/engines/SoComposeVec3f.h>
40
#include <Inventor/engines/SoConcatenate.h>
41
#include <Inventor/engines/SoComposeMatrix.h>
42
#include <Inventor/engines/SoComposeRotation.h>
43
#include <Inventor/engines/SoComposeRotationFromTo.h>
44
#include <Inventor/engines/SoDecomposeRotation.h>
45
#include <Inventor/engines/SoTransformVec3f.h>
46
#include <Inventor/nodekits/SoShapeKit.h>
47
#include <Inventor/nodes/SoFont.h>
48
#include <Inventor/nodes/SoLineSet.h>
49
#include <Inventor/nodes/SoMatrixTransform.h>
50
#include <Inventor/nodes/SoSeparator.h>
51
#include <Inventor/nodes/SoTransform.h>
52
#include <Inventor/nodes/SoVertexProperty.h>
53
#include <Inventor/nodekits/SoBaseKit.h>
54
#endif
55

56
#include <Precision.hxx>
57
#include <Geom_Curve.hxx>
58
#include <Geom_Line.hxx>
59
#include <gp_Vec.hxx>
60
#include <gp_Lin.hxx>
61
#include <gp_Pnt.hxx>
62
#include <GeomAPI_ExtremaCurveCurve.hxx>
63
#include <GeomAPI_ProjectPointOnCurve.hxx>
64

65
#include <App/Application.h>
66
#include <App/Document.h>
67
#include <Base/Console.h>
68
#include <Base/Exception.h>
69
#include <Base/Quantity.h>
70
#include <Gui/ArcEngine.h>
71
#include <Gui/Command.h>
72
#include <Gui/Document.h>
73
#include <Gui/ViewParams.h>
74

75
#include <Mod/Measure/App/Preferences.h>
76

77
#include "ViewProviderMeasureAngle.h"
78

79

80
using namespace MeasureGui;
81
using namespace Measure;
82

83
gp_Lin getLine(gp_Vec& vec, gp_Vec& origin)
84
{
85
    gp_Pnt tempOrigin;
86
    tempOrigin.SetXYZ(origin.XYZ());
87
    return gp_Lin(tempOrigin, gp_Dir(vec));
88
}
89

90
SbMatrix ViewProviderMeasureAngle::getMatrix()
91
{
92
    // Code ported from src/Mod/Part/Gui/TaskDimension.cpp
93

94
    if (pcObject == nullptr) {
95
        throw Base::RuntimeError("no DocumentObject");
96
    }
97

98
    Measure::MeasureAngle* measurement = static_cast<Measure::MeasureAngle*>(pcObject);
99

100
    if (!measurement->Element1.getValue() || measurement->Element1.getSubValues().empty()) {
101
        return SbMatrix();
102
    }
103
    if (!measurement->Element2.getValue() || measurement->Element2.getSubValues().empty()) {
104
        return SbMatrix();
105
    }
106

107

108
    gp_Vec vector1 = measurement->vector1();
109
    gp_Vec vector2 = measurement->vector2();
110

111
    gp_Vec loc1 = measurement->location1();
112
    gp_Vec loc2 = measurement->location2();
113

114
    if (vector1.Magnitude() == 0 || vector2.Magnitude() == 0) {
115
        return SbMatrix();
116
    }
117

118
    gp_Lin lin1 = getLine(vector1, loc1);
119
    gp_Lin lin2 = getLine(vector2, loc2);
120

121
    SbMatrix dimSys = SbMatrix();
122
    double radius;
123

124
    if (vector1.IsParallel(vector2, Precision::Angular())) {
125
        // take first point project it onto second vector.
126
        Handle(Geom_Curve) heapLine2 = new Geom_Line(lin2);
127
        gp_Pnt tempPoint(loc1.XYZ());
128

129
        GeomAPI_ProjectPointOnCurve projection(tempPoint, heapLine2);
130
        if (projection.NbPoints() < 1) {
131
            throw Base::RuntimeError("parallel vectors: couldn't project onto line");
132
        }
133
        gp_Vec newPoint2;
134
        newPoint2.SetXYZ(projection.Point(1).XYZ());
135

136
        // if points are colinear, projection doesn't work and returns the same point.
137
        // In this case we just use the original point.
138
        if ((newPoint2 - loc1).Magnitude() < Precision::Confusion()) {
139
            newPoint2 = loc2;
140
        }
141

142
        // now get midpoint between for dim origin.
143
        gp_Vec point1 = loc1;
144
        gp_Vec midPointProjection = newPoint2 - point1;
145
        double distance = midPointProjection.Magnitude();
146
        midPointProjection.Normalize();
147
        midPointProjection *= distance / 2.0;
148

149
        gp_Vec origin = point1 + midPointProjection;
150

151
        // yaxis should be the same as vector1, but doing this to eliminate any potential slop from
152
        // using precision::angular. If lines are colinear and we have no plane, we can't establish
153
        // zAxis from crossing. we just the absolute axis.
154
        gp_Vec xAxis = (point1 - origin).Normalized();
155
        gp_Vec zAxis;
156
        if (xAxis.IsParallel(vector1, Precision::Angular())) {
157
            if (!xAxis.IsParallel(gp_Vec(0.0, 0.0, 1.0), Precision::Angular())) {
158
                zAxis = gp_Vec(0.0, 0.0, 1.0);
159
            }
160
            else {
161
                zAxis = gp_Vec(0.0, 1.0, 0.0);
162
            }
163
        }
164
        else {
165
            zAxis = xAxis.Crossed(vector1).Normalized();
166
        }
167
        gp_Vec yAxis = zAxis.Crossed(xAxis).Normalized();
168
        zAxis = xAxis.Crossed(yAxis).Normalized();
169

170
        dimSys = SbMatrix(xAxis.X(),
171
                          yAxis.X(),
172
                          zAxis.X(),
173
                          origin.X(),
174
                          xAxis.Y(),
175
                          yAxis.Y(),
176
                          zAxis.Y(),
177
                          origin.Y(),
178
                          xAxis.Z(),
179
                          yAxis.Z(),
180
                          zAxis.Z(),
181
                          origin.Z(),
182
                          0.0,
183
                          0.0,
184
                          0.0,
185
                          1.0);
186
        dimSys = dimSys.transpose();
187

188
        radius = midPointProjection.Magnitude();
189
    }
190
    else {
191
        Handle(Geom_Curve) heapLine1 = new Geom_Line(lin1);
192
        Handle(Geom_Curve) heapLine2 = new Geom_Line(lin2);
193

194
        GeomAPI_ExtremaCurveCurve extrema(heapLine1, heapLine2);
195

196
        if (extrema.NbExtrema() < 1) {
197
            throw Base::RuntimeError("couldn't get extrema");
198
        }
199

200
        gp_Pnt extremaPoint1, extremaPoint2, dimensionOriginPoint;
201
        extrema.Points(1, extremaPoint1, extremaPoint2);
202
        if (extremaPoint1.Distance(extremaPoint2) < Precision::Confusion()) {
203
            dimensionOriginPoint = extremaPoint1;
204
        }
205
        else {
206
            // find halfway point in between extrema points for dimension origin.
207
            gp_Vec vec1(extremaPoint1.XYZ());
208
            gp_Vec vec2(extremaPoint2.XYZ());
209
            gp_Vec connection(vec2 - vec1);
210
            Standard_Real distance = connection.Magnitude();
211
            connection.Normalize();
212
            connection *= (distance / 2.0);
213
            dimensionOriginPoint.SetXYZ((vec1 + connection).XYZ());
214
        }
215

216
        gp_Vec thirdPoint(loc2);
217
        gp_Vec originVector(dimensionOriginPoint.XYZ());
218
        gp_Vec extrema2Vector(extremaPoint2.XYZ());
219
        radius = (loc1 - originVector).Magnitude();
220
        double legOne = (extrema2Vector - originVector).Magnitude();
221
        if (legOne > Precision::Confusion()) {
222
            double legTwo = sqrt(pow(radius, 2) - pow(legOne, 2));
223
            gp_Vec projectionVector(vector2);
224
            projectionVector.Normalize();
225
            projectionVector *= legTwo;
226
            thirdPoint = extrema2Vector + projectionVector;
227
            gp_Vec hyp(thirdPoint - originVector);
228
            hyp.Normalize();
229
            gp_Vec otherSide(loc1 - originVector);
230
            otherSide.Normalize();
231
        }
232

233
        gp_Vec xAxis = (loc1 - originVector).Normalized();
234
        gp_Vec fakeYAxis = (thirdPoint - originVector).Normalized();
235
        gp_Vec zAxis = (xAxis.Crossed(fakeYAxis)).Normalized();
236
        gp_Vec yAxis = zAxis.Crossed(xAxis).Normalized();
237

238
        dimSys = SbMatrix(xAxis.X(),
239
                          yAxis.X(),
240
                          zAxis.X(),
241
                          dimensionOriginPoint.X(),
242
                          xAxis.Y(),
243
                          yAxis.Y(),
244
                          zAxis.Y(),
245
                          dimensionOriginPoint.Y(),
246
                          xAxis.Z(),
247
                          yAxis.Z(),
248
                          zAxis.Z(),
249
                          dimensionOriginPoint.Z(),
250
                          0.0,
251
                          0.0,
252
                          0.0,
253
                          1.0);
254

255
        dimSys = dimSys.transpose();
256
    }
257

258
    return dimSys;
259
}
260

261

262
PROPERTY_SOURCE(MeasureGui::ViewProviderMeasureAngle, MeasureGui::ViewProviderMeasureBase)
263

264

265
ViewProviderMeasureAngle::ViewProviderMeasureAngle()
266
{
267
    sPixmap = "Measurement-Angle";
268

269
    // Primary Arc
270
    Gui::ArcEngine* arcEngine = new Gui::ArcEngine();
271
    arcEngine->angle.connectFrom(&fieldAngle);
272

273
    auto calculatorRadius = new SoCalculator();
274
    calculatorRadius->A.connectFrom(&pDragger->translation);
275
    calculatorRadius->expression.setValue("oa=length(A)");
276
    arcEngine->radius.connectFrom(&calculatorRadius->oa);
277
    arcEngine->deviation.setValue(0.1f);
278

279
    SoCoordinate3* coordinates = new SoCoordinate3();
280
    coordinates->point.connectFrom(&arcEngine->points);
281

282
    SoLineSet* lineSet = new SoLineSet();
283
    lineSet->vertexProperty.setValue(coordinates);
284
    lineSet->numVertices.connectFrom(&arcEngine->pointCount);
285
    lineSet->startIndex.setValue(0);
286

287
    pLineSeparator->addChild(lineSet);
288

289
    // Secondary Arc, from midpoint to label
290
    auto engineAngle = new SoCalculator();
291
    engineAngle->A.connectFrom(&arcEngine->midpoint);
292
    engineAngle->B.connectFrom(&pLabelTranslation->translation);
293
    engineAngle->expression.setValue(
294
        "tA=normalize(A); tB=normalize(B); oa=atan2(tB[1], tB[0])-atan2(tA[1], tA[0])");
295

296
    Gui::ArcEngine* arcEngineSecondary = new Gui::ArcEngine();
297
    arcEngineSecondary->radius.connectFrom(&calculatorRadius->oa);
298
    arcEngineSecondary->deviation.setValue(0.1f);
299
    arcEngineSecondary->angle.connectFrom(&engineAngle->oa);
300

301
    // Rotate arc
302
    auto engineRotMidpoint = new SoComposeRotationFromTo();  // absolute angle to midpoint
303
    engineRotMidpoint->from.setValue(SbVec3f(1.0, 0.0, 0.0));
304
    engineRotMidpoint->to.connectFrom(&arcEngine->midpoint);
305

306
    auto matrixEngine = new SoComposeMatrix();
307
    matrixEngine->rotation.connectFrom(&engineRotMidpoint->rotation);
308
    auto transformEngine = new SoTransformVec3f();
309
    transformEngine->matrix.connectFrom(&matrixEngine->matrix);
310
    transformEngine->vector.connectFrom(&arcEngineSecondary->points);
311

312
    SoCoordinate3* coordinatesSecondary = new SoCoordinate3();
313
    coordinatesSecondary->point.connectFrom(&transformEngine->point);
314

315
    SoLineSet* lineSetSecondary = new SoLineSet();
316
    lineSetSecondary->vertexProperty.setValue(coordinatesSecondary);
317
    lineSetSecondary->numVertices.connectFrom(&arcEngineSecondary->pointCount);
318
    lineSetSecondary->startIndex.setValue(0);
319

320
    pLineSeparatorSecondary->addChild(lineSetSecondary);
321
}
322

323

324
void ViewProviderMeasureAngle::redrawAnnotation()
325
{
326
    auto obj = dynamic_cast<Measure::MeasureAngle*>(getMeasureObject());
327
    double angleDeg = obj->Angle.getValue();
328
    constexpr double radiansPerDegree = M_PI / 180.0;
329
    this->fieldAngle = angleDeg * radiansPerDegree;
330

331
    // Set matrix
332
    try {
333
        SbMatrix matrix = getMatrix();
334
        pcTransform->setMatrix(matrix);
335
    }
336
    catch (const Base::Exception& e) {
337
        Base::Console().Error("Error in ViewProviderMeasureAngle::redrawAnnotation: %s\n",
338
                              e.what());
339
        return;
340
    }
341

342
    // Set Label
343
    setLabelValue(static_cast<Measure::MeasureBase*>(pcObject)->getResultString());
344
}
345

346

347
//! return the feature as a MeasureAngle
348
Measure::MeasureAngle* ViewProviderMeasureAngle::getMeasureAngle()
349
{
350
    Measure::MeasureAngle* feature = dynamic_cast<Measure::MeasureAngle*>(pcObject);
351
    if (!feature) {
352
        throw Base::RuntimeError("Feature not found for ViewProviderMeasureAngle");
353
    }
354
    return feature;
355
}
356

357

358
void ViewProviderMeasureAngle::positionAnno(const Measure::MeasureBase* measureObject)
359
{
360
    (void)measureObject;
361
    setLabelTranslation(SbVec3f(0, 0.1 * getViewScale(), 0));
362
}
363

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.