Eclipse SUMO - Simulation of Urban MObility
GUISUMOAbstractView.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2020 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 /****************************************************************************/
22 // The base class for a view
23 /****************************************************************************/
24 #include <config.h>
25 
26 #include <iostream>
27 #include <utility>
28 #include <cmath>
29 #include <cassert>
30 #include <limits>
31 #include <fxkeys.h>
32 #ifdef HAVE_GL2PS
33 #include <gl2ps.h>
34 #endif
38 #include <utils/common/RGBColor.h>
39 #include <utils/common/ToString.h>
42 #include <utils/common/SysUtils.h>
47 #include <utils/gui/div/GLHelper.h>
55 #include <utils/geom/GeomHelper.h>
60 
61 #include "GUISUMOAbstractView.h"
62 #include "GUIMainWindow.h"
63 #include "GUIGlChildWindow.h"
65 #include "GUIDialog_EditViewport.h"
66 
67 #ifdef HAVE_GDAL
68 #if __GNUC__ > 3
69 #pragma GCC diagnostic push
70 #pragma GCC diagnostic ignored "-Wpedantic"
71 #endif
72 #include <gdal_priv.h>
73 #if __GNUC__ > 3
74 #pragma GCC diagnostic pop
75 #endif
76 #endif
77 
78 
79 // ===========================================================================
80 // debug constants
81 // ===========================================================================
82 //#define DEBUG_SNAPSHOT
83 
84 // ===========================================================================
85 // static members
86 // ===========================================================================
87 
88 const double GUISUMOAbstractView::SENSITIVITY = 0.1; // meters
89 
90 
91 // ===========================================================================
92 // member method definitions
93 // ===========================================================================
94 /* -------------------------------------------------------------------------
95  * GUISUMOAbstractView - FOX callback mapping
96  * ----------------------------------------------------------------------- */
97 FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[] = {
98  FXMAPFUNC(SEL_CONFIGURE, 0, GUISUMOAbstractView::onConfigure),
99  FXMAPFUNC(SEL_PAINT, 0, GUISUMOAbstractView::onPaint),
100  FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, GUISUMOAbstractView::onLeftBtnPress),
101  FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, GUISUMOAbstractView::onLeftBtnRelease),
102  FXMAPFUNC(SEL_MIDDLEBUTTONPRESS, 0, GUISUMOAbstractView::onMiddleBtnPress),
103  FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE, 0, GUISUMOAbstractView::onMiddleBtnRelease),
104  FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 0, GUISUMOAbstractView::onRightBtnPress),
105  FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, GUISUMOAbstractView::onRightBtnRelease),
106  FXMAPFUNC(SEL_DOUBLECLICKED, 0, GUISUMOAbstractView::onDoubleClicked),
107  FXMAPFUNC(SEL_MOUSEWHEEL, 0, GUISUMOAbstractView::onMouseWheel),
108  FXMAPFUNC(SEL_MOTION, 0, GUISUMOAbstractView::onMouseMove),
109  FXMAPFUNC(SEL_LEAVE, 0, GUISUMOAbstractView::onMouseLeft),
110  FXMAPFUNC(SEL_KEYPRESS, 0, GUISUMOAbstractView::onKeyPress),
111  FXMAPFUNC(SEL_KEYRELEASE, 0, GUISUMOAbstractView::onKeyRelease),
112 
113 };
114 
115 
116 FXIMPLEMENT_ABSTRACT(GUISUMOAbstractView, FXGLCanvas, GUISUMOAbstractViewMap, ARRAYNUMBER(GUISUMOAbstractViewMap))
117 
118 
119 /* -------------------------------------------------------------------------
120  * GUISUMOAbstractView - methods
121  * ----------------------------------------------------------------------- */
122 GUISUMOAbstractView::GUISUMOAbstractView(FXComposite* p, GUIMainWindow& app, GUIGlChildWindow* parent, const SUMORTree& grid, FXGLVisual* glVis, FXGLCanvas* share) :
123  FXGLCanvas(p, glVis, share, p, MID_GLCANVAS, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0),
124  myApp(&app),
125  myParent(parent),
126  myGrid(&grid),
127  myChanger(nullptr),
128  myMouseHotspotX(app.getDefaultCursor()->getHotX()),
129  myMouseHotspotY(app.getDefaultCursor()->getHotY()),
130  myPopup(nullptr),
131  myPopupPosition(Position(0, 0)),
132  myUseToolTips(false),
133  myAmInitialised(false),
134  myViewportChooser(nullptr),
135  myWindowCursorPositionX(getWidth() / 2),
136  myWindowCursorPositionY(getHeight() / 2),
137  myVisualizationChanger(nullptr),
138  myFrameDrawTime(0) {
139  setTarget(this);
140  enable();
141  flags |= FLAG_ENABLED;
142  myInEditMode = false;
143  // show the middle at the beginning
144  myChanger = new GUIDanielPerspectiveChanger(*this, *myGrid);
145  myVisualizationSettings = &gSchemeStorage.getDefault();
146  myVisualizationSettings->gaming = myApp->isGaming();
148 }
149 
150 
154  delete myPopup;
155  delete myChanger;
156  delete myViewportChooser;
157  delete myVisualizationChanger;
158  // cleanup decals
159  for (std::vector<GUISUMOAbstractView::Decal>::iterator it = myDecals.begin(); it != myDecals.end(); ++it) {
160  delete it->image;
161  }
162  for (auto i : myAdditionallyDrawn) {
163  i.first->removeActiveAddVisualisation(this, ~0); // remove all
164  }
165 }
166 
167 
168 bool
170  return myInEditMode;
171 }
172 
173 
176  return *myChanger;
177 }
178 
179 
180 void
182  if (!myUseToolTips) {
183  return;
184  }
185  update();
186 }
187 
188 
189 Position
192 }
193 
194 
195 Position
196 GUISUMOAbstractView::snapToActiveGrid(const Position& pos, bool snapXY) const {
197  Position result = pos;
199  if (snapXY) {
200  const double xRest = std::fmod(pos.x(), myVisualizationSettings->gridXSize) + (pos.x() < 0 ? myVisualizationSettings->gridXSize : 0);
201  const double yRest = std::fmod(pos.y(), myVisualizationSettings->gridYSize) + (pos.y() < 0 ? myVisualizationSettings->gridYSize : 0);
202  result.setx(pos.x() - xRest + (xRest < myVisualizationSettings->gridXSize * 0.5 ? 0 : myVisualizationSettings->gridXSize));
203  result.sety(pos.y() - yRest + (yRest < myVisualizationSettings->gridYSize * 0.5 ? 0 : myVisualizationSettings->gridYSize));
204  } else {
205  // snapZToActiveGrid uses grid Y Size
206  const double zRest = std::fmod(pos.z(), myVisualizationSettings->gridYSize) + (pos.z() < 0 ? myVisualizationSettings->gridYSize : 0);
207  result.setz(pos.z() - zRest + (zRest < myVisualizationSettings->gridYSize * 0.5 ? 0 : myVisualizationSettings->gridYSize));
208  }
209  }
210  return result;
211 }
212 
213 
214 Position
216  Boundary bound = myChanger->getViewport();
217  double xNet = bound.xmin() + bound.getWidth() * x / getWidth();
218  // cursor origin is in the top-left corner
219  double yNet = bound.ymin() + bound.getHeight() * (getHeight() - y) / getHeight();
220  // rotate around the viewport center
221  if (myChanger->getRotation() != 0) {
222  return Position(xNet, yNet).rotateAround2D(-DEG2RAD(myChanger->getRotation()), bound.getCenter());
223  } else {
224  return Position(xNet, yNet);
225  }
226 }
227 
228 
229 void
230 GUISUMOAbstractView::addDecals(const std::vector<Decal>& decals) {
231  myDecals.insert(myDecals.end(), decals.begin(), decals.end());
232 }
233 
234 
235 void
238  std::string text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y());
239  myApp->getCartesianLabel().setText(text.c_str());
241  if (GeoConvHelper::getFinal().usingGeoProjection()) {
242  text = "lat:" + toString(pos.y(), gPrecisionGeo) + ", lon:" + toString(pos.x(), gPrecisionGeo);
243  } else {
244  text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y());
245  }
246  myApp->getGeoLabel().setText(text.c_str());
247 }
248 
249 
250 int
251 GUISUMOAbstractView::doPaintGL(int /*mode*/, const Boundary& /*boundary*/) {
252  return 0;
253 }
254 
255 
256 void
258 }
259 
260 
261 Boundary
263  return myChanger->getViewport();
264 }
265 
266 
267 void
269  if (getWidth() == 0 || getHeight() == 0) {
270  return;
271  }
272  const long start = SysUtils::getCurrentMillis();
273 
275  centerTo(getTrackedID(), false);
276  }
277 
279  if (myUseToolTips) {
280  id = getObjectUnderCursor();
281  }
282 
283  // draw
284  glClearColor(
289  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
290  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
291 
293  glEnable(GL_DITHER);
294  } else {
295  glDisable(GL_DITHER);
296  }
297  glEnable(GL_BLEND);
298  glDisable(GL_LINE_SMOOTH);
299 
300  Boundary bound = applyGLTransform();
301  doPaintGL(GL_RENDER, bound);
302  displayLegends();
303  const long end = SysUtils::getCurrentMillis();
304  myFrameDrawTime = end - start;
306  drawFPS();
307  }
308  // check whether the select mode /tooltips)
309  // shall be computed, too
310  if (myUseToolTips && id != GUIGlObject::INVALID_ID) {
311  showToolTipFor(id);
312  }
313  swapBuffers();
314 }
315 
316 
317 GUIGlID
320 }
321 
322 
323 std::vector<GUIGlID>
326 }
327 
328 
329 std::vector<GUIGlObject*>
332 }
333 
334 
335 std::vector<GUIGlObject*>
338 }
339 
340 
341 GUIGlID
343  // calculate a boundary for the given position
344  Boundary positionBoundary;
345  positionBoundary.add(pos);
346  positionBoundary.grow(SENSITIVITY);
347  const std::vector<GUIGlID> ids = getObjectsInBoundary(positionBoundary, true);
348  // Interpret results
349  int idMax = 0;
350  double maxLayer = -std::numeric_limits<double>::max();
351  // iterate over obtained GUIGlIDs
352  for (const auto& i : ids) {
353  // obtain GUIGlObject
355  // check that GUIGlObject exist
356  if (o == nullptr) {
357  continue;
358  }
359  // check that GUIGlObject isn't the network
360  if (o->getGlID() == 0) {
361  continue;
362  }
363  //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
364  GUIGlObjectType type = o->getType();
365  // avoid network
366  if (type != GLO_NETWORK) {
367  double layer = (double)type;
368  // determine an "abstract" layer for shapes
369  // this "layer" resembles the layer of the shape
370  // taking into account the stac of other objects
371  if (type == GLO_POI || type == GLO_POLYGON) {
372  layer = dynamic_cast<Shape*>(o)->getShapeLayer();
373  }
375  // do not select lanes in meso mode
376  continue;
377  }
378  // check whether the current object is above a previous one
379  if (layer > maxLayer) {
380  idMax = i;
381  maxLayer = layer;
382  }
383  }
384  // unblock object
386  }
387  return idMax;
388 }
389 
390 
391 std::vector<GUIGlID>
393  // declare result vector
394  std::vector<GUIGlID> result;
395  // calculate boundary
396  Boundary selection;
397  selection.add(pos);
398  selection.grow(radius);
399  // obtain GUIGlID of objects in boundary
400  const std::vector<GUIGlID> ids = getObjectsInBoundary(selection, true);
401  // iterate over obtained GUIGlIDs
402  for (const auto& i : ids) {
403  // obtain GUIGlObject
405  // check that GUIGlObject exist
406  if (o == nullptr) {
407  continue;
408  }
409  // check that GUIGlObject isn't the network
410  if (o->getGlID() == 0) {
411  continue;
412  }
413  //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
414  GUIGlObjectType type = o->getType();
415  // avoid network
416  if (type != GLO_NETWORK) {
417  result.push_back(i);
418  }
419  // unblock object
421  }
422  return result;
423 }
424 
425 
426 std::vector<GUIGlObject*>
428  // declare result vector
429  std::vector<GUIGlObject*> result;
430  // calculate boundary
431  Boundary selection;
432  selection.add(pos);
433  selection.grow(radius);
434  // obtain GUIGlID of objects in boundary
435  const std::vector<GUIGlID> ids = getObjectsInBoundary(selection, true);
436  // iterate over obtained GUIGlIDs
437  for (const auto& i : ids) {
438  // obtain GUIGlObject
440  // check that GUIGlObject exist
441  if (o == nullptr) {
442  continue;
443  }
444  // check that GUIGlObject isn't the network
445  if (o->getGlID() == 0) {
446  continue;
447  }
448  result.push_back(o);
449  // unblock object
451  }
452  return result;
453 }
454 
455 
456 std::vector<GUIGlID>
458  const int NB_HITS_MAX = 1024 * 1024;
459  // Prepare the selection mode
460  static GUIGlID hits[NB_HITS_MAX];
461  static GLint nb_hits = 0;
462  glSelectBuffer(NB_HITS_MAX, hits);
463  glInitNames();
464 
466  Boundary oldViewPort = myChanger->getViewport(false); // backup the actual viewPort
467  myChanger->setViewport(bound);
468  bound = applyGLTransform(false);
469  // enable draw for selecting (to draw objects with less details)
470  if (singlePosition) {
472  } else {
474  }
475  int hits2 = doPaintGL(GL_SELECT, bound);
476  // reset flags
479  // Get the results
480  nb_hits = glRenderMode(GL_RENDER);
481  if (nb_hits == -1) {
482  myApp->setStatusBarText("Selection in boundary failed. Try to select fewer than " + toString(hits2) + " items");
483  }
484  std::vector<GUIGlID> result;
485  GLuint numNames;
486  GLuint* ptr = hits;
487  for (int i = 0; i < nb_hits; ++i) {
488  numNames = *ptr;
489  ptr += 3;
490  for (int j = 0; j < (int)numNames; j++) {
491  result.push_back(*ptr);
492  ptr++;
493  }
494  }
495  // switch viewport back to normal
496  myChanger->setViewport(oldViewPort);
497  return result;
498 }
499 
500 
501 void
503  if (id != 0) {
505  if (object != nullptr) {
507  pos.add(0, p2m(15));
508  std::string label = object->getFullName();
510  (object->getType() == GLO_EDGE || object->getType() == GLO_LANE)) {
511  const int activeScheme = myVisualizationSettings->getLaneEdgeMode();
512  label += " (" + toString(object->getColorValue(*myVisualizationSettings, activeScheme)) + ")";
513  }
514  GLHelper::drawTextBox(label, pos, GLO_MAX - 1, p2m(20), RGBColor::BLACK, RGBColor(255, 179, 0, 255));
516  }
517  }
518 }
519 
520 
521 void
523  // obtain minimum grid
525  // Check if the distance is enought to draw grid
527  glEnable(GL_DEPTH_TEST);
528  glLineWidth(1);
529  // get multiplication values (2 is the marging)
530  int multXmin = (int)(myChanger->getViewport().xmin() / myVisualizationSettings->gridXSize) - 2;
531  int multYmin = (int)(myChanger->getViewport().ymin() / myVisualizationSettings->gridYSize) - 2;
532  int multXmax = (int)(myChanger->getViewport().xmax() / myVisualizationSettings->gridXSize) + 2;
533  int multYmax = (int)(myChanger->getViewport().ymax() / myVisualizationSettings->gridYSize) + 2;
534  // obtain references
535  double xmin = myVisualizationSettings->gridXSize * multXmin;
536  double ymin = myVisualizationSettings->gridYSize * multYmin;
537  double xmax = myVisualizationSettings->gridXSize * multXmax;
538  double ymax = myVisualizationSettings->gridYSize * multYmax;
539  double xpos = xmin;
540  double ypos = ymin;
541  // move drawing matrix
542  glTranslated(0, 0, .55);
543  glColor3d(0.5, 0.5, 0.5);
544  // draw horizontal lines
545  glBegin(GL_LINES);
546  while (ypos <= ymax) {
547  glVertex2d(xmin, ypos);
548  glVertex2d(xmax, ypos);
550  }
551  // draw vertical lines
552  while (xpos <= xmax) {
553  glVertex2d(xpos, ymin);
554  glVertex2d(xpos, ymax);
556  }
557  glEnd();
558  glTranslated(0, 0, -.55);
559  }
560 }
561 
562 
563 void
565  // compute the scale bar length
566  int length = 1;
567  const std::string text("10000000000");
568  int noDigits = 1;
569  int pixelSize = (int) m2p((double) length);
570  while (pixelSize <= 20) {
571  length *= 10;
572  noDigits++;
573  if (noDigits > (int)text.length()) {
574  return;
575  }
576  pixelSize = (int) m2p((double) length);
577  }
578  glLineWidth(1.0);
579 
580  glMatrixMode(GL_PROJECTION);
581  glPushMatrix();
582  glLoadIdentity();
583  glMatrixMode(GL_MODELVIEW);
584  glPushMatrix();
585  glLoadIdentity();
586 
587  // draw the scale bar
588  const double z = -1;
589  glDisable(GL_TEXTURE_2D);
590  glDisable(GL_ALPHA_TEST);
591  glDisable(GL_BLEND);
592  glEnable(GL_DEPTH_TEST);
593  glPushMatrix();
594  glTranslated(0, 0, z);
595 
596  double len = (double) pixelSize / (double)(getWidth() - 1) * (double) 2.0;
597  glColor3d(0, 0, 0);
598  double o = double(15) / double(getHeight());
599  double o2 = o + o;
600  double oo = double(5) / double(getHeight());
601  glBegin(GL_LINES);
602  // vertical
603  glVertex2d(-.98, -1. + o);
604  glVertex2d(-.98 + len, -1. + o);
605  // tick at begin
606  glVertex2d(-.98, -1. + o);
607  glVertex2d(-.98, -1. + o2);
608  // tick at end
609  glVertex2d(-.98 + len, -1. + o);
610  glVertex2d(-.98 + len, -1. + o2);
611  glEnd();
612  glPopMatrix();
613 
614  const double fontHeight = 0.1 * 300. / getHeight();
615  const double fontWidth = 0.1 * 300. / getWidth();
616  // draw 0
617  GLHelper::drawText("0", Position(-.99, -0.99 + o2 + oo), z, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT, fontWidth);
618 
619  // draw current scale
620  GLHelper::drawText((text.substr(0, noDigits) + "m").c_str(), Position(-.99 + len, -0.99 + o2 + oo), z, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT, fontWidth);
621 
622  // restore matrices
623  glMatrixMode(GL_PROJECTION);
624  glPopMatrix();
625  glMatrixMode(GL_MODELVIEW);
626  glPopMatrix();
627 }
628 
629 void
632  displayLegend();
633  }
636  }
639  }
640 }
641 
642 void
644  // compute the scale bar length
645  glLineWidth(1.0);
646  glMatrixMode(GL_PROJECTION);
647  glPushMatrix();
648  glLoadIdentity();
649  glMatrixMode(GL_MODELVIEW);
650  glPushMatrix();
651  glLoadIdentity();
652 
653  const double z = -1;
654  glEnable(GL_DEPTH_TEST);
655  glEnable(GL_BLEND);
656  glPushMatrix();
657  glTranslated(0, 0, z);
658 
659  const bool fixed = scheme.isFixed();
660  const int numColors = (int)scheme.getColors().size();
661 
662  // vertical
663  double right = 0.98;
664  double left = 0.95;
665  double textX = left - 0.01;
666  FONSalign textAlign = FONS_ALIGN_RIGHT;
667  const double top = -0.8;
668  const double bot = 0.8;
669  const double dy = (top - bot) / numColors;
670  const double bot2 = fixed ? bot : bot + dy / 2;
671  // legend placement
672  if (leftSide) {
673  right = -right;
674  left = -left;
675  std::swap(right, left);
676  textX = right + 0.01;
677  textAlign = FONS_ALIGN_LEFT;
678  }
679  // draw black boundary around legend colors
680  glColor3d(0, 0, 0);
681  glBegin(GL_LINES);
682  glVertex2d(right, top);
683  glVertex2d(right, bot2);
684  glVertex2d(left, bot2);
685  glVertex2d(left, top);
686  glVertex2d(right, top);
687  glVertex2d(left, top);
688  glVertex2d(right, bot2);
689  glVertex2d(left, bot2);
690  glEnd();
691 
692  const double fontHeight = 0.20 * 300. / getHeight();
693  const double fontWidth = 0.20 * 300. / getWidth();
694 
695  const int fadeSteps = fixed ? 1 : 10;
696  double colorStep = dy / fadeSteps;
697  for (int i = 0; i < numColors; i++) {
698  RGBColor col = scheme.getColors()[i];
699  const double topi = top - i * dy;
700  //const double boti = top - (i + 1) * dy;
701  //std::cout << " col=" << scheme.getColors()[i] << " i=" << i << " topi=" << topi << " boti=" << boti << "\n";
702  if (i + 1 < numColors) {
703  // fade
704  RGBColor col2 = scheme.getColors()[i + 1];
705  for (double j = 0.0; j < fadeSteps; j++) {
706  GLHelper::setColor(RGBColor::interpolate(col, col2, j / fadeSteps));
707  glBegin(GL_QUADS);
708  glVertex2d(left, topi - j * colorStep);
709  glVertex2d(right, topi - j * colorStep);
710  glVertex2d(right, topi - (j + 1) * colorStep);
711  glVertex2d(left, topi - (j + 1) * colorStep);
712  glEnd();
713  }
714  } else {
715  GLHelper::setColor(col);
716  glBegin(GL_QUADS);
717  glVertex2d(left, topi);
718  glVertex2d(right, topi);
719  glVertex2d(right, bot2);
720  glVertex2d(left, bot2);
721  glEnd();
722  }
723 
724  const double threshold = scheme.getThresholds()[i];
725  std::string name = scheme.getNames()[i];
726  std::string text = fixed || threshold == GUIVisualizationSettings::MISSING_DATA ? name : toString(threshold);
727 
728  const double bgShift = 0.0;
729  const double textShift = 0.02;
730 
732  glTranslated(0, 0, 0.1);
733  glBegin(GL_QUADS);
734  glVertex2d(left, topi + fontHeight * bgShift);
735  glVertex2d(left - fontWidth * text.size() / 2, topi + fontHeight * bgShift);
736  glVertex2d(left - fontWidth * text.size() / 2, topi + fontHeight * (1 + bgShift));
737  glVertex2d(left, topi + fontHeight * (1 + bgShift));
738  glEnd();
739  glTranslated(0, 0, -0.1);
740  GLHelper::drawText(text, Position(textX, topi + textShift), 0, fontHeight, RGBColor::BLACK, 0, textAlign, fontWidth);
741  }
742  glPopMatrix();
743  // restore matrices
744  glMatrixMode(GL_PROJECTION);
745  glPopMatrix();
746  glMatrixMode(GL_MODELVIEW);
747  glPopMatrix();
748 }
749 
750 
751 double
753  return 1000.0 / MAX2((long)1, myFrameDrawTime);
754 }
755 
756 void
758  glMatrixMode(GL_PROJECTION);
759  glPushMatrix();
760  glLoadIdentity();
761  glMatrixMode(GL_MODELVIEW);
762  glPushMatrix();
763  glLoadIdentity();
764  const double fontHeight = 0.2 * 300. / getHeight();
765  const double fontWidth = 0.2 * 300. / getWidth();
766  GLHelper::drawText(toString((int)getFPS()) + " FPS", Position(0.82, 0.88), -1, fontHeight, RGBColor::RED, 0, FONS_ALIGN_LEFT, fontWidth);
767 
768  // restore matrices
769  glMatrixMode(GL_PROJECTION);
770  glPopMatrix();
771  glMatrixMode(GL_MODELVIEW);
772  glPopMatrix();
773 }
774 
775 
776 double
777 GUISUMOAbstractView::m2p(double meter) const {
778  return meter * getWidth() / myChanger->getViewport().getWidth();
779 }
780 
781 
782 double
783 GUISUMOAbstractView::p2m(double pixel) const {
784  return pixel * myChanger->getViewport().getWidth() / getWidth();
785 }
786 
787 
788 void
791 }
792 
793 
794 void
795 GUISUMOAbstractView::centerTo(GUIGlID id, bool applyZoom, double zoomDist) {
797  if (o != nullptr && dynamic_cast<GUIGlObject*>(o) != nullptr) {
798  if (applyZoom && zoomDist < 0) {
800  update(); // only update when centering onto an object once
801  } else {
802  // called during tracking. update is triggered somewhere else
803  myChanger->centerTo(o->getCenteringBoundary().getCenter(), zoomDist, applyZoom);
805  }
806  }
808 }
809 
810 
811 void
812 GUISUMOAbstractView::centerTo(const Position& pos, bool applyZoom, double zoomDist) {
813  // called during tracking. update is triggered somewhere else
814  myChanger->centerTo(pos, zoomDist, applyZoom);
816 }
817 
818 
819 void
821  myChanger->setViewport(bound);
822  update();
823 }
824 
825 /*
826 bool
827 GUISUMOAbstractView::allowRotation() const
828 {
829  return myParent->allowRotation();
830 }
831 */
832 
833 Position
836 }
837 
838 
839 void
843 }
844 
845 
846 FXbool
848  FXbool ret = FXGLCanvas::makeCurrent();
849  return ret;
850 }
851 
852 
853 long
854 GUISUMOAbstractView::onConfigure(FXObject*, FXSelector, void*) {
855  if (makeCurrent()) {
856  glViewport(0, 0, getWidth() - 1, getHeight() - 1);
857  glClearColor(
862  doInit();
863  myAmInitialised = true;
864  makeNonCurrent();
865  checkSnapshots();
866  }
867  return 1;
868 }
869 
870 
871 long
872 GUISUMOAbstractView::onPaint(FXObject*, FXSelector, void*) {
873  if (!isEnabled() || !myAmInitialised) {
874  return 1;
875  }
876  if (makeCurrent()) {
877  paintGL();
878  makeNonCurrent();
879  }
880  return 1;
881 }
882 
883 
884 const Position&
886  return myPopupPosition;
887 }
888 
889 void
891  if (myPopup != nullptr) {
892  delete myPopup;
893  myPopupPosition.set(0, 0);
894  myPopup = nullptr;
895  }
896 }
897 
898 
899 long
900 GUISUMOAbstractView::onLeftBtnPress(FXObject*, FXSelector, void* data) {
901  destroyPopup();
902  setFocus();
903  FXEvent* e = (FXEvent*) data;
904  // check whether the selection-mode is activated
905  if ((e->state & CONTROLMASK) != 0) {
906  // toggle selection of object under cursor
907  if (makeCurrent()) {
908  int id = getObjectUnderCursor();
909  if (id != 0) {
911  }
912  makeNonCurrent();
913  if (id != 0) {
914  // possibly, the selection-colouring is used,
915  // so we should update the screen again...
916  update();
917  }
918  }
919  }
920  if ((e->state & SHIFTMASK) != 0) {
921  // track vehicle or person under cursor
922  if (makeCurrent()) {
923  int id = getObjectUnderCursor();
924  if (id != 0) {
926  if (o != nullptr) {
927  if (o->getType() == GLO_VEHICLE || o->getType() == GLO_PERSON) {
928  startTrack(id);
929  } else if (o->getType() == GLO_REROUTER_EDGE) {
930  o->onLeftBtnPress(data);
931  update();
932  }
933  }
934  }
935  makeNonCurrent();
936  }
937  }
938  myChanger->onLeftBtnPress(data);
939  grab();
940  // Check there are double click
941  if (e->click_count == 2) {
942  handle(this, FXSEL(SEL_DOUBLECLICKED, 0), data);
943  }
944  return 1;
945 }
946 
947 
948 long
949 GUISUMOAbstractView::onLeftBtnRelease(FXObject*, FXSelector, void* data) {
950  destroyPopup();
952  if (myApp->isGaming()) {
954  }
955  ungrab();
956  return 1;
957 }
958 
959 
960 long
961 GUISUMOAbstractView::onMiddleBtnPress(FXObject*, FXSelector, void*) {
962  return 1;
963 }
964 
965 
966 long
967 GUISUMOAbstractView::onMiddleBtnRelease(FXObject*, FXSelector, void*) {
968  return 1;
969 }
970 
971 
972 long
973 GUISUMOAbstractView::onRightBtnPress(FXObject*, FXSelector, void* data) {
974  destroyPopup();
975  myChanger->onRightBtnPress(data);
976  grab();
977  return 1;
978 }
979 
980 
981 long
982 GUISUMOAbstractView::onRightBtnRelease(FXObject* o, FXSelector sel, void* data) {
983  destroyPopup();
984  onMouseMove(o, sel, data);
985  if (!myChanger->onRightBtnRelease(data) && !myApp->isGaming()) {
987  }
988  if (myApp->isGaming()) {
990  }
991  ungrab();
992  return 1;
993 }
994 
995 
996 long
997 GUISUMOAbstractView::onDoubleClicked(FXObject*, FXSelector, void*) {
998  return 1;
999 }
1000 
1001 
1002 long
1003 GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector, void* data) {
1004  if (!myApp->isGaming()) {
1005  myChanger->onMouseWheel(data);
1006  // upddate viewport
1007  if (myViewportChooser != nullptr) {
1010  myChanger->getRotation());
1011  }
1013  }
1014  return 1;
1015 }
1016 
1017 
1018 long
1019 GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector, void* data) {
1020  // if popup exist but isn't shown, destroy it first
1021  if (myPopup && (myPopup->shown() == false)) {
1022  destroyPopup();
1023  }
1024  if (myPopup == nullptr) {
1025  if (myViewportChooser == nullptr || !myViewportChooser->haveGrabbed()) {
1026  myChanger->onMouseMove(data);
1027  }
1028  if (myViewportChooser != nullptr) {
1031  myChanger->getRotation());
1032  }
1034  }
1035  return 1;
1036 }
1037 
1038 
1039 long
1040 GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector, void* /*data*/) {
1041  return 1;
1042 }
1043 
1044 
1045 void
1047  ungrab();
1048  if (!isEnabled() || !myAmInitialised) {
1049  return;
1050  }
1051  if (makeCurrent()) {
1052  // initialise the select mode
1053  int id = getObjectUnderCursor();
1054  GUIGlObject* o = nullptr;
1055  if (id != 0) {
1057  } else {
1059  }
1060  if (o != nullptr) {
1061  myPopup = o->getPopUpMenu(*myApp, *this);
1062  int x, y;
1063  FXuint b;
1064  myApp->getCursorPosition(x, y, b);
1065  myPopup->setX(x + myApp->getX());
1066  myPopup->setY(y + myApp->getY());
1067  myPopup->create();
1068  myPopup->show();
1070  myChanger->onRightBtnRelease(nullptr);
1072  setFocus();
1073  }
1074  makeNonCurrent();
1075  }
1076 }
1077 
1078 
1079 long
1080 GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* data) {
1081  if (myPopup != nullptr) {
1082  return myPopup->onKeyPress(o, sel, data);
1083  } else {
1084  FXEvent* e = (FXEvent*) data;
1085  if (e->state & CONTROLMASK) {
1086  if (e->code == FX::KEY_Page_Up) {
1089  update();
1090  return 1;
1091  } else if (e->code == FX::KEY_Page_Down) {
1094  update();
1095  return 1;
1096  }
1097  }
1098  FXGLCanvas::onKeyPress(o, sel, data);
1099  return myChanger->onKeyPress(data);
1100  }
1101 }
1102 
1103 
1104 long
1105 GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* data) {
1106  if (myPopup != nullptr) {
1107  return myPopup->onKeyRelease(o, sel, data);
1108  } else {
1109  FXGLCanvas::onKeyRelease(o, sel, data);
1110  return myChanger->onKeyRelease(data);
1111  }
1112 }
1113 
1114 
1115 // ------------ Dealing with snapshots
1116 void
1117 GUISUMOAbstractView::addSnapshot(SUMOTime time, const std::string& file, const int w, const int h) {
1118 #ifdef DEBUG_SNAPSHOT
1119  std::cout << "add snapshot time=" << time << " file=" << file << "\n";
1120 #endif
1121  FXMutexLock lock(mySnapshotsMutex);
1122  mySnapshots[time].push_back(std::make_tuple(file, w, h));
1123 }
1124 
1125 
1126 std::string
1127 GUISUMOAbstractView::makeSnapshot(const std::string& destFile, const int w, const int h) {
1128  if (w >= 0) {
1129  resize(w, h);
1130  repaint();
1131  }
1132  std::string errorMessage;
1133  FXString ext = FXPath::extension(destFile.c_str());
1134  const bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
1135 #ifdef HAVE_FFMPEG
1136  const bool useVideo = destFile == "" || ext == "h264" || ext == "hevc";
1137 #endif
1138  for (int i = 0; i < 10 && !makeCurrent(); ++i) {
1140  }
1141  // draw
1142  glClearColor(
1147  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
1148  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1149 
1151  glEnable(GL_DITHER);
1152  } else {
1153  glDisable(GL_DITHER);
1154  }
1155  glEnable(GL_BLEND);
1156  glDisable(GL_LINE_SMOOTH);
1157 
1158  applyGLTransform();
1159 
1160  if (useGL2PS) {
1161 #ifdef HAVE_GL2PS
1162  GLint format = GL2PS_PS;
1163  if (ext == "ps") {
1164  format = GL2PS_PS;
1165  } else if (ext == "eps") {
1166  format = GL2PS_EPS;
1167  } else if (ext == "pdf") {
1168  format = GL2PS_PDF;
1169  } else if (ext == "tex") {
1170  format = GL2PS_TEX;
1171  } else if (ext == "svg") {
1172  format = GL2PS_SVG;
1173  } else if (ext == "pgf") {
1174  format = GL2PS_PGF;
1175  } else {
1176  return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
1177  }
1178  FILE* fp = fopen(destFile.c_str(), "wb");
1179  if (fp == 0) {
1180  return "Could not save '" + destFile + "'.\n Could not open file for writing";
1181  }
1183  GLint buffsize = 0, state = GL2PS_OVERFLOW;
1184  GLint viewport[4];
1185  glGetIntegerv(GL_VIEWPORT, viewport);
1186  while (state == GL2PS_OVERFLOW) {
1187  buffsize += 1024 * 1024;
1188  gl2psBeginPage(destFile.c_str(), "sumo-gui; https://sumo.dlr.de", viewport, format, GL2PS_SIMPLE_SORT,
1189  GL2PS_DRAW_BACKGROUND | GL2PS_USE_CURRENT_VIEWPORT,
1190  GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
1191  glMatrixMode(GL_MODELVIEW);
1192  glPushMatrix();
1193  glDisable(GL_TEXTURE_2D);
1194  glDisable(GL_ALPHA_TEST);
1195  glDisable(GL_BLEND);
1196  glEnable(GL_DEPTH_TEST);
1197  // draw decals (if not in grabbing mode)
1198 
1199  drawDecals();
1201  paintGLGrid();
1202  }
1203 
1204  glLineWidth(1);
1205  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1206  Boundary viewPort = myChanger->getViewport();
1207  const float minB[2] = { (float)viewPort.xmin(), (float)viewPort.ymin() };
1208  const float maxB[2] = { (float)viewPort.xmax(), (float)viewPort.ymax() };
1210  glEnable(GL_POLYGON_OFFSET_FILL);
1211  glEnable(GL_POLYGON_OFFSET_LINE);
1212  myGrid->Search(minB, maxB, *myVisualizationSettings);
1213 
1214  displayLegends();
1215  state = gl2psEndPage();
1216  glFinish();
1217  }
1218  GLHelper::setGL2PS(false);
1219  fclose(fp);
1220 #else
1221  return "Could not save '" + destFile + "', gl2ps was not enabled at compile time.";
1222 #endif
1223  } else {
1224  doPaintGL(GL_RENDER, myChanger->getViewport());
1225  displayLegends();
1226  swapBuffers();
1227  glFinish();
1228  FXColor* buf;
1229  FXMALLOC(&buf, FXColor, getWidth()*getHeight());
1230  // read from the back buffer
1231  glReadBuffer(GL_BACK);
1232  // Read the pixels
1233  glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
1234  makeNonCurrent();
1235  update();
1236  // mirror
1237  int mwidth = getWidth();
1238  int mheight = getHeight();
1239  FXColor* paa = buf;
1240  FXColor* pbb = buf + mwidth * (mheight - 1);
1241  do {
1242  FXColor* pa = paa;
1243  paa += mwidth;
1244  FXColor* pb = pbb;
1245  pbb -= mwidth;
1246  do {
1247  FXColor t = *pa;
1248  *pa++ = *pb;
1249  *pb++ = t;
1250  } while (pa < paa);
1251  } while (paa < pbb);
1252  try {
1253 #ifdef HAVE_FFMPEG
1254  if (useVideo) {
1255  try {
1256  saveFrame(destFile, buf);
1257  errorMessage = "video";
1258  } catch (std::runtime_error& err) {
1259  errorMessage = err.what();
1260  }
1261  } else
1262 #endif
1263  if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
1264  errorMessage = "Could not save '" + destFile + "'.";
1265  }
1266  } catch (InvalidArgument& e) {
1267  errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
1268  }
1269  FXFREE(&buf);
1270  }
1271  return errorMessage;
1272 }
1273 
1274 
1275 void
1276 GUISUMOAbstractView::saveFrame(const std::string& destFile, FXColor* buf) {
1277  UNUSED_PARAMETER(destFile);
1278  UNUSED_PARAMETER(buf);
1279 }
1280 
1281 
1282 void
1284  const SUMOTime time = getCurrentTimeStep() - DELTA_T;
1285 #ifdef DEBUG_SNAPSHOT
1286  std::cout << "check snapshots time=" << time << " registeredTimes=" << mySnapshots.size() << "\n";
1287 #endif
1288  FXMutexLock lock(mySnapshotsMutex);
1289  const auto snapIt = mySnapshots.find(time);
1290  if (snapIt == mySnapshots.end()) {
1291  return;
1292  }
1293  std::vector<std::tuple<std::string, int, int> > files = snapIt->second;
1294  lock.unlock();
1295  // decouple map access and painting to avoid deadlock
1296  for (const auto& entry : files) {
1297 #ifdef DEBUG_SNAPSHOT
1298  std::cout << "make snapshot time=" << time << " file=" << file << "\n";
1299 #endif
1300  const std::string& error = makeSnapshot(std::get<0>(entry), std::get<1>(entry), std::get<2>(entry));
1301  if (error != "" && error != "video") {
1302  WRITE_WARNING(error);
1303  }
1304  }
1305  // synchronization with a waiting run thread
1306  lock.lock();
1307  mySnapshots.erase(time);
1308  mySnapshotCondition.signal();
1309 #ifdef DEBUG_SNAPSHOT
1310  std::cout << " files=" << toString(files) << " myApplicationSnapshots=" << joinToString(*myApplicationSnapshots, ",") << "\n";
1311 #endif
1312 }
1313 
1314 
1315 void
1317  FXMutexLock lock(mySnapshotsMutex);
1318  if (mySnapshots.count(snapshotTime) > 0) {
1320  }
1321 }
1322 
1323 
1324 SUMOTime
1326  return 0;
1327 }
1328 
1329 
1330 void
1332  if (myVisualizationChanger == nullptr) {
1336  &myDecals, &myDecalsLock);
1337  myVisualizationChanger->create();
1338  } else {
1340  }
1342 }
1343 
1344 
1347  if (myViewportChooser == nullptr) {
1348  const FXint minSize = 100;
1349  const FXint minTitlebarHeight = 20;
1350  int x = MAX2(0, MIN2(getApp()->reg().readIntEntry(
1351  "VIEWPORT_DIALOG_SETTINGS", "x", 150),
1352  getApp()->getRootWindow()->getWidth() - minSize));
1353  int y = MAX2(minTitlebarHeight, MIN2(getApp()->reg().readIntEntry(
1354  "VIEWPORT_DIALOG_SETTINGS", "y", 150),
1355  getApp()->getRootWindow()->getHeight() - minSize));
1356  myViewportChooser = new GUIDialog_EditViewport(this, "Edit Viewport", x, y);
1357  myViewportChooser->create();
1358  }
1361  myChanger->getRotation());
1362  return myViewportChooser;
1363 }
1364 
1365 
1366 void
1368  getViewportEditor(); // make sure it exists;
1372 }
1373 
1374 
1375 void
1376 GUISUMOAbstractView::setViewportFromToRot(const Position& lookFrom, const Position& /* lookAt */, double rotation) {
1377  myChanger->setViewportFrom(lookFrom.x(), lookFrom.y(), lookFrom.z());
1378  myChanger->setRotation(rotation);
1379  update();
1380 }
1381 
1382 
1383 void
1385  // look straight down
1388  myChanger->getRotation());
1389 }
1390 
1391 
1392 void
1394  myUseToolTips = val;
1395 }
1396 
1397 
1398 bool
1400  return true;
1401 }
1402 
1403 
1406  return *myVisualizationSettings;
1407 }
1408 
1409 
1410 void
1412  myViewportChooser = nullptr;
1413 }
1414 
1415 
1416 void
1418  myVisualizationChanger = nullptr;
1419 }
1420 
1421 
1422 double
1424  return myGrid->getWidth();
1425 }
1426 
1427 
1428 double
1430  return myGrid->getHeight();
1431 }
1432 
1433 
1434 void
1436 }
1437 
1438 
1439 void
1441 }
1442 
1443 
1444 GUIGlID
1446  return GUIGlObject::INVALID_ID;
1447 }
1448 
1449 
1450 void
1452 }
1453 
1454 void
1456 }
1457 
1458 
1459 FXComboBox*
1462 }
1463 
1464 
1465 FXImage*
1467 #ifdef HAVE_GDAL
1468  GDALAllRegister();
1469  GDALDataset* poDataset = (GDALDataset*)GDALOpen(d.filename.c_str(), GA_ReadOnly);
1470  if (poDataset == 0) {
1471  return 0;
1472  }
1473  const int xSize = poDataset->GetRasterXSize();
1474  const int ySize = poDataset->GetRasterYSize();
1475  // checking for geodata in the picture and try to adapt position and scale
1476  if (d.width <= 0.) {
1477  double adfGeoTransform[6];
1478  if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
1479  Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
1480  const double horizontalSize = xSize * adfGeoTransform[1];
1481  const double verticalSize = ySize * adfGeoTransform[5];
1482  Position bottomRight(topLeft.x() + horizontalSize, topLeft.y() + verticalSize);
1483  if (GeoConvHelper::getProcessing().x2cartesian(topLeft) && GeoConvHelper::getProcessing().x2cartesian(bottomRight)) {
1484  d.width = bottomRight.x() - topLeft.x();
1485  d.height = topLeft.y() - bottomRight.y();
1486  d.centerX = (topLeft.x() + bottomRight.x()) / 2;
1487  d.centerY = (topLeft.y() + bottomRight.y()) / 2;
1488  //WRITE_MESSAGE("proj: " + toString(poDataset->GetProjectionRef()) + " dim: " + toString(d.width) + "," + toString(d.height) + " center: " + toString(d.centerX) + "," + toString(d.centerY));
1489  } else {
1490  WRITE_WARNING("Could not convert coordinates in " + d.filename + ".");
1491  }
1492  }
1493  }
1494 #endif
1495  if (d.width <= 0.) {
1496  d.width = getGridWidth();
1497  d.height = getGridHeight();
1498  }
1499 
1500  // trying to read the picture
1501 #ifdef HAVE_GDAL
1502  const int picSize = xSize * ySize;
1503  FXColor* result;
1504  if (!FXMALLOC(&result, FXColor, picSize)) {
1505  WRITE_WARNING("Could not allocate memory for " + d.filename + ".");
1506  return 0;
1507  }
1508  for (int j = 0; j < picSize; j++) {
1509  result[j] = FXRGB(0, 0, 0);
1510  }
1511  bool valid = true;
1512  for (int i = 1; i <= poDataset->GetRasterCount(); i++) {
1513  GDALRasterBand* poBand = poDataset->GetRasterBand(i);
1514  int shift = -1;
1515  if (poBand->GetColorInterpretation() == GCI_RedBand) {
1516  shift = 0;
1517  } else if (poBand->GetColorInterpretation() == GCI_GreenBand) {
1518  shift = 1;
1519  } else if (poBand->GetColorInterpretation() == GCI_BlueBand) {
1520  shift = 2;
1521  } else if (poBand->GetColorInterpretation() == GCI_AlphaBand) {
1522  shift = 3;
1523  } else {
1524  valid = false;
1525  break;
1526  }
1527  assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
1528  if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, ((unsigned char*)result) + shift, xSize, ySize, GDT_Byte, 4, 4 * xSize) == CE_Failure) {
1529  valid = false;
1530  break;
1531  }
1532  }
1533  GDALClose(poDataset);
1534  if (valid) {
1535  return new FXImage(getApp(), result, IMAGE_OWNED | IMAGE_KEEP | IMAGE_SHMI | IMAGE_SHMP, xSize, ySize);
1536  }
1537  FXFREE(&result);
1538 #endif
1539  return nullptr;
1540 }
1541 
1542 
1543 void
1545  glPushName(0);
1546  myDecalsLock.lock();
1547  for (std::vector<GUISUMOAbstractView::Decal>::iterator l = myDecals.begin(); l != myDecals.end(); ++l) {
1549  if (d.skip2D) {
1550  continue;
1551  }
1552  if (!d.initialised) {
1553  try {
1554  FXImage* img = checkGDALImage(d);
1555  if (img == nullptr) {
1556  img = MFXImageHelper::loadImage(getApp(), d.filename);
1557  }
1559  d.glID = GUITexturesHelper::add(img);
1560  d.initialised = true;
1561  d.image = img;
1562  } catch (InvalidArgument& e) {
1563  WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what());
1564  d.skip2D = true;
1565  }
1566  }
1567  glPushMatrix();
1568  if (d.screenRelative) {
1569  Position center = screenPos2NetPos((int)d.centerX, (int)d.centerY);
1570  glTranslated(center.x(), center.y(), d.layer);
1571  } else {
1572  glTranslated(d.centerX, d.centerY, d.layer);
1573  }
1574  glRotated(d.rot, 0, 0, 1);
1575  glColor3d(1, 1, 1);
1576  double halfWidth = d.width / 2.;
1577  double halfHeight = d.height / 2.;
1578  if (d.screenRelative) {
1579  halfWidth = p2m(halfWidth);
1580  halfHeight = p2m(halfHeight);
1581  }
1582  GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
1583  glPopMatrix();
1584  }
1585  myDecalsLock.unlock();
1586  glPopName();
1587 }
1588 
1589 
1590 // ------------ Additional visualisations
1591 bool
1593  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1594  myAdditionallyDrawn[which] = 1;
1595  } else {
1596  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
1597  }
1598  update();
1599  return true;
1600 }
1601 
1602 
1603 bool
1605  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1606  return false;
1607  }
1608  int cnt = myAdditionallyDrawn[which];
1609  if (cnt == 1) {
1610  myAdditionallyDrawn.erase(which);
1611  } else {
1612  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
1613  }
1614  update();
1615  return true;
1616 }
1617 
1618 
1619 bool
1621  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1622  return false;
1623  } else {
1624  return true;
1625  }
1626 }
1627 
1628 
1629 Boundary
1631  Boundary bound = myChanger->getViewport(fixRatio);
1632  glMatrixMode(GL_PROJECTION);
1633  glLoadIdentity();
1634  // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
1635  // thus, objects with a higher value will be closer (drawn on top)
1636  // // @todo last param should be 0 after modifying all glDraw methods
1637  glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
1638  glMatrixMode(GL_MODELVIEW);
1639  glLoadIdentity();
1640  double scaleX = (double)getWidth() / bound.getWidth();
1641  double scaleY = (double)getHeight() / bound.getHeight();
1642  glScaled(scaleX, scaleY, 1);
1643  glTranslated(-bound.xmin(), -bound.ymin(), 0);
1644  // rotate around the center of the screen
1645  //double angle = -90;
1646  if (myChanger->getRotation() != 0) {
1647  glTranslated(bound.getCenter().x(), bound.getCenter().y(), 0);
1648  glRotated(myChanger->getRotation(), 0, 0, 1);
1649  glTranslated(-bound.getCenter().x(), -bound.getCenter().y(), 0);
1650  Boundary rotBound;
1651  double rad = -DEG2RAD(myChanger->getRotation());
1652  rotBound.add(Position(bound.xmin(), bound.ymin()).rotateAround2D(rad, bound.getCenter()));
1653  rotBound.add(Position(bound.xmin(), bound.ymax()).rotateAround2D(rad, bound.getCenter()));
1654  rotBound.add(Position(bound.xmax(), bound.ymin()).rotateAround2D(rad, bound.getCenter()));
1655  rotBound.add(Position(bound.xmax(), bound.ymax()).rotateAround2D(rad, bound.getCenter()));
1656  bound = rotBound;
1657  }
1659  return bound;
1660 }
1661 
1662 
1663 double
1665  return myApp->getDelay();
1666 }
1667 
1668 
1669 void
1671  myApp->setDelay(delay);
1672 }
1673 
1674 
1675 void
1676 GUISUMOAbstractView::setBreakpoints(const std::vector<SUMOTime>& breakpoints) {
1677  myApp->setBreakpoints(breakpoints);
1678 }
1679 
1680 
1682  filename(),
1683  centerX(0),
1684  centerY(0),
1685  centerZ(0),
1686  width(0),
1687  height(0),
1688  altitude(0),
1689  rot(0),
1690  tilt(0),
1691  roll(0),
1692  layer(0),
1693  initialised(false),
1694  skip2D(false),
1695  screenRelative(false),
1696  glID(-1),
1697  image(nullptr) {
1698 }
1699 
1700 
1701 /****************************************************************************/
@ MID_GLCANVAS
GLCanvas - ID.
Definition: GUIAppEnum.h:380
GUICompleteSchemeStorage gSchemeStorage
unsigned int GUIGlID
Definition: GUIGlObject.h:40
GUIGlObjectType
@ GLO_REROUTER_EDGE
a Rerouter
@ GLO_MAX
empty max
@ GLO_LANE
a lane
@ GLO_EDGE
an edge
@ GLO_VEHICLE
a vehicle
@ GLO_PERSON
a person
@ GLO_NETWORK
The network - empty.
@ GLO_POI
a poi
@ GLO_POLYGON
a polygon
GUISelectedStorage gSelected
A global holder of selected objects.
FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[]
#define DEG2RAD(x)
Definition: GeomHelper.h:35
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
long long int SUMOTime
Definition: SUMOTime.h:31
int gPrecisionGeo
Definition: StdDefs.cpp:26
const double SUMO_const_laneWidth
Definition: StdDefs.h:47
#define UNUSED_PARAMETER(x)
Definition: StdDefs.h:29
T MIN2(T a, T b)
Definition: StdDefs.h:73
T MAX2(T a, T b)
Definition: StdDefs.h:79
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:250
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:39
Position getCenter() const
Returns the center of the boundary.
Definition: Boundary.cpp:111
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
Definition: Boundary.cpp:77
double ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:129
double xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:117
Boundary & grow(double by)
extends the boundary by the given amount
Definition: Boundary.cpp:299
double getHeight() const
Returns the height of the boundary (y-axis)
Definition: Boundary.cpp:159
double getWidth() const
Returns the width of the boudary (x-axis)
Definition: Boundary.cpp:153
double ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:135
double xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:123
static void sleep(long ms)
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:546
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition: GLHelper.cpp:446
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:498
static void setGL2PS(bool active=true)
Definition: GLHelper.h:331
GUIVisualizationSettings & getDefault()
Returns the default scheme.
void saveViewport(const double x, const double y, const double z, const double rot)
Makes the given viewport the default.
void setDefault(const std::string &name)
Makes the scheme with the given name the default.
void setViewport(GUISUMOAbstractView *view)
Sets the default viewport.
A dialog to change the viewport.
void setOldValues(const Position &lookFrom, const Position &lookAt, double rotation)
Resets old values.
bool haveGrabbed() const
Returns the information whether one of the spin dialers is grabbed.
void setValues(double zoom, double xoff, double yoff, double rotation)
Sets the given values into the dialog.
void show()
overload show function to focus always in OK Button
The dialog to change the view (gui) settings.
void show()
show view settings dialog
void setCurrent(GUIVisualizationSettings *settings)
Sets current settings (called if reopened)
FXComboBox * getColoringSchemesCombo()
return combobox with the current coloring schemes (standard, fastest standard, real world....
virtual double getColorValue(const GUIVisualizationSettings &, int) const
Definition: GUIGlObject.h:148
static const GUIGlID INVALID_ID
Definition: GUIGlObject.h:67
virtual Boundary getCenteringBoundary() const =0
virtual void onLeftBtnPress(void *)
notify object about left click
Definition: GUIGlObject.h:163
GUIGlObjectType getType() const
Returns the type of the object as coded in GUIGlObjectType.
virtual GUIGLObjectPopupMenu * getPopUpMenu(GUIMainWindow &app, GUISUMOAbstractView &parent)=0
Returns an own popup-menu.
GUIGlID getGlID() const
Returns the numerical id of the object.
void unblockObject(GUIGlID id)
Marks an object as unblocked.
GUIGlObject * getNetObject() const
Returns the network object.
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
GUIGlObject * getObjectBlocking(GUIGlID id)
Returns the object from the container locking it.
FXLabel & getCartesianLabel()
get cartesian label
virtual double getDelay() const
Returns the delay (should be overwritten by subclasses if applicable)
bool isGaming() const
return whether the gui is in gaming mode
virtual void setBreakpoints(const std::vector< SUMOTime > &)
Sets the breakpoints of the parent application.
virtual void setStatusBarText(const std::string &)
get status bar text (can be implemented in children)
Definition: GUIMainWindow.h:96
virtual void setDelay(double)
Sets the delay of the parent application.
FXLabel & getGeoLabel()
get geo label
virtual void setViewportFrom(double xPos, double yPos, double zPos)=0
Alternative method for setting the viewport.
virtual long onKeyPress(void *data)
called when user press a key
virtual void setRotation(double rotation)=0
Sets the rotation.
virtual void onRightBtnPress(void *data)
called when user press right button
virtual void centerTo(const Position &pos, double radius, bool applyZoom=true)=0
Centers the view to the given position, setting it to a size that covers the radius....
virtual double getRotation() const =0
Returns the rotation of the canvas stored in this changer.
virtual bool onLeftBtnRelease(void *data)
called when user releases left button
virtual double getZoom() const =0
Returns the zoom factor computed stored in this changer.
virtual void onLeftBtnPress(void *data)
mouse functions
virtual double getXPos() const =0
Returns the x-offset of the field to show stored in this changer.
virtual double getYPos() const =0
Returns the y-offset of the field to show stored in this changer.
virtual long onKeyRelease(void *data)
called when user releases a key
virtual void onMouseMove(void *data)
called when user moves mouse
virtual double getZPos() const =0
Returns the camera height corresponding to the current zoom factor.
virtual void onMouseWheel(void *data)
called when user changes mouse wheel
virtual bool onRightBtnRelease(void *data)
called when user releases right button
Boundary getViewport(bool fixRatio=true)
get viewport
virtual void setViewport(double zoom, double xPos, double yPos)=0
Sets the viewport Used for: Adapting a new viewport.
const std::vector< double > & getThresholds() const
const std::vector< T > & getColors() const
const std::vector< std::string > & getNames() const
void paintGLGrid()
paints a grid
bool myAmInitialised
Internal information whether doInit() was called.
Position snapToActiveGrid(const Position &pos, bool snapXY=true) const
Returns a position that is mapped to the closest grid point if the grid is active.
std::string makeSnapshot(const std::string &destFile, const int w=-1, const int h=-1)
Takes a snapshots and writes it into the given file.
void updateToolTip()
A method that updates the tooltip.
void addDecals(const std::vector< Decal > &decals)
add decals
virtual void checkSnapshots()
Checks whether it is time for a snapshot.
void showViewschemeEditor()
show viewsscheme editor
static const double SENSITIVITY
virtual long onLeftBtnRelease(FXObject *, FXSelector, void *)
FXMutex myDecalsLock
The mutex to use before accessing the decals list in order to avoid thread conflicts.
void displayLegend()
Draws a line with ticks, and the length information.
std::vector< GUIGlObject * > getGUIGlObjectsUnderCursor()
returns the GUIGlObject under the cursor using GL_SELECT (including overlapped objects)
long myFrameDrawTime
counter for measuring rendering time
std::vector< GUIGlID > getObjectsAtPosition(Position pos, double radius)
returns the ids of the object at position within the given (rectangular) radius using GL_SELECT
const SUMORTree * myGrid
The visualization speed-up.
virtual void saveFrame(const std::string &destFile, FXColor *buf)
Adds a frame to a video snapshot which will be initialized if neccessary.
virtual void recenterView()
recenters the view
virtual SUMOTime getCurrentTimeStep() const
get the current simulation time
GUIDialog_ViewSettings * myVisualizationChanger
Visualization changer.
std::vector< GUIGlID > getObjectsInBoundary(Boundary bound, bool singlePosition)
returns the ids of all objects in the given boundary
FXbool makeCurrent()
A reimplementation due to some internal reasons.
int myMouseHotspotX
Offset to the mouse-hotspot from the mouse position.
bool isInEditMode()
returns true, if the edit button was pressed
void updatePositionInformation() const
update position information
virtual long onMiddleBtnRelease(FXObject *, FXSelector, void *)
virtual long onMouseMove(FXObject *, FXSelector, void *)
GUIDialog_EditViewport * myViewportChooser
viewport chooser
GUIVisualizationSettings & getVisualisationSettings() const
get visualization settings
bool isAdditionalGLVisualisationEnabled(GUIGlObject *const which) const
Check if an object is added in the additional GL visualitation.
FXCondition mySnapshotCondition
the semaphore when waiting for snapshots to finish
Position myPopupPosition
The current popup-menu position.
virtual void doInit()
doInit
virtual int doPaintGL(int, const Boundary &)
paint GL
virtual void showViewportEditor()
show viewport editor
void setDelay(double delay)
Sets the delay of the parent application.
Boundary getVisibleBoundary() const
get visible boundary
Position screenPos2NetPos(int x, int y) const
Translate screen position to network position.
void addSnapshot(SUMOTime time, const std::string &file, const int w=-1, const int h=-1)
Sets the snapshot time to file map.
GUIGlID getObjectUnderCursor()
returns the id of the front object under the cursor using GL_SELECT
GUIPerspectiveChanger & getChanger() const
get changer
virtual void centerTo(GUIGlID id, bool applyZoom, double zoomDist=20)
centers to the chosen artifact
GUIMainWindow * myApp
The application.
GUIDialog_EditViewport * getViewportEditor()
get the viewport and create it on first access
void showToolTips(bool val)
show tool tips
void drawFPS()
Draws frames-per-second indicator.
virtual long onMouseWheel(FXObject *, FXSelector, void *)
double getGridWidth() const
get grid width
bool removeAdditionalGLVisualisation(GUIGlObject *const which)
Removes an object from the list of objects that show additional things.
double getDelay() const
Returns the delay of the parent application.
std::vector< GUIGlObject * > getGUIGlObjectsAtPosition(Position pos, double radius)
returns the GUIGlObjects at position within the given (rectangular) radius using GL_SELECT
virtual long onLeftBtnPress(FXObject *, FXSelector, void *)
bool myUseToolTips
use tool tips
virtual void setViewportFromToRot(const Position &lookFrom, const Position &lookAt, double rotation)
applies the given viewport settings
double p2m(double pixel) const
pixels-to-meters conversion method
std::vector< Decal > myDecals
const Position & getPopupPosition() const
get position of current popup
double m2p(double meter) const
meter-to-pixels conversion method
virtual void onGamingClick(Position)
on gaming click
bool myInEditMode
Information whether too-tip informations shall be generated.
GUIVisualizationSettings * myVisualizationSettings
visualization settings
void destroyPopup()
destoys the popup
Position getWindowCursorPosition() const
Returns the information whether rotation is allowd.
virtual long onKeyPress(FXObject *o, FXSelector sel, void *data)
keyboard functions
virtual long onMiddleBtnPress(FXObject *, FXSelector, void *)
void paintGL()
performs the painting of the simulation
virtual void stopTrack()
stop track
Position getPositionInformation() const
Returns the cursor's x/y position within the network.
GUIGlID getObjectAtPosition(Position pos)
returns the id of the object at position using GL_SELECT
std::vector< GUIGlObject * > getGUIGlObjectsUnderSnappedCursor()
returns the GUIGlObject under the gripped cursor using GL_SELECT (including overlapped objects)
virtual long onKeyRelease(FXObject *o, FXSelector sel, void *data)
void showToolTipFor(const GUIGlID id)
invokes the tooltip for the given object
virtual void onGamingRightClick(Position)
void setWindowCursorPosition(FXint x, FXint y)
Returns the gl-id of the object under the given coordinates.
double getFPS() const
retrieve FPS
std::map< GUIGlObject *, int > myAdditionallyDrawn
List of objects for which GUIGlObject::drawGLAdditional is called.
void drawDecals()
Draws the stored decals.
std::vector< GUIGlID > getObjectsUnderCursor()
returns the id of the objects under the cursor using GL_SELECT (including overlapped objects)
Boundary applyGLTransform(bool fixRatio=true)
applies gl-transformations to fit the Boundary given by myChanger onto the canvas....
FXImage * checkGDALImage(Decal &d)
check whether we can read image data or position with gdal
double getGridHeight() const
get grid height
virtual void startTrack(int)
star track
virtual long onDoubleClicked(FXObject *, FXSelector, void *)
void displayLegends()
Draws the configured legends.
void displayColorLegend(const GUIColorScheme &scheme, bool leftSide)
Draws a legend for the given scheme.
FXMutex mySnapshotsMutex
The mutex to use before accessing the decals list in order to avoid thread conflicts.
virtual long onMouseLeft(FXObject *, FXSelector, void *)
virtual long onRightBtnRelease(FXObject *, FXSelector, void *)
FXint myWindowCursorPositionX
Position of the cursor relative to the window.
GUIPerspectiveChanger * myChanger
The perspective changer.
GUIGLObjectPopupMenu * myPopup
The current popup-menu.
virtual void copyViewportTo(GUISUMOAbstractView *view)
copy the viewport to the given view
void setBreakpoints(const std::vector< SUMOTime > &breakpoints)
Sets the breakpoints of the parent application.
FXComboBox * getColoringSchemesCombo()
get coloring schemes combo
void waitForSnapshots(const SUMOTime snapshotTime)
bool addAdditionalGLVisualisation(GUIGlObject *const which)
Adds an object to call its additional visualisation method.
virtual bool setColorScheme(const std::string &)
set color scheme
GUIGlChildWindow * myParent
The parent window.
virtual long onPaint(FXObject *, FXSelector, void *)
virtual long onRightBtnPress(FXObject *, FXSelector, void *)
virtual ~GUISUMOAbstractView()
destructor
virtual long onConfigure(FXObject *, FXSelector, void *)
mouse functions
std::map< SUMOTime, std::vector< std::tuple< std::string, int, int > > > mySnapshots
Snapshots.
void remove(GUIDialog_EditViewport *)
remove viewport
virtual GUIGlID getTrackedID() const
get tracked id
void toggleSelection(GUIGlID id)
Toggles selection of an object.
static void drawTexturedBox(int which, double size)
Draws a named texture as a box with the given size.
static GUIGlID add(FXImage *i)
Adds a texture to use.
static int getMaxTextureSize()
return maximum number of pixels in x and y direction
Stores the information about how to visualize structures.
RGBColor backgroundColor
The background color to use.
bool dither
Information whether dithering shall be enabled.
GUIColorer vehicleColorer
The vehicle colorer.
bool drawForRectangleSelection
whether drawing is performed for the purpose of selecting objects using a rectangle
GUIVisualizationSizeSettings addSize
std::string name
The name of this setting.
bool drawForPositionSelection
whether drawing is performed for the purpose of selecting objects with a single click
bool gaming
whether the application is in gaming mode or not
GUIVisualizationTextSettings edgeValue
bool fps
Information whether frames-per-second should be drawn.
bool showGrid
Information whether a grid shall be shown.
bool showVehicleColorLegend
Information whether the vehicle color legend shall be drawn.
static bool UseMesoSim
this should be set at the same time as MSGlobals::gUseMesoSim
int getLaneEdgeMode() const
Returns the number of the active lane (edge) coloring schme.
double scale
information about a lane's width (temporary, used for a single view)
GUIColorScheme & getLaneEdgeScheme()
Returns the current lane (edge) coloring schme.
bool showSizeLegend
Information whether the size legend shall be drawn.
double gridXSize
Information about the grid spacings.
bool showColorLegend
Information whether the edge color legend shall be drawn.
double angle
The current view rotation angle.
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
Definition: GeoConvHelper.h:84
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
static FXImage * loadImage(FXApp *a, const std::string &file)
static FXbool scalePower2(FXImage *image, int maxSize=(2<< 29))
static FXbool saveImage(const std::string &file, int width, int height, FXColor *data)
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:36
void setx(double x)
set position x
Definition: Position.h:69
void set(double x, double y)
set positions x and y
Definition: Position.h:84
static const Position INVALID
used to indicate that a position is valid
Definition: Position.h:282
double x() const
Returns the x-position.
Definition: Position.h:54
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:124
void setz(double z)
set position z
Definition: Position.h:79
Position rotateAround2D(double rad, const Position &origin)
rotate this position by rad around origin and return the result
Definition: Position.cpp:41
double z() const
Returns the z-position.
Definition: Position.h:64
void sety(double y)
set position y
Definition: Position.h:74
double y() const
Returns the y-position.
Definition: Position.h:59
static RGBColor interpolate(const RGBColor &minColor, const RGBColor &maxColor, double weight)
Interpolates between two colors.
Definition: RGBColor.cpp:284
static const RGBColor WHITE
Definition: RGBColor.h:187
unsigned char red() const
Returns the red-amount of the color.
Definition: RGBColor.h:52
unsigned char alpha() const
Returns the alpha-amount of the color.
Definition: RGBColor.h:73
unsigned char green() const
Returns the green-amount of the color.
Definition: RGBColor.h:59
unsigned char blue() const
Returns the blue-amount of the color.
Definition: RGBColor.h:66
static const RGBColor BLACK
Definition: RGBColor.h:188
static const RGBColor RED
named colors
Definition: RGBColor.h:180
A RT-tree for efficient storing of SUMO's GL-objects.
Definition: SUMORTree.h:66
virtual int Search(const float a_min[2], const float a_max[2], const GUIVisualizationSettings &c) const
Find all within search rectangle.
Definition: SUMORTree.h:116
A 2D- or 3D-Shape.
Definition: Shape.h:36
static long getCurrentMillis()
Returns the current time in milliseconds.
Definition: SysUtils.cpp:39
FONSalign
Definition: fontstash.h:40
@ FONS_ALIGN_LEFT
Definition: fontstash.h:42
@ FONS_ALIGN_RIGHT
Definition: fontstash.h:44
A decal (an image) that can be shown.
double centerX
The center of the image in x-direction (net coordinates, in m)
double height
The height of the image (net coordinates in y-direction, in m)
bool skip2D
Whether this image should be skipped in 2D-views.
double width
The width of the image (net coordinates in x-direction, in m)
bool initialised
Whether this image was initialised (inserted as a texture)
FXImage * image
The image pointer for later cleanup.
double rot
The rotation of the image in the ground plane (in degrees)
double layer
The layer of the image.
double centerY
The center of the image in y-direction (net coordinates, in m)
std::string filename
The path to the file the image is located at.
int glID
whether the decal shall be drawn in screen coordinates, rather than network coordinates
bool screenRelative
Whether this image should be skipped in 2D-views.
double getExaggeration(const GUIVisualizationSettings &s, const GUIGlObject *o, double factor=20) const
return the drawing size including exaggeration and constantSize values