SUMO - Simulation of Urban MObility
GLHelper.cpp
Go to the documentation of this file.
1 /****************************************************************************/
9 // Some methods which help to draw certain geometrical objects in openGL
10 /****************************************************************************/
11 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
12 // Copyright (C) 2001-2017 DLR (http://www.dlr.de/) and contributors
13 /****************************************************************************/
14 //
15 // This file is part of SUMO.
16 // SUMO is free software: you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation, either version 3 of the License, or
19 // (at your option) any later version.
20 //
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <cassert>
34 #include <utils/geom/GeomHelper.h>
35 #include <utils/common/StdDefs.h>
37 #include <utils/common/ToString.h>
40 #include "GLHelper.h"
41 
42 
43 #define CIRCLE_RESOLUTION (double)10 // inverse in degrees
44 
45 // ===========================================================================
46 // static member definitions
47 // ===========================================================================
48 std::vector<std::pair<double, double> > GLHelper::myCircleCoords;
49 
50 
51 void APIENTRY combCallback(GLdouble coords[3],
52  GLdouble* vertex_data[4],
53  GLfloat weight[4], GLdouble** dataOut) {
54  UNUSED_PARAMETER(weight);
55  UNUSED_PARAMETER(*vertex_data);
56  GLdouble* vertex;
57 
58  vertex = (GLdouble*)malloc(7 * sizeof(GLdouble));
59 
60  vertex[0] = coords[0];
61  vertex[1] = coords[1];
62  vertex[2] = coords[2];
63  *dataOut = vertex;
64 }
65 
66 // ===========================================================================
67 // method definitions
68 // ===========================================================================
69 
70 
71 void
73  if (v.size() == 0) {
74  return;
75  }
76  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
77  glBegin(GL_POLYGON);
78  for (PositionVector::const_iterator i = v.begin(); i != v.end(); i++) {
79  const Position& p = *i;
80  glVertex2d(p.x(), p.y());
81  }
82  if (close) {
83  const Position& p = *(v.begin());
84  glVertex2d(p.x(), p.y());
85  }
86  glEnd();
87 }
88 
89 
90 void
92  if (v.size() == 0) {
93  return;
94  }
95  GLUtesselator* tobj = gluNewTess();
96  gluTessCallback(tobj, GLU_TESS_VERTEX, (GLvoid(APIENTRY*)()) &glVertex3dv);
97  gluTessCallback(tobj, GLU_TESS_BEGIN, (GLvoid(APIENTRY*)()) &glBegin);
98  gluTessCallback(tobj, GLU_TESS_END, (GLvoid(APIENTRY*)()) &glEnd);
99  gluTessCallback(tobj, GLU_TESS_COMBINE, (GLvoid(APIENTRY*)()) &combCallback);
100  gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
101  gluTessBeginPolygon(tobj, NULL);
102  gluTessBeginContour(tobj);
103  double* points = new double[(v.size() + int(close)) * 3];
104 
105  for (int i = 0; i != (int)v.size(); ++i) {
106  points[3 * i] = v[i].x();
107  points[3 * i + 1] = v[i].y();
108  points[3 * i + 2] = 0;
109  gluTessVertex(tobj, points + 3 * i, points + 3 * i);
110  }
111  if (close) {
112  const int i = (int)v.size();
113  points[3 * i] = v[0].x();
114  points[3 * i + 1] = v[0].y();
115  points[3 * i + 2] = 0;
116  gluTessVertex(tobj, points + 3 * i, points + 3 * i);
117  }
118  gluTessEndContour(tobj);
119  gluTessEndPolygon(tobj);
120  gluDeleteTess(tobj);
121  delete[] points;
122 }
123 
124 
125 void
126 GLHelper::drawBoxLine(const Position& beg, double rot, double visLength,
127  double width, double offset) {
128  glPushMatrix();
129  glTranslated(beg.x(), beg.y(), 0);
130  glRotated(rot, 0, 0, 1);
131  glBegin(GL_QUADS);
132  glVertex2d(-width - offset, 0);
133  glVertex2d(-width - offset, -visLength);
134  glVertex2d(width - offset, -visLength);
135  glVertex2d(width - offset, 0);
136  glEnd();
137  glPopMatrix();
138 }
139 
140 
141 void
142 GLHelper::drawBoxLine(const Position& beg1, const Position& beg2,
143  double rot, double visLength,
144  double width) {
145  glPushMatrix();
146  glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
147  glRotated(rot, 0, 0, 1);
148  glBegin(GL_QUADS);
149  glVertex2d(-width, 0);
150  glVertex2d(-width, -visLength);
151  glVertex2d(width, -visLength);
152  glVertex2d(width, 0);
153  glEnd();
154  glPopMatrix();
155 }
156 
157 
158 bool
159 GLHelper::rightTurn(double angle1, double angle2) {
160  double delta = angle2 - angle1;
161  while (delta > 180) {
162  delta -= 360;
163  }
164  while (delta < -180) {
165  delta += 360;
166  }
167  return delta <= 0;
168 }
169 
170 
171 void
173  const std::vector<double>& rots,
174  const std::vector<double>& lengths,
175  double width, int cornerDetail, double offset) {
176  // draw the lane
177  int e = (int) geom.size() - 1;
178  for (int i = 0; i < e; i++) {
179  drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
180  }
181  // draw the corner details
182  if (cornerDetail > 0) {
183  for (int i = 1; i < e; i++) {
184  glPushMatrix();
185  glTranslated(geom[i].x(), geom[i].y(), 0.1);
186  if (rightTurn(rots[i - 1], rots[i])) {
187  // inside corner
188  drawFilledCircle(MIN2(lengths[i], width - offset), cornerDetail);
189  } else {
190  // outside corner, make sure to only draw a segment of the circle
191  double angleBeg = -rots[i - 1];
192  double angleEnd = 180 - rots[i];
193  // avoid drawing more than 360 degrees
194  if (angleEnd - angleBeg > 360) {
195  angleBeg += 360;
196  }
197  if (angleEnd - angleBeg < -360) {
198  angleEnd += 360;
199  }
200  // for a left tur, draw the right way around
201  if (angleEnd > angleBeg) {
202  angleEnd -= 360;
203  }
204  drawFilledCircle(MIN2(lengths[i], width + offset), cornerDetail, angleBeg, angleEnd);
205  }
206  glEnd();
207  glPopMatrix();
208  }
209  }
210 }
211 
212 
213 void
215  const std::vector<double>& rots,
216  const std::vector<double>& lengths,
217  const std::vector<RGBColor>& cols,
218  double width, int cornerDetail, double offset) {
219  int e = (int) geom.size() - 1;
220  for (int i = 0; i < e; i++) {
221  setColor(cols[i]);
222  drawBoxLine(geom[i], rots[i], lengths[i], width, offset);
223  }
224  if (cornerDetail > 0) {
225  for (int i = 1; i < e; i++) {
226  glPushMatrix();
227  setColor(cols[i]);
228  glTranslated(geom[i].x(), geom[i].y(), 0);
229  drawFilledCircle(width, cornerDetail);
230  glEnd();
231  glPopMatrix();
232  }
233  }
234 }
235 
236 
237 void
239  const PositionVector& geom2,
240  const std::vector<double>& rots,
241  const std::vector<double>& lengths,
242  double width) {
243  int minS = (int) MIN4(rots.size(), lengths.size(), geom1.size(), geom2.size());
244  for (int i = 0; i < minS; i++) {
245  GLHelper::drawBoxLine(geom1[i], geom2[i], rots[i], lengths[i], width);
246  }
247 }
248 
249 
250 void
251 GLHelper::drawBoxLines(const PositionVector& geom, double width) {
252  int e = (int) geom.size() - 1;
253  for (int i = 0; i < e; i++) {
254  const Position& f = geom[i];
255  const Position& s = geom[i + 1];
256  drawBoxLine(f,
257  RAD2DEG(atan2((s.x() - f.x()), (f.y() - s.y()))),
258  f.distanceTo(s),
259  width);
260  }
261 }
262 
263 
264 void
265 GLHelper::drawLine(const Position& beg, double rot, double visLength) {
266  glPushMatrix();
267  glTranslated(beg.x(), beg.y(), 0);
268  glRotated(rot, 0, 0, 1);
269  glBegin(GL_LINES);
270  glVertex2d(0, 0);
271  glVertex2d(0, -visLength);
272  glEnd();
273  glPopMatrix();
274 }
275 
276 
277 void
278 GLHelper::drawLine(const Position& beg1, const Position& beg2,
279  double rot, double visLength) {
280  glPushMatrix();
281  glTranslated((beg2.x() + beg1.x())*.5, (beg2.y() + beg1.y())*.5, 0);
282  glRotated(rot, 0, 0, 1);
283  glBegin(GL_LINES);
284  glVertex2d(0, 0);
285  glVertex2d(0, -visLength);
286  glEnd();
287  glPopMatrix();
288 }
289 
290 
291 
292 void
294  glBegin(GL_LINES);
295  int e = (int) v.size() - 1;
296  for (int i = 0; i < e; ++i) {
297  glVertex2d(v[i].x(), v[i].y());
298  glVertex2d(v[i + 1].x(), v[i + 1].y());
299  }
300  glEnd();
301 }
302 
303 
304 void
305 GLHelper::drawLine(const PositionVector& v, const std::vector<RGBColor>& cols) {
306  glBegin(GL_LINES);
307  int e = (int) v.size() - 1;
308  for (int i = 0; i < e; ++i) {
309  setColor(cols[i]);
310  glVertex2d(v[i].x(), v[i].y());
311  glVertex2d(v[i + 1].x(), v[i + 1].y());
312  }
313  glEnd();
314 }
315 
316 
317 
318 void
319 GLHelper::drawLine(const Position& beg, const Position& end) {
320  glBegin(GL_LINES);
321  glVertex2d(beg.x(), beg.y());
322  glVertex2d(end.x(), end.y());
323  glEnd();
324 }
325 
326 
327 int
328 GLHelper::angleLookup(double angleDeg) {
329  const int numCoords = (int)myCircleCoords.size() - 1;
330  int index = ((int)(floor(angleDeg * CIRCLE_RESOLUTION + 0.5))) % numCoords;
331  if (index < 0) {
332  index += numCoords;
333  }
334  assert(index >= 0);
335  return (int)index;
336 }
337 
338 
339 void
340 GLHelper::drawFilledCircle(double width, int steps) {
341  drawFilledCircle(width, steps, 0, 360);
342 }
343 
344 
345 void
346 GLHelper::drawFilledCircle(double width, int steps, double beg, double end) {
347  if (myCircleCoords.size() == 0) {
348  for (int i = 0; i <= (int)(360 * CIRCLE_RESOLUTION); ++i) {
349  const double x = (double) sin(DEG2RAD(i / CIRCLE_RESOLUTION));
350  const double y = (double) cos(DEG2RAD(i / CIRCLE_RESOLUTION));
351  myCircleCoords.push_back(std::pair<double, double>(x, y));
352  }
353  }
354  const double inc = (end - beg) / (double)steps;
355  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
356  std::pair<double, double> p1 = myCircleCoords[angleLookup(beg)];
357 
358  for (int i = 0; i <= steps; ++i) {
359  const std::pair<double, double>& p2 = myCircleCoords[angleLookup(beg + i * inc)];
360  glBegin(GL_TRIANGLES);
361  glVertex2d(p1.first * width, p1.second * width);
362  glVertex2d(p2.first * width, p2.second * width);
363  glVertex2d(0, 0);
364  glEnd();
365  p1 = p2;
366  }
367 }
368 
369 
370 void
371 GLHelper::drawOutlineCircle(double width, double iwidth, int steps) {
372  drawOutlineCircle(width, iwidth, steps, 0, 360);
373 }
374 
375 
376 void
377 GLHelper::drawOutlineCircle(double width, double iwidth, int steps,
378  double beg, double end) {
379  if (myCircleCoords.size() == 0) {
380  for (int i = 0; i < 360; i += 10) {
381  double x = (double) sin(DEG2RAD(i));
382  double y = (double) cos(DEG2RAD(i));
383  myCircleCoords.push_back(std::pair<double, double>(x, y));
384  }
385  }
386  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
387  std::pair<double, double> p1 =
388  beg == 0 ? myCircleCoords[0] : myCircleCoords[((int) beg / 10) % 36];
389  for (int i = (int)(beg / 10); i < steps && (36.0 / (double) steps * (double) i) * 10 < end; i++) {
390  const std::pair<double, double>& p2 =
391  myCircleCoords[(int)(36.0 / (double) steps * (double) i)];
392  glBegin(GL_TRIANGLES);
393  glVertex2d(p1.first * width, p1.second * width);
394  glVertex2d(p2.first * width, p2.second * width);
395  glVertex2d(p2.first * iwidth, p2.second * iwidth);
396 
397  glVertex2d(p2.first * iwidth, p2.second * iwidth);
398  glVertex2d(p1.first * iwidth, p1.second * iwidth);
399  glVertex2d(p1.first * width, p1.second * width);
400  glEnd();
401  p1 = p2;
402  }
403  const std::pair<double, double>& p2 =
404  end == 360 ? myCircleCoords[0] : myCircleCoords[((int) end / 10) % 36];
405  glBegin(GL_TRIANGLES);
406  glVertex2d(p1.first * width, p1.second * width);
407  glVertex2d(p2.first * width, p2.second * width);
408  glVertex2d(p2.first * iwidth, p2.second * iwidth);
409 
410  glVertex2d(p2.first * iwidth, p2.second * iwidth);
411  glVertex2d(p1.first * iwidth, p1.second * iwidth);
412  glVertex2d(p1.first * width, p1.second * width);
413  glEnd();
414 }
415 
416 
417 void
419  double tLength, double tWidth) {
420  const double length = p1.distanceTo(p2);
421  if (length < tLength) {
422  tWidth *= length / tLength;
423  tLength = length;
424  }
425  Position rl(PositionVector::positionAtOffset(p1, p2, length - tLength));
426  glPushMatrix();
427  glTranslated(rl.x(), rl.y(), 0);
428  glRotated(-GeomHelper::naviDegree(p1.angleTo2D(p2)), 0, 0, 1);
429  glBegin(GL_TRIANGLES);
430  glVertex2d(0, tLength);
431  glVertex2d(-tWidth, 0);
432  glVertex2d(+tWidth, 0);
433  glEnd();
434  glPopMatrix();
435 }
436 
437 
438 void
440  glColor4ub(c.red(), c.green(), c.blue(), c.alpha());
441 }
442 
443 
444 RGBColor
446  GLdouble current[4];
447  glGetDoublev(GL_CURRENT_COLOR, current);
448  return RGBColor(static_cast<unsigned char>(current[0] * 255. + 0.5),
449  static_cast<unsigned char>(current[1] * 255. + 0.5),
450  static_cast<unsigned char>(current[2] * 255. + 0.5),
451  static_cast<unsigned char>(current[3] * 255. + 0.5));
452 }
453 
454 
455 void
456 GLHelper::drawText(const std::string& text, const Position& pos,
457  const double layer, const double size,
458  const RGBColor& col, const double angle) {
459  glPushMatrix();
460  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
461  setColor(col);
462  glTranslated(pos.x(), pos.y(), layer);
463  pfSetPosition(0, 0);
464  pfSetScale(size);
465  double w = pfdkGetStringWidth(text.c_str());
466  glRotated(180, 1, 0, 0);
467  glRotated(angle, 0, 0, 1);
468  glTranslated(-w / 2., size / 4, 0);
469  pfDrawString(text.c_str());
470  glPopMatrix();
471 }
472 
473 void
474 GLHelper::drawTextBox(const std::string& text, const Position& pos,
475  const double layer, const double size,
476  const RGBColor& txtColor, const RGBColor& bgColor, const RGBColor& borderColor,
477  const double angle) {
478  double boxAngle = angle + 90;
479  if (boxAngle > 360) {
480  boxAngle -= 360;
481  }
482  pfSetScale(size);
483  const double stringWidth = pfdkGetStringWidth(text.c_str());
484  const double borderWidth = size / 20;
485  const double boxHeight = size * 0.8;
486  const double boxWidth = stringWidth + size / 2;
487  glPushMatrix();
488  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
489  glTranslated(0, 0, layer);
490  setColor(borderColor);
491  Position left = pos;
492  left.sub(boxWidth / 2, -boxHeight / 2.7);
493  drawBoxLine(left, boxAngle, boxWidth, boxHeight);
494  left.add(borderWidth * 1.5, 0);
495  setColor(bgColor);
496  glTranslated(0, 0, 0.01);
497  drawBoxLine(left, boxAngle, boxWidth - 3 * borderWidth, boxHeight - 2 * borderWidth);
498  // actually we should be able to use drawText here. however, there's
499  // something about the constant 0.4 offset which causes trouble
500  //drawText(text, pos, layer+0.02, size, txtColor, angle);
501  setColor(txtColor);
502  glTranslated(pos.x(), pos.y(), 0.01);
503  pfSetPosition(0, 0);
504  pfSetScale(size);
505  glRotated(180, 1, 0, 0);
506  glRotated(angle, 0, 0, 1);
507  glTranslated(-stringWidth / 2., 0, 0);
508  pfDrawString(text.c_str());
509  glPopMatrix();
510 }
511 
512 
513 void
514 GLHelper::drawTextAtEnd(const std::string& text, const PositionVector& shape, double x, double size, RGBColor color) {
515  glPushMatrix();
516  const Position& end = shape.back();
517  const Position& f = shape[-2];
518  const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
519  glTranslated(end.x(), end.y(), 0);
520  glRotated(rot, 0, 0, 1);
521  GLHelper::drawText(text, Position(x, 0.26), 0, .6 * size / 50, color, 180);
522  glPopMatrix();
523 }
524 
525 
526 
527 void
528 GLHelper::debugVertices(const PositionVector& shape, double size, double layer) {
529  RGBColor color = RGBColor::fromHSV(RandHelper::rand(360), 1, 1);
530  for (int i = 0; i < (int)shape.size(); ++i) {
531  GLHelper::drawText(toString(i), shape[i], layer, size, color, 0);
532  }
533 }
534 /****************************************************************************/
535 
int pfDrawString(const char *c)
Definition: polyfonts.c:1074
static std::vector< std::pair< double, double > > myCircleCoords
Storage for precomputed sin/cos-values describing a circle.
Definition: GLHelper.h:309
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:172
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:133
void pfSetScale(double s)
Definition: polyfonts.c:465
static void drawTextAtEnd(const std::string &text, const PositionVector &shape, double x, double size, RGBColor color)
draw text and the end of shape
Definition: GLHelper.cpp:514
static RGBColor fromHSV(double h, double s, double v)
Converts the given hsv-triplet to rgb.
Definition: RGBColor.cpp:290
unsigned char alpha() const
Returns the alpha-amount of the color.
Definition: RGBColor.h:99
T MIN4(T a, T b, T c, T d)
Definition: StdDefs.h:91
static void debugVertices(const PositionVector &shape, double size, double layer=256)
draw vertex numbers for the given shape (in a random color)
Definition: GLHelper.cpp:528
double y() const
Returns the y-position.
Definition: Position.h:68
double x() const
Returns the x-position.
Definition: Position.h:63
double angleTo2D(const Position &other) const
returns the angle in the plane of the vector pointing from here to the other position ...
Definition: Position.h:260
static void drawFilledPoly(const PositionVector &v, bool close)
Draws a filled polygon described by the list of points.
Definition: GLHelper.cpp:72
unsigned char blue() const
Returns the blue-amount of the color.
Definition: RGBColor.h:91
void pfSetPosition(double x, double y)
Definition: polyfonts.c:480
#define RAD2DEG(x)
Definition: GeomHelper.h:46
static void drawFilledCircle(double width, int steps=8)
Draws a filled circle around (0,0)
Definition: GLHelper.cpp:340
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:38
static void drawFilledPolyTesselated(const PositionVector &v, bool close)
Draws a filled polygon described by the list of points.
Definition: GLHelper.cpp:91
static double naviDegree(const double angle)
Definition: GeomHelper.cpp:187
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:56
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition: GLHelper.cpp:439
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
A list of positions.
static int angleLookup(double angleDeg)
normalize angle for lookup in myCircleCoords
Definition: GLHelper.cpp:328
static double rand()
Returns a random real number in [0, 1)
Definition: RandHelper.h:62
T MIN2(T a, T b)
Definition: StdDefs.h:64
static void drawOutlineCircle(double width, double iwidth, int steps=8)
Draws an unfilled circle around (0,0)
Definition: GLHelper.cpp:371
static void drawLine(const Position &beg, double rot, double visLength)
Draws a thin line.
Definition: GLHelper.cpp:265
#define DEG2RAD(x)
Definition: GeomHelper.h:45
double pfdkGetStringWidth(const char *c)
Definition: polyfonts.c:1113
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)
draw Text box with given parameters
Definition: GLHelper.cpp:474
void APIENTRY combCallback(GLdouble coords[3], GLdouble *vertex_data[4], GLfloat weight[4], GLdouble **dataOut)
Definition: GLHelper.cpp:51
unsigned char green() const
Returns the green-amount of the color.
Definition: RGBColor.h:83
static bool rightTurn(double angle1, double angle2)
whether the road makes a right turn (or goes straight)
Definition: GLHelper.cpp:159
#define CIRCLE_RESOLUTION
Definition: GLHelper.cpp:43
unsigned char red() const
Returns the red-amount of the color.
Definition: RGBColor.h:75
static void drawTriangleAtEnd(const Position &p1, const Position &p2, double tLength, double tWidth)
Draws a triangle at the end of the given line.
Definition: GLHelper.cpp:418
double distanceTo(const Position &p2) const
returns the euclidean distance in 3 dimension
Definition: Position.h:240
static void drawBoxLine(const Position &beg, double rot, double visLength, double width, double offset=0)
Draws a thick line.
Definition: GLHelper.cpp:126
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)
draw Text with given parameters
Definition: GLHelper.cpp:456
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
static RGBColor getColor()
gets the gl-color
Definition: GLHelper.cpp:445
void sub(double dx, double dy)
Substracts the given position from this one.
Definition: Position.h:153