FreeCAD

Форк
0
/
SoDatumLabel.cpp 
1385 строк · 43.8 Кб
1
/***************************************************************************
2
 *   Copyright (c) 2011-2012 Luke Parry <l.parry@warwick.ac.uk>            *
3
 *                                                                         *
4
 *   This file is part of the FreeCAD CAx development system.              *
5
 *                                                                         *
6
 *   This library is free software; you can redistribute it and/or         *
7
 *   modify it under the terms of the GNU Library General Public           *
8
 *   License as published by the Free Software Foundation; either          *
9
 *   version 2 of the License, or (at your option) any later version.      *
10
 *                                                                         *
11
 *   This library  is distributed in the hope that it will be useful,      *
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
14
 *   GNU Library General Public License for more details.                  *
15
 *                                                                         *
16
 *   You should have received a copy of the GNU Library General Public     *
17
 *   License along with this library; see the file COPYING.LIB. If not,    *
18
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
19
 *   Suite 330, Boston, MA  02111-1307, USA                                *
20
 *                                                                         *
21
 ***************************************************************************/
22

23
#include "PreCompiled.h"
24
#ifndef _PreComp_
25
# ifdef FC_OS_WIN32
26
# include <windows.h>
27
# undef min
28
# undef max
29
# endif
30
# ifdef FC_OS_MACOSX
31
# include <OpenGL/gl.h>
32
# else
33
# include <GL/gl.h>
34
# endif
35

36
# include <algorithm>
37
# include <cfloat>
38
# include <cmath>
39
# include <QFontMetrics>
40
# include <QPainter>
41

42
# include <Inventor/SoPrimitiveVertex.h>
43
# include <Inventor/actions/SoGLRenderAction.h>
44
# include <Inventor/elements/SoFocalDistanceElement.h>
45
# include <Inventor/elements/SoViewportRegionElement.h>
46
# include <Inventor/elements/SoViewVolumeElement.h>
47
# include <Inventor/misc/SoState.h>
48
#endif // _PreComp_
49

50
#include <Gui/BitmapFactory.h>
51
#include <Gui/Tools.h>
52

53
#include "SoDatumLabel.h"
54

55

56
#define ZCONSTR 0.006f
57

58
using namespace Gui;
59

60
// ------------------------------------------------------
61

62
SO_NODE_SOURCE(SoDatumLabel)
63

64
void SoDatumLabel::initClass()
65
{
66
    SO_NODE_INIT_CLASS(SoDatumLabel, SoShape, "Shape");
67
}
68

69

70
SoDatumLabel::SoDatumLabel()
71
{
72
    SO_NODE_CONSTRUCTOR(SoDatumLabel);
73
    SO_NODE_ADD_FIELD(string, (""));
74
    SO_NODE_ADD_FIELD(textColor, (SbVec3f(1.0f,1.0f,1.0f)));
75
    SO_NODE_ADD_FIELD(pnts, (SbVec3f(.0f,.0f,.0f)));
76
    SO_NODE_ADD_FIELD(norm, (SbVec3f(.0f,.0f,1.f)));
77

78
    SO_NODE_ADD_FIELD(name, ("Helvetica"));
79
    SO_NODE_ADD_FIELD(size, (10.f));
80
    SO_NODE_ADD_FIELD(lineWidth, (2.f));
81

82
    SO_NODE_ADD_FIELD(datumtype, (SoDatumLabel::DISTANCE));
83

84
    SO_NODE_DEFINE_ENUM_VALUE(Type, DISTANCE);
85
    SO_NODE_DEFINE_ENUM_VALUE(Type, DISTANCEX);
86
    SO_NODE_DEFINE_ENUM_VALUE(Type, DISTANCEY);
87
    SO_NODE_DEFINE_ENUM_VALUE(Type, ANGLE);
88
    SO_NODE_DEFINE_ENUM_VALUE(Type, RADIUS);
89
    SO_NODE_DEFINE_ENUM_VALUE(Type, DIAMETER);
90
    SO_NODE_SET_SF_ENUM_TYPE(datumtype, Type);
91

92
    SO_NODE_ADD_FIELD(param1, (0.f));
93
    SO_NODE_ADD_FIELD(param2, (0.f));
94
    SO_NODE_ADD_FIELD(param4, (0.f));
95
    SO_NODE_ADD_FIELD(param5, (0.f));
96
    SO_NODE_ADD_FIELD(param6, (0.f));
97
    SO_NODE_ADD_FIELD(param7, (0.f));
98
    SO_NODE_ADD_FIELD(param8, (0.f));
99

100
    useAntialiasing = true;
101

102
    this->imgWidth = 0;
103
    this->imgHeight = 0;
104
    this->glimagevalid = false;
105
}
106

107
void SoDatumLabel::drawImage()
108
{
109
    const SbString* s = string.getValues(0);
110
    int num = string.getNum();
111
    if (num == 0) {
112
        this->image = SoSFImage();
113
        return;
114
    }
115

116
    QFont font(QString::fromLatin1(name.getValue(), -1), size.getValue());
117
    QFontMetrics fm(font);
118
    QString str = QString::fromUtf8(s[0].getString());
119

120
    int w = Gui::QtTools::horizontalAdvance(fm, str);
121
    int h = fm.height();
122

123
    // No Valid text
124
    if (!w) {
125
        this->image = SoSFImage();
126
        return;
127
    }
128

129
    const SbColor& t = textColor.getValue();
130
    QColor front;
131
    front.setRgbF(t[0],t[1], t[2]);
132

133
    QImage image(w, h,QImage::Format_ARGB32_Premultiplied);
134
    image.fill(0x00000000);
135

136
    QPainter painter(&image);
137
    if(useAntialiasing)
138
        painter.setRenderHint(QPainter::Antialiasing);
139

140
    painter.setPen(front);
141
    painter.setFont(font);
142
    painter.drawText(0, 0, w, h, Qt::AlignLeft, str);
143
    painter.end();
144

145
    Gui::BitmapFactory().convert(image, this->image);
146
}
147

