Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file GLHelper.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Sept 2002
19 : ///
20 : // Some methods which help to draw certain geometrical objects in openGL
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <cassert>
25 : #include <utils/geom/GeomHelper.h>
26 : #include <utils/common/StdDefs.h>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/ToString.h>
29 : #include <utils/options/OptionsCont.h>
30 : #include <utils/gui/div/GUIGeometry.h>
31 : #define FONTSTASH_IMPLEMENTATION // Expands implementation
32 : #ifdef _MSC_VER
33 : #pragma warning(disable: 4505 5219) // do not warn about unused functions and implicit float conversions
34 : #endif
35 : #if __GNUC__ > 3
36 : #pragma GCC diagnostic push
37 : #pragma GCC diagnostic ignored "-Wunused-function"
38 : #endif
39 : #include <foreign/fontstash/fontstash.h>
40 : #include <utils/gui/globjects/GLIncludes.h>
41 : #define GLFONTSTASH_IMPLEMENTATION // Expands implementation
42 : #include <foreign/fontstash/glfontstash.h>
43 : #include <utils/geom/Boundary.h>
44 : #ifdef HAVE_GL2PS
45 : #include <gl2ps.h>
46 : #endif
47 : #include "Roboto.h"
48 : #include "GLHelper.h"
49 :
50 : #define CIRCLE_RESOLUTION (double)10 // inverse in degrees
51 : //#define CHECK_PUSHPOP // enable or disable check push and pop matrix/names
52 : //#define CHECK_ELEMENTCOUNTER // enable or disable element counter (for matrix and vertex)
53 :
54 : #ifndef CALLBACK
55 : #define CALLBACK
56 : #endif
57 :
58 : // ===========================================================================
59 : // static member definitions
60 : // ===========================================================================
61 :
62 : int GLHelper::myMatrixCounter = 0;
63 : int GLHelper::myVertexCounter = 0;
64 : int GLHelper::myMatrixCounterDebug = 0;
65 : int GLHelper::myNameCounter = 0;
66 : std::vector<std::pair<double, double> > GLHelper::myCircleCoords;
67 : std::vector<RGBColor> GLHelper::myDottedcontourColors;
68 : FONScontext* GLHelper::myFont = nullptr;
69 : double GLHelper::myFontSize = 50.0;
70 : bool GLHelper::myGL2PSActive = false;
71 :
72 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 253753474 : GLHelper::getCircleCoords() {
93 : // fill in first call
94 253753474 : if (myCircleCoords.size() == 0) {
95 5204890 : for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
96 5203445 : const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
97 5203445 : const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
98 5203445 : myCircleCoords.push_back(std::pair<double, double>(x, y));
99 : }
100 : }
101 253753474 : return myCircleCoords;
102 : }
103 :
104 :
105 : int
106 126876737 : GLHelper::angleLookup(double angleDeg) {
107 126876737 : const int numCoords = (int)getCircleCoords().size() - 1;
108 126876737 : int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
109 126876737 : if (index < 0) {
110 914628 : index += numCoords;
111 : }
112 : assert(index >= 0);
113 126876737 : return (int)index;
114 : }
115 :
116 :
117 : void
118 121079980 : GLHelper::pushMatrix() {
119 121079980 : glPushMatrix();
120 : // update counters
121 : #ifdef CHECK_ELEMENTCOUNTER
122 : myMatrixCounter++;
123 : #endif
124 : #ifdef CHECK_PUSHPOP
125 : myMatrixCounterDebug++;
126 : #endif
127 121079980 : }
128 :
129 :
130 : void
131 121867051 : GLHelper::popMatrix() {
132 121867051 : glPopMatrix();
133 : #ifdef CHECK_PUSHPOP
134 : myMatrixCounterDebug--;
135 : #endif
136 121867051 : }
137 :
138 :
139 : void
140 92840394 : GLHelper::pushName(unsigned int name) {
141 92840394 : glPushName(name);
142 : #ifdef CHECK_PUSHPOP
143 : myNameCounter++;
144 : #endif
145 92840394 : }
146 :
147 :
148 : void
149 92840394 : GLHelper::popName() {
150 92840394 : glPopName();
151 : #ifdef CHECK_PUSHPOP
152 : myNameCounter--;
153 : #endif
154 92840394 : }
155 :
156 :
157 : int
158 0 : GLHelper::getMatrixCounter() {
159 0 : return myMatrixCounter;
160 : }
161 :
162 :
163 : void
164 768689 : GLHelper::resetMatrixCounter() {
165 768689 : myMatrixCounter = 0;
166 768689 : }
167 :
168 :
169 : int
170 0 : GLHelper::getVertexCounter() {
171 0 : return myVertexCounter;
172 : }
173 :
174 :
175 : void
176 768689 : GLHelper::resetVertexCounter() {
177 768689 : myVertexCounter = 0;
178 768689 : }
179 :
180 :
181 : void
182 768689 : 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 768689 : }
190 :
191 :
192 : void
193 768689 : 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 768689 : }
201 :
202 :
203 : void
204 1553007 : GLHelper::drawFilledPoly(const PositionVector& v, bool close) {
205 1553007 : if (v.size() == 0) {
206 : return;
207 : }
208 1553007 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
209 1553007 : glBegin(GL_POLYGON);
210 11010050 : for (PositionVector::const_iterator i = v.begin(); i != v.end(); i++) {
211 : const Position& p = *i;
212 9457043 : glVertex2d(p.x(), p.y());
213 : #ifdef CHECK_ELEMENTCOUNTER
214 : myVertexCounter++;
215 : #endif
216 : }
217 1553007 : if (close) {
218 : const Position& p = *(v.begin());
219 1553007 : glVertex2d(p.x(), p.y());
220 : #ifdef CHECK_ELEMENTCOUNTER
221 : myVertexCounter++;
222 : #endif
223 : }
224 1553007 : 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 25450207 : GLHelper::drawBoxLine(const Position& beg, double rot, double visLength,
297 : double width, double offset) {
298 25450207 : GLHelper::pushMatrix();
299 25450207 : glTranslated(beg.x(), beg.y(), 0);
300 25450207 : glRotated(rot, 0, 0, 1);
301 25450207 : glBegin(GL_QUADS);
302 25450207 : glVertex2d(-width - offset, 0);
303 25450207 : glVertex2d(-width - offset, -visLength);
304 25450207 : glVertex2d(width - offset, -visLength);
305 25450207 : glVertex2d(width - offset, 0);
306 25450207 : glEnd();
307 25450207 : GLHelper::popMatrix();
308 : #ifdef CHECK_ELEMENTCOUNTER
309 : myVertexCounter += 4;
310 : #endif
311 25450207 : }
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 190359 : GLHelper::rightTurn(double angle1, double angle2) {
336 190359 : double delta = angle2 - angle1;
337 190547 : while (delta > 180) {
338 188 : delta -= 360;
339 : }
340 194237 : while (delta < -180) {
341 3878 : delta += 360;
342 : }
343 190359 : return delta <= 0;
344 : }
345 :
346 :
347 : void
348 10376230 : 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 10376230 : int e = (int) geom.size() - 1;
354 35137614 : for (int i = 0; i < e; i++) {
355 24761384 : drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
356 : }
357 : // draw the corner details
358 10376230 : if (cornerDetail > 0) {
359 598957 : for (int i = 1; i < e; i++) {
360 190359 : GLHelper::pushMatrix();
361 190359 : glTranslated(geom[i].x(), geom[i].y(), 0.1);
362 190359 : double angleBeg = -rots[i - 1];
363 190359 : double angleEnd = 180 - rots[i];
364 190359 : if (rightTurn(rots[i - 1], rots[i])) {
365 : std::swap(angleBeg, angleEnd);
366 : }
367 : // only draw the missing piece
368 190359 : angleBeg -= 90;
369 190359 : angleEnd += 90;
370 : // avoid drawing more than 360 degrees
371 190359 : if (angleEnd - angleBeg > 360) {
372 3878 : angleBeg += 360;
373 : }
374 190359 : if (angleEnd - angleBeg < -360) {
375 0 : angleEnd += 360;
376 : }
377 : // draw the right way around
378 190359 : if (angleEnd > angleBeg) {
379 87511 : angleEnd -= 360;
380 : }
381 190359 : drawFilledCircle(width + offset, cornerDetail, angleBeg, angleEnd);
382 190359 : GLHelper::popMatrix();
383 : }
384 : }
385 10376230 : }
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 58399 : GLHelper::drawBoxLines(const PositionVector& geom, double width) {
426 : // first convert to GUIGeometry to avoid graphical errors with Z value (see #13992)
427 58399 : const auto geometry = GUIGeometry(geom);
428 58399 : drawBoxLines(geometry.getShape(), geometry.getShapeRotations(), geometry.getShapeLengths(), width);
429 58399 : }
430 :
431 :
432 : void
433 1232 : GLHelper::drawLine(const Position& beg, double rot, double visLength) {
434 1232 : GLHelper::pushMatrix();
435 1232 : glTranslated(beg.x(), beg.y(), 0);
436 1232 : glRotated(rot, 0, 0, 1);
437 1232 : glBegin(GL_LINES);
438 1232 : glVertex2d(0, 0);
439 1232 : glVertex2d(0, -visLength);
440 1232 : glEnd();
441 1232 : GLHelper::popMatrix();
442 : #ifdef CHECK_ELEMENTCOUNTER
443 : myVertexCounter += 2;
444 : #endif
445 1232 : }
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 13063034 : GLHelper::drawLine(const PositionVector& v) {
468 13063034 : glBegin(GL_LINES);
469 13063034 : int e = (int) v.size() - 1;
470 35512879 : for (int i = 0; i < e; ++i) {
471 22449845 : glVertex2d(v[i].x(), v[i].y());
472 22449845 : glVertex2d(v[i + 1].x(), v[i + 1].y());
473 : #ifdef CHECK_ELEMENTCOUNTER
474 : myVertexCounter += 2;
475 : #endif
476 : }
477 13063034 : glEnd();
478 13063034 : }
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 15522233 : GLHelper::drawFilledCircle(double const radius, int const steps) {
565 15522233 : drawFilledCircle(radius, steps, 0, 360);
566 15522233 : }
567 :
568 :
569 : void
570 15712607 : GLHelper::drawFilledCircle(double radius, int steps, double beg, double end) {
571 15712607 : const double inc = (end - beg) / (double)steps;
572 15712607 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
573 15712607 : std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
574 :
575 126876737 : for (int i = 0; i <= steps; ++i) {
576 111164130 : const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
577 111164130 : glBegin(GL_TRIANGLES);
578 111164130 : glVertex2d(p1.first * radius, p1.second * radius);
579 111164130 : glVertex2d(p2.first * radius, p2.second * radius);
580 111164130 : glVertex2d(0, 0);
581 111164130 : glEnd();
582 : p1 = p2;
583 : #ifdef CHECK_ELEMENTCOUNTER
584 : myVertexCounter += 3;
585 : #endif
586 : }
587 15712607 : }
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 524099 : GLHelper::drawTriangleAtEnd(const Position& p1, const Position& p2, double tLength,
625 : double tWidth, const double extraOffset) {
626 524099 : const double length = p1.distanceTo(p2);
627 524099 : if (length < tLength) {
628 0 : tWidth *= length / tLength;
629 : tLength = length;
630 : }
631 524099 : Position rl(PositionVector::positionAtOffset(p1, p2, length - tLength));
632 524099 : GLHelper::pushMatrix();
633 524099 : glTranslated(rl.x(), rl.y(), 0);
634 524099 : glRotated(-GeomHelper::naviDegree(p1.angleTo2D(p2)), 0, 0, 1);
635 524099 : glTranslated(0, extraOffset, 0);
636 524099 : glBegin(GL_TRIANGLES);
637 524099 : glVertex2d(0, tLength);
638 524099 : glVertex2d(-tWidth, 0);
639 524099 : glVertex2d(+tWidth, 0);
640 524099 : glEnd();
641 524099 : GLHelper::popMatrix();
642 : #ifdef CHECK_ELEMENTCOUNTER
643 : myVertexCounter += 3;
644 : #endif
645 524099 : }
646 :
647 :
648 : void
649 60851900 : GLHelper::setColor(const RGBColor& c) {
650 60851900 : glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
651 60851900 : }
652 :
653 :
654 : RGBColor
655 1548997 : GLHelper::getColor() {
656 : GLdouble current[4];
657 1548997 : glGetDoublev(GL_CURRENT_COLOR, current);
658 3097994 : return RGBColor(static_cast<unsigned char>(current[0] * 255. + 0.5),
659 1548997 : static_cast<unsigned char>(current[1] * 255. + 0.5),
660 1548997 : static_cast<unsigned char>(current[2] * 255. + 0.5),
661 1548997 : static_cast<unsigned char>(current[3] * 255. + 0.5));
662 : }
663 :
664 :
665 : void
666 23542 : GLHelper::resetFont() {
667 23542 : glfonsDelete(myFont);
668 23542 : myFont = nullptr;
669 23542 : }
670 :
671 :
672 : void
673 0 : GLHelper::setGL2PS(bool active) {
674 0 : myGL2PSActive = active;
675 0 : }
676 :
677 :
678 : void
679 49214 : GLHelper::drawSpaceOccupancies(const double exaggeration, const Position& pos, const double rotation,
680 : const double width, const double length, const bool vehicle) {
681 : // declare geometry
682 49214 : PositionVector geom;
683 49214 : const double w = width / 2. - 0.1 * exaggeration;
684 : const double h = length;
685 : // set geometry
686 49214 : geom.push_back(Position(-w, +0, 0.));
687 49214 : geom.push_back(Position(+w, +0, 0.));
688 49214 : geom.push_back(Position(+w, +h, 0.));
689 49214 : geom.push_back(Position(-w, +h, 0.));
690 49214 : geom.push_back(Position(-w, +0, 0.));
691 :
692 : // push matrix
693 49214 : GLHelper::pushMatrix();
694 : // translate
695 49214 : glTranslated(pos.x(), pos.y(), pos.z());
696 : // rotate
697 49214 : glRotated(rotation, 0, 0, 1);
698 : // set color
699 80079 : GLHelper::setColor(vehicle ? RGBColor::RED : RGBColor::GREEN);
700 : // draw box lines
701 49214 : GLHelper::drawBoxLines(geom, 0.1 * exaggeration);
702 : // pop matrix
703 49214 : GLHelper::popMatrix();
704 49214 : }
705 :
706 :
707 : bool
708 1556878 : GLHelper::initFont() {
709 1556878 : if (myFont == nullptr) {
710 7099 : myFont = glfonsCreate(2048, 2048, FONS_ZERO_BOTTOMLEFT);
711 7099 : if (myFont != nullptr) {
712 7099 : const int fontNormal = fonsAddFontMem(myFont, "medium", data_font_Roboto_Medium_ttf, data_font_Roboto_Medium_ttf_len, 0);
713 7099 : fonsSetFont(myFont, fontNormal);
714 7099 : fonsSetSize(myFont, (float)myFontSize);
715 : }
716 : }
717 1556878 : return myFont != nullptr;
718 : }
719 :
720 :
721 : const std::vector<RGBColor>&
722 0 : GLHelper::getDottedcontourColors(const int size) {
723 : // check if more colors has to be added
724 0 : while ((int)myDottedcontourColors.size() < size) {
725 0 : if (myDottedcontourColors.empty() || myDottedcontourColors.back() == RGBColor::WHITE) {
726 0 : myDottedcontourColors.push_back(RGBColor::BLACK);
727 : } else {
728 0 : myDottedcontourColors.push_back(RGBColor::WHITE);
729 : }
730 : }
731 0 : return myDottedcontourColors;
732 : }
733 :
734 :
735 : double
736 0 : GLHelper::getTextWidth(const std::string& text, double size) {
737 0 : return size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
738 : }
739 :
740 :
741 : void
742 1556878 : GLHelper::drawText(const std::string& text, const Position& pos, const double layer, const double size,
743 : const RGBColor& col, const double angle, const int align, double width) {
744 1556878 : if (width <= 0) {
745 : width = size;
746 : }
747 1556878 : if (!initFont()) {
748 : return;
749 : }
750 1556878 : GLHelper::pushMatrix();
751 1556878 : glAlphaFunc(GL_GREATER, 0.5);
752 1556878 : glEnable(GL_ALPHA_TEST);
753 : #ifdef HAVE_GL2PS
754 1556878 : if (myGL2PSActive) {
755 0 : glRasterPos3d(pos.x(), pos.y(), layer);
756 0 : GLfloat color[] = {col.red() / 255.f, col.green() / 255.f, col.blue() / 255.f, col.alpha() / 255.f};
757 0 : gl2psTextOptColor(text.c_str(), "Roboto", 10, align == 0 ? GL2PS_TEXT_C : align, (GLfloat) - angle, color);
758 0 : GLHelper::popMatrix();
759 : return;
760 : }
761 : #endif
762 1556878 : glTranslated(pos.x(), pos.y(), layer);
763 1556878 : glScaled(width / myFontSize, size / myFontSize, 1.);
764 1556878 : glRotated(-angle, 0, 0, 1);
765 1575762 : fonsSetAlign(myFont, align == 0 ? FONS_ALIGN_CENTER | FONS_ALIGN_MIDDLE : align);
766 1556878 : fonsSetColor(myFont, glfonsRGBA(col.red(), col.green(), col.blue(), col.alpha()));
767 1556878 : fonsDrawText(myFont, 0., 0., text.c_str(), nullptr);
768 1556878 : GLHelper::popMatrix();
769 : }
770 :
771 :
772 : void
773 0 : GLHelper::drawTextSettings(
774 : const GUIVisualizationTextSettings& settings,
775 : const std::string& text, const Position& pos,
776 : const double scale,
777 : const double angle,
778 : const double layer,
779 : const int align) {
780 0 : drawTextBox(text, pos, layer,
781 : settings.scaledSize(scale),
782 0 : settings.color,
783 0 : settings.bgColor,
784 : RGBColor::INVISIBLE,
785 : angle, 0, 0.2, align);
786 0 : }
787 :
788 :
789 : void
790 0 : GLHelper::drawTextBox(const std::string& text, const Position& pos,
791 : const double layer, const double size,
792 : const RGBColor& txtColor, const RGBColor& bgColor, const RGBColor& borderColor,
793 : const double angle,
794 : const double relBorder,
795 : const double relMargin,
796 : const int align) {
797 0 : if (!initFont()) {
798 : return;
799 : };
800 0 : if (bgColor.alpha() != 0) {
801 : const double boxAngle = 90;
802 0 : const double stringWidth = size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
803 0 : const double borderWidth = size * relBorder;
804 0 : const double boxHeight = size * (0.32 + 0.6 * relMargin);
805 0 : const double boxWidth = stringWidth + size * relMargin;
806 0 : GLHelper::pushMatrix();
807 0 : glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
808 0 : glTranslated(pos.x(), pos.y(), layer);
809 0 : glRotated(-angle, 0, 0, 1);
810 0 : Position left(-boxWidth * 0.5, 0);
811 0 : setColor(borderColor);
812 0 : drawBoxLine(left, boxAngle, boxWidth, boxHeight);
813 0 : left.add(borderWidth * 1.5, 0);
814 0 : setColor(bgColor);
815 0 : glTranslated(0, 0, 0.01);
816 0 : drawBoxLine(left, boxAngle, boxWidth - 3 * borderWidth, boxHeight - 2 * borderWidth);
817 0 : GLHelper::popMatrix();
818 : }
819 0 : drawText(text, pos, layer + 0.02, size, txtColor, angle, align);
820 : }
821 :
822 :
823 : void
824 0 : GLHelper::drawTextAtEnd(const std::string& text, const PositionVector& shape, double x,
825 : const GUIVisualizationTextSettings& settings, const double scale) {
826 0 : GLHelper::pushMatrix();
827 : const Position& end = shape.back();
828 0 : const Position& f = shape[-2];
829 0 : const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
830 0 : glTranslated(end.x(), end.y(), 0);
831 0 : glRotated(rot, 0, 0, 1);
832 0 : drawTextBox(text, Position(x, 0.26), 0,
833 : settings.scaledSize(scale, 0.01),
834 0 : settings.color,
835 0 : settings.bgColor,
836 : RGBColor::INVISIBLE,
837 : 180, 0, 0.2);
838 0 : GLHelper::popMatrix();
839 0 : }
840 :
841 :
842 : void
843 48491 : GLHelper::drawCrossTies(const PositionVector& geom, const std::vector<double>& rots,
844 : const std::vector<double>& lengths, double length, double spacing,
845 : double halfWidth, double offset, bool lessDetail) {
846 48491 : GLHelper::pushMatrix();
847 : // draw on top of of the white area between the rails
848 48491 : glTranslated(0, 0, 0.1);
849 48491 : int e = (int) geom.size() - 1;
850 97381 : for (int i = 0; i < e; ++i) {
851 48890 : GLHelper::pushMatrix();
852 48890 : glTranslated(geom[i].x(), geom[i].y(), 0.0);
853 48890 : glRotated(rots[i], 0, 0, 1);
854 : // draw crossing depending of detail
855 48890 : if (!lessDetail) {
856 824660 : for (double t = 0; t < lengths[i]; t += spacing) {
857 775770 : glBegin(GL_QUADS);
858 775770 : glVertex2d(-halfWidth - offset, -t);
859 775770 : glVertex2d(-halfWidth - offset, -t - length);
860 775770 : glVertex2d(halfWidth - offset, -t - length);
861 775770 : glVertex2d(halfWidth - offset, -t);
862 775770 : glEnd();
863 : #ifdef CHECK_ELEMENTCOUNTER
864 : myVertexCounter += 4;
865 : #endif
866 : }
867 : } else {
868 : // only draw a single rectangle if it's being drawn only for selecting
869 0 : glBegin(GL_QUADS);
870 0 : glVertex2d(-halfWidth - offset, 0);
871 0 : glVertex2d(-halfWidth - offset, -lengths.back());
872 0 : glVertex2d(halfWidth - offset, -lengths.back());
873 0 : glVertex2d(halfWidth - offset, 0);
874 0 : glEnd();
875 : #ifdef CHECK_ELEMENTCOUNTER
876 : myVertexCounter += 4;
877 : #endif
878 : }
879 : // pop three draw matrix
880 48890 : GLHelper::popMatrix();
881 : }
882 48491 : GLHelper::popMatrix();
883 48491 : }
884 :
885 : void
886 105645 : GLHelper::drawInverseMarkings(const PositionVector& geom,
887 : const std::vector<double>& rots,
888 : const std::vector<double>& lengths,
889 : double maxLength, double spacing,
890 : double halfWidth, bool cl, bool cr, bool lefthand, double scale) {
891 :
892 105645 : double mw = (halfWidth + SUMO_const_laneMarkWidth * (cl ? 0.6 : 0.2)) * scale;
893 105645 : double mw2 = (halfWidth - SUMO_const_laneMarkWidth * (cr ? 0.6 : 0.2)) * scale;
894 105645 : if (cl || cr) {
895 104638 : if (lefthand) {
896 12 : mw *= -1;
897 12 : mw2 *= -1;
898 : }
899 104638 : int e = (int) geom.size() - 1;
900 : double offset = 0;
901 248480 : for (int i = 0; i < e; ++i) {
902 143842 : GLHelper::pushMatrix();
903 143842 : glTranslated(geom[i].x(), geom[i].y(), 2.1);
904 143842 : glRotated(rots[i], 0, 0, 1);
905 : double t;
906 1884816 : for (t = offset; t < lengths[i]; t += spacing) {
907 1740974 : const double length = MIN2((double)maxLength, lengths[i] - t);
908 1740974 : glBegin(GL_QUADS);
909 1740974 : glVertex2d(-mw, -t);
910 1740974 : glVertex2d(-mw, -t - length);
911 1740974 : glVertex2d(-mw2, -t - length);
912 1740974 : glVertex2d(-mw2, -t);
913 1740974 : glEnd();
914 : #ifdef CHECK_ELEMENTCOUNTER
915 : myVertexCounter += 4;
916 : #endif
917 1740974 : if (!cl || !cr) {
918 : // draw inverse marking between asymmetrical lane markings
919 530 : const double length2 = MIN2((double)6, lengths[i] - t);
920 530 : glBegin(GL_QUADS);
921 530 : glVertex2d(-halfWidth + 0.02, -t - length2);
922 530 : glVertex2d(-halfWidth + 0.02, -t - length);
923 530 : glVertex2d(-halfWidth - 0.02, -t - length);
924 530 : glVertex2d(-halfWidth - 0.02, -t - length2);
925 530 : glEnd();
926 : #ifdef CHECK_ELEMENTCOUNTER
927 : myVertexCounter += 4;
928 : #endif
929 : }
930 : }
931 143842 : offset = t - lengths[i] - spacing;
932 143842 : GLHelper::popMatrix();
933 : }
934 : }
935 105645 : }
936 :
937 :
938 : void
939 0 : GLHelper::debugVertices(const PositionVector& shape, const GUIVisualizationTextSettings& settings, double scale, double layer) {
940 0 : for (int i = 0; i < (int)shape.size(); ++i) {
941 0 : drawTextBox(toString(i), shape[i], layer,
942 : settings.scaledSize(scale),
943 0 : settings.color,
944 0 : settings.bgColor,
945 : RGBColor::INVISIBLE,
946 : 0, 0, 0.2);
947 : }
948 0 : }
949 :
950 :
951 : void
952 0 : GLHelper::drawBoundary(const GUIVisualizationSettings& s, const Boundary& b) {
953 0 : if (s.drawBoundaries) {
954 0 : GLHelper::pushMatrix();
955 0 : GLHelper::setColor(RGBColor::MAGENTA);
956 : // draw on top
957 0 : glTranslated(0, 0, 1024);
958 0 : drawLine(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()));
959 0 : drawLine(Position(b.xmax(), b.ymax()), Position(b.xmax(), b.ymin()));
960 0 : drawLine(Position(b.xmax(), b.ymin()), Position(b.xmin(), b.ymin()));
961 0 : drawLine(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()));
962 0 : GLHelper::popMatrix();
963 : }
964 0 : }
965 :
966 :
967 : /****************************************************************************/
|