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 187009806 : GLHelper::getCircleCoords() {
92 : // fill in first call
93 187009806 : if (myCircleCoords.size() == 0) {
94 4437664 : for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
95 4436432 : const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
96 4436432 : const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
97 4436432 : myCircleCoords.push_back(std::pair<double, double>(x, y));
98 : }
99 : }
100 187009806 : return myCircleCoords;
101 : }
102 :
103 :
104 : int
105 93504903 : GLHelper::angleLookup(double angleDeg) {
106 93504903 : const int numCoords = (int)getCircleCoords().size() - 1;
107 93504903 : int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
108 93504903 : if (index < 0) {
109 619415 : index += numCoords;
110 : }
111 : assert(index >= 0);
112 93504903 : return (int)index;
113 : }
114 :
115 :
116 : void
117 83890541 : GLHelper::pushMatrix() {
118 83890541 : glPushMatrix();
119 : // update counters
120 : #ifdef CHECK_ELEMENTCOUNTER
121 : myMatrixCounter++;
122 : #endif
123 : #ifdef CHECK_PUSHPOP
124 : myMatrixCounterDebug++;
125 : #endif
126 83890541 : }
127 :
128 :
129 : void
130 84386307 : GLHelper::popMatrix() {
131 84386307 : glPopMatrix();
132 : #ifdef CHECK_PUSHPOP
133 : myMatrixCounterDebug--;
134 : #endif
135 84386307 : }
136 :
137 :
138 : void
139 59874043 : GLHelper::pushName(unsigned int name) {
140 59874043 : glPushName(name);
141 : #ifdef CHECK_PUSHPOP
142 : myNameCounter++;
143 : #endif
144 59874043 : }
145 :
146 :
147 : void
148 59874043 : GLHelper::popName() {
149 59874043 : glPopName();
150 : #ifdef CHECK_PUSHPOP
151 : myNameCounter--;
152 : #endif
153 59874043 : }
154 :
155 :
156 : int
157 0 : GLHelper::getMatrixCounter() {
158 0 : return myMatrixCounter;
159 : }
160 :
161 :
162 : void
163 546620 : GLHelper::resetMatrixCounter() {
164 546620 : myMatrixCounter = 0;
165 546620 : }
166 :
167 :
168 : int
169 0 : GLHelper::getVertexCounter() {
170 0 : return myVertexCounter;
171 : }
172 :
173 :
174 : void
175 546620 : GLHelper::resetVertexCounter() {
176 546620 : myVertexCounter = 0;
177 546620 : }
178 :
179 :
180 : void
181 546620 : 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 546620 : }
189 :
190 :
191 : void
192 546620 : 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 546620 : }
200 :
201 :
202 : void
203 1015435 : GLHelper::drawFilledPoly(const PositionVector& v, bool close) {
204 1015435 : if (v.size() == 0) {
205 : return;
206 : }
207 1015435 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
208 1015435 : glBegin(GL_POLYGON);
209 7239077 : for (PositionVector::const_iterator i = v.begin(); i != v.end(); i++) {
210 : const Position& p = *i;
211 6223642 : glVertex2d(p.x(), p.y());
212 : #ifdef CHECK_ELEMENTCOUNTER
213 : myVertexCounter++;
214 : #endif
215 : }
216 1015435 : if (close) {
217 : const Position& p = *(v.begin());
218 1015435 : glVertex2d(p.x(), p.y());
219 : #ifdef CHECK_ELEMENTCOUNTER
220 : myVertexCounter++;
221 : #endif
222 : }
223 1015435 : 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 18188275 : GLHelper::drawBoxLine(const Position& beg, double rot, double visLength,
296 : double width, double offset) {
297 18188275 : GLHelper::pushMatrix();
298 18188275 : glTranslated(beg.x(), beg.y(), 0);
299 18188275 : glRotated(rot, 0, 0, 1);
300 18188275 : glBegin(GL_QUADS);
301 18188275 : glVertex2d(-width - offset, 0);
302 18188275 : glVertex2d(-width - offset, -visLength);
303 18188275 : glVertex2d(width - offset, -visLength);
304 18188275 : glVertex2d(width - offset, 0);
305 18188275 : glEnd();
306 18188275 : GLHelper::popMatrix();
307 : #ifdef CHECK_ELEMENTCOUNTER
308 : myVertexCounter += 4;
309 : #endif
310 18188275 : }
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 116568 : GLHelper::rightTurn(double angle1, double angle2) {
335 116568 : double delta = angle2 - angle1;
336 116677 : while (delta > 180) {
337 109 : delta -= 360;
338 : }
339 120130 : while (delta < -180) {
340 3562 : delta += 360;
341 : }
342 116568 : return delta <= 0;
343 : }
344 :
345 :
346 : void
347 7460146 : 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 7460146 : int e = (int) geom.size() - 1;
353 25063880 : for (int i = 0; i < e; i++) {
354 17603734 : drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
355 : }
356 : // draw the corner details
357 7460146 : if (cornerDetail > 0) {
358 475877 : for (int i = 1; i < e; i++) {
359 116568 : GLHelper::pushMatrix();
360 116568 : glTranslated(geom[i].x(), geom[i].y(), 0.1);
361 116568 : double angleBeg = -rots[i - 1];
362 116568 : double angleEnd = 180 - rots[i];
363 116568 : if (rightTurn(rots[i - 1], rots[i])) {
364 : std::swap(angleBeg, angleEnd);
365 : }
366 : // only draw the missing piece
367 116568 : angleBeg -= 90;
368 116568 : angleEnd += 90;
369 : // avoid drawing more than 360 degrees
370 116568 : if (angleEnd - angleBeg > 360) {
371 3562 : angleBeg += 360;
372 : }
373 116568 : if (angleEnd - angleBeg < -360) {
374 0 : angleEnd += 360;
375 : }
376 : // draw the right way around
377 116568 : if (angleEnd > angleBeg) {
378 57272 : angleEnd -= 360;
379 : }
380 116568 : drawFilledCircle(width + offset, cornerDetail, angleBeg, angleEnd);
381 116568 : GLHelper::popMatrix();
382 : }
383 : }
384 7460146 : }
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 : GLHelper::popMatrix();
405 : }
406 : }
407 0 : }
408 :
409 :
410 : void
411 0 : GLHelper::drawBoxLines(const PositionVector& geom1,
412 : const PositionVector& geom2,
413 : const std::vector<double>& rots,
414 : const std::vector<double>& lengths,
415 : double width) {
416 0 : int minS = (int) MIN4(rots.size(), lengths.size(), geom1.size(), geom2.size());
417 0 : for (int i = 0; i < minS; i++) {
418 0 : GLHelper::drawBoxLine(geom1[i], geom2[i], rots[i], lengths[i], width);
419 : }
420 0 : }
421 :
422 :
423 : void
424 23136 : GLHelper::drawBoxLines(const PositionVector& geom, double width) {
425 23136 : int e = (int) geom.size() - 1;
426 102348 : for (int i = 0; i < e; i++) {
427 79212 : const Position& f = geom[i];
428 79212 : const Position& s = geom[i + 1];
429 79212 : drawBoxLine(f,
430 79212 : RAD2DEG(atan2((s.x() - f.x()), (f.y() - s.y()))),
431 : f.distanceTo(s),
432 : width);
433 : }
434 23136 : }
435 :
436 :
437 : void
438 970 : GLHelper::drawLine(const Position& beg, double rot, double visLength) {
439 970 : GLHelper::pushMatrix();
440 970 : glTranslated(beg.x(), beg.y(), 0);
441 970 : glRotated(rot, 0, 0, 1);
442 970 : glBegin(GL_LINES);
443 970 : glVertex2d(0, 0);
444 970 : glVertex2d(0, -visLength);
445 970 : glEnd();
446 970 : GLHelper::popMatrix();
447 : #ifdef CHECK_ELEMENTCOUNTER
448 : myVertexCounter += 2;
449 : #endif
450 970 : }
451 :
452 :
453 : void
454 0 : GLHelper::drawLine(const Position& beg1, const Position& beg2,
455 : double rot, double visLength) {
456 0 : GLHelper::pushMatrix();
457 0 : glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
458 0 : glRotated(rot, 0, 0, 1);
459 0 : glBegin(GL_LINES);
460 0 : glVertex2d(0, 0);
461 0 : glVertex2d(0, -visLength);
462 0 : glEnd();
463 0 : GLHelper::popMatrix();
464 : #ifdef CHECK_ELEMENTCOUNTER
465 : myVertexCounter += 2;
466 : #endif
467 0 : }
468 :
469 :
470 :
471 : void
472 8730406 : GLHelper::drawLine(const PositionVector& v) {
473 8730406 : glBegin(GL_LINES);
474 8730406 : int e = (int) v.size() - 1;
475 22927359 : for (int i = 0; i < e; ++i) {
476 14196953 : glVertex2d(v[i].x(), v[i].y());
477 14196953 : glVertex2d(v[i + 1].x(), v[i + 1].y());
478 : #ifdef CHECK_ELEMENTCOUNTER
479 : myVertexCounter += 2;
480 : #endif
481 : }
482 8730406 : glEnd();
483 8730406 : }
484 :
485 :
486 : void
487 0 : GLHelper::drawLine(const PositionVector& v, const std::vector<RGBColor>& cols) {
488 0 : glBegin(GL_LINES);
489 0 : int e = (int) v.size() - 1;
490 0 : for (int i = 0; i < e; ++i) {
491 0 : setColor(cols[i]);
492 0 : glVertex2d(v[i].x(), v[i].y());
493 0 : glVertex2d(v[i + 1].x(), v[i + 1].y());
494 : #ifdef CHECK_ELEMENTCOUNTER
495 : myVertexCounter += 2;
496 : #endif
497 : }
498 0 : glEnd();
499 0 : }
500 :
501 :
502 : void
503 0 : GLHelper::drawLine(const Position& beg, const Position& end) {
504 0 : glBegin(GL_LINES);
505 0 : glVertex2d(beg.x(), beg.y());
506 0 : glVertex2d(end.x(), end.y());
507 0 : glEnd();
508 : #ifdef CHECK_ELEMENTCOUNTER
509 : myVertexCounter += 2;
510 : #endif
511 0 : }
512 :
513 :
514 : void
515 0 : GLHelper::drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius,
516 : double beg, double end) {
517 : // get current resolution level
518 0 : switch (d) {
519 0 : case GUIVisualizationSettings::Detail::CircleResolution32:
520 0 : drawFilledCircle(radius, 32, beg, end);
521 0 : break;
522 0 : case GUIVisualizationSettings::Detail::CircleResolution16:
523 0 : drawFilledCircle(radius, 16, beg, end);
524 0 : break;
525 0 : case GUIVisualizationSettings::Detail::CircleResolution8:
526 0 : drawFilledCircle(radius, 8, beg, end);
527 0 : break;
528 0 : case GUIVisualizationSettings::Detail::CircleResolution4:
529 0 : drawFilledCircleDetailled(d, radius);
530 0 : break;
531 : default:
532 : // nothing to draw
533 : break;
534 : }
535 0 : }
536 :
537 :
538 : void
539 0 : GLHelper::drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius) {
540 : // get current resolution level
541 0 : switch (d) {
542 0 : case GUIVisualizationSettings::Detail::CircleResolution32:
543 0 : drawFilledCircle(radius, 32);
544 0 : break;
545 0 : case GUIVisualizationSettings::Detail::CircleResolution16:
546 0 : drawFilledCircle(radius, 16);
547 0 : break;
548 0 : case GUIVisualizationSettings::Detail::CircleResolution8:
549 0 : drawFilledCircle(radius, 8);
550 0 : break;
551 0 : default:
552 : // draw only a square
553 0 : GLHelper::pushMatrix();
554 0 : glBegin(GL_QUADS);
555 0 : glVertex2d(-radius, radius);
556 0 : glVertex2d(-radius, -radius);
557 0 : glVertex2d(radius, -radius);
558 0 : glVertex2d(radius, radius);
559 0 : glEnd();
560 0 : GLHelper::popMatrix();
561 : #ifdef CHECK_ELEMENTCOUNTER
562 : myVertexCounter += 4;
563 : #endif
564 0 : break;
565 : }
566 0 : }
567 :
568 : void
569 11458698 : GLHelper::drawFilledCircle(double const radius, int const steps) {
570 11458698 : drawFilledCircle(radius, steps, 0, 360);
571 11458698 : }
572 :
573 :
574 : void
575 11575281 : GLHelper::drawFilledCircle(double radius, int steps, double beg, double end) {
576 11575281 : const double inc = (end - beg) / (double)steps;
577 11575281 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
578 11575281 : std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
579 :
580 93504903 : for (int i = 0; i <= steps; ++i) {
581 81929622 : const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
582 81929622 : glBegin(GL_TRIANGLES);
583 81929622 : glVertex2d(p1.first * radius, p1.second * radius);
584 81929622 : glVertex2d(p2.first * radius, p2.second * radius);
585 81929622 : glVertex2d(0, 0);
586 81929622 : glEnd();
587 : p1 = p2;
588 : #ifdef CHECK_ELEMENTCOUNTER
589 : myVertexCounter += 3;
590 : #endif
591 : }
592 11575281 : }
593 :
594 :
595 : void
596 0 : GLHelper::drawOutlineCircle(double radius, double iRadius, int steps) {
597 0 : drawOutlineCircle(radius, iRadius, steps, 0, 360);
598 0 : }
599 :
600 :
601 : void
602 0 : GLHelper::drawOutlineCircle(double radius, double iRadius, int steps,
603 : double beg, double end) {
604 0 : const double inc = (end - beg) / (double)steps;
605 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
606 0 : std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
607 :
608 0 : for (int i = 0; i <= steps; ++i) {
609 0 : const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
610 0 : glBegin(GL_TRIANGLES);
611 0 : glVertex2d(p1.first * radius, p1.second * radius);
612 0 : glVertex2d(p2.first * radius, p2.second * radius);
613 0 : glVertex2d(p2.first * iRadius, p2.second * iRadius);
614 :
615 0 : glVertex2d(p2.first * iRadius, p2.second * iRadius);
616 0 : glVertex2d(p1.first * iRadius, p1.second * iRadius);
617 0 : glVertex2d(p1.first * radius, p1.second * radius);
618 :
619 0 : glEnd();
620 : p1 = p2;
621 : #ifdef CHECK_ELEMENTCOUNTER
622 : myVertexCounter += 6;
623 : #endif
624 : }
625 0 : }
626 :
627 :
628 : void
629 399580 : GLHelper::drawTriangleAtEnd(const Position& p1, const Position& p2, double tLength,
630 : double tWidth, const double extraOffset) {
631 399580 : const double length = p1.distanceTo(p2);
632 399580 : if (length < tLength) {
633 0 : tWidth *= length / tLength;
634 : tLength = length;
635 : }
636 399580 : Position rl(PositionVector::positionAtOffset(p1, p2, length - tLength));
637 399580 : GLHelper::pushMatrix();
638 399580 : glTranslated(rl.x(), rl.y(), 0);
639 399580 : glRotated(-GeomHelper::naviDegree(p1.angleTo2D(p2)), 0, 0, 1);
640 399580 : glTranslated(0, extraOffset, 0);
641 399580 : glBegin(GL_TRIANGLES);
642 399580 : glVertex2d(0, tLength);
643 399580 : glVertex2d(-tWidth, 0);
644 399580 : glVertex2d(+tWidth, 0);
645 399580 : glEnd();
646 399580 : GLHelper::popMatrix();
647 : #ifdef CHECK_ELEMENTCOUNTER
648 : myVertexCounter += 3;
649 : #endif
650 399580 : }
651 :
652 :
653 : void
654 41142465 : GLHelper::setColor(const RGBColor& c) {
655 41142465 : glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
656 41142465 : }
657 :
658 :
659 : RGBColor
660 1920583 : GLHelper::getColor() {
661 : GLdouble current[4];
662 1920583 : glGetDoublev(GL_CURRENT_COLOR, current);
663 3841166 : return RGBColor(static_cast<unsigned char>(current[0] * 255. + 0.5),
664 1920583 : static_cast<unsigned char>(current[1] * 255. + 0.5),
665 1920583 : static_cast<unsigned char>(current[2] * 255. + 0.5),
666 1920583 : static_cast<unsigned char>(current[3] * 255. + 0.5));
667 : }
668 :
669 :
670 : void
671 22107 : GLHelper::resetFont() {
672 22107 : glfonsDelete(myFont);
673 22107 : myFont = nullptr;
674 22107 : }
675 :
676 :
677 : void
678 0 : GLHelper::setGL2PS(bool active) {
679 0 : myGL2PSActive = active;
680 0 : }
681 :
682 :
683 : void
684 16313 : GLHelper::drawSpaceOccupancies(const double exaggeration, const Position& pos, const double rotation,
685 : const double width, const double length, const bool vehicle) {
686 : // declare colors
687 16313 : const RGBColor red(255, 0, 0, 255);
688 16313 : const RGBColor green(0, 255, 0, 255);
689 : // declare geometry
690 16313 : PositionVector geom;
691 16313 : const double w = width / 2. - 0.1 * exaggeration;
692 : const double h = length;
693 : // set geometry
694 16313 : geom.push_back(Position(-w, +0, 0.));
695 16313 : geom.push_back(Position(+w, +0, 0.));
696 16313 : geom.push_back(Position(+w, +h, 0.));
697 16313 : geom.push_back(Position(-w, +h, 0.));
698 16313 : geom.push_back(Position(-w, +0, 0.));
699 : /*
700 : geom.push_back(Position(pos.x(), pos.y(), pos.z()));
701 : geom.push_back(Position(pos.x() + (*l).second.myWidth, pos.y(), pos.z()));
702 : geom.push_back(Position(pos.x() + (*l).second.myWidth, pos.y() - (*l).second.myLength, pos.z()));
703 : geom.push_back(Position(pos.x(), pos.y() - (*l).second.myLength, pos.z()));
704 : geom.push_back(Position(pos.x(), pos.y(), pos.z()));
705 : */
706 : // push matrix
707 16313 : GLHelper::pushMatrix();
708 : // translate
709 16313 : glTranslated(pos.x(), pos.y(), pos.z());
710 : // rotate
711 16313 : glRotated(rotation, 0, 0, 1);
712 : // set color
713 23164 : GLHelper::setColor(vehicle ? green : red);
714 : // draw box lines
715 16313 : GLHelper::drawBoxLines(geom, 0.1 * exaggeration);
716 : // pop matrix
717 16313 : GLHelper::popMatrix();
718 16313 : }
719 :
720 :
721 : bool
722 1112254 : GLHelper::initFont() {
723 1112254 : if (myFont == nullptr) {
724 6568 : myFont = glfonsCreate(2048, 2048, FONS_ZERO_BOTTOMLEFT);
725 6568 : if (myFont != nullptr) {
726 6568 : const int fontNormal = fonsAddFontMem(myFont, "medium", data_font_Roboto_Medium_ttf, data_font_Roboto_Medium_ttf_len, 0);
727 6568 : fonsSetFont(myFont, fontNormal);
728 6568 : fonsSetSize(myFont, (float)myFontSize);
729 : }
730 : }
731 1112254 : return myFont != nullptr;
732 : }
733 :
734 :
735 : const std::vector<RGBColor>&
736 0 : GLHelper::getDottedcontourColors(const int size) {
737 : // check if more colors has to be added
738 0 : while ((int)myDottedcontourColors.size() < size) {
739 0 : if (myDottedcontourColors.empty() || myDottedcontourColors.back() == RGBColor::WHITE) {
740 0 : myDottedcontourColors.push_back(RGBColor::BLACK);
741 : } else {
742 0 : myDottedcontourColors.push_back(RGBColor::WHITE);
743 : }
744 : }
745 0 : return myDottedcontourColors;
746 : }
747 :
748 :
749 : double
750 0 : GLHelper::getTextWidth(const std::string& text, double size) {
751 0 : return size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
752 : }
753 :
754 :
755 : void
756 1112254 : GLHelper::drawText(const std::string& text, const Position& pos, const double layer, const double size,
757 : const RGBColor& col, const double angle, const int align, double width) {
758 1112254 : if (width <= 0) {
759 : width = size;
760 : }
761 1112254 : if (!initFont()) {
762 : return;
763 : }
764 1112254 : GLHelper::pushMatrix();
765 1112254 : glAlphaFunc(GL_GREATER, 0.5);
766 1112254 : glEnable(GL_ALPHA_TEST);
767 : #ifdef HAVE_GL2PS
768 1112254 : if (myGL2PSActive) {
769 0 : glRasterPos3d(pos.x(), pos.y(), layer);
770 0 : GLfloat color[] = {col.red() / 255.f, col.green() / 255.f, col.blue() / 255.f, col.alpha() / 255.f};
771 0 : gl2psTextOptColor(text.c_str(), "Roboto", 10, align == 0 ? GL2PS_TEXT_C : align, (GLfloat) - angle, color);
772 0 : GLHelper::popMatrix();
773 : return;
774 : }
775 : #endif
776 1112254 : glTranslated(pos.x(), pos.y(), layer);
777 1112254 : glScaled(width / myFontSize, size / myFontSize, 1.);
778 1112254 : glRotated(-angle, 0, 0, 1);
779 1130664 : fonsSetAlign(myFont, align == 0 ? FONS_ALIGN_CENTER | FONS_ALIGN_MIDDLE : align);
780 1112254 : fonsSetColor(myFont, glfonsRGBA(col.red(), col.green(), col.blue(), col.alpha()));
781 1112254 : fonsDrawText(myFont, 0., 0., text.c_str(), nullptr);
782 1112254 : GLHelper::popMatrix();
783 : }
784 :
785 :
786 : void
787 0 : GLHelper::drawTextSettings(
788 : const GUIVisualizationTextSettings& settings,
789 : const std::string& text, const Position& pos,
790 : const double scale,
791 : const double angle,
792 : const double layer,
793 : const int align) {
794 0 : drawTextBox(text, pos, layer,
795 : settings.scaledSize(scale),
796 0 : settings.color,
797 0 : settings.bgColor,
798 : RGBColor::INVISIBLE,
799 : angle, 0, 0.2, align);
800 0 : }
801 :
802 :
803 : void
804 0 : GLHelper::drawTextBox(const std::string& text, const Position& pos,
805 : const double layer, const double size,
806 : const RGBColor& txtColor, const RGBColor& bgColor, const RGBColor& borderColor,
807 : const double angle,
808 : const double relBorder,
809 : const double relMargin,
810 : const int align) {
811 0 : if (!initFont()) {
812 : return;
813 : };
814 0 : if (bgColor.alpha() != 0) {
815 : const double boxAngle = 90;
816 0 : const double stringWidth = size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
817 0 : const double borderWidth = size * relBorder;
818 0 : const double boxHeight = size * (0.32 + 0.6 * relMargin);
819 0 : const double boxWidth = stringWidth + size * relMargin;
820 0 : GLHelper::pushMatrix();
821 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
822 0 : glTranslated(pos.x(), pos.y(), layer);
823 0 : glRotated(-angle, 0, 0, 1);
824 0 : Position left(-boxWidth * 0.5, 0);
825 0 : setColor(borderColor);
826 0 : drawBoxLine(left, boxAngle, boxWidth, boxHeight);
827 0 : left.add(borderWidth * 1.5, 0);
828 0 : setColor(bgColor);
829 0 : glTranslated(0, 0, 0.01);
830 0 : drawBoxLine(left, boxAngle, boxWidth - 3 * borderWidth, boxHeight - 2 * borderWidth);
831 0 : GLHelper::popMatrix();
832 : }
833 0 : drawText(text, pos, layer + 0.02, size, txtColor, angle, align);
834 : }
835 :
836 :
837 : void
838 0 : GLHelper::drawTextAtEnd(const std::string& text, const PositionVector& shape, double x,
839 : const GUIVisualizationTextSettings& settings, const double scale) {
840 0 : GLHelper::pushMatrix();
841 : const Position& end = shape.back();
842 0 : const Position& f = shape[-2];
843 0 : const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
844 0 : glTranslated(end.x(), end.y(), 0);
845 0 : glRotated(rot, 0, 0, 1);
846 0 : drawTextBox(text, Position(x, 0.26), 0,
847 : settings.scaledSize(scale, 0.01),
848 0 : settings.color,
849 0 : settings.bgColor,
850 : RGBColor::INVISIBLE,
851 : 180, 0, 0.2);
852 0 : GLHelper::popMatrix();
853 0 : }
854 :
855 :
856 : void
857 79176 : GLHelper::drawCrossTies(const PositionVector& geom, const std::vector<double>& rots,
858 : const std::vector<double>& lengths, double length, double spacing,
859 : double halfWidth, double offset, bool lessDetail) {
860 79176 : GLHelper::pushMatrix();
861 : // draw on top of of the white area between the rails
862 79176 : glTranslated(0, 0, 0.1);
863 79176 : int e = (int) geom.size() - 1;
864 158623 : for (int i = 0; i < e; ++i) {
865 79447 : GLHelper::pushMatrix();
866 79447 : glTranslated(geom[i].x(), geom[i].y(), 0.0);
867 79447 : glRotated(rots[i], 0, 0, 1);
868 : // draw crossing depending of detail
869 79447 : if (!lessDetail) {
870 1122365 : for (double t = 0; t < lengths[i]; t += spacing) {
871 1042918 : glBegin(GL_QUADS);
872 1042918 : glVertex2d(-halfWidth - offset, -t);
873 1042918 : glVertex2d(-halfWidth - offset, -t - length);
874 1042918 : glVertex2d(halfWidth - offset, -t - length);
875 1042918 : glVertex2d(halfWidth - offset, -t);
876 1042918 : glEnd();
877 : #ifdef CHECK_ELEMENTCOUNTER
878 : myVertexCounter += 4;
879 : #endif
880 : }
881 : } else {
882 : // only draw a single rectangle if it's being drawn only for selecting
883 0 : glBegin(GL_QUADS);
884 0 : glVertex2d(-halfWidth - offset, 0);
885 0 : glVertex2d(-halfWidth - offset, -lengths.back());
886 0 : glVertex2d(halfWidth - offset, -lengths.back());
887 0 : glVertex2d(halfWidth - offset, 0);
888 0 : glEnd();
889 : #ifdef CHECK_ELEMENTCOUNTER
890 : myVertexCounter += 4;
891 : #endif
892 : }
893 : // pop three draw matrix
894 79447 : GLHelper::popMatrix();
895 : }
896 79176 : GLHelper::popMatrix();
897 79176 : }
898 :
899 : void
900 56242 : GLHelper::drawInverseMarkings(const PositionVector& geom,
901 : const std::vector<double>& rots,
902 : const std::vector<double>& lengths,
903 : double maxLength, double spacing,
904 : double halfWidth, bool cl, bool cr, bool lefthand, double scale) {
905 :
906 56242 : double mw = (halfWidth + SUMO_const_laneMarkWidth * (cl ? 0.6 : 0.2)) * scale;
907 56242 : double mw2 = (halfWidth - SUMO_const_laneMarkWidth * (cr ? 0.6 : 0.2)) * scale;
908 56242 : if (cl || cr) {
909 55773 : if (lefthand) {
910 12 : mw *= -1;
911 12 : mw2 *= -1;
912 : }
913 55773 : int e = (int) geom.size() - 1;
914 : double offset = 0;
915 135276 : for (int i = 0; i < e; ++i) {
916 79503 : GLHelper::pushMatrix();
917 79503 : glTranslated(geom[i].x(), geom[i].y(), 2.1);
918 79503 : glRotated(rots[i], 0, 0, 1);
919 : double t;
920 994153 : for (t = offset; t < lengths[i]; t += spacing) {
921 914650 : const double length = MIN2((double)maxLength, lengths[i] - t);
922 914650 : glBegin(GL_QUADS);
923 914650 : glVertex2d(-mw, -t);
924 914650 : glVertex2d(-mw, -t - length);
925 914650 : glVertex2d(-mw2, -t - length);
926 914650 : glVertex2d(-mw2, -t);
927 914650 : glEnd();
928 : #ifdef CHECK_ELEMENTCOUNTER
929 : myVertexCounter += 4;
930 : #endif
931 914650 : if (!cl || !cr) {
932 : // draw inverse marking between asymmetrical lane markings
933 551 : const double length2 = MIN2((double)6, lengths[i] - t);
934 551 : glBegin(GL_QUADS);
935 551 : glVertex2d(-halfWidth + 0.02, -t - length2);
936 551 : glVertex2d(-halfWidth + 0.02, -t - length);
937 551 : glVertex2d(-halfWidth - 0.02, -t - length);
938 551 : glVertex2d(-halfWidth - 0.02, -t - length2);
939 551 : glEnd();
940 : #ifdef CHECK_ELEMENTCOUNTER
941 : myVertexCounter += 4;
942 : #endif
943 : }
944 : }
945 79503 : offset = t - lengths[i] - spacing;
946 79503 : GLHelper::popMatrix();
947 : }
948 : }
949 56242 : }
950 :
951 :
952 : void
953 0 : GLHelper::debugVertices(const PositionVector& shape, const GUIVisualizationTextSettings& settings, double scale, double layer) {
954 0 : for (int i = 0; i < (int)shape.size(); ++i) {
955 0 : drawTextBox(toString(i), shape[i], layer,
956 : settings.scaledSize(scale),
957 0 : settings.color,
958 0 : settings.bgColor,
959 : RGBColor::INVISIBLE,
960 : 0, 0, 0.2);
961 : }
962 0 : }
963 :
964 :
965 : void
966 0 : GLHelper::drawBoundary(const GUIVisualizationSettings& s, const Boundary& b) {
967 0 : if (s.drawBoundaries) {
968 0 : GLHelper::pushMatrix();
969 0 : GLHelper::setColor(RGBColor::MAGENTA);
970 : // draw on top
971 0 : glTranslated(0, 0, 1024);
972 0 : drawLine(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()));
973 0 : drawLine(Position(b.xmax(), b.ymax()), Position(b.xmax(), b.ymin()));
974 0 : drawLine(Position(b.xmax(), b.ymin()), Position(b.xmin(), b.ymin()));
975 0 : drawLine(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()));
976 0 : GLHelper::popMatrix();
977 : }
978 0 : }
979 :
980 :
981 : /****************************************************************************/
|