148
namespace {
149
// Helper class to determine the bounding box of a datum label
150
class DatumLabelBox
151
{
152
public:
153
    DatumLabelBox(float scale, SoDatumLabel* label)
154
        : scale{scale}
155
        , label{label}
156
    {
157

158
    }
159
    void computeBBox(SbBox3f& box, SbVec3f& center) const
160
    {
161
        std::vector<SbVec3f> corners;
162
        if (label->datumtype.getValue() == SoDatumLabel::DISTANCE ||
163
            label->datumtype.getValue() == SoDatumLabel::DISTANCEX ||
164
            label->datumtype.getValue() == SoDatumLabel::DISTANCEY ) {
165
            corners = computeDistanceBBox();
166
        }
167
        else if (label->datumtype.getValue() == SoDatumLabel::RADIUS ||
168
                 label->datumtype.getValue() == SoDatumLabel::DIAMETER) {
169
            corners = computeRadiusDiameterBBox();
170
        }
171
        else if (label->datumtype.getValue() == SoDatumLabel::ANGLE) {
172
            corners = computeAngleBBox();
173
        }
174
        else if (label->datumtype.getValue() == SoDatumLabel::SYMMETRIC) {
175
            corners = computeSymmetricBBox();
176
        }
177

178
        getBBox(corners, box, center);
179
    }
180

181
private:
182
    void getBBox(const std::vector<SbVec3f>& corners, SbBox3f& box, SbVec3f& center) const
183
    {
184
        if (corners.size() > 1) {
185
            float minX = FLT_MAX;
186
            float minY = FLT_MAX;
187
            float maxX = -FLT_MAX;
188
            float maxY = -FLT_MAX;
189
            for (SbVec3f it : corners) {
190
                minX = (it[0] < minX) ? it[0] : minX;
191
                minY = (it[1] < minY) ? it[1] : minY;
192
                maxX = (it[0] > maxX) ? it[0] : maxX;
193
                maxY = (it[1] > maxY) ? it[1] : maxY;
194
            }
195

196
            // Store the bounding box
197
            box.setBounds(SbVec3f(minX, minY, 0.0F), SbVec3f (maxX, maxY, 0.0F));
198
            center = box.getCenter();
199
        }
200
    }
201
    std::vector<SbVec3f> computeDistanceBBox() const
202
    {
203
        SbVec2s imgsize;
204
        int nc;
205
        int srcw = 1;
206
        int srch = 1;
207

208
        const unsigned char * dataptr = label->image.getValue(imgsize, nc);
209
        if (dataptr) {
210
            srcw = imgsize[0];
211
            srch = imgsize[1];
212
        }
213

214
        float aspectRatio =  (float) srcw / (float) srch;
215
        float imgHeight = scale * (float) (srch);
216
        float imgWidth  = aspectRatio * imgHeight;
217

218
        // Get the points stored in the pnt field
219
        const SbVec3f *points = label->pnts.getValues(0);
220
        if (label->pnts.getNum() < 2) {
221
            return {};
222
        }
223

224
        SbVec3f textOffset;
225

226
        float length = label->param1.getValue();
227
        float length2 = label->param2.getValue();
228

229
        SbVec3f p1 = points[0];
230
        SbVec3f p2 = points[1];
231

232
        SbVec3f dir;
233
        SbVec3f normal;
234
        if (label->datumtype.getValue() == SoDatumLabel::DISTANCE) {
235
            dir = (p2-p1);
236
        }
237
        else if (label->datumtype.getValue() == SoDatumLabel::DISTANCEX) {
238
            dir = SbVec3f( (p2[0] - p1[0] >= FLT_EPSILON) ? 1 : -1, 0, 0);
239
        }
240
        else if (label->datumtype.getValue() == SoDatumLabel::DISTANCEY) {
241
            dir = SbVec3f(0, (p2[1] - p1[1] >= FLT_EPSILON) ? 1 : -1, 0);
242
        }
243

244
        dir.normalize();
245
        normal = SbVec3f (-dir[1], dir[0], 0);
246

247
        // when the datum line is not parallel to p1-p2 the projection of
248
        // p1-p2 on normal is not zero, p2 is considered as reference and p1
249
        // is replaced by its projection p1_
250
        float normproj12 = (p2 - p1).dot(normal);
251
        SbVec3f p1_ = p1 + normproj12 * normal;
252

253
        SbVec3f midpos = (p1_ + p2)/2;
254

255
        float offset1 = ((length + normproj12 < 0.0F) ? -1.0F  : 1.0F) * float(srch);
256
        float offset2 = ((length < 0.0F) ? -1.0F  : 1.0F) * float(srch);
257

258
        textOffset = midpos + normal * length + dir * length2;
259
        float margin = imgHeight / 4.0F;
260

261
        SbVec3f perp1 = p1_ + normal * (length + offset1 * scale);
262
        SbVec3f perp2 = p2  + normal * (length + offset2 * scale);
263

264
        // Finds the mins and maxes
265
        std::vector<SbVec3f> corners;
266
        corners.push_back(p1);
267
        corners.push_back(p2);
268
        corners.push_back(perp1);
269
        corners.push_back(perp2);
270

271
        // Make sure that the label is inside the bounding box
272
        corners.push_back(textOffset + dir * (imgWidth / 2.0F + margin) + normal * (srch + margin));
273
        corners.push_back(textOffset - dir * (imgWidth / 2.0F + margin) + normal * (srch + margin));
274
        corners.push_back(textOffset + dir * (imgWidth / 2.0F + margin) - normal * margin);
275
        corners.push_back(textOffset - dir * (imgWidth / 2.0F + margin) - normal * margin);
276

277
        return corners;
278
    }
279

280
    std::vector<SbVec3f> computeRadiusDiameterBBox() const
281
    {
282
        SbVec2s imgsize;
283
        int nc;
284
        int srcw = 1;
285
        int srch = 1;
286

287
        const unsigned char * dataptr = label->image.getValue(imgsize, nc);
288
        if (dataptr) {
289
            srcw = imgsize[0];
290
            srch = imgsize[1];
291
        }
292

293
        float aspectRatio =  (float) srcw / (float) srch;
294
        float imgHeight = scale * (float) (srch);
295
        float imgWidth  = aspectRatio * imgHeight;
296

297
        // Get the points stored in the pnt field
298
        const SbVec3f *points = label->pnts.getValues(0);
299
        if (label->pnts.getNum() < 2) {
300
            return {};
301
        }
302

303
        // Get the Points
304
        SbVec3f p1 = points[0];
305
        SbVec3f p2 = points[1];
306

307
        SbVec3f dir = p2 - p1;
308
        dir.normalize();
309
        SbVec3f normal (-dir[1], dir[0], 0);
310

311
        float length = label->param1.getValue();
312
        SbVec3f pos = p2 + length*dir;
313

314
        float margin = imgHeight / 4.0F;
315

316
        SbVec3f p3 = pos +  dir * (imgWidth / 2.0F + margin);
317
        if ((p3-p1).length() > (p2-p1).length()) {
318
            p2 = p3;
319
        }
320

321
        // Calculate the points
322
        SbVec3f pnt1 = pos - dir * (margin + imgWidth / 2.0F);
323
        SbVec3f pnt2 = pos + dir * (margin + imgWidth / 2.0F);
324

325
        // Finds the mins and maxes
326
        std::vector<SbVec3f> corners;
327
        corners.push_back(p1);
328
        corners.push_back(p2);
329
        corners.push_back(pnt1);
330
        corners.push_back(pnt2);
331

332
        return corners;
333
    }
334

335
    std::vector<SbVec3f> computeAngleBBox() const
336
    {
337
        SbVec2s imgsize;
338
        int nc;
339
        int srcw = 1;
340
        int srch = 1;
341

342
        const unsigned char * dataptr = label->image.getValue(imgsize, nc);
343
        if (dataptr) {
344
            srcw = imgsize[0];
345
            srch = imgsize[1];
346
        }
347

348
        float aspectRatio =  (float) srcw / (float) srch;
349
        float imgHeight = scale * (float) (srch);
350
        float imgWidth  = aspectRatio * imgHeight;
351

352
        // Get the points stored in the pnt field
353
        const SbVec3f *points = label->pnts.getValues(0);
354
        if (label->pnts.getNum() < 1) {
355
            return {};
356
        }
357

358
        // Only the angle intersection point is needed
359
        SbVec3f p0 = points[0];
360

361
        // Load the Parameters
362
        float length     = label->param1.getValue();
363
        float startangle = label->param2.getValue();
364
        float range      = label->param3.getValue();
365
        float endangle   = startangle + range;
366

367

368
        float len2 = 2.0F * length;
369

370
        // Useful Information
371
        // v0 - vector for text position
372
        // p0 - vector for angle intersect
373
        SbVec3f v0(cos(startangle+range/2), sin(startangle+range/2), 0);
374

375
        SbVec3f textOffset = p0 + v0 * len2;
376

377
        float margin = imgHeight / 4.0F;
378

379
        // Direction vectors for start and end lines
380
        SbVec3f v1(cos(startangle), sin(startangle), 0);
381
        SbVec3f v2(cos(endangle), sin(endangle), 0);
382

383
        SbVec3f pnt1 = p0+(len2-margin)*v1;
384
        SbVec3f pnt2 = p0+(len2+margin)*v1;
385
        SbVec3f pnt3 = p0+(len2-margin)*v2;
386
        SbVec3f pnt4 = p0+(len2+margin)*v2;
387

388
        // Finds the mins and maxes
389
        // We may need to include the text position too
390

391
        SbVec3f img1 = SbVec3f(-imgWidth / 2.0F, -imgHeight / 2, 0.0F);
392
        SbVec3f img2 = SbVec3f(-imgWidth / 2.0F,  imgHeight / 2, 0.0F);
393
        SbVec3f img3 = SbVec3f( imgWidth / 2.0F, -imgHeight / 2, 0.0F);
394
        SbVec3f img4 = SbVec3f( imgWidth / 2.0F,  imgHeight / 2, 0.0F);
395

396
        img1 += textOffset;
397
        img2 += textOffset;
398
        img3 += textOffset;
399
        img4 += textOffset;
400

401
        std::vector<SbVec3f> corners;
402
        corners.push_back(pnt1);
403
        corners.push_back(pnt2);
404
        corners.push_back(pnt3);
405
        corners.push_back(pnt4);
406
        corners.push_back(img1);
407
        corners.push_back(img2);
408
        corners.push_back(img3);
409
        corners.push_back(img4);
410

411
        return corners;
412
    }
413

414
    std::vector<SbVec3f> computeSymmetricBBox() const
415
    {
416
        // Get the points stored in the pnt field
417
        const SbVec3f *points = label->pnts.getValues(0);
418
        if (label->pnts.getNum() < 2) {
419
            return {};
420
        }
421

422
        SbVec3f p1 = points[0];
423
        SbVec3f p2 = points[1];
424

425
        // Finds the mins and maxes
426
        std::vector<SbVec3f> corners;
427
        corners.push_back(p1);
428
        corners.push_back(p2);
429

430
        return corners;
431
    }
432

433
private:
434
    float scale;
435
    SoDatumLabel* label;
436
};
437
}
438

