Eclipse SUMO - Simulation of Urban MObility
GLHelper.cpp
Go to the documentation of this file.
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 /****************************************************************************/
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>
28 #include <utils/common/ToString.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
40 #define GLFONTSTASH_IMPLEMENTATION // Expands implementation
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 
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 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  vertex = (GLdouble*)malloc(7 * sizeof(GLdouble));
79 
80  vertex[0] = coords[0];
81  vertex[1] = coords[1];
82  vertex[2] = coords[2];
83  *dataOut = vertex;
84 }
85 
86 // ===========================================================================
87 // method definitions
88 // ===========================================================================
89 
90 const std::vector<std::pair<double, double> >&
92  // fill in first call
93  if (myCircleCoords.size() == 0) {
94  for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
95  const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
96  const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
97  myCircleCoords.push_back(std::pair<double, double>(x, y));
98  }
99  }
100  return myCircleCoords;
101 }
102 
103 
104 int
105 GLHelper::angleLookup(double angleDeg) {
106  const int numCoords = (int)getCircleCoords().size() - 1;
107  int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
108  if (index < 0) {
109  index += numCoords;
110  }
111  assert(index >= 0);
112  return (int)index;
113 }
114 
115 
116 void
118  glPushMatrix();
119  // update counters
120 #ifdef CHECK_ELEMENTCOUNTER
121  myMatrixCounter++;
122 #endif
123 #ifdef CHECK_PUSHPOP
125 #endif
126 }
127 
128 
129 void
131  glPopMatrix();
132 #ifdef CHECK_PUSHPOP
134 #endif
135 }
136 
137 
138 void
139 GLHelper::pushName(unsigned int name) {
140  glPushName(name);
141 #ifdef CHECK_PUSHPOP
142  myNameCounter++;
143 #endif
144 }
145 
146 
147 void
149  glPopName();
150 #ifdef CHECK_PUSHPOP
151  myNameCounter--;
152 #endif
153 }
154 
155 
156 int
158  return myMatrixCounter;
159 }
160 
161 
162 void
164  myMatrixCounter = 0;
165 }
166 
167 
168 int
170  return myVertexCounter;
171 }
172 
173 
174 void
176  myVertexCounter = 0;
177 }
178 
179 
180 void
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  }
187 #endif
188 }
189 
190 
191 void
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 }
200 
201 
202 void
204  if (v.size() == 0) {
205  return;
206  }
207  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
208  glBegin(GL_POLYGON);
209  for (PositionVector::const_iterator i = v.begin(); i != v.end(); i++) {
210  const Position& p = *i;
211  glVertex2d(p.x(), p.y());
212 #ifdef CHECK_ELEMENTCOUNTER
213  myVertexCounter++;
214 #endif
215  }
216  if (close) {
217  const Position& p = *(v.begin());
218  glVertex2d(p.x(), p.y());
219 #ifdef CHECK_ELEMENTCOUNTER
220  myVertexCounter++;
221 #endif
222  }
223  glEnd();
224 }
225 
226 
227 void
229  if (v.size() == 0) {
230  return;
231  }
232  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  gluTessCallback(tobj, GLU_TESS_VERTEX, (GLvoid(CALLBACK*)()) &glVertex3dv);
242  gluTessCallback(tobj, GLU_TESS_BEGIN, (GLvoid(CALLBACK*)()) &glBegin);
243  gluTessCallback(tobj, GLU_TESS_END, (GLvoid(CALLBACK*)()) &glEnd);
244  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  gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
252  gluTessBeginPolygon(tobj, nullptr);
253  gluTessBeginContour(tobj);
254  double* points = new double[(v.size() + int(close)) * 3];
255 
256  for (int i = 0; i != (int)v.size(); ++i) {
257  points[3 * i] = v[i].x();
258  points[3 * i + 1] = v[i].y();
259  points[3 * i + 2] = 0;
260  gluTessVertex(tobj, points + 3 * i, points + 3 * i);
261  }
262  if (close) {
263  const int i = (int)v.size();
264  points[3 * i] = v[0].x();
265  points[3 * i + 1] = v[0].y();
266  points[3 * i + 2] = 0;
267  gluTessVertex(tobj, points + 3 * i, points + 3 * i);
268  }
269  gluTessEndContour(tobj);
270  gluTessEndPolygon(tobj);
271  gluDeleteTess(tobj);
272  delete[] points;
273 }
274 
275 
276 void
277 GLHelper::drawRectangle(const Position& center, const double width, const double height) {
278  const double halfWidth = width * 0.5;
279  const double halfHeight = height * 0.5;
281  glTranslated(center.x(), center.y(), 0);
282  glBegin(GL_QUADS);
283  glVertex2d(-halfWidth, halfHeight);
284  glVertex2d(-halfWidth, -halfHeight);
285  glVertex2d(halfWidth, -halfHeight);
286  glVertex2d(halfWidth, halfHeight);
287  glEnd();
289 #ifdef CHECK_ELEMENTCOUNTER
290  myVertexCounter += 4;
291 #endif
292 }
293 
294 void
295 GLHelper::drawBoxLine(const Position& beg, double rot, double visLength,
296  double width, double offset) {
298  glTranslated(beg.x(), beg.y(), 0);
299  glRotated(rot, 0, 0, 1);
300  glBegin(GL_QUADS);
301  glVertex2d(-width - offset, 0);
302  glVertex2d(-width - offset, -visLength);
303  glVertex2d(width - offset, -visLength);
304  glVertex2d(width - offset, 0);
305  glEnd();
307 #ifdef CHECK_ELEMENTCOUNTER
308  myVertexCounter += 4;
309 #endif
310 }
311 
312 
313 void
314 GLHelper::drawBoxLine(const Position& beg1, const Position& beg2,
315  double rot, double visLength,
316  double width) {
318  glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
319  glRotated(rot, 0, 0, 1);
320  glBegin(GL_QUADS);
321  glVertex2d(-width, 0);
322  glVertex2d(-width, -visLength);
323  glVertex2d(width, -visLength);
324  glVertex2d(width, 0);
325  glEnd();
327 #ifdef CHECK_ELEMENTCOUNTER
328  myVertexCounter += 4;
329 #endif
330 }
331 
332 
333 bool
334 GLHelper::rightTurn(double angle1, double angle2) {
335  double delta = angle2 - angle1;
336  while (delta > 180) {
337  delta -= 360;
338  }
339  while (delta < -180) {
340  delta += 360;
341  }
342  return delta <= 0;
343 }
344 
345 
346 void
348  const std::vector<double>& rots,
349  const std::vector<double>& lengths,
350  double width, int cornerDetail, double offset) {
351  // draw the lane
352  int e = (int) geom.size() - 1;
353  for (int i = 0; i < e; i++) {
354  drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
355  }
356  // draw the corner details
357  if (cornerDetail > 0) {
358  for (int i = 1; i < e; i++) {
360  glTranslated(geom[i].x(), geom[i].y(), 0.1);
361  double angleBeg = -rots[i - 1];
362  double angleEnd = 180 - rots[i];
363  if (rightTurn(rots[i - 1], rots[i])) {
364  std::swap(angleBeg, angleEnd);
365  }
366  // only draw the missing piece
367  angleBeg -= 90;
368  angleEnd += 90;
369  // avoid drawing more than 360 degrees
370  if (angleEnd - angleBeg > 360) {
371  angleBeg += 360;
372  }
373  if (angleEnd - angleBeg < -360) {
374  angleEnd += 360;
375  }
376  // draw the right way around
377  if (angleEnd > angleBeg) {
378  angleEnd -= 360;
379  }
380  drawFilledCircle(width + offset, cornerDetail, angleBeg, angleEnd);
382  }
383  }
384 }
385 
386 
387 void
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  int e = (int) geom.size() - 1;
394  for (int i = 0; i < e; i++) {
395  setColor(cols[i]);
396  drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
397  }
398  if (cornerDetail > 0) {
399  for (int i = 1; i < e; i++) {
401  setColor(cols[i]);
402  glTranslated(geom[i].x(), geom[i].y(), 0);
403  drawFilledCircle(width, cornerDetail);
404  glEnd();
406  }
407  }
408 }
409 
410 
411 void
413  const PositionVector& geom2,
414  const std::vector<double>& rots,
415  const std::vector<double>& lengths,
416  double width) {
417  int minS = (int) MIN4(rots.size(), lengths.size(), geom1.size(), geom2.size());
418  for (int i = 0; i < minS; i++) {
419  GLHelper::drawBoxLine(geom1[i], geom2[i], rots[i], lengths[i], width);
420  }
421 }
422 
423 
424 void
425 GLHelper::drawBoxLines(const PositionVector& geom, double width) {
426  int e = (int) geom.size() - 1;
427  for (int i = 0; i < e; i++) {
428  const Position& f = geom[i];
429  const Position& s = geom[i + 1];
430  drawBoxLine(f,
431  RAD2DEG(atan2((s.x() - f.x()), (f.y() - s.y()))),
432  f.distanceTo(s),
433  width);
434  }
435 }
436 
437 
438 void
439 GLHelper::drawLine(const Position& beg, double rot, double visLength) {
441  glTranslated(beg.x(), beg.y(), 0);
442  glRotated(rot, 0, 0, 1);
443  glBegin(GL_LINES);
444  glVertex2d(0, 0);
445  glVertex2d(0, -visLength);
446  glEnd();
448 #ifdef CHECK_ELEMENTCOUNTER
449  myVertexCounter += 2;
450 #endif
451 }
452 
453 
454 void
455 GLHelper::drawLine(const Position& beg1, const Position& beg2,
456  double rot, double visLength) {
458  glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
459  glRotated(rot, 0, 0, 1);
460  glBegin(GL_LINES);
461  glVertex2d(0, 0);
462  glVertex2d(0, -visLength);
463  glEnd();
465 #ifdef CHECK_ELEMENTCOUNTER
466  myVertexCounter += 2;
467 #endif
468 }
469 
470 
471 
472 void
474  glBegin(GL_LINES);
475  int e = (int) v.size() - 1;
476  for (int i = 0; i < e; ++i) {
477  glVertex2d(v[i].x(), v[i].y());
478  glVertex2d(v[i + 1].x(), v[i + 1].y());
479 #ifdef CHECK_ELEMENTCOUNTER
480  myVertexCounter += 2;
481 #endif
482  }
483  glEnd();
484 }
485 
486 
487 void
488 GLHelper::drawLine(const PositionVector& v, const std::vector<RGBColor>& cols) {
489  glBegin(GL_LINES);
490  int e = (int) v.size() - 1;
491  for (int i = 0; i < e; ++i) {
492  setColor(cols[i]);
493  glVertex2d(v[i].x(), v[i].y());
494  glVertex2d(v[i + 1].x(), v[i + 1].y());
495 #ifdef CHECK_ELEMENTCOUNTER
496  myVertexCounter += 2;
497 #endif
498  }
499  glEnd();
500 }
501 
502 
503 void
504 GLHelper::drawLine(const Position& beg, const Position& end) {
505  glBegin(GL_LINES);
506  glVertex2d(beg.x(), beg.y());
507  glVertex2d(end.x(), end.y());
508  glEnd();
509 #ifdef CHECK_ELEMENTCOUNTER
510  myVertexCounter += 2;
511 #endif
512 }
513 
514 
515 void
517  double beg, double end) {
518  // get current resolution level
519  switch (d) {
521  drawFilledCircle(radius, 32, beg, end);
522  break;
524  drawFilledCircle(radius, 16, beg, end);
525  break;
527  drawFilledCircle(radius, 8, beg, end);
528  break;
530  drawFilledCircleDetailled(d, radius);
531  break;
532  default:
533  // nothing to draw
534  break;
535  }
536 }
537 
538 
539 void
541  // get current resolution level
542  switch (d) {
544  drawFilledCircle(radius, 32);
545  break;
547  drawFilledCircle(radius, 16);
548  break;
550  drawFilledCircle(radius, 8);
551  break;
552  default:
553  // draw only a square
555  glBegin(GL_QUADS);
556  glVertex2d(-radius, radius);
557  glVertex2d(-radius, -radius);
558  glVertex2d(radius, -radius);
559  glVertex2d(radius, radius);
560  glEnd();
562 #ifdef CHECK_ELEMENTCOUNTER
563  myVertexCounter += 4;
564 #endif
565  break;
566  }
567 }
568 
569 void
570 GLHelper::drawFilledCircle(double const radius, int const steps) {
571  drawFilledCircle(radius, steps, 0, 360);
572 }
573 
574 
575 void
576 GLHelper::drawFilledCircle(double radius, int steps, double beg, double end) {
577  const double inc = (end - beg) / (double)steps;
578  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
579  std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
580 
581  for (int i = 0; i <= steps; ++i) {
582  const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
583  glBegin(GL_TRIANGLES);
584  glVertex2d(p1.first * radius, p1.second * radius);
585  glVertex2d(p2.first * radius, p2.second * radius);
586  glVertex2d(0, 0);
587  glEnd();
588  p1 = p2;
589 #ifdef CHECK_ELEMENTCOUNTER
590  myVertexCounter += 3;
591 #endif
592  }
593 }
594 
595 
596 void
597 GLHelper::drawOutlineCircle(double radius, double iRadius, int steps) {
598  drawOutlineCircle(radius, iRadius, steps, 0, 360);
599 }
600 
601 
602 void
603 GLHelper::drawOutlineCircle(double radius, double iRadius, int steps,
604  double beg, double end) {
605  const double inc = (end - beg) / (double)steps;
606  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
607  std::pair<double, double> p1 = getCircleCoords().at(angleLookup(beg));
608 
609  for (int i = 0; i <= steps; ++i) {
610  const std::pair<double, double>& p2 = getCircleCoords().at(angleLookup(beg + i * inc));
611  glBegin(GL_TRIANGLES);
612  glVertex2d(p1.first * radius, p1.second * radius);
613  glVertex2d(p2.first * radius, p2.second * radius);
614  glVertex2d(p2.first * iRadius, p2.second * iRadius);
615 
616  glVertex2d(p2.first * iRadius, p2.second * iRadius);
617  glVertex2d(p1.first * iRadius, p1.second * iRadius);
618  glVertex2d(p1.first * radius, p1.second * radius);
619 
620  glEnd();
621  p1 = p2;
622 #ifdef CHECK_ELEMENTCOUNTER
623  myVertexCounter += 6;
624 #endif
625  }
626 }
627 
628 
629 void
630 GLHelper::drawTriangleAtEnd(const Position& p1, const Position& p2, double tLength,
631  double tWidth, const double extraOffset) {
632  const double length = p1.distanceTo(p2);
633  if (length < tLength) {
634  tWidth *= length / tLength;
635  tLength = length;
636  }
637  Position rl(PositionVector::positionAtOffset(p1, p2, length - tLength));
639  glTranslated(rl.x(), rl.y(), 0);
640  glRotated(-GeomHelper::naviDegree(p1.angleTo2D(p2)), 0, 0, 1);
641  glTranslated(0, extraOffset, 0);
642  glBegin(GL_TRIANGLES);
643  glVertex2d(0, tLength);
644  glVertex2d(-tWidth, 0);
645  glVertex2d(+tWidth, 0);
646  glEnd();
648 #ifdef CHECK_ELEMENTCOUNTER
649  myVertexCounter += 3;
650 #endif
651 }
652 
653 
654 void
656  glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
657 }
658 
659 
660 RGBColor
662  GLdouble current[4];
663  glGetDoublev(GL_CURRENT_COLOR, current);
664  return RGBColor(static_cast<unsigned char>(current[0] * 255. + 0.5),
665  static_cast<unsigned char>(current[1] * 255. + 0.5),
666  static_cast<unsigned char>(current[2] * 255. + 0.5),
667  static_cast<unsigned char>(current[3] * 255. + 0.5));
668 }
669 
670 
671 void
674  myFont = nullptr;
675 }
676 
677 
678 void
679 GLHelper::setGL2PS(bool active) {
680  myGL2PSActive = active;
681 }
682 
683 
684 void
685 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  const RGBColor red(255, 0, 0, 255);
689  const RGBColor green(0, 255, 0, 255);
690  // declare geometry
691  PositionVector geom;
692  const double w = width / 2. - 0.1 * exaggeration;
693  const double h = length;
694  // set geometry
695  geom.push_back(Position(-w, +0, 0.));
696  geom.push_back(Position(+w, +0, 0.));
697  geom.push_back(Position(+w, +h, 0.));
698  geom.push_back(Position(-w, +h, 0.));
699  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
709  // translate
710  glTranslated(pos.x(), pos.y(), pos.z());
711  // rotate
712  glRotated(rotation, 0, 0, 1);
713  // set color
714  GLHelper::setColor(vehicle ? green : red);
715  // draw box lines
716  GLHelper::drawBoxLines(geom, 0.1 * exaggeration);
717  // pop matrix
719 }
720 
721 
722 bool
724  if (myFont == nullptr) {
726  if (myFont != nullptr) {
728  fonsSetFont(myFont, fontNormal);
729  fonsSetSize(myFont, (float)myFontSize);
730  }
731  }
732  return myFont != nullptr;
733 }
734 
735 
736 const std::vector<RGBColor>&
738  // check if more colors has to be added
739  while ((int)myDottedcontourColors.size() < size) {
742  } else {
744  }
745  }
746  return myDottedcontourColors;
747 }
748 
749 
750 double
751 GLHelper::getTextWidth(const std::string& text, double size) {
752  return size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
753 }
754 
755 
756 void
757 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  if (width <= 0) {
760  width = size;
761  }
762  if (!initFont()) {
763  return;
764  }
766  glAlphaFunc(GL_GREATER, 0.5);
767  glEnable(GL_ALPHA_TEST);
768 #ifdef HAVE_GL2PS
769  if (myGL2PSActive) {
770  glRasterPos3d(pos.x(), pos.y(), layer);
771  GLfloat color[] = {col.red() / 255.f, col.green() / 255.f, col.blue() / 255.f, col.alpha() / 255.f};
772  gl2psTextOptColor(text.c_str(), "Roboto", 10, align == 0 ? GL2PS_TEXT_C : align, (GLfloat) - angle, color);
774  return;
775  }
776 #endif
777  glTranslated(pos.x(), pos.y(), layer);
778  glScaled(width / myFontSize, size / myFontSize, 1.);
779  glRotated(-angle, 0, 0, 1);
780  fonsSetAlign(myFont, align == 0 ? FONS_ALIGN_CENTER | FONS_ALIGN_MIDDLE : align);
781  fonsSetColor(myFont, glfonsRGBA(col.red(), col.green(), col.blue(), col.alpha()));
782  fonsDrawText(myFont, 0., 0., text.c_str(), nullptr);
784 }
785 
786 
787 void
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  drawTextBox(text, pos, layer,
796  settings.scaledSize(scale),
797  settings.color,
798  settings.bgColor,
800  angle, 0, 0.2, align);
801 }
802 
803 
804 void
805 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  if (!initFont()) {
813  return;
814  };
815  if (bgColor.alpha() != 0) {
816  const double boxAngle = 90;
817  const double stringWidth = size / myFontSize * fonsTextBounds(myFont, 0, 0, text.c_str(), nullptr, nullptr);
818  const double borderWidth = size * relBorder;
819  const double boxHeight = size * (0.32 + 0.6 * relMargin);
820  const double boxWidth = stringWidth + size * relMargin;
822  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
823  glTranslated(pos.x(), pos.y(), layer);
824  glRotated(-angle, 0, 0, 1);
825  Position left(-boxWidth * 0.5, 0);
826  setColor(borderColor);
827  drawBoxLine(left, boxAngle, boxWidth, boxHeight);
828  left.add(borderWidth * 1.5, 0);
829  setColor(bgColor);
830  glTranslated(0, 0, 0.01);
831  drawBoxLine(left, boxAngle, boxWidth - 3 * borderWidth, boxHeight - 2 * borderWidth);
833  }
834  drawText(text, pos, layer + 0.02, size, txtColor, angle, align);
835 }
836 
837 
838 void
839 GLHelper::drawTextAtEnd(const std::string& text, const PositionVector& shape, double x,
840  const GUIVisualizationTextSettings& settings, const double scale) {
842  const Position& end = shape.back();
843  const Position& f = shape[-2];
844  const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
845  glTranslated(end.x(), end.y(), 0);
846  glRotated(rot, 0, 0, 1);
847  drawTextBox(text, Position(x, 0.26), 0,
848  settings.scaledSize(scale, 0.01),
849  settings.color,
850  settings.bgColor,
852  180, 0, 0.2);
854 }
855 
856 
857 void
858 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) {
862  // draw on top of of the white area between the rails
863  glTranslated(0, 0, 0.1);
864  int e = (int) geom.size() - 1;
865  for (int i = 0; i < e; ++i) {
867  glTranslated(geom[i].x(), geom[i].y(), 0.0);
868  glRotated(rots[i], 0, 0, 1);
869  // draw crossing depending of detail
870  if (!lessDetail) {
871  for (double t = 0; t < lengths[i]; t += spacing) {
872  glBegin(GL_QUADS);
873  glVertex2d(-halfWidth - offset, -t);
874  glVertex2d(-halfWidth - offset, -t - length);
875  glVertex2d(halfWidth - offset, -t - length);
876  glVertex2d(halfWidth - offset, -t);
877  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  glBegin(GL_QUADS);
885  glVertex2d(-halfWidth - offset, 0);
886  glVertex2d(-halfWidth - offset, -lengths.back());
887  glVertex2d(halfWidth - offset, -lengths.back());
888  glVertex2d(halfWidth - offset, 0);
889  glEnd();
890 #ifdef CHECK_ELEMENTCOUNTER
891  myVertexCounter += 4;
892 #endif
893  }
894  // pop three draw matrix
896  }
898 }
899 
900 void
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  double mw = (halfWidth + SUMO_const_laneMarkWidth * (cl ? 0.6 : 0.2)) * scale;
908  double mw2 = (halfWidth - SUMO_const_laneMarkWidth * (cr ? 0.6 : 0.2)) * scale;
909  if (cl || cr) {
910  if (lefthand) {
911  mw *= -1;
912  mw2 *= -1;
913  }
914  int e = (int) geom.size() - 1;
915  double offset = 0;
916  for (int i = 0; i < e; ++i) {
918  glTranslated(geom[i].x(), geom[i].y(), 2.1);
919  glRotated(rots[i], 0, 0, 1);
920  double t;
921  for (t = offset; t < lengths[i]; t += spacing) {
922  const double length = MIN2((double)maxLength, lengths[i] - t);
923  glBegin(GL_QUADS);
924  glVertex2d(-mw, -t);
925  glVertex2d(-mw, -t - length);
926  glVertex2d(-mw2, -t - length);
927  glVertex2d(-mw2, -t);
928  glEnd();
929 #ifdef CHECK_ELEMENTCOUNTER
930  myVertexCounter += 4;
931 #endif
932  if (!cl || !cr) {
933  // draw inverse marking between asymmetrical lane markings
934  const double length2 = MIN2((double)6, lengths[i] - t);
935  glBegin(GL_QUADS);
936  glVertex2d(-halfWidth + 0.02, -t - length2);
937  glVertex2d(-halfWidth + 0.02, -t - length);
938  glVertex2d(-halfWidth - 0.02, -t - length);
939  glVertex2d(-halfWidth - 0.02, -t - length2);
940  glEnd();
941 #ifdef CHECK_ELEMENTCOUNTER
942  myVertexCounter += 4;
943 #endif
944  }
945  }
946  offset = t - lengths[i] - spacing;
948  }
949  }
950 }
951 
952 
953 void
954 GLHelper::debugVertices(const PositionVector& shape, const GUIVisualizationTextSettings& settings, double scale, double layer) {
955  RGBColor color = RGBColor::randomHue();
956  for (int i = 0; i < (int)shape.size(); ++i) {
957  drawTextBox(toString(i), shape[i], layer,
958  settings.scaledSize(scale),
959  color,
960  settings.bgColor,
962  0, 0, 0.2);
963  }
964 }
965 
966 
967 void
969  if (s.drawBoundaries) {
972  // draw on top
973  glTranslated(0, 0, 1024);
974  drawLine(Position(b.xmin(), b.ymax()), Position(b.xmax(), b.ymax()));
975  drawLine(Position(b.xmax(), b.ymax()), Position(b.xmax(), b.ymin()));
976  drawLine(Position(b.xmax(), b.ymin()), Position(b.xmin(), b.ymin()));
977  drawLine(Position(b.xmin(), b.ymin()), Position(b.xmin(), b.ymax()));
979  }
980 }
981 
982 
983 /****************************************************************************/
void CALLBACK combCallback(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **dataOut)
Definition: GLHelper.cpp:71
#define CIRCLE_RESOLUTION
Definition: GLHelper.cpp:49
#define CALLBACK
Definition: GLHelper.cpp:54
#define DEG2RAD(x)
Definition: GeomHelper.h:35
#define RAD2DEG(x)
Definition: GeomHelper.h:36
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:295
static unsigned int data_font_Roboto_Medium_ttf_len
Definition: Roboto.h:22
static unsigned char data_font_Roboto_Medium_ttf[]
Definition: Roboto.h:24
T MIN4(T a, T b, T c, T d)
Definition: StdDefs.h:103
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:30
T MIN2(T a, T b)
Definition: StdDefs.h:76
const double SUMO_const_laneMarkWidth
Definition: StdDefs.h:51
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:130
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:118
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:136
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:124
static void drawFilledPoly(const PositionVector &v, bool close)
Draws a filled polygon described by the list of points.
Definition: GLHelper.cpp:203
static void drawFilledPolyTesselated(const PositionVector &v, bool close)
Draws a filled polygon described by the list of points.
Definition: GLHelper.cpp:228
static void drawTextBox(const std::string &text, const Position &pos, const double layer, const double size, const RGBColor &txtColor=RGBColor::BLACK, const RGBColor &bgColor=RGBColor::WHITE, const RGBColor &borderColor=RGBColor::BLACK, const double angle=0, const double relBorder=0.05, const double relMargin=0.5, const int align=0)
draw Text box with given parameters
Definition: GLHelper.cpp:805
static void resetVertexCounter()
reset vertex counter
Definition: GLHelper.cpp:175
static std::vector< std::pair< double, double > > myCircleCoords
Storage for precomputed sin/cos-values describing a circle.
Definition: GLHelper.h:436
static void drawLine(const Position &beg, double rot, double visLength)
Draws a thin line.
Definition: GLHelper.cpp:439
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition: GLHelper.cpp:655
static void drawOutlineCircle(double radius, double iRadius, int steps=8)
Draws an unfilled circle around (0,0)
Definition: GLHelper.cpp:597
static struct FONScontext * myFont
Font context.
Definition: GLHelper.h:439
static void drawTriangleAtEnd(const Position &p1, const Position &p2, double tLength, double tWidth, const double extraOffset=0)
Draws a triangle at the end of the given line.
Definition: GLHelper.cpp:630
static void drawTextAtEnd(const std::string &text, const PositionVector &shape, double x, const GUIVisualizationTextSettings &settings, const double scale)
draw text and the end of shape
Definition: GLHelper.cpp:839
static void resetFont()
to be called when the font context is invalidated
Definition: GLHelper.cpp:672
static void pushName(unsigned int name)
push Name
Definition: GLHelper.cpp:139
static void checkCounterMatrix()
check counter matrix (for debug purposes)
Definition: GLHelper.cpp:181
static void drawFilledCircle(const double widradiusth, const int steps=8)
Draws a filled circle around (0,0)
Definition: GLHelper.cpp:570
static const std::vector< RGBColor > & getDottedcontourColors(const int size)
get dotted contour colors (black and white). Vector will be automatically increased if current size i...
Definition: GLHelper.cpp:737
static std::vector< RGBColor > myDottedcontourColors
static vector with a list of alternated black/white colors (used for contours)
Definition: GLHelper.h:446
static int angleLookup(double angleDeg)
normalize angle for lookup in myCircleCoords
Definition: GLHelper.cpp:105
static double getTextWidth(const std::string &text, double size)
get required width of text
Definition: GLHelper.cpp:751
static int myMatrixCounter
matrix counter (for debug purposes)
Definition: GLHelper.h:424
static void popMatrix()
pop matrix
Definition: GLHelper.cpp:130
static void drawBoxLines(const PositionVector &geom, const std::vector< double > &rots, const std::vector< double > &lengths, double width, int cornerDetail=0, double offset=0)
Draws thick lines.
Definition: GLHelper.cpp:347
static int myMatrixCounterDebug
matrix counter (for debug purposes)
Definition: GLHelper.h:430
static void drawBoundary(const GUIVisualizationSettings &s, const Boundary &b)
Draw a boundary (used for debugging)
Definition: GLHelper.cpp:968
static RGBColor getColor()
gets the gl-color
Definition: GLHelper.cpp:661
static int getMatrixCounter()
get matrix counter
Definition: GLHelper.cpp:157
static void drawRectangle(const Position &center, const double width, const double height)
Draws a rectangle line.
Definition: GLHelper.cpp:277
static const std::vector< std::pair< double, double > > & getCircleCoords()
Storage for precomputed sin/cos-values describing a circle.
Definition: GLHelper.cpp:91
static void drawBoxLine(const Position &beg, double rot, double visLength, double width, double offset=0)
Draws a thick line.
Definition: GLHelper.cpp:295
static void checkCounterName()
check counter name (for debug purposes)
Definition: GLHelper.cpp:192
static void debugVertices(const PositionVector &shape, const GUIVisualizationTextSettings &settings, double scale, double layer=1024)
draw vertex numbers for the given shape (in a random color)
Definition: GLHelper.cpp:954
static void drawFilledCircleDetailled(const GUIVisualizationSettings::Detail d, const double radius)
Draws a filled circle around (0,0) depending of level of detail.
Definition: GLHelper.cpp:540
static void popName()
pop Name
Definition: GLHelper.cpp:148
static bool rightTurn(double angle1, double angle2)
whether the road makes a right turn (or goes straight)
Definition: GLHelper.cpp:334
static int myNameCounter
name counter
Definition: GLHelper.h:433
static void pushMatrix()
push matrix
Definition: GLHelper.cpp:117
static void setGL2PS(bool active=true)
set GL2PS
Definition: GLHelper.cpp:679
static int getVertexCounter()
get vertex counter
Definition: GLHelper.cpp:169
static void drawInverseMarkings(const PositionVector &geom, const std::vector< double > &rots, const std::vector< double > &lengths, double maxLength, double spacing, double halfWidth, bool cl, bool cr, bool lefthand, double scale)
@bried draw the space between markings (in road color)
Definition: GLHelper.cpp:901
static bool myGL2PSActive
whether we are currently rendering for gl2ps
Definition: GLHelper.h:443
static void drawText(const std::string &text, const Position &pos, const double layer, const double size, const RGBColor &col=RGBColor::BLACK, const double angle=0, const int align=0, double width=-1)
Definition: GLHelper.cpp:757
static void drawSpaceOccupancies(const double exaggeration, const Position &pos, const double rotation, const double width, const double length, const bool vehicle)
draw
Definition: GLHelper.cpp:685
static bool initFont()
init myFont
Definition: GLHelper.cpp:723
static double myFontSize
Definition: GLHelper.h:440
static int myVertexCounter
matrix counter (for debug purposes)
Definition: GLHelper.h:427
static void drawTextSettings(const GUIVisualizationTextSettings &settings, const std::string &text, const Position &pos, const double scale, const double angle=0, const double layer=2048, const int align=0)
Definition: GLHelper.cpp:788
static void drawCrossTies(const PositionVector &geom, const std::vector< double > &rots, const std::vector< double > &lengths, double length, double spacing, double halfWidth, double offset, bool lessDetail)
draw crossties for railroads or pedestrian crossings
Definition: GLHelper.cpp:858
static void resetMatrixCounter()
reset matrix counter
Definition: GLHelper.cpp:163
Stores the information about how to visualize structures.
bool drawBoundaries
enable or disable draw boundaries
static double naviDegree(const double angle)
Definition: GeomHelper.cpp:191
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:261
double x() const
Returns the x-position.
Definition: Position.h:55
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:132
double z() const
Returns the z-position.
Definition: Position.h:65
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position (in radians bet...
Definition: Position.h:281
double y() const
Returns the y-position.
Definition: Position.h:60
A list of positions.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
static const RGBColor WHITE
Definition: RGBColor.h:192
unsigned char red() const
Returns the red-amount of the color.
Definition: RGBColor.cpp:74
unsigned char alpha() const
Returns the alpha-amount of the color.
Definition: RGBColor.cpp:92
static const RGBColor INVISIBLE
Definition: RGBColor.h:195
unsigned char green() const
Returns the green-amount of the color.
Definition: RGBColor.cpp:80
unsigned char blue() const
Returns the blue-amount of the color.
Definition: RGBColor.cpp:86
static const RGBColor BLACK
Definition: RGBColor.h:193
static const RGBColor MAGENTA
Definition: RGBColor.h:190
static RGBColor randomHue(double s=1, double v=1)
Return color with random hue.
Definition: RGBColor.cpp:403
@ FONS_ZERO_BOTTOMLEFT
Definition: fontstash.h:37
FONS_DEF void fonsSetSize(FONScontext *s, float size)
FONS_DEF float fonsDrawText(FONScontext *s, float x, float y, const char *string, const char *end)
FONS_DEF float fonsTextBounds(FONScontext *s, float x, float y, const char *string, const char *end, float *bounds)
@ FONS_ALIGN_MIDDLE
Definition: fontstash.h:47
@ FONS_ALIGN_CENTER
Definition: fontstash.h:43
FONS_DEF void fonsSetColor(FONScontext *s, unsigned int color)
FONS_DEF void fonsSetAlign(FONScontext *s, int align)
FONS_DEF int fonsAddFontMem(FONScontext *s, const char *name, unsigned char *data, int ndata, int freeData)
FONS_DEF void fonsSetFont(FONScontext *s, int font)
struct FONScontext FONScontext
Definition: fontstash.h:95
unsigned int glfonsRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
void glfonsDelete(FONScontext *ctx)
FONScontext * glfonsCreate(int width, int height, int flags)
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:21884
RGBColor bgColor
background text color
double scaledSize(double scale, double constFactor=0.1) const
get scale size