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