439
void SoDatumLabel::computeBBox(SoAction * action, SbBox3f &box, SbVec3f &center)
440
{
441
    SoState *state = action->getState();
442
    float scale = getScaleFactor(state);
443

444
    DatumLabelBox datumBox(scale, this);
445
    datumBox.computeBBox(box, center);
446
}
447

448
SbVec3f SoDatumLabel::getLabelTextCenter()
449
{
450
    // Get the points stored
451
    const SbVec3f* points = this->pnts.getValues(0);
452
    SbVec3f p1 = points[0];
453
    SbVec3f p2 = points[1];
454

455
    if (datumtype.getValue() == SoDatumLabel::DISTANCE ||
456
        datumtype.getValue() == SoDatumLabel::DISTANCEX ||
457
        datumtype.getValue() == SoDatumLabel::DISTANCEY) {
458
        return getLabelTextCenterDistance(p1, p2);
459
    }
460
    else if (datumtype.getValue() == SoDatumLabel::RADIUS ||
461
        datumtype.getValue() == SoDatumLabel::DIAMETER) {
462
        return getLabelTextCenterDiameter(p1, p2);
463

464
    }
465
    else if (datumtype.getValue() == SoDatumLabel::ANGLE) {
466
        return getLabelTextCenterAngle(p1);
467
    }
468

469
    return p1;
470
}
471

472
SbVec3f SoDatumLabel::getLabelTextCenterDistance(const SbVec3f& p1, const SbVec3f& p2)
473
{
474
    float length = param1.getValue();
475
    float length2 = param2.getValue();
476

477
    SbVec3f dir;
478
    SbVec3f normal;
479
    if (datumtype.getValue() == SoDatumLabel::DISTANCE) {
480
        dir = (p2 - p1);
481
    }
482
    else if (datumtype.getValue() == SoDatumLabel::DISTANCEX) {
483
        dir = SbVec3f((p2[0] - p1[0] >= FLT_EPSILON) ? 1 : -1, 0, 0);
484
    }
485
    else if (datumtype.getValue() == SoDatumLabel::DISTANCEY) {
486
        dir = SbVec3f(0, (p2[1] - p1[1] >= FLT_EPSILON) ? 1 : -1, 0);
487
    }
488

489
    dir.normalize();
490
    normal = SbVec3f(-dir[1], dir[0], 0);
491

492
    float normproj12 = (p2 - p1).dot(normal);
493
    SbVec3f p1_ = p1 + normproj12 * normal;
494

495
    SbVec3f midpos = (p1_ + p2) / 2;
496

497
    SbVec3f textCenter = midpos + normal * length + dir * length2;
498
    return textCenter;
499
}
500

501
SbVec3f SoDatumLabel::getLabelTextCenterDiameter(const SbVec3f& p1, const SbVec3f& p2)
502
{
503
    SbVec3f dir = (p2 - p1);
504
    dir.normalize();
505

506
    float length = this->param1.getValue();
507
    SbVec3f textCenter = p2 + length * dir;
508
    return textCenter;
509
}
510

511
SbVec3f SoDatumLabel::getLabelTextCenterAngle(const SbVec3f& p0)
512
{
513
    // Load the Parameters
514
    float length = param1.getValue();
515
    float startangle = param2.getValue();
516
    float range = param3.getValue();
517
    float len2 = 2.0F * length;
518

519
    // Useful Information
520
    // v0 - vector for text position
521
    // p0 - vector for angle intersect
522
    SbVec3f v0(cos(startangle + range / 2), sin(startangle + range / 2), 0);
523

524
    SbVec3f textCenter = p0 + v0 * len2;
525
    return textCenter;
526
}
527

