Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 0 : 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 0 : vertex = (GLdouble*)malloc(7 * sizeof(GLdouble));
80 :
81 0 : vertex[0] = coords[0];
82 0 : vertex[1] = coords[1];
83 0 : vertex[2] = coords[2];
84 0 : *dataOut = vertex;
85 0 : }
86 :
87 : // ===========================================================================
88 : // method definitions
89 : // ===========================================================================
90 :
91 : const std::vector<std::pair<double, double> >&
92 183711430 : GLHelper::getCircleCoords() {
93 : // fill in first call
94 183711430 : if (myCircleCoords.size() == 0) {
95 4570938 : for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
96 4569669 : const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
97 4569669 : const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
98 4569669 : myCircleCoords.push_back(std::pair<double, double>(x, y));
99 : }
100 : }
101 183711430 : return myCircleCoords;
102 : }
103 :
104 :
105 : int
106 91855715 : GLHelper::angleLookup(double angleDeg) {
107 91855715 : const int numCoords = (int)getCircleCoords().size() - 1;
108 91855715 : int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
109 91855715 : if (index < 0) {
110 644111 : index += numCoords;
111 : }
112 : assert(index >= 0);
113 91855715 : return (int)index;
114 : }
115 :
116 :
117 : void
118 79324447 : GLHelper::pushMatrix() {
119 79324447 : glPushMatrix();
120 : // update counters
121 : #ifdef CHECK_ELEMENTCOUNTER
122 : myMatrixCounter++;
123 : #endif
124 : #ifdef CHECK_PUSHPOP
125 : myMatrixCounterDebug++;
126 : #endif
127 79324447 : }
128 :
129 :
130 : void
131 79843153 : GLHelper::popMatrix() {
132 79843153 : glPopMatrix();
133 : #ifdef CHECK_PUSHPOP
134 : myMatrixCounterDebug--;
135 : #endif
136 79843149 : }
137 :
138 :
139 : void
140 56009922 : GLHelper::pushName(unsigned int name) {
141 56009922 : glPushName(name);
142 : #ifdef CHECK_PUSHPOP
143 : myNameCounter++;
144 : #endif
145 56009922 : }
146 :
147 :
148 : void
149 56009921 : GLHelper::popName() {
150 56009921 : glPopName();
151 : #ifdef CHECK_PUSHPOP
152 : myNameCounter--;
153 : #endif
154 56009921 : }
155 :
156 :
157 : int
158 0 : GLHelper::getMatrixCounter() {
159 0 : return myMatrixCounter;
160 : }
161 :
162 :
163 : void
164 519271 : GLHelper::resetMatrixCounter() {
165 519271 : myMatrixCounter = 0;
166 519271 : }
167 :
168 :
169 : int
170 0 : GLHelper::getVertexCounter() {
171 0 : return myVertexCounter;
172 : }
173 :
174 :
175 : void
176 519271 : GLHelper::resetVertexCounter() {
177 519271 : myVertexCounter = 0;
178 519271 : }
179 :
180 :
181 : void
182 519267 : 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 519267 : }
190 :
191 :
192 : void
193 519267 : 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 519267 : }
201 :
202 :
203 : void
204 979822 : GLHelper::drawFilledPoly(const PositionVector& v, bool close) {
205 979822 : if (v.size() == 0) {
206 : return;
207 : }
208 979822 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
209 979822 : glBegin(GL_POLYGON);
210 6991688 : for (PositionVector::const_iterator i = v.begin(); i != v.end(); i++) {
211 : const Position& p = *i;
212 6011866 : glVertex2d(p.x(), p.y());
213 : #ifdef CHECK_ELEMENTCOUNTER
214 : myVertexCounter++;
215 : #endif
216 : }
217 979822 : if (close) {
218 : const Position& p = *(v.begin());
219 979822 : glVertex2d(p.x(), p.y());
220 : #ifdef CHECK_ELEMENTCOUNTER
221 : myVertexCounter++;
222 : #endif
223 : }
224 979822 : glEnd();
225 : }
226 :
227 :
228 : void
229 0 : GLHelper::drawFilledPolyTesselated(const PositionVector& v, bool close) {
230 0 : if (v.size() == 0) {
231 : return;
232 : }
233 0 : 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 0 : gluTessCallback(tobj, GLU_TESS_VERTEX, (GLvoid(CALLBACK*)()) &glVertex3dv);
243 0 : gluTessCallback(tobj, GLU_TESS_BEGIN, (GLvoid(CALLBACK*)()) &glBegin);
244 0 : gluTessCallback(tobj, GLU_TESS_END, (GLvoid(CALLBACK*)()) &glEnd);
245 0 : 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 0 : gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
253 0 : gluTessBeginPolygon(tobj, nullptr);
254 0 : gluTessBeginContour(tobj);
255 0 : double* points = new double[(v.size() + int(close)) * 3];
256 :
257 0 : for (int i = 0; i != (int)v.size(); ++i) {
258 0 : points[3 * i] = v[i].x();
259 0 : points[3 * i + 1] = v[i].y();
260 0 : points[3 * i + 2] = 0;
261 0 : gluTessVertex(tobj, points + 3 * i, points + 3 * i);
262 : }
263 0 : if (close) {
264 : const int i = (int)v.size();
265 0 : points[3 * i] = v[0].x();
266 0 : points[3 * i + 1] = v[0].y();
267 0 : points[3 * i + 2] = 0;
268 0 : gluTessVertex(tobj, points + 3 * i, points + 3 * i);
269 : }
270 0 : gluTessEndContour(tobj);
271 0 : gluTessEndPolygon(tobj);
272 0 : gluDeleteTess(tobj);
273 0 : delete[] points;
274 : }
275 :
276 :
277 : void
278 0 : GLHelper::drawRectangle(const Position& center, const double width, const double height) {
279 0 : const double halfWidth = width * 0.5;
280 0 : const double halfHeight = height * 0.5;
281 0 : GLHelper::pushMatrix();
282 0 : glTranslated(center.x(), center.y(), 0);
283 0 : glBegin(GL_QUADS);
284 0 : glVertex2d(-halfWidth, halfHeight);
285 0 : glVertex2d(-halfWidth, -halfHeight);
286 0 : glVertex2d(halfWidth, -halfHeight);
287 0 : glVertex2d(halfWidth, halfHeight);
288 0 : glEnd();
289 0 : GLHelper::popMatrix();
290 : #ifdef CHECK_ELEMENTCOUNTER
291 : myVertexCounter += 4;
292 : #endif
293 0 : }
294 :
295 : void
296 17126676 : GLHelper::drawBoxLine(const Position& beg, double rot, double visLength,
297 : double width, double offset) {
298 17126676 : GLHelper::pushMatrix();
299 17126676 : glTranslated(beg.x(), beg.y(), 0);
300 17126676 : glRotated(rot, 0, 0, 1);
301 17126676 : glBegin(GL_QUADS);
302 17126676 : glVertex2d(-width - offset, 0);
303 17126676 : glVertex2d(-width - offset, -visLength);
304 17126676 : glVertex2d(width - offset, -visLength);
305 17126676 : glVertex2d(width - offset, 0);
306 17126676 : glEnd();
307 17126676 : GLHelper::popMatrix();
308 : #ifdef CHECK_ELEMENTCOUNTER
309 : myVertexCounter += 4;
310 : #endif
311 17126675 : }
312 :
313 :
314 : void
315 0 : GLHelper::drawBoxLine(const Position& beg1, const Position& beg2,
316 : double rot, double visLength,
317 : double width) {
318 0 : GLHelper::pushMatrix();
319 0 : glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
320 0 : glRotated(rot, 0, 0, 1);
321 0 : glBegin(GL_QUADS);
322 0 : glVertex2d(-width, 0);
323 0 : glVertex2d(-width, -visLength);
324 0 : glVertex2d(width, -visLength);
325 0 : glVertex2d(width, 0);
326 0 : glEnd();
327 0 : GLHelper::popMatrix();
328 : #ifdef CHECK_ELEMENTCOUNTER
329 : myVertexCounter += 4;
330 : #endif
331 0 : }
332 :
333 :
334 : bool
335 121775 : GLHelper::rightTurn(double angle1, double angle2) {
336 121775 : double delta = angle2 - angle1;
337 121888 : while (delta > 180) {
338 113 : delta -= 360;
339 : }
340 125413 : while (delta < -180) {
341 3638 : delta += 360;
342 : }
343 121775 : return delta <= 0;
344 : }
345 :
346 :
347 : void
348 6769145 : 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 6769145 : int e = (int) geom.size() - 1;
354 23419274 : for (int i = 0; i < e; i++) {
355 16650130 : drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
356 : }
357 : // draw the corner details
358 6769144 : if (cornerDetail > 0) {
359 353322 : for (int i = 1; i < e; i++) {
360 121775 : GLHelper::pushMatrix();
361 121775 : glTranslated(geom[i].x(), geom[i].y(), 0.1);
362 121775 : double angleBeg = -rots[i - 1];
363 121775 : double angleEnd = 180 - rots[i];
364 121775 : if (rightTurn(rots[i - 1], rots[i])) {
365 : std::swap(angleBeg, angleEnd);
366 : }
367 : // only draw the missing piece
368 121775 : angleBeg -= 90;
369 121775 : angleEnd += 90;
370 : // avoid drawing more than 360 degrees
371 121775 : if (angleEnd - angleBeg > 360) {
372 3638 : angleBeg += 360;
373 : }
374 121775 : if (angleEnd - angleBeg < -360) {
375 0 : angleEnd += 360;
376 : }
377 : // draw the right way around
378 121775 : if (angleEnd > angleBeg) {
379 58667 : angleEnd -= 360;
380 : }
381 121775 : drawFilledCircle(width + offset, cornerDetail, angleBeg, angleEnd);
382 121775 : GLHelper::popMatrix();
383 : }
384 : }
385 6769144 : }
386 :
387 :
388 : void
389 0 : 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 0 : int e = (int) geom.size() - 1;
395 0 : for (int i = 0; i < e; i++) {
396 0 : setColor(cols[i]);
397 0 : drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
398 : }
399 0 : if (cornerDetail > 0) {
400 0 : for (int i = 1; i < e; i++) {
401 0 : GLHelper::pushMatrix();
402 0 : setColor(cols[i]);
403 0 : glTranslated(geom[i].x(), geom[i].y(), 0);
404 0 : drawFilledCircle(width, cornerDetail);
405 0 : GLHelper::popMatrix();
406 : }
407 : }
408 0 : }
409 :
410 :
411 : void
412 0 : 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 0 : int minS = (int) MIN4(rots.size(), lengths.size(), geom1.size(), geom2.size());
418 0 : for (int i = 0; i < minS; i++) {
419 0 : GLHelper::drawBoxLine(geom1[i], geom2[i], rots[i], lengths[i], width);
420 : }
421 0 : }
422 :
423 :
424 : void
425 25563 : GLHelper::drawBoxLines(const PositionVector& geom, double width) {
426 : // first convert to GUIGeometry to avoid graphical errors with Z value (see #13992)
427 25563 : const auto geometry = GUIGeometry(geom);
428 25563 : drawBoxLines(geometry.getShape(), geometry.getShapeRotations(), geometry.getShapeLengths(), width);
429 25563 : }
430 :
431 :
432 : void
433 1104 : GLHelper::drawLine(const Position& beg, double rot, double visLength) {
434 1104 : GLHelper::pushMatrix();
435 1104 : glTranslated(beg.x(), beg.y(), 0);
436 1104 : glRotated(rot, 0, 0, 1);
437 1104 : glBegin(GL_LINES);
438 1104 : glVertex2d(0, 0);
439 1104 : glVertex2d(0, -visLength);
440 1104 : glEnd();
441 1104 : GLHelper::popMatrix();
442 : #ifdef CHECK_ELEMENTCOUNTER
443 : myVertexCounter += 2;
444 : #endif
445 1104 : }
446 :
447 :
448 : void
449 0 : GLHelper::drawLine(const Position& beg1, const Position& beg2,
450 : double rot, double visLength) {
451 0 : GLHelper::pushMatrix();
452 0 : glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
453 0 : glRotated(rot, 0, 0, 1);
454 0 : glBegin(GL_LINES);
455 0 : glVertex2d(0, 0);
456 0 : glVertex2d(0, -visLength);
457 0 : glEnd();
458 0 : GLHelper::popMatrix();
459 : #ifdef CHECK_ELEMENTCOUNTER
460 : myVertexCounter += 2;
461 : #endif
462 0 : }
463 :
464 :
465 :
466 : void
467 8531018 : GLHelper::drawLine(const PositionVector& v) {
468 8531018 : glBegin(GL_LINES);
469 8531018 : int e = (int) v.size() - 1;
470 22555105 : for (int i = 0; i < e; ++i) {
471 14024087 : glVertex2d(v[i].x(), v[i].y());
472 14024087 : glVertex2d(v[i + 1].x(), v[i + 1].y());
473 : #ifdef CHECK_ELEMENTCOUNTER
474 : myVertexCounter += 2;
475 : #endif
476 : }
477 8531018 : glEnd();
478 8531018 : }
479 :
480 :
481 : void
482 0 : GLHelper::drawLine(const PositionVector& v, const std::vector<RGBColor>& cols) {
483 0 : glBegin(GL_LINES);
484 0 : int e = (int) v.size() - 1;
485 0 : for (int i = 0; i < e; ++i) {
486 0 : setColor(cols[i]);
487 0 : glVertex2d(v[i].x(), v[i].y());
488 0 : glVertex2d(v[i + 1].x(), v[i + 1].y());
489 : #ifdef CHECK_ELEMENTCOUNTER
490 : myVertexCounter += 2;
491 : #endif
492 : }
493 0 : glEnd();
494 0 : }
495 :
496 :
497 : void
498 0 : GLHelper::drawLine(const Position& beg, const Position& end) {
499 0 : glBegin(GL_LINES);
500 0 : glVertex2d(beg.x(), beg.y());
501 0 : glVertex2d(end.x(), end.y());
502 0 : glEnd();
503 : #ifdef CHECK_ELEMENTCOUNTER
504 : myVertexCounter += 2;
505 : #endif
506 0 : }
507 :
508 :
509 : void
510 0 : GLHelper::drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius,
511 : double beg, double end) {
512 : // get current resolution level
513 0 : switch (d) {
514 0 : case GUIVisualizationSettings::Detail::CircleResolution32:
515 0 : drawFilledCircle(radius, 32, beg, end);
516 0 : break;
517 0 : case GUIVisualizationSettings::Detail::CircleResolution16:
518 0 : drawFilledCircle(radius, 16, beg, end);
519 0 : break;
520 0 : case GUIVisualizationSettings::Detail::CircleResolution8:
521 0 : drawFilledCircle(radius, 8, beg, end);
522 0 : break;
523 0 : case GUIVisualizationSettings::Detail::CircleResolution4:
524 0 : drawFilledCircleDetailled(d, radius);
525 0 : break;
526 : default:
527 : // nothing to draw
528 : break;
529 : }
530 0 : }
531 :
532 :
533 : void
534 0 : GLHelper::drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius) {
535 : // get current resolution level
536 0 : switch (d) {
537 0 : case GUIVisualizationSettings::Detail::CircleResolution32:
538 0 : drawFilledCircle(radius, 32);
539 0 : break;
540 0 : case GUIVisualizationSettings::Detail::CircleResolution16:
541 0 : drawFilledCircle(radius, 16);
542 0 : break;
543 0 : case GUIVisualizationSettings::Detail::CircleResolution8:
544 0 : drawFilledCircle(radius, 8);
545 0 : break;
546 0 : default:
547 : // draw only a square
548 0 : GLHelper::pushMatrix();
549 0 : glBegin(GL_QUADS);
550 0 : glVertex2d(-radius, radius);
551 0 : glVertex2d(-radius, -radius);
552 0 : glVertex2d(radius, -radius);
553 0 : glVertex2d(radius, radius);
554 0 : glEnd();
555 0 : GLHelper::popMatrix();
556 : #ifdef CHECK_ELEMENTCOUNTER
557 : myVertexCounter += 4;
558 : #endif
559 0 : break;
560 : }
561 0 : }
562 :
563 : void
564 11242953 : GLHelper::drawFilledCircle(double const radius, int const steps) {
565 11242953 : drawFilledCircle(radius, steps, 0, 360);
566 11242953 : }
567 :
568 :
569 : void
570 11364736 : GLHelper::drawFilledCircle(double radius, int steps, double beg, double end) {
571 11364736 : const double inc = (end - beg) / (double)steps;
572 11364736 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
573 11364736 : std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
574 :
575 91855715 : for (int i = 0; i <= steps; ++i) {
576 80490979 : const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
577 80490979 : glBegin(GL_TRIANGLES);
578 80490979 : glVertex2d(p1.first * radius, p1.second * radius);
579 80490979 : glVertex2d(p2.first * radius, p2.second * radius);
580 80490979 : glVertex2d(0, 0);
581 80490979 : glEnd();
582 : p1 = p2;
583 : #ifdef CHECK_ELEMENTCOUNTER
584 : myVertexCounter += 3;
585 : #endif
586 : }
587 11364736 : }
588 :
589 :
590 : void
591 0 : GLHelper::drawOutlineCircle(double radius, double iRadius, int steps) {
592 0 : drawOutlineCircle(radius, iRadius, steps, 0, 360);
593 0 : }
594 :
595 :
596 : void
597 0 : GLHelper::drawOutlineCircle(double radius, double iRadius, int steps,
598 : double beg, double end) {
599 0 : const double inc = (end - beg) / (double)steps;
600 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
601 0 : std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
602 :
603 0 : for (int i = 0; i <= steps; ++i) {
604 0 : const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
605 0 : glBegin(GL_TRIANGLES);
606 0 : glVertex2d(p1.first * radius, p1.second * radius);
607 0 : glVertex2d(p2.first * radius, p2.second * radius);
608 0 : glVertex2d(p2.first * iRadius, p2.second * iRadius);
609 :
610 0 : glVertex2d(p2.first * iRadius, p2.second * iRadius);
611 0 : glVertex2d(p1.first * iRadius, p1.second * iRadius);
612 0 : glVertex2d(p1.first * radius, p1.second * radius);
613 :
614 0 : glEnd();
615 : p1 = p2;
616 : #ifdef CHECK_ELEMENTCOUNTER
617 : myVertexCounter += 6;
618 : #endif
619 : }
620 0 : }
621 :
622 :
623 : void
624 370589 : GLHelper::drawTriangleAtEnd(const Position& p1, const Position& p2, double tLength,
625 : double tWidth, const double extraOffset) {
626 370589 : const double length = p1.distanceTo(p2);
627 370589 : if (length < tLength) {
628 0 : tWidth *= length / tLength;
629 : tLength = length;
630 : }
631 370589 : Position rl(PositionVector::positionAtOffset(p1, p2, length - tLength));
632 370589 : GLHelper::pushMatrix();
633 370589 : glTranslated(rl.x(), rl.y(), 0);
634 370589 : glRotated(-GeomHelper::naviDegree(p1.angleTo2D(p2)), 0, 0, 1);
635 370589 : glTranslated(0, extraOffset, 0);
636 370589 : glBegin(GL_TRIANGLES);
637 370589 : glVertex2d(0, tLength);
638 370589 : glVertex2d(-tWidth, 0);
639 370589 : glVertex2d(+tWidth, 0);
640 370589 : glEnd();
641 370589 : GLHelper::popMatrix();
642 : #ifdef CHECK_ELEMENTCOUNTER
643 : myVertexCounter += 3;
644 : #endif
645 370589 : }
646 :
647 :
648 : void
649 37801524 : GLHelper::setColor(const RGBColor& c) {
650 37801524 : glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
651 37801524 : }
652 :
653 :
654 : RGBColor
655 1259979 : GLHelper::getColor() {
656 : GLdouble current[4];
657 1259979 : glGetDoublev(GL_CURRENT_COLOR, current);
658 2519958 : return RGBColor(static_cast<unsigned char>(current[0] * 255. + 0.5),
659 1259979 : static_cast<unsigned char>(current[1] * 255. + 0.5),
660 1259979 : static_cast<unsigned char>(current[2] * 255. + 0.5),
661 1259979 : static_cast<unsigned char>(current[3] * 255. + 0.5));
662 : }
663 :
664 :
665 : void
666 22280 : GLHelper::resetFont() {
667 22280 : glfonsDelete(myFont);
668 22280 : myFont = nullptr;
669 22280 : }
670 :
671 :
672 : void
673 0 : GLHelper::setGL2PS(bool active) {
674 0 : myGL2PSActive = active;
675 0 : }
676 :
677 :
678 : void
679 17876 : GLHelper::drawSpaceOccupancies(const double exaggeration, const Position& pos, const double rotation,
680 : const double width, const double length, const bool vehicle) {
681 : // declare colors
682 17876 : const RGBColor red(255, 0, 0, 255);
683 17876 : const RGBColor green(0, 255, 0, 255);
684 : // declare geometry
685 17876 : PositionVector geom;
686 17876 : const double w = width / 2. - 0.1 * exaggeration;
687 : const double h = length;
688 : // set geometry
689 17876 : geom.push_back(Position(-w, +0, 0.));
690 17876 : geom.push_back(Position(+w, +0, 0.));
691 17876 : geom.push_back(Position(+w, +h, 0.));
692 17876 : geom.push_back(Position(-w, +h, 0.));
693 17876 : geom.push_back(Position(-w, +0, 0.));
694 : /*
695 : geom.push_back(Position(pos.x(), pos.y(), pos.z()));
696 : geom.push_back(Position(pos.x() + (*l).second.myWidth, pos.y(), pos.z()));
697 : geom.push_back(Position(pos.x() + (*l).second.myWidth, pos.y() - (*l).second.myLength, pos.z()));
698 : geom.push_back(Position(pos.x(), pos.y() - (*l).second.myLength, pos.z()));
699 : geom.push_back(Position(pos.x(), pos.y(), pos.z()));
700 : */
701 : // push matrix
702 17876 : GLHelper::pushMatrix();
703 : // translate
704 17876 : glTranslated(pos.x(), pos.y(), pos.z());
705 : // rotate
706 17876 : glRotated(rotation, 0, 0, 1);
707 : // set color
708 25139 : GLHelper::setColor(vehicle ? green : red);
709 : // draw box lines
710 17876 : GLHelper::drawBoxLines(geom, 0.1 * exaggeration);
711 : // pop matrix
712 17876 : GLHelper::popMatrix();
713 17876 : }
714 :
715 :
716 : bool
717 1058675 : GLHelper::initFont() {
718 1058675 : if (myFont == nullptr) {
719 6636 : myFont = glfonsCreate(2048, 2048, FONS_ZERO_BOTTOMLEFT);
720 6636 : if (myFont != nullptr) {
721 6636 : const int fontNormal = fonsAddFontMem(myFont, "medium", data_font_Roboto_Medium_ttf, data_font_Roboto_Medium_ttf_len, 0);
722 6636 : fonsSetFont(myFont, fontNormal);
723 6636 : fonsSetSize(myFont, (float)myFontSize);
724 : }
725 : }
726 1058675 : return myFont != nullptr;
727 : }
728 :
729 :
730 : const std::vector<RGBColor>&
731 0 : GLHelper::getDottedcontourColors(const int size) {
732 : // check if more colors has to be added
733 0 : while ((int)myDottedcontourColors.size() < size) {
734 0 : if (myDottedcontourColors.empty() || myDottedcontourColors.back() == RGBColor::WHITE) {
735 0 : myDottedcontourColors.push_back(RGBColor::BLACK);
736 : } else {
737 0 : myDottedcontourColors.push_back(RGBColor::WHITE);
738 : }
739 : }
740 0 : return myDottedcontourColors;
741 : }
742 :
743 :
744 : double
745 0 : GLHelper::getTextWidth(const std::string& text, double size) {
746 0 : return size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
747 : }
748 :
749 :
750 : void
751 1058675 : GLHelper::drawText(const std::string& text, const Position& pos, const double layer, const double size,
752 : const RGBColor& col, const double angle, const int align, double width) {
753 1058675 : if (width <= 0) {
754 : width = size;
755 : }
756 1058675 : if (!initFont()) {
757 : return;
758 : }
759 1058675 : GLHelper::pushMatrix();
760 1058675 : glAlphaFunc(GL_GREATER, 0.5);
761 1058675 : glEnable(GL_ALPHA_TEST);
762 : #ifdef HAVE_GL2PS
763 1058675 : if (myGL2PSActive) {
764 0 : glRasterPos3d(pos.x(), pos.y(), layer);
765 0 : GLfloat color[] = {col.red() / 255.f, col.green() / 255.f, col.blue() / 255.f, col.alpha() / 255.f};
766 0 : gl2psTextOptColor(text.c_str(), "Roboto", 10, align == 0 ? GL2PS_TEXT_C : align, (GLfloat) - angle, color);
767 0 : GLHelper::popMatrix();
768 : return;
769 : }
770 : #endif
771 1058675 : glTranslated(pos.x(), pos.y(), layer);
772 1058675 : glScaled(width / myFontSize, size / myFontSize, 1.);
773 1058675 : glRotated(-angle, 0, 0, 1);
774 1078212 : fonsSetAlign(myFont, align == 0 ? FONS_ALIGN_CENTER | FONS_ALIGN_MIDDLE : align);
775 1058675 : fonsSetColor(myFont, glfonsRGBA(col.red(), col.green(), col.blue(), col.alpha()));
776 1058675 : fonsDrawText(myFont, 0., 0., text.c_str(), nullptr);
777 1058675 : GLHelper::popMatrix();
778 : }
779 :
780 :
781 : void
782 0 : GLHelper::drawTextSettings(
783 : const GUIVisualizationTextSettings& settings,
784 : const std::string& text, const Position& pos,
785 : const double scale,
786 : const double angle,
787 : const double layer,
788 : const int align) {
789 0 : drawTextBox(text, pos, layer,
790 : settings.scaledSize(scale),
791 0 : settings.color,
792 0 : settings.bgColor,
793 : RGBColor::INVISIBLE,
794 : angle, 0, 0.2, align);
795 0 : }
796 :
797 :
798 : void
799 0 : GLHelper::drawTextBox(const std::string& text, const Position& pos,
800 : const double layer, const double size,
801 : const RGBColor& txtColor, const RGBColor& bgColor, const RGBColor& borderColor,
802 : const double angle,
803 : const double relBorder,
804 : const double relMargin,
805 : const int align) {
806 0 : if (!initFont()) {
807 : return;
808 : };
809 0 : if (bgColor.alpha() != 0) {
810 : const double boxAngle = 90;
811 0 : const double stringWidth = size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
812 0 : const double borderWidth = size * relBorder;
813 0 : const double boxHeight = size * (0.32 + 0.6 * relMargin);
814 0 : const double boxWidth = stringWidth + size * relMargin;
815 0 : GLHelper::pushMatrix();
816 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
817 0 : glTranslated(pos.x(), pos.y(), layer);
818 0 : glRotated(-angle, 0, 0, 1);
819 0 : Position left(-boxWidth * 0.5, 0);
820 0 : setColor(borderColor);
821 0 : drawBoxLine(left, boxAngle, boxWidth, boxHeight);
822 0 : left.add(borderWidth * 1.5, 0);
823 0 : setColor(bgColor);
824 0 : glTranslated(0, 0, 0.01);
825 0 : drawBoxLine(left, boxAngle, boxWidth - 3 * borderWidth, boxHeight - 2 * borderWidth);
826 0 : GLHelper::popMatrix();
827 : }
828 0 : drawText(text, pos, layer + 0.02, size, txtColor, angle, align);
829 : }
830 :
831 :
832 : void
833 0 : GLHelper::drawTextAtEnd(const std::string& text, const PositionVector& shape, double x,
834 : const GUIVisualizationTextSettings& settings, const double scale) {
835 0 : GLHelper::pushMatrix();
836 : const Position& end = shape.back();
837 0 : const Position& f = shape[-2];
838 0 : const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
839 0 : glTranslated(end.x(), end.y(), 0);
840 0 : glRotated(rot, 0, 0, 1);
841 0 : drawTextBox(text, Position(x, 0.26), 0,
842 : settings.scaledSize(scale, 0.01),
843 0 : settings.color,
844 0 : settings.bgColor,
845 : RGBColor::INVISIBLE,
846 : 180, 0, 0.2);
847 0 : GLHelper::popMatrix();
848 0 : }
849 :
850 :
851 : void
852 30156 : GLHelper::drawCrossTies(const PositionVector& geom, const std::vector<double>& rots,
853 : const std::vector<double>& lengths, double length, double spacing,
854 : double halfWidth, double offset, bool lessDetail) {
855 30156 : GLHelper::pushMatrix();
856 : // draw on top of of the white area between the rails
857 30156 : glTranslated(0, 0, 0.1);
858 30156 : int e = (int) geom.size() - 1;
859 60639 : for (int i = 0; i < e; ++i) {
860 30483 : GLHelper::pushMatrix();
861 30483 : glTranslated(geom[i].x(), geom[i].y(), 0.0);
862 30483 : glRotated(rots[i], 0, 0, 1);
863 : // draw crossing depending of detail
864 30483 : if (!lessDetail) {
865 521697 : for (double t = 0; t < lengths[i]; t += spacing) {
866 491214 : glBegin(GL_QUADS);
867 491214 : glVertex2d(-halfWidth - offset, -t);
868 491214 : glVertex2d(-halfWidth - offset, -t - length);
869 491214 : glVertex2d(halfWidth - offset, -t - length);
870 491214 : glVertex2d(halfWidth - offset, -t);
871 491214 : glEnd();
872 : #ifdef CHECK_ELEMENTCOUNTER
873 : myVertexCounter += 4;
874 : #endif
875 : }
876 : } else {
877 : // only draw a single rectangle if it's being drawn only for selecting
878 0 : glBegin(GL_QUADS);
879 0 : glVertex2d(-halfWidth - offset, 0);
880 0 : glVertex2d(-halfWidth - offset, -lengths.back());
881 0 : glVertex2d(halfWidth - offset, -lengths.back());
882 0 : glVertex2d(halfWidth - offset, 0);
883 0 : glEnd();
884 : #ifdef CHECK_ELEMENTCOUNTER
885 : myVertexCounter += 4;
886 : #endif
887 : }
888 : // pop three draw matrix
889 30483 : GLHelper::popMatrix();
890 : }
891 30156 : GLHelper::popMatrix();
892 30156 : }
893 :
894 : void
895 59587 : GLHelper::drawInverseMarkings(const PositionVector& geom,
896 : const std::vector<double>& rots,
897 : const std::vector<double>& lengths,
898 : double maxLength, double spacing,
899 : double halfWidth, bool cl, bool cr, bool lefthand, double scale) {
900 :
901 59587 : double mw = (halfWidth + SUMO_const_laneMarkWidth * (cl ? 0.6 : 0.2)) * scale;
902 59587 : double mw2 = (halfWidth - SUMO_const_laneMarkWidth * (cr ? 0.6 : 0.2)) * scale;
903 59587 : if (cl || cr) {
904 59137 : if (lefthand) {
905 12 : mw *= -1;
906 12 : mw2 *= -1;
907 : }
908 59137 : int e = (int) geom.size() - 1;
909 : double offset = 0;
910 142662 : for (int i = 0; i < e; ++i) {
911 83525 : GLHelper::pushMatrix();
912 83525 : glTranslated(geom[i].x(), geom[i].y(), 2.1);
913 83525 : glRotated(rots[i], 0, 0, 1);
914 : double t;
915 1072595 : for (t = offset; t < lengths[i]; t += spacing) {
916 989070 : const double length = MIN2((double)maxLength, lengths[i] - t);
917 989070 : glBegin(GL_QUADS);
918 989070 : glVertex2d(-mw, -t);
919 989070 : glVertex2d(-mw, -t - length);
920 989070 : glVertex2d(-mw2, -t - length);
921 989070 : glVertex2d(-mw2, -t);
922 989070 : glEnd();
923 : #ifdef CHECK_ELEMENTCOUNTER
924 : myVertexCounter += 4;
925 : #endif
926 989070 : if (!cl || !cr) {
927 : // draw inverse marking between asymmetrical lane markings
928 572 : const double length2 = MIN2((double)6, lengths[i] - t);
929 572 : glBegin(GL_QUADS);
930 572 : glVertex2d(-halfWidth + 0.02, -t - length2);
931 572 : glVertex2d(-halfWidth + 0.02, -t - length);
932 572 : glVertex2d(-halfWidth - 0.02, -t - length);
933 572 : glVertex2d(-halfWidth - 0.02, -t - length2);
934 572 : glEnd();
935 : #ifdef CHECK_ELEMENTCOUNTER
936 : myVertexCounter += 4;
937 : #endif
938 : }
939 : }
940 83525 : offset = t - lengths[i] - spacing;
941 83525 : GLHelper::popMatrix();
942 : }
943 : }
944 59587 : }
945 :
946 :
947 : void
948 0 : GLHelper::debugVertices(const PositionVector& shape, const GUIVisualizationTextSettings& settings, double scale, double layer) {
949 0 : for (int i = 0; i < (int)shape.size(); ++i) {
950 0 : drawTextBox(toString(i), shape[i], layer,
951 : settings.scaledSize(scale),
952 0 : settings.color,
953 0 : settings.bgColor,
954 : RGBColor::INVISIBLE,
955 : 0, 0, 0.2);
956 : }
957 0 : }
958 :
959 :
960 : void
961 0 : GLHelper::drawBoundary(const GUIVisualizationSettings& s, const Boundary& b) {
962 0 : if (s.drawBoundaries) {
963 0 : GLHelper::pushMatrix();
964 0 : GLHelper::setColor(RGBColor::MAGENTA);
965 : // draw on top
966 0 : glTranslated(0, 0, 1024);
967 0 : drawLine(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()));
968 0 : drawLine(Position(b.xmax(), b.ymax()), Position(b.xmax(), b.ymin()));
969 0 : drawLine(Position(b.xmax(), b.ymin()), Position(b.xmin(), b.ymin()));
970 0 : drawLine(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()));
971 0 : GLHelper::popMatrix();
972 : }
973 0 : }
974 :
975 :
976 : /****************************************************************************/
|