Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/utils/gui/div/GLHelper.cpp
169684 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file GLHelper.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Sept 2002
19
///
20
// Some methods which help to draw certain geometrical objects in openGL
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <cassert>
25
#include <utils/geom/GeomHelper.h>
26
#include <utils/common/StdDefs.h>
27
#include <utils/common/MsgHandler.h>
28
#include <utils/common/ToString.h>
29
#include <utils/options/OptionsCont.h>
30
#include <utils/gui/div/GUIGeometry.h>
31
#define FONTSTASH_IMPLEMENTATION // Expands implementation
32
#ifdef _MSC_VER
33
#pragma warning(disable: 4505 5219) // do not warn about unused functions and implicit float conversions
34
#endif
35
#if __GNUC__ > 3
36
#pragma GCC diagnostic push
37
#pragma GCC diagnostic ignored "-Wunused-function"
38
#endif
39
#include <foreign/fontstash/fontstash.h>
40
#include <utils/gui/globjects/GLIncludes.h>
41
#define GLFONTSTASH_IMPLEMENTATION // Expands implementation
42
#include <foreign/fontstash/glfontstash.h>
43
#include <utils/geom/Boundary.h>
44
#ifdef HAVE_GL2PS
45
#include <gl2ps.h>
46
#endif
47
#include "Roboto.h"
48
#include "GLHelper.h"
49
50
#define CIRCLE_RESOLUTION (double)10 // inverse in degrees
51
//#define CHECK_PUSHPOP // enable or disable check push and pop matrix/names
52
//#define CHECK_ELEMENTCOUNTER // enable or disable element counter (for matrix and vertex)
53
54
#ifndef CALLBACK
55
#define CALLBACK
56
#endif
57
58
// ===========================================================================
59
// static member definitions
60
// ===========================================================================
61
62
int GLHelper::myMatrixCounter = 0;
63
int GLHelper::myVertexCounter = 0;
64
int GLHelper::myMatrixCounterDebug = 0;
65
int GLHelper::myNameCounter = 0;
66
std::vector<std::pair<double, double> > GLHelper::myCircleCoords;
67
std::vector<RGBColor> GLHelper::myDottedcontourColors;
68
FONScontext* GLHelper::myFont = nullptr;
69
double GLHelper::myFontSize = 50.0;
70
bool GLHelper::myGL2PSActive = false;
71
72
void CALLBACK combCallback(GLdouble coords[3],
73
GLdouble* vertex_data[4],
74
GLfloat weight[4], GLdouble** dataOut) {
75
UNUSED_PARAMETER(weight);
76
UNUSED_PARAMETER(*vertex_data);
77
GLdouble* vertex;
78
79
vertex = (GLdouble*)malloc(7 * sizeof(GLdouble));
80
81
vertex[0] = coords[0];
82
vertex[1] = coords[1];
83
vertex[2] = coords[2];
84
*dataOut = vertex;
85
}
86
87
// ===========================================================================
88
// method definitions
89
// ===========================================================================
90
91
const std::vector<std::pair<double, double> >&
92
GLHelper::getCircleCoords() {
93
// fill in first call
94
if (myCircleCoords.size() == 0) {
95
for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
96
const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
97
const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
98
myCircleCoords.push_back(std::pair<double, double>(x, y));
99
}
100
}
101
return myCircleCoords;
102
}
103
104
105
int
106
GLHelper::angleLookup(double angleDeg) {
107
const int numCoords = (int)getCircleCoords().size() - 1;
108
int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
109
if (index < 0) {
110
index += numCoords;
111
}
112
assert(index >= 0);
113
return (int)index;
114
}
115
116
117
void
118
GLHelper::pushMatrix() {
119
glPushMatrix();
120
// update counters
121
#ifdef CHECK_ELEMENTCOUNTER
122
myMatrixCounter++;
123
#endif
124
#ifdef CHECK_PUSHPOP
125
myMatrixCounterDebug++;
126
#endif
127
}
128
129
130
void
131
GLHelper::popMatrix() {
132
glPopMatrix();
133
#ifdef CHECK_PUSHPOP
134
myMatrixCounterDebug--;
135
#endif
136
}
137
138
139
void
140
GLHelper::pushName(unsigned int name) {
141
glPushName(name);
142
#ifdef CHECK_PUSHPOP
143
myNameCounter++;
144
#endif
145
}
146
147
148
void
149
GLHelper::popName() {
150
glPopName();
151
#ifdef CHECK_PUSHPOP
152
myNameCounter--;
153
#endif
154
}
155
156
157
int
158
GLHelper::getMatrixCounter() {
159
return myMatrixCounter;
160
}
161
162
163
void
164
GLHelper::resetMatrixCounter() {
165
myMatrixCounter = 0;
166
}
167
168
169
int
170
GLHelper::getVertexCounter() {
171
return myVertexCounter;
172
}
173
174
175
void
176
GLHelper::resetVertexCounter() {
177
myVertexCounter = 0;
178
}
179
180
181
void
182
GLHelper::checkCounterMatrix() {
183
#ifdef CHECK_PUSHPOP
184
if (myMatrixCounterDebug != 0) {
185
WRITE_WARNING("invalid matrix counter. Check that number of pushMatrix and popMatrix functions calls are the same");
186
}
187
myMatrixCounterDebug = 0;
188
#endif
189
}
190
191
192
void
193
GLHelper::checkCounterName() {
194
#ifdef CHECK_PUSHPOP
195
if (myNameCounter != 0) {
196
WRITE_WARNING("invalid Name counter. Check that number of pushName and popName functions calls are the same");
197
}
198
myNameCounter = 0;
199
#endif
200
}
201
202
203
void
204
GLHelper::drawFilledPoly(const PositionVector& v, bool close) {
205
if (v.size() == 0) {
206
return;
207
}
208
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
209
glBegin(GL_POLYGON);
210
for (PositionVector::const_iterator i = v.begin(); i != v.end(); i++) {
211
const Position& p = *i;
212
glVertex2d(p.x(), p.y());
213
#ifdef CHECK_ELEMENTCOUNTER
214
myVertexCounter++;
215
#endif
216
}
217
if (close) {
218
const Position& p = *(v.begin());
219
glVertex2d(p.x(), p.y());
220
#ifdef CHECK_ELEMENTCOUNTER
221
myVertexCounter++;
222
#endif
223
}
224
glEnd();
225
}
226
227
228
void
229
GLHelper::drawFilledPolyTesselated(const PositionVector& v, bool close) {
230
if (v.size() == 0) {
231
return;
232
}
233
GLUtesselator* tobj = gluNewTess();
234
#ifdef _MSC_VER
235
#pragma warning(push)
236
#pragma warning(disable: 4191)
237
#endif
238
#if defined(__GNUC__) && __GNUC__ >= 8
239
#pragma GCC diagnostic push
240
#pragma GCC diagnostic ignored "-Wcast-function-type"
241
#endif
242
gluTessCallback(tobj, GLU_TESS_VERTEX, (GLvoid(CALLBACK*)()) &glVertex3dv);
243
gluTessCallback(tobj, GLU_TESS_BEGIN, (GLvoid(CALLBACK*)()) &glBegin);
244
gluTessCallback(tobj, GLU_TESS_END, (GLvoid(CALLBACK*)()) &glEnd);
245
gluTessCallback(tobj, GLU_TESS_COMBINE, (GLvoid(CALLBACK*)()) &combCallback);
246
#if defined(__GNUC__) && __GNUC__ >= 8
247
#pragma GCC diagnostic pop
248
#endif
249
#ifdef _MSC_VER
250
#pragma warning(pop)
251
#endif
252
gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
253
gluTessBeginPolygon(tobj, nullptr);
254
gluTessBeginContour(tobj);
255
double* points = new double[(v.size() + int(close)) * 3];
256
257
for (int i = 0; i != (int)v.size(); ++i) {
258
points[3 * i] = v[i].x();
259
points[3 * i + 1] = v[i].y();
260
points[3 * i + 2] = 0;
261
gluTessVertex(tobj, points + 3 * i, points + 3 * i);
262
}
263
if (close) {
264
const int i = (int)v.size();
265
points[3 * i] = v[0].x();
266
points[3 * i + 1] = v[0].y();
267
points[3 * i + 2] = 0;
268
gluTessVertex(tobj, points + 3 * i, points + 3 * i);
269
}
270
gluTessEndContour(tobj);
271
gluTessEndPolygon(tobj);
272
gluDeleteTess(tobj);
273
delete[] points;
274
}
275
276
277
void
278
GLHelper::drawRectangle(const Position& center, const double width, const double height) {
279
const double halfWidth = width * 0.5;
280
const double halfHeight = height * 0.5;
281
GLHelper::pushMatrix();
282
glTranslated(center.x(), center.y(), 0);
283
glBegin(GL_QUADS);
284
glVertex2d(-halfWidth, halfHeight);
285
glVertex2d(-halfWidth, -halfHeight);
286
glVertex2d(halfWidth, -halfHeight);
287
glVertex2d(halfWidth, halfHeight);
288
glEnd();
289
GLHelper::popMatrix();
290
#ifdef CHECK_ELEMENTCOUNTER
291
myVertexCounter += 4;
292
#endif
293
}
294
295
void
296
GLHelper::drawBoxLine(const Position& beg, double rot, double visLength,
297
double width, double offset) {
298
GLHelper::pushMatrix();
299
glTranslated(beg.x(), beg.y(), 0);
300
glRotated(rot, 0, 0, 1);
301
glBegin(GL_QUADS);
302
glVertex2d(-width - offset, 0);
303
glVertex2d(-width - offset, -visLength);
304
glVertex2d(width - offset, -visLength);
305
glVertex2d(width - offset, 0);
306
glEnd();
307
GLHelper::popMatrix();
308
#ifdef CHECK_ELEMENTCOUNTER
309
myVertexCounter += 4;
310
#endif
311
}
312
313
314
void
315
GLHelper::drawBoxLine(const Position& beg1, const Position& beg2,
316
double rot, double visLength,
317
double width) {
318
GLHelper::pushMatrix();
319
glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
320
glRotated(rot, 0, 0, 1);
321
glBegin(GL_QUADS);
322
glVertex2d(-width, 0);
323
glVertex2d(-width, -visLength);
324
glVertex2d(width, -visLength);
325
glVertex2d(width, 0);
326
glEnd();
327
GLHelper::popMatrix();
328
#ifdef CHECK_ELEMENTCOUNTER
329
myVertexCounter += 4;
330
#endif
331
}
332
333
334
bool
335
GLHelper::rightTurn(double angle1, double angle2) {
336
double delta = angle2 - angle1;
337
while (delta > 180) {
338
delta -= 360;
339
}
340
while (delta < -180) {
341
delta += 360;
342
}
343
return delta <= 0;
344
}
345
346
347
void
348
GLHelper::drawBoxLines(const PositionVector& geom,
349
const std::vector<double>& rots,
350
const std::vector<double>& lengths,
351
double width, int cornerDetail, double offset) {
352
// draw the lane
353
int e = (int) geom.size() - 1;
354
for (int i = 0; i < e; i++) {
355
drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
356
}
357
// draw the corner details
358
if (cornerDetail > 0) {
359
for (int i = 1; i < e; i++) {
360
GLHelper::pushMatrix();
361
glTranslated(geom[i].x(), geom[i].y(), 0.1);
362
double angleBeg = -rots[i - 1];
363
double angleEnd = 180 - rots[i];
364
if (rightTurn(rots[i - 1], rots[i])) {
365
std::swap(angleBeg, angleEnd);
366
}
367
// only draw the missing piece
368
angleBeg -= 90;
369
angleEnd += 90;
370
// avoid drawing more than 360 degrees
371
if (angleEnd - angleBeg > 360) {
372
angleBeg += 360;
373
}
374
if (angleEnd - angleBeg < -360) {
375
angleEnd += 360;
376
}
377
// draw the right way around
378
if (angleEnd > angleBeg) {
379
angleEnd -= 360;
380
}
381
drawFilledCircle(width + offset, cornerDetail, angleBeg, angleEnd);
382
GLHelper::popMatrix();
383
}
384
}
385
}
386
387
388
void
389
GLHelper::drawBoxLines(const PositionVector& geom,
390
const std::vector<double>& rots,
391
const std::vector<double>& lengths,
392
const std::vector<RGBColor>& cols,
393
double width, int cornerDetail, double offset) {
394
int e = (int) geom.size() - 1;
395
for (int i = 0; i < e; i++) {
396
setColor(cols[i]);
397
drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
398
}
399
if (cornerDetail > 0) {
400
for (int i = 1; i < e; i++) {
401
GLHelper::pushMatrix();
402
setColor(cols[i]);
403
glTranslated(geom[i].x(), geom[i].y(), 0);
404
drawFilledCircle(width, cornerDetail);
405
GLHelper::popMatrix();
406
}
407
}
408
}
409
410
411
void
412
GLHelper::drawBoxLines(const PositionVector& geom1,
413
const PositionVector& geom2,
414
const std::vector<double>& rots,
415
const std::vector<double>& lengths,
416
double width) {
417
int minS = (int) MIN4(rots.size(), lengths.size(), geom1.size(), geom2.size());
418
for (int i = 0; i < minS; i++) {
419
GLHelper::drawBoxLine(geom1[i], geom2[i], rots[i], lengths[i], width);
420
}
421
}
422
423
424
void
425
GLHelper::drawBoxLines(const PositionVector& geom, double width) {
426
// first convert to GUIGeometry to avoid graphical errors with Z value (see #13992)
427
const auto geometry = GUIGeometry(geom);
428
drawBoxLines(geometry.getShape(), geometry.getShapeRotations(), geometry.getShapeLengths(), width);
429
}
430
431
432
void
433
GLHelper::drawLine(const Position& beg, double rot, double visLength) {
434
GLHelper::pushMatrix();
435
glTranslated(beg.x(), beg.y(), 0);
436
glRotated(rot, 0, 0, 1);
437
glBegin(GL_LINES);
438
glVertex2d(0, 0);
439
glVertex2d(0, -visLength);
440
glEnd();
441
GLHelper::popMatrix();
442
#ifdef CHECK_ELEMENTCOUNTER
443
myVertexCounter += 2;
444
#endif
445
}
446
447
448
void
449
GLHelper::drawLine(const Position& beg1, const Position& beg2,
450
double rot, double visLength) {
451
GLHelper::pushMatrix();
452
glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
453
glRotated(rot, 0, 0, 1);
454
glBegin(GL_LINES);
455
glVertex2d(0, 0);
456
glVertex2d(0, -visLength);
457
glEnd();
458
GLHelper::popMatrix();
459
#ifdef CHECK_ELEMENTCOUNTER
460
myVertexCounter += 2;
461
#endif
462
}
463
464
465
466
void
467
GLHelper::drawLine(const PositionVector& v) {
468
glBegin(GL_LINES);
469
int e = (int) v.size() - 1;
470
for (int i = 0; i < e; ++i) {
471
glVertex2d(v[i].x(), v[i].y());
472
glVertex2d(v[i + 1].x(), v[i + 1].y());
473
#ifdef CHECK_ELEMENTCOUNTER
474
myVertexCounter += 2;
475
#endif
476
}
477
glEnd();
478
}
479
480
481
void
482
GLHelper::drawLine(const PositionVector& v, const std::vector<RGBColor>& cols) {
483
glBegin(GL_LINES);
484
int e = (int) v.size() - 1;
485
for (int i = 0; i < e; ++i) {
486
setColor(cols[i]);
487
glVertex2d(v[i].x(), v[i].y());
488
glVertex2d(v[i + 1].x(), v[i + 1].y());
489
#ifdef CHECK_ELEMENTCOUNTER
490
myVertexCounter += 2;
491
#endif
492
}
493
glEnd();
494
}
495
496
497
void
498
GLHelper::drawLine(const Position& beg, const Position& end) {
499
glBegin(GL_LINES);
500
glVertex2d(beg.x(), beg.y());
501
glVertex2d(end.x(), end.y());
502
glEnd();
503
#ifdef CHECK_ELEMENTCOUNTER
504
myVertexCounter += 2;
505
#endif
506
}
507
508
509
void
510
GLHelper::drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius,
511
double beg, double end) {
512
// get current resolution level
513
switch (d) {
514
case GUIVisualizationSettings::Detail::CircleResolution32:
515
drawFilledCircle(radius, 32, beg, end);
516
break;
517
case GUIVisualizationSettings::Detail::CircleResolution16:
518
drawFilledCircle(radius, 16, beg, end);
519
break;
520
case GUIVisualizationSettings::Detail::CircleResolution8:
521
drawFilledCircle(radius, 8, beg, end);
522
break;
523
case GUIVisualizationSettings::Detail::CircleResolution4:
524
drawFilledCircleDetailled(d, radius);
525
break;
526
default:
527
// nothing to draw
528
break;
529
}
530
}
531
532
533
void
534
GLHelper::drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius) {
535
// get current resolution level
536
switch (d) {
537
case GUIVisualizationSettings::Detail::CircleResolution32:
538
drawFilledCircle(radius, 32);
539
break;
540
case GUIVisualizationSettings::Detail::CircleResolution16:
541
drawFilledCircle(radius, 16);
542
break;
543
case GUIVisualizationSettings::Detail::CircleResolution8:
544
drawFilledCircle(radius, 8);
545
break;
546
default:
547
// draw only a square
548
GLHelper::pushMatrix();
549
glBegin(GL_QUADS);
550
glVertex2d(-radius, radius);
551
glVertex2d(-radius, -radius);
552
glVertex2d(radius, -radius);
553
glVertex2d(radius, radius);
554
glEnd();
555
GLHelper::popMatrix();
556
#ifdef CHECK_ELEMENTCOUNTER
557
myVertexCounter += 4;
558
#endif
559
break;
560
}
561
}
562
563
void
564
GLHelper::drawFilledCircle(double const radius, int const steps) {
565
drawFilledCircle(radius, steps, 0, 360);
566
}
567
568
569
void
570
GLHelper::drawFilledCircle(double radius, int steps, double beg, double end) {
571
const double inc = (end - beg) / (double)steps;
572
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
573
std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
574
575
for (int i = 0; i <= steps; ++i) {
576
const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
577
glBegin(GL_TRIANGLES);
578
glVertex2d(p1.first * radius, p1.second * radius);
579
glVertex2d(p2.first * radius, p2.second * radius);
580
glVertex2d(0, 0);
581
glEnd();
582
p1 = p2;
583
#ifdef CHECK_ELEMENTCOUNTER
584
myVertexCounter += 3;
585
#endif
586
}
587
}
588
589
590
void
591
GLHelper::drawOutlineCircle(double radius, double iRadius, int steps) {
592
drawOutlineCircle(radius, iRadius, steps, 0, 360);
593
}
594
595
596
void
597
GLHelper::drawOutlineCircle(double radius, double iRadius, int steps,
598
double beg, double end) {
599
const double inc = (end - beg) / (double)steps;
600
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
601
std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
602
603
for (int i = 0; i <= steps; ++i) {
604
const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
605
glBegin(GL_TRIANGLES);
606
glVertex2d(p1.first * radius, p1.second * radius);
607
glVertex2d(p2.first * radius, p2.second * radius);
608
glVertex2d(p2.first * iRadius, p2.second * iRadius);
609
610
glVertex2d(p2.first * iRadius, p2.second * iRadius);
611
glVertex2d(p1.first * iRadius, p1.second * iRadius);
612
glVertex2d(p1.first * radius, p1.second * radius);
613
614
glEnd();
615
p1 = p2;
616
#ifdef CHECK_ELEMENTCOUNTER
617
myVertexCounter += 6;
618
#endif
619
}
620
}
621
622
623
void
624
GLHelper::drawTriangleAtEnd(const Position& p1, const Position& p2, double tLength,
625
double tWidth, const double extraOffset) {
626
const double length = p1.distanceTo(p2);
627
if (length < tLength) {
628
tWidth *= length / tLength;
629
tLength = length;
630
}
631
Position rl(PositionVector::positionAtOffset(p1, p2, length - tLength));
632
GLHelper::pushMatrix();
633
glTranslated(rl.x(), rl.y(), 0);
634
glRotated(-GeomHelper::naviDegree(p1.angleTo2D(p2)), 0, 0, 1);
635
glTranslated(0, extraOffset, 0);
636
glBegin(GL_TRIANGLES);
637
glVertex2d(0, tLength);
638
glVertex2d(-tWidth, 0);
639
glVertex2d(+tWidth, 0);
640
glEnd();
641
GLHelper::popMatrix();
642
#ifdef CHECK_ELEMENTCOUNTER
643
myVertexCounter += 3;
644
#endif
645
}
646
647
648
void
649
GLHelper::setColor(const RGBColor& c) {
650
glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
651
}
652
653
654
RGBColor
655
GLHelper::getColor() {
656
GLdouble current[4];
657
glGetDoublev(GL_CURRENT_COLOR, current);
658
return RGBColor(static_cast<unsigned char>(current[0] * 255. + 0.5),
659
static_cast<unsigned char>(current[1] * 255. + 0.5),
660
static_cast<unsigned char>(current[2] * 255. + 0.5),
661
static_cast<unsigned char>(current[3] * 255. + 0.5));
662
}
663
664
665
void
666
GLHelper::resetFont() {
667
glfonsDelete(myFont);
668
myFont = nullptr;
669
}
670
671
672
void
673
GLHelper::setGL2PS(bool active) {
674
myGL2PSActive = active;
675
}
676
677
678
void
679
GLHelper::drawSpaceOccupancies(const double exaggeration, const Position& pos, const double rotation,
680
const double width, const double length, const bool vehicle) {
681
// declare geometry
682
PositionVector geom;
683
const double w = width / 2. - 0.1 * exaggeration;
684
const double h = length;
685
// set geometry
686
geom.push_back(Position(-w, +0, 0.));
687
geom.push_back(Position(+w, +0, 0.));
688
geom.push_back(Position(+w, +h, 0.));
689
geom.push_back(Position(-w, +h, 0.));
690
geom.push_back(Position(-w, +0, 0.));
691
692
// push matrix
693
GLHelper::pushMatrix();
694
// translate
695
glTranslated(pos.x(), pos.y(), pos.z());
696
// rotate
697
glRotated(rotation, 0, 0, 1);
698
// set color
699
GLHelper::setColor(vehicle ? RGBColor::RED : RGBColor::GREEN);
700
// draw box lines
701
GLHelper::drawBoxLines(geom, 0.1 * exaggeration);
702
// pop matrix
703
GLHelper::popMatrix();
704
}
705
706
707
bool
708
GLHelper::initFont() {
709
if (myFont == nullptr) {
710
myFont = glfonsCreate(2048, 2048, FONS_ZERO_BOTTOMLEFT);
711
if (myFont != nullptr) {
712
const int fontNormal = fonsAddFontMem(myFont, "medium", data_font_Roboto_Medium_ttf, data_font_Roboto_Medium_ttf_len, 0);
713
fonsSetFont(myFont, fontNormal);
714
fonsSetSize(myFont, (float)myFontSize);
715
}
716
}
717
return myFont != nullptr;
718
}
719
720
721
const std::vector<RGBColor>&
722
GLHelper::getDottedcontourColors(const int size) {
723
// check if more colors has to be added
724
while ((int)myDottedcontourColors.size() < size) {
725
if (myDottedcontourColors.empty() || myDottedcontourColors.back() == RGBColor::WHITE) {
726
myDottedcontourColors.push_back(RGBColor::BLACK);
727
} else {
728
myDottedcontourColors.push_back(RGBColor::WHITE);
729
}
730
}
731
return myDottedcontourColors;
732
}
733
734
735
double
736
GLHelper::getTextWidth(const std::string& text, double size) {
737
return size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
738
}
739
740
741
void
742
GLHelper::drawText(const std::string& text, const Position& pos, const double layer, const double size,
743
const RGBColor& col, const double angle, const int align, double width) {
744
if (width <= 0) {
745
width = size;
746
}
747
if (!initFont()) {
748
return;
749
}
750
GLHelper::pushMatrix();
751
glAlphaFunc(GL_GREATER, 0.5);
752
glEnable(GL_ALPHA_TEST);
753
#ifdef HAVE_GL2PS
754
if (myGL2PSActive) {
755
glRasterPos3d(pos.x(), pos.y(), layer);
756
GLfloat color[] = {col.red() / 255.f, col.green() / 255.f, col.blue() / 255.f, col.alpha() / 255.f};
757
gl2psTextOptColor(text.c_str(), "Roboto", 10, align == 0 ? GL2PS_TEXT_C : align, (GLfloat) - angle, color);
758
GLHelper::popMatrix();
759
return;
760
}
761
#endif
762
glTranslated(pos.x(), pos.y(), layer);
763
glScaled(width / myFontSize, size / myFontSize, 1.);
764
glRotated(-angle, 0, 0, 1);
765
fonsSetAlign(myFont, align == 0 ? FONS_ALIGN_CENTER | FONS_ALIGN_MIDDLE : align);
766
fonsSetColor(myFont, glfonsRGBA(col.red(), col.green(), col.blue(), col.alpha()));
767
fonsDrawText(myFont, 0., 0., text.c_str(), nullptr);
768
GLHelper::popMatrix();
769
}
770
771
772
void
773
GLHelper::drawTextSettings(
774
const GUIVisualizationTextSettings& settings,
775
const std::string& text, const Position& pos,
776
const double scale,
777
const double angle,
778
const double layer,
779
const int align) {
780
drawTextBox(text, pos, layer,
781
settings.scaledSize(scale),
782
settings.color,
783
settings.bgColor,
784
RGBColor::INVISIBLE,
785
angle, 0, 0.2, align);
786
}
787
788
789
void
790
GLHelper::drawTextBox(const std::string& text, const Position& pos,
791
const double layer, const double size,
792
const RGBColor& txtColor, const RGBColor& bgColor, const RGBColor& borderColor,
793
const double angle,
794
const double relBorder,
795
const double relMargin,
796
const int align) {
797
if (!initFont()) {
798
return;
799
};
800
if (bgColor.alpha() != 0) {
801
const double boxAngle = 90;
802
const double stringWidth = size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
803
const double borderWidth = size * relBorder;
804
const double boxHeight = size * (0.32 + 0.6 * relMargin);
805
const double boxWidth = stringWidth + size * relMargin;
806
GLHelper::pushMatrix();
807
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
808
glTranslated(pos.x(), pos.y(), layer);
809
glRotated(-angle, 0, 0, 1);
810
Position left(-boxWidth * 0.5, 0);
811
setColor(borderColor);
812
drawBoxLine(left, boxAngle, boxWidth, boxHeight);
813
left.add(borderWidth * 1.5, 0);
814
setColor(bgColor);
815
glTranslated(0, 0, 0.01);
816
drawBoxLine(left, boxAngle, boxWidth - 3 * borderWidth, boxHeight - 2 * borderWidth);
817
GLHelper::popMatrix();
818
}
819
drawText(text, pos, layer + 0.02, size, txtColor, angle, align);
820
}
821
822
823
void
824
GLHelper::drawTextAtEnd(const std::string& text, const PositionVector& shape, double x,
825
const GUIVisualizationTextSettings& settings, const double scale) {
826
GLHelper::pushMatrix();
827
const Position& end = shape.back();
828
const Position& f = shape[-2];
829
const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
830
glTranslated(end.x(), end.y(), 0);
831
glRotated(rot, 0, 0, 1);
832
drawTextBox(text, Position(x, 0.26), 0,
833
settings.scaledSize(scale, 0.01),
834
settings.color,
835
settings.bgColor,
836
RGBColor::INVISIBLE,
837
180, 0, 0.2);
838
GLHelper::popMatrix();
839
}
840
841
842
void
843
GLHelper::drawCrossTies(const PositionVector& geom, const std::vector<double>& rots,
844
const std::vector<double>& lengths, double length, double spacing,
845
double halfWidth, double offset, bool lessDetail) {
846
GLHelper::pushMatrix();
847
// draw on top of of the white area between the rails
848
glTranslated(0, 0, 0.1);
849
int e = (int) geom.size() - 1;
850
for (int i = 0; i < e; ++i) {
851
GLHelper::pushMatrix();
852
glTranslated(geom[i].x(), geom[i].y(), 0.0);
853
glRotated(rots[i], 0, 0, 1);
854
// draw crossing depending of detail
855
if (!lessDetail) {
856
for (double t = 0; t < lengths[i]; t += spacing) {
857
glBegin(GL_QUADS);
858
glVertex2d(-halfWidth - offset, -t);
859
glVertex2d(-halfWidth - offset, -t - length);
860
glVertex2d(halfWidth - offset, -t - length);
861
glVertex2d(halfWidth - offset, -t);
862
glEnd();
863
#ifdef CHECK_ELEMENTCOUNTER
864
myVertexCounter += 4;
865
#endif
866
}
867
} else {
868
// only draw a single rectangle if it's being drawn only for selecting
869
glBegin(GL_QUADS);
870
glVertex2d(-halfWidth - offset, 0);
871
glVertex2d(-halfWidth - offset, -lengths.back());
872
glVertex2d(halfWidth - offset, -lengths.back());
873
glVertex2d(halfWidth - offset, 0);
874
glEnd();
875
#ifdef CHECK_ELEMENTCOUNTER
876
myVertexCounter += 4;
877
#endif
878
}
879
// pop three draw matrix
880
GLHelper::popMatrix();
881
}
882
GLHelper::popMatrix();
883
}
884
885
void
886
GLHelper::drawInverseMarkings(const PositionVector& geom,
887
const std::vector<double>& rots,
888
const std::vector<double>& lengths,
889
double maxLength, double spacing,
890
double halfWidth, bool cl, bool cr, bool lefthand, double scale) {
891
892
double mw = (halfWidth + SUMO_const_laneMarkWidth * (cl ? 0.6 : 0.2)) * scale;
893
double mw2 = (halfWidth - SUMO_const_laneMarkWidth * (cr ? 0.6 : 0.2)) * scale;
894
if (cl || cr) {
895
if (lefthand) {
896
mw *= -1;
897
mw2 *= -1;
898
}
899
int e = (int) geom.size() - 1;
900
double offset = 0;
901
for (int i = 0; i < e; ++i) {
902
GLHelper::pushMatrix();
903
glTranslated(geom[i].x(), geom[i].y(), 2.1);
904
glRotated(rots[i], 0, 0, 1);
905
double t;
906
for (t = offset; t < lengths[i]; t += spacing) {
907
const double length = MIN2((double)maxLength, lengths[i] - t);
908
glBegin(GL_QUADS);
909
glVertex2d(-mw, -t);
910
glVertex2d(-mw, -t - length);
911
glVertex2d(-mw2, -t - length);
912
glVertex2d(-mw2, -t);
913
glEnd();
914
#ifdef CHECK_ELEMENTCOUNTER
915
myVertexCounter += 4;
916
#endif
917
if (!cl || !cr) {
918
// draw inverse marking between asymmetrical lane markings
919
const double length2 = MIN2((double)6, lengths[i] - t);
920
glBegin(GL_QUADS);
921
glVertex2d(-halfWidth + 0.02, -t - length2);
922
glVertex2d(-halfWidth + 0.02, -t - length);
923
glVertex2d(-halfWidth - 0.02, -t - length);
924
glVertex2d(-halfWidth - 0.02, -t - length2);
925
glEnd();
926
#ifdef CHECK_ELEMENTCOUNTER
927
myVertexCounter += 4;
928
#endif
929
}
930
}
931
offset = t - lengths[i] - spacing;
932
GLHelper::popMatrix();
933
}
934
}
935
}
936
937
938
void
939
GLHelper::debugVertices(const PositionVector& shape, const GUIVisualizationTextSettings& settings, double scale, double layer) {
940
for (int i = 0; i < (int)shape.size(); ++i) {
941
drawTextBox(toString(i), shape[i], layer,
942
settings.scaledSize(scale),
943
settings.color,
944
settings.bgColor,
945
RGBColor::INVISIBLE,
946
0, 0, 0.2);
947
}
948
}
949
950
951
void
952
GLHelper::drawBoundary(const GUIVisualizationSettings& s, const Boundary& b) {
953
if (s.drawBoundaries) {
954
GLHelper::pushMatrix();
955
GLHelper::setColor(RGBColor::MAGENTA);
956
// draw on top
957
glTranslated(0, 0, 1024);
958
drawLine(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()));
959
drawLine(Position(b.xmax(), b.ymax()), Position(b.xmax(), b.ymin()));
960
drawLine(Position(b.xmax(), b.ymin()), Position(b.xmin(), b.ymin()));
961
drawLine(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()));
962
GLHelper::popMatrix();
963
}
964
}
965
966
967
/****************************************************************************/
968
969