528
void SoDatumLabel::generateDistancePrimitives(SoAction * action, const SbVec3f& p1, const SbVec3f& p2)
529
{
530
    SbVec3f dir;
531
    if (this->datumtype.getValue() == DISTANCE) {
532
        dir = (p2-p1);
533
    } else if (this->datumtype.getValue() == DISTANCEX) {
534
        dir = SbVec3f( (p2[0] - p1[0] >= FLT_EPSILON) ? 1 : -1, 0, 0);
535
    } else if (this->datumtype.getValue() == DISTANCEY) {
536
        dir = SbVec3f(0, (p2[1] - p1[1] >= FLT_EPSILON) ? 1 : -1, 0);
537
    }
538

539
    dir.normalize();
540

541
    // Get magnitude of angle between horizontal
542
    float angle = atan2f(dir[1],dir[0]);
543

544
    SbVec3f img1 = SbVec3f(-this->imgWidth / 2, -this->imgHeight / 2, 0.f);
545
    SbVec3f img2 = SbVec3f(-this->imgWidth / 2,  this->imgHeight / 2, 0.f);
546
    SbVec3f img3 = SbVec3f( this->imgWidth / 2, -this->imgHeight / 2, 0.f);
547
    SbVec3f img4 = SbVec3f( this->imgWidth / 2,  this->imgHeight / 2, 0.f);
548

549
    // Rotate through an angle
550
    float s = sin(angle);
551
    float c = cos(angle);
552

553
    img1 = SbVec3f((img1[0] * c) - (img1[1] * s), (img1[0] * s) + (img1[1] * c), 0.f);
554
    img2 = SbVec3f((img2[0] * c) - (img2[1] * s), (img2[0] * s) + (img2[1] * c), 0.f);
555
    img3 = SbVec3f((img3[0] * c) - (img3[1] * s), (img3[0] * s) + (img3[1] * c), 0.f);
556
    img4 = SbVec3f((img4[0] * c) - (img4[1] * s), (img4[0] * s) + (img4[1] * c), 0.f);
557

558
    SbVec3f textOffset = getLabelTextCenterDistance(p1, p2);
559

560
    img1 += textOffset;
561
    img2 += textOffset;
562
    img3 += textOffset;
563
    img4 += textOffset;
564

565
    // Primitive Shape is only for text as this should only be selectable
566
    SoPrimitiveVertex pv;
567

568
    this->beginShape(action, TRIANGLE_STRIP);
569

570
    pv.setNormal( SbVec3f(0.f, 0.f, 1.f) );
571

572
    // Set coordinates
573
    pv.setPoint( img1 );
574
    shapeVertex(&pv);
575

576
    pv.setPoint( img2 );
577
    shapeVertex(&pv);
578

579
    pv.setPoint( img3 );
580
    shapeVertex(&pv);
581

582
    pv.setPoint( img4 );
583
    shapeVertex(&pv);
584

585
    this->endShape();
586
}
587

588
void SoDatumLabel::generateDiameterPrimitives(SoAction * action, const SbVec3f& p1, const SbVec3f& p2)
589
{
590
    SbVec3f dir = (p2-p1);
591
    dir.normalize();
592

593
    float angle = atan2f(dir[1],dir[0]);
594

595
    SbVec3f img1 = SbVec3f(-this->imgWidth / 2, -this->imgHeight / 2, 0.f);
596
    SbVec3f img2 = SbVec3f(-this->imgWidth / 2,  this->imgHeight / 2, 0.f);
597
    SbVec3f img3 = SbVec3f( this->imgWidth / 2, -this->imgHeight / 2, 0.f);
598
    SbVec3f img4 = SbVec3f( this->imgWidth / 2,  this->imgHeight / 2, 0.f);
599

600
    // Rotate through an angle
601
    float s = sin(angle);
602
    float c = cos(angle);
603

604
    img1 = SbVec3f((img1[0] * c) - (img1[1] * s), (img1[0] * s) + (img1[1] * c), 0.f);
605
    img2 = SbVec3f((img2[0] * c) - (img2[1] * s), (img2[0] * s) + (img2[1] * c), 0.f);
606
    img3 = SbVec3f((img3[0] * c) - (img3[1] * s), (img3[0] * s) + (img3[1] * c), 0.f);
607
    img4 = SbVec3f((img4[0] * c) - (img4[1] * s), (img4[0] * s) + (img4[1] * c), 0.f);
608

609
    SbVec3f textOffset = getLabelTextCenterDiameter(p1, p2);
610

611
    img1 += textOffset;
612
    img2 += textOffset;
613
    img3 += textOffset;
614
    img4 += textOffset;
615

616
    // Primitive Shape is only for text as this should only be selectable
617
    SoPrimitiveVertex pv;
618

619
    this->beginShape(action, TRIANGLE_STRIP);
620

621
    pv.setNormal( SbVec3f(0.f, 0.f, 1.f) );
622

623
    // Set coordinates
624
    pv.setPoint( img1 );
625
    shapeVertex(&pv);
626

627
    pv.setPoint( img2 );
628
    shapeVertex(&pv);
629

630
    pv.setPoint( img3 );
631
    shapeVertex(&pv);
632

633
    pv.setPoint( img4 );
634
    shapeVertex(&pv);
635

636
    this->endShape();
637
}
638

639
void SoDatumLabel::generateAnglePrimitives(SoAction * action, const SbVec3f& p0)
640
{
641
    SbVec3f textOffset = getLabelTextCenterAngle(p0);
642

643
    SbVec3f img1 = SbVec3f(-this->imgWidth / 2, -this->imgHeight / 2, 0.f);
644
    SbVec3f img2 = SbVec3f(-this->imgWidth / 2,  this->imgHeight / 2, 0.f);
645
    SbVec3f img3 = SbVec3f( this->imgWidth / 2, -this->imgHeight / 2, 0.f);
646
    SbVec3f img4 = SbVec3f( this->imgWidth / 2,  this->imgHeight / 2, 0.f);
647

648
    img1 += textOffset;
649
    img2 += textOffset;
650
    img3 += textOffset;
651
    img4 += textOffset;
652

653
    // Primitive Shape is only for text as this should only be selectable
654
    SoPrimitiveVertex pv;
655

656
    this->beginShape(action, TRIANGLE_STRIP);
657

658
    pv.setNormal( SbVec3f(0.f, 0.f, 1.f) );
659

660
    // Set coordinates
661
    pv.setPoint( img1 );
662
    shapeVertex(&pv);
663

664
    pv.setPoint( img2 );
665
    shapeVertex(&pv);
666

667
    pv.setPoint( img3 );
668
    shapeVertex(&pv);
669

670
    pv.setPoint( img4 );
671
    shapeVertex(&pv);
672

673
    this->endShape();
674
}
675

676
void SoDatumLabel::generateSymmetricPrimitives(SoAction * action, const SbVec3f& p1, const SbVec3f& p2)
677
{
678
    SbVec3f dir = (p2-p1);
679
    dir.normalize();
680
    SbVec3f normal (-dir[1],dir[0],0);
681

682
    float margin = this->imgHeight / 4.0;
683

684
    // Calculate coordinates for the first arrow
685
    SbVec3f ar0, ar1, ar2;
686
    ar0  = p1 + dir * 5 * margin ;
687
    ar1  = ar0 - dir * 0.866f * 2 * margin; // Base Point of Arrow
688
    ar2  = ar1 + normal * margin; // Triangular corners
689
    ar1 -= normal * margin;
690

691
    // Calculate coordinates for the second arrow
692
    SbVec3f ar3, ar4, ar5;
693
    ar3  = p2 - dir * 5 * margin ;
694
    ar4  = ar3 + dir * 0.866f * 2 * margin; // Base Point of 2nd Arrow
695

696
    ar5  = ar4 + normal * margin; // Triangular corners
697
    ar4 -= normal * margin;
698

699
    SoPrimitiveVertex pv;
700

701
    this->beginShape(action, TRIANGLES);
702

703
    pv.setNormal( SbVec3f(0.f, 0.f, 1.f) );
704

705
    // Set coordinates
706
    pv.setPoint( ar0 );
707
    shapeVertex(&pv);
708

709
    pv.setPoint( ar1 );
710
    shapeVertex(&pv);
711

712
    pv.setPoint( ar2 );
713
    shapeVertex(&pv);
714

715
    // Set coordinates
716
    pv.setPoint( ar3 );
717
    shapeVertex(&pv);
718

719
    pv.setPoint( ar4 );
720
    shapeVertex(&pv);
721

722
    pv.setPoint( ar5 );
723
    shapeVertex(&pv);
724

725
    this->endShape();
726
}
727

728
void SoDatumLabel::generatePrimitives(SoAction * action)
729
{
730
    // Initialisation check (needs something more sensible) prevents an infinite loop bug
731
    if (this->imgHeight <= FLT_EPSILON || this->imgWidth <= FLT_EPSILON)
732
        return;
733

734
    // Get the points stored
735
    const SbVec3f *points = this->pnts.getValues(0);
736
    SbVec3f p1 = points[0];
737
    SbVec3f p2 = points[1];
738

739
    // Change the offset and bounding box parameters depending on Datum Type
740
    if (this->datumtype.getValue() == DISTANCE ||
741
        this->datumtype.getValue() == DISTANCEX ||
742
        this->datumtype.getValue() == DISTANCEY) {
743

744
        generateDistancePrimitives(action, p1, p2);
745
    }
746
    else if (this->datumtype.getValue() == RADIUS ||
747
             this->datumtype.getValue() == DIAMETER) {
748

749
        generateDiameterPrimitives(action, p1, p2);
750
    }
751
    else if (this->datumtype.getValue() == ANGLE) {
752

753
        generateAnglePrimitives(action, p1);
754
    }
755
    else if (this->datumtype.getValue() == SYMMETRIC) {
756

757
        generateSymmetricPrimitives(action, p1, p2);
758
    }
759
}
760

761
void SoDatumLabel::notify(SoNotList * l)
762
{
763
    SoField * f = l->getLastField();
764
    if (f == &this->string) {
765
        this->glimagevalid = false;
766
    }
767
    else if (f == &this->textColor) {
768
        this->glimagevalid = false;
769
    }
770
    else if (f == &this->name) {
771
        this->glimagevalid = false;
772
    }
773
    else if (f == &this->size) {
774
        this->glimagevalid = false;
775
    }
776
    else if (f == &this->image) {
777
        this->glimagevalid = false;
778
    }
779
    inherited::notify(l);
780
}
781

782
float SoDatumLabel::getScaleFactor(SoState* state) const
783
{
784
    /**Remark from Stefan Tröger:
785
    * The scale calculation is based on knowledge of SbViewVolume::getWorldToScreenScale
786
    * implementation internals. The factor returned from this function is calculated from the view frustums
787
    * nearplane width, height is not taken into account, and hence we divide it with the viewport width
788
    * to get the exact pixel scale factor.
789
    * This is not documented and therefore may change on later coin versions!
790
    */
791
    const SbViewVolume & vv = SoViewVolumeElement::get(state);
792
    // As reference use the center point the camera is looking at on the focal plane
793
    // because then independent of the camera we get a constant scale factor when panning.
794
    // If we used (0,0,0) instead then the scale factor would change heavily in perspective
795
    // rendering mode. See #0002921 and #0002922.
796
    // It's important to use the distance to the focal plane an not near or far plane because
797
    // depending on additionally displayed objects they may change heavily and thus impact the
798
    // scale factor. See #7082 and #7860.
799
    float focal = SoFocalDistanceElement::get(state);
800
    SbVec3f center = vv.getSightPoint(focal);
801
    float scale = vv.getWorldToScreenScale(center, 1.f);
802
    const SbViewportRegion & vp = SoViewportRegionElement::get(state);
803
    SbVec2s vp_size = vp.getViewportSizePixels();
804
    scale /= float(vp_size[0]);
805

806
    return scale;
807
}
808

809
void SoDatumLabel::GLRender(SoGLRenderAction * action)
810
{
811
    SoState *state = action->getState();
812

813
    if (!shouldGLRender(action))
814
        return;
815
    if (action->handleTransparency(true))
816
        return;
817

818
    float scale = getScaleFactor(state);
819

820
    const SbString* s = string.getValues(0);
821
    bool hasText = (s->getLength() > 0) ? true : false;
822

823
    SbVec2s imgsize;
824
    int nc;
825
    int srcw=1, srch=1;
826

827
    if (hasText) {
828
        if (!this->glimagevalid) {
829
            drawImage();
830
            this->glimagevalid = true;
831
        }
832

833
        const unsigned char * dataptr = this->image.getValue(imgsize, nc);
834
        if (!dataptr) // no image
835
            return;
836

837
        srcw = imgsize[0];
838
        srch = imgsize[1];
839

840
        float aspectRatio =  (float) srcw / (float) srch;
841
        this->imgHeight = scale * (float) (srch);
842
        this->imgWidth  = aspectRatio * (float) this->imgHeight;
843
    }
844

845
    if (this->datumtype.getValue() == SYMMETRIC) {
846
        this->imgHeight = scale*25.0f;
847
        this->imgWidth = scale*25.0f;
848
    }
849

850
    // Get the points stored in the pnt field
851
    const SbVec3f *points = this->pnts.getValues(0);
852

853
    state->push();
854

855
    //Set General OpenGL Properties
856
    glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT);
857
    glDisable(GL_LIGHTING);
858

859
    //Enable Anti-alias
860
    if (action->isSmoothing()) {
861
        glEnable(GL_LINE_SMOOTH);
862
        glEnable(GL_BLEND);
863
        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
864
        glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
865
    }
866

867
    // Position for Datum Text Label
868
    float angle = 0;
869

870
    // Get the colour
871
    const SbColor& t = textColor.getValue();
872

873
    // Set GL Properties
874
    glLineWidth(this->lineWidth.getValue());
875
    glColor3f(t[0], t[1], t[2]);
876

877
    SbVec3f textOffset;
878

879
    if (this->datumtype.getValue() == DISTANCE ||
880
        this->datumtype.getValue() == DISTANCEX ||
881
        this->datumtype.getValue() == DISTANCEY ) {
882
        float length = this->param1.getValue();
883
        float length2 = this->param2.getValue();
884

885
        SbVec3f p1 = points[0];
886
        SbVec3f p2 = points[1];
887

888
        SbVec3f dir, normal;
889
        if (this->datumtype.getValue() == DISTANCE) {
890
            dir = (p2-p1);
891
        } else if (this->datumtype.getValue() == DISTANCEX) {
892
            dir = SbVec3f( (p2[0] - p1[0] >= FLT_EPSILON) ? 1 : -1, 0, 0);
893
        } else if (this->datumtype.getValue() == DISTANCEY) {
894
            dir = SbVec3f(0, (p2[1] - p1[1] >= FLT_EPSILON) ? 1 : -1, 0);
895
        }
896

897
        dir.normalize();
898
        normal = SbVec3f (-dir[1],dir[0],0);
899

900
        // when the datum line is not parallel to p1-p2 the projection of
901
        // p1-p2 on normal is not zero, p2 is considered as reference and p1
902
        // is replaced by its projection p1_
903
        float normproj12 = (p2-p1).dot(normal);
904
        SbVec3f p1_ = p1 + normproj12 * normal;
905

906
        SbVec3f midpos = (p1_ + p2)/2;
907

908
        float offset1 = ((length + normproj12 < 0) ? -1.  : 1.) * srch;
909
        float offset2 = ((length < 0) ? -1  : 1)*srch;
910

911
        // Get magnitude of angle between horizontal
912
        angle = atan2f(dir[1],dir[0]);
913
        if (angle > M_PI_2+M_PI/12) {
914
            angle -= (float)M_PI;
915
        } else if (angle <= -M_PI_2+M_PI/12) {
916
            angle += (float)M_PI;
917
        }
918

919
        textOffset = midpos + normal * length + dir * length2;
920

921
        // Get the colour
922
        const SbColor& t = textColor.getValue();
923

924
        // Set GL Properties
925
        glLineWidth(this->lineWidth.getValue());
926
        glColor3f(t[0], t[1], t[2]);
927
        float margin = this->imgHeight / 3.0;
928

929

930
        SbVec3f perp1 = p1_ + normal * (length + offset1 * scale);
931
        SbVec3f perp2 = p2  + normal * (length + offset2 * scale);
932

933
        // Calculate the coordinates for the parallel datum lines
934
        SbVec3f par1 = p1_ + normal * length;
935
        SbVec3f par2 = midpos + normal * length + dir * (length2 - this->imgWidth / 2 - margin);
936
        SbVec3f par3 = midpos + normal * length + dir * (length2 + this->imgWidth / 2 + margin);
937
        SbVec3f par4 = p2  + normal * length;
938

939
        bool flipTriang = false;
940

941
        if ((par3-par1).dot(dir) > (par4 - par1).length()) {
942
            // Increase Margin to improve visibility
943
            float tmpMargin = this->imgHeight /0.75;
944
            par3 = par4;
945
            if ((par2-par1).dot(dir) > (par4 - par1).length()) {
946
                par3 = par2;
947
                par2 = par1 - dir * tmpMargin;
948
                flipTriang = true;
949
            }
950
        }
951
        else if ((par2-par1).dot(dir) < 0.f) {
952
            float tmpMargin = this->imgHeight /0.75;
953
            par2 = par1;
954
            if((par3-par1).dot(dir) < 0.f) {
955
                par2 = par3;
956
                par3 = par4 + dir * tmpMargin;
957
                flipTriang = true;
958
            }
959
        }
960
        // Perp Lines
961
        glBegin(GL_LINES);
962
            if (length != 0.) {
963
                glVertex2f(p1[0], p1[1]);
964
                glVertex2f(perp1[0], perp1[1]);
965

966
                glVertex2f(p2[0], p2[1]);
967
                glVertex2f(perp2[0], perp2[1]);
968
            }
969

970
            glVertex2f(par1[0], par1[1]);
971
            glVertex2f(par2[0], par2[1]);
972

973
            glVertex2f(par3[0], par3[1]);
974
            glVertex2f(par4[0], par4[1]);
975
        glEnd();
976

977
        float arrowWidth = margin * 0.5;
978

979
        SbVec3f ar1 = par1 + ((flipTriang) ? -1 : 1) * dir * 0.866f * 2 * margin;
980
        SbVec3f ar2 = ar1 + normal * arrowWidth;
981
        ar1 -= normal * arrowWidth;
982

983
        SbVec3f ar3 = par4 - ((flipTriang) ? -1 : 1) * dir * 0.866f * 2 * margin;
984
        SbVec3f ar4 = ar3 + normal * arrowWidth;
985
        ar3 -= normal * arrowWidth;
986

987
        // Draw the arrowheads
988
        glBegin(GL_TRIANGLES);
989
            glVertex2f(par1[0], par1[1]);
990
            glVertex2f(ar1[0], ar1[1]);
991
            glVertex2f(ar2[0], ar2[1]);
992

993
            glVertex2f(par4[0], par4[1]);
994
            glVertex2f(ar3[0], ar3[1]);
995
            glVertex2f(ar4[0], ar4[1]);
996
        glEnd();
997

998

999
        if (this->datumtype.getValue() == DISTANCE) {
1000
            // Draw arc helpers if needed
1001
            float range1 = this->param4.getValue();
1002
            if (range1 != 0.0) {
1003
                float startangle1 = this->param3.getValue();
1004
                float radius1 = this->param5.getValue();
1005
                SbVec3f center = points[2];
1006
                int countSegments = std::max(6, abs(int(50.0 * range1 / (2 * M_PI))));
1007
                double segment = range1 / (countSegments - 1);
1008

1009
                glBegin(GL_LINE_STRIP);
1010
                for (int i = 0; i < countSegments; i++) {
1011
                    double theta = startangle1 + segment * i;
1012
                    SbVec3f v1 = center + SbVec3f(radius1 * cos(theta), radius1 * sin(theta), 0);
1013
                    glVertex2f(v1[0], v1[1]);
1014
                }
1015
                glEnd();
1016
            }
1017
            float range2 = this->param7.getValue();
1018
            if (range2 != 0.0) {
1019
                float startangle2 = this->param6.getValue();
1020
                float radius2 = this->param8.getValue();
1021
                SbVec3f center = points[3];
1022
                int countSegments = std::max(6, abs(int(50.0 * range2 / (2 * M_PI))));
1023
                double segment = range2 / (countSegments - 1);
1024

1025
                glBegin(GL_LINE_STRIP);
1026
                for (int i = 0; i < countSegments; i++) {
1027
                    double theta = startangle2 + segment * i;
1028
                    SbVec3f v1 = center + SbVec3f(radius2 * cos(theta), radius2 * sin(theta), 0);
1029
                    glVertex2f(v1[0], v1[1]);
1030
                }
1031
                glEnd();
1032
            }
1033
        }
1034
    }
1035
    else if (this->datumtype.getValue() == RADIUS || this->datumtype.getValue() == DIAMETER) {
1036
        // Get the Points
1037
        SbVec3f p1 = points[0];
1038
        SbVec3f p2 = points[1];
1039

1040
        SbVec3f dir = (p2-p1);
1041
        SbVec3f center = p1;
1042
        double radius = (p2 - p1).length();
1043
        if (this->datumtype.getValue() == DIAMETER) {
1044
            center = (p1 + p2) / 2;
1045
            radius = radius / 2;
1046
        }
1047

1048
        dir.normalize();
1049
        SbVec3f normal (-dir[1],dir[0],0);
1050

1051
        float length = this->param1.getValue();
1052
        SbVec3f pos = p2 + length*dir;
1053

1054
        // Get magnitude of angle between horizontal
1055
        angle = atan2f(dir[1],dir[0]);
1056
        if (angle > M_PI_2+M_PI/12) {
1057
            angle -= (float)M_PI;
1058
        } else if (angle <= -M_PI_2+M_PI/12) {
1059
            angle += (float)M_PI;
1060
        }
1061

1062
        textOffset = pos;
1063

1064
        float margin = this->imgHeight / 3.0;
1065

1066
        // Create the arrowhead
1067
        float arrowWidth = margin * 0.5;
1068
        SbVec3f ar0  = p2;
1069
        SbVec3f ar1  = p2 - dir * 0.866f * 2 * margin;
1070
        SbVec3f ar2  = ar1 + normal * arrowWidth;
1071
        ar1 -= normal * arrowWidth;
1072

1073
        SbVec3f p3 = pos +  dir * (this->imgWidth / 2 + margin);
1074
        if ((p3-p1).length() > (p2-p1).length())
1075
            p2 = p3;
1076

1077
        // Calculate the points
1078
        SbVec3f pnt1 = pos - dir * (margin + this->imgWidth / 2);
1079
        SbVec3f pnt2 = pos + dir * (margin + this->imgWidth / 2);
1080

1081
        // Draw the Lines
1082
        glBegin(GL_LINES);
1083
            glVertex2f(p1[0], p1[1]);
1084
            glVertex2f(pnt1[0], pnt1[1]);
1085

1086
            glVertex2f(pnt2[0], pnt2[1]);
1087
            glVertex2f(p2[0], p2[1]);
1088
        glEnd();
1089

1090
        glBegin(GL_TRIANGLES);
1091
            glVertex2f(ar0[0], ar0[1]);
1092
            glVertex2f(ar1[0], ar1[1]);
1093
            glVertex2f(ar2[0], ar2[1]);
1094
        glEnd();
1095

1096
        if (this->datumtype.getValue() == DIAMETER) {
1097
            // create second arrowhead
1098
            SbVec3f ar0_1  = p1;
1099
            SbVec3f ar1_1  = p1 + dir * 0.866f * 2 * margin;
1100
            SbVec3f ar2_1  = ar1_1 + normal * arrowWidth;
1101
            ar1_1 -= normal * arrowWidth;
1102

1103
            glBegin(GL_TRIANGLES);
1104
                glVertex2f(ar0_1[0], ar0_1[1]);
1105
                glVertex2f(ar1_1[0], ar1_1[1]);
1106
                glVertex2f(ar2_1[0], ar2_1[1]);
1107
            glEnd();
1108
        }
1109

1110
        // Draw arc helper if needed
1111
        float startangle = this->param3.getValue();
1112
        float range = this->param4.getValue();
1113
        if (range != 0.0) {
1114
            int countSegments = std::max(6, abs(int(50.0 * range / (2 * M_PI))));
1115
            double segment = range / (countSegments - 1);
1116

1117
            glBegin(GL_LINE_STRIP);
1118
            for (int i = 0; i < countSegments; i++) {
1119
                double theta = startangle + segment * i;
1120
                SbVec3f v1 = center + SbVec3f(radius * cos(theta), radius * sin(theta), 0);
1121
                glVertex2f(v1[0], v1[1]);
1122
            }
1123
            glEnd();
1124
        }
1125

1126
    }
1127
    else if (this->datumtype.getValue() == ANGLE) {
1128
        // Only the angle intersection point is needed
1129
        SbVec3f p0 = points[0];
1130

1131
        float margin = this->imgHeight / 3.0;
1132

1133
        // Load the Parameters
1134
        float length     = this->param1.getValue();
1135
        float startangle = this->param2.getValue();
1136
        float range      = this->param3.getValue();
1137
        float endangle   = startangle + range;
1138
        float endLineLength1 = std::max(this->param4.getValue(), margin);
1139
        float endLineLength2 = std::max(this->param5.getValue(), margin);
1140
        float endLineLength12 = std::max(- this->param4.getValue(), margin);
1141
        float endLineLength22 = std::max(- this->param5.getValue(), margin);
1142

1143

1144
        float r = 2*length;
1145

1146
        // Set the Text label angle to zero
1147
        angle = 0.f;
1148

1149
        // Useful Information
1150
        // v0 - vector for text position
1151
        // p0 - vector for angle intersect
1152
        SbVec3f v0(cos(startangle+range/2),sin(startangle+range/2),0);
1153

1154
        // leave some space for the text
1155
        if (range >= 0)
1156
            range = std::max(0.2f*range, range - this->imgWidth/(2*r));
1157
        else
1158
            range = std::min(0.2f*range, range + this->imgWidth/(2*r));
1159

1160
        int countSegments = std::max(6, abs(int(50.0 * range / (2 * M_PI))));
1161
        double segment = range / (2*countSegments-2);
1162

1163
        textOffset = p0 + v0 * r;
1164

1165

1166
        // Draw
1167
        glBegin(GL_LINE_STRIP);
1168

1169
        for (int i=0; i < countSegments; i++) {
1170
            double theta = startangle + segment*i;
1171
            SbVec3f v1 = p0+SbVec3f(r*cos(theta),r*sin(theta),0);
1172
            glVertex2f(v1[0],v1[1]);
1173
        }
1174
        glEnd();
1175

1176
        glBegin(GL_LINE_STRIP);
1177
        for (int i=0; i < countSegments; i++) {
1178
            double theta = endangle - segment*i;
1179
            SbVec3f v1 = p0+SbVec3f(r*cos(theta),r*sin(theta),0);
1180
            glVertex2f(v1[0],v1[1]);
1181
        }
1182
        glEnd();
1183

1184
        // Direction vectors for start and end lines
1185
        SbVec3f v1(cos(startangle),sin(startangle),0);
1186
        SbVec3f v2(cos(endangle),sin(endangle),0);
1187

1188
        SbVec3f pnt1 = p0 + (r - endLineLength1) * v1;
1189
        SbVec3f pnt2 = p0 + (r + endLineLength12) * v1;
1190
        SbVec3f pnt3 = p0 + (r - endLineLength2) * v2;
1191
        SbVec3f pnt4 = p0 + (r + endLineLength22) * v2;
1192

1193
        glBegin(GL_LINES);
1194
            glVertex2f(pnt1[0],pnt1[1]);
1195
            glVertex2f(pnt2[0],pnt2[1]);
1196

1197
            glVertex2f(pnt3[0],pnt3[1]);
1198
            glVertex2f(pnt4[0],pnt4[1]);
1199
        glEnd();
1200

1201
        // Create the arrowheads
1202
        float arrowLength = margin * 2;
1203
        float arrowWidth = margin * 0.5;
1204

1205
        // Normals for the arrowheads
1206
        SbVec3f dirStart(v1[1], -v1[0], 0);
1207
        SbVec3f dirEnd(-v2[1], v2[0], 0);
1208

1209
        // Calculate arrowhead points for start angle
1210
        SbVec3f startArrowBase = p0 + r * v1;
1211
        SbVec3f startArrowLeft = startArrowBase - arrowLength * dirStart + arrowWidth * v1;
1212
        SbVec3f startArrowRight = startArrowBase - arrowLength * dirStart - arrowWidth * v1;
1213

1214
        // Calculate arrowhead points for end angle
1215
        SbVec3f endArrowBase = p0 + r * v2;
1216
        SbVec3f endArrowLeft = endArrowBase - arrowLength * dirEnd + arrowWidth * v2;
1217
        SbVec3f endArrowRight = endArrowBase - arrowLength * dirEnd - arrowWidth * v2;
1218

1219
        // Draw arrowheads
1220
        glBegin(GL_TRIANGLES);
1221
        // Start angle arrowhead
1222
        glVertex2f(startArrowBase[0], startArrowBase[1]);
1223
        glVertex2f(startArrowLeft[0], startArrowLeft[1]);
1224
        glVertex2f(startArrowRight[0], startArrowRight[1]);
1225

1226
        // End angle arrowhead
1227
        glVertex2f(endArrowBase[0], endArrowBase[1]);
1228
        glVertex2f(endArrowLeft[0], endArrowLeft[1]);
1229
        glVertex2f(endArrowRight[0], endArrowRight[1]);
1230
        glEnd();
1231
    }
1232
    else if (this->datumtype.getValue() == SYMMETRIC) {
1233

1234
        SbVec3f p1 = points[0];
1235
        SbVec3f p2 = points[1];
1236

1237
        SbVec3f dir = (p2-p1);
1238
        dir.normalize();
1239
        SbVec3f normal (-dir[1],dir[0],0);
1240

1241
        float margin = this->imgHeight / 4.0;
1242

1243
        // Calculate coordinates for the first arrow
1244
        SbVec3f ar0, ar1, ar2;
1245
        ar0  = p1 + dir * 4 * margin; // Tip of Arrow
1246
        ar1  = ar0 - dir * 0.866f * 2 * margin;
1247
        ar2  = ar1 + normal * margin;
1248
        ar1 -= normal * margin;
1249

1250
        glBegin(GL_LINES);
1251
            glVertex3f(p1[0], p1[1], ZCONSTR);
1252
            glVertex3f(ar0[0], ar0[1], ZCONSTR);
1253
            glVertex3f(ar0[0], ar0[1], ZCONSTR);
1254
            glVertex3f(ar1[0], ar1[1], ZCONSTR);
1255
            glVertex3f(ar0[0], ar0[1], ZCONSTR);
1256
            glVertex3f(ar2[0], ar2[1], ZCONSTR);
1257
        glEnd();
1258

1259
        // Calculate coordinates for the second arrow
1260
        SbVec3f ar3, ar4, ar5;
1261
        ar3  = p2 - dir * 4 * margin; // Tip of 2nd Arrow
1262
        ar4  = ar3 + dir * 0.866f * 2 * margin;
1263
        ar5  = ar4 + normal * margin;
1264
        ar4 -= normal * margin;
1265

1266
        glBegin(GL_LINES);
1267
            glVertex3f(p2[0], p2[1], ZCONSTR);
1268
            glVertex3f(ar3[0], ar3[1], ZCONSTR);
1269
            glVertex3f(ar3[0], ar3[1], ZCONSTR);
1270
            glVertex3f(ar4[0], ar4[1], ZCONSTR);
1271
            glVertex3f(ar3[0], ar3[1], ZCONSTR);
1272
            glVertex3f(ar5[0], ar5[1], ZCONSTR);
1273
        glEnd();
1274
    }
1275

1276
    if (hasText) {
1277
        const unsigned char * dataptr = this->image.getValue(imgsize, nc);
1278

1279
        //Get the camera z-direction
1280
        const SbViewVolume & vv = SoViewVolumeElement::get(state);
1281
        SbVec3f z = vv.zVector();
1282

1283
        bool flip = norm.getValue().dot(z) > FLT_EPSILON;
1284

1285
        static bool init = false;
1286
        static bool npot = false;
1287
        if (!init) {
1288
            init = true;
1289
            std::string ext = (const char*)(glGetString(GL_EXTENSIONS));
1290
            npot = (ext.find("GL_ARB_texture_non_power_of_two") != std::string::npos);
1291
        }
1292

1293
        int w = srcw;
1294
        int h = srch;
1295
        if (!npot) {
1296
            // make power of two
1297
            if ((w & (w-1)) != 0) {
1298
                int i=1;
1299
                while (i < 8) {
1300
                    if ((w >> i) == 0)
1301
                        break;
1302
                    i++;
1303
                }
1304
                w = (1 << i);
1305
            }
1306
            // make power of two
1307
            if ((h & (h-1)) != 0) {
1308
                int i=1;
1309
                while (i < 8) {
1310
                    if ((h >> i) == 0)
1311
                        break;
1312
                    i++;
1313
                }
1314
                h = (1 << i);
1315
            }
1316
        }
1317

1318
        glDisable(GL_DEPTH_TEST);
1319
        glEnable(GL_TEXTURE_2D); // Enable Textures
1320
        glEnable(GL_BLEND);
1321

1322
        // glGenTextures/glBindTexture was commented out but it must be active, see:
1323
        // #0000971: Tracing over a background image in Sketcher: image is overwritten by first dimensional constraint text
1324
        // #0001185: Planer image changes to number graphic when a part design constraint is made after the planar image
1325
        //
1326
        // Copy the text bitmap into memory and bind
1327
        GLuint myTexture;
1328
        // generate a texture
1329
        glGenTextures(1, &myTexture);
1330
        glBindTexture(GL_TEXTURE_2D, myTexture);
1331

1332
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1333
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1334

1335
        if (!npot) {
1336
            QImage imagedata(w, h,QImage::Format_ARGB32_Premultiplied);
1337
            imagedata.fill(0x00000000);
1338
            int sx = (w - srcw)/2;
1339
            int sy = (h - srch)/2;
1340
            glTexImage2D(GL_TEXTURE_2D, 0, nc, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)imagedata.bits());
1341
            glTexSubImage2D(GL_TEXTURE_2D, 0, sx, sy, srcw, srch, GL_RGBA, GL_UNSIGNED_BYTE,(const GLvoid*)  dataptr);
1342
        }
1343
        else {
1344
            glTexImage2D(GL_TEXTURE_2D, 0, nc, srcw, srch, 0, GL_RGBA, GL_UNSIGNED_BYTE,(const GLvoid*)  dataptr);
1345
        }
1346
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1347

1348
        glMatrixMode(GL_MODELVIEW);
1349
        glPushMatrix();
1350

1351
        // Apply a rotation and translation matrix
1352
        glTranslatef(textOffset[0],textOffset[1], textOffset[2]);
1353
        glRotatef((GLfloat) angle * 180 / M_PI, 0,0,1);
1354
        glBegin(GL_QUADS);
1355

1356
        glColor3f(1.f, 1.f, 1.f);
1357

1358
        glTexCoord2f(flip ? 0.f : 1.f, 1.f); glVertex2f( -this->imgWidth / 2,  this->imgHeight / 2);
1359
        glTexCoord2f(flip ? 0.f : 1.f, 0.f); glVertex2f( -this->imgWidth / 2, -this->imgHeight / 2);
1360
        glTexCoord2f(flip ? 1.f : 0.f, 0.f); glVertex2f( this->imgWidth / 2, -this->imgHeight / 2);
1361
        glTexCoord2f(flip ? 1.f : 0.f, 1.f); glVertex2f( this->imgWidth / 2,  this->imgHeight / 2);
1362

1363
        glEnd();
1364

1365
        // Reset the Mode
1366
        glPopMatrix();
1367

1368
        // wmayer: see bug report below which is caused by generating but not
1369
        // deleting the texture.
1370
        // #0000721: massive memory leak when dragging an unconstrained model
1371
        glDeleteTextures(1, &myTexture);
1372
    }
1373

1374
    glPopAttrib();
1375
    state->pop();
1376
}
1377

1378
void SoDatumLabel::setPoints(SbVec3f p1, SbVec3f p2)
1379
{
1380
    pnts.setNum(2);
1381
    SbVec3f* verts = pnts.startEditing();
1382
    verts[0] = p1;
1383
    verts[1] = p2;
1384
    pnts.finishEditing();
1385
}
1386

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

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

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

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