SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GUISUMOAbstractView.cpp
Go to the documentation of this file.
1 /****************************************************************************/
11 // The base class for a view
12 /****************************************************************************/
13 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
14 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
15 /****************************************************************************/
16 //
17 // This file is part of SUMO.
18 // SUMO is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 /****************************************************************************/
24 
25 
26 // ===========================================================================
27 // included modules
28 // ===========================================================================
29 #ifdef _MSC_VER
30 #include <windows_config.h>
31 #else
32 #include <config.h>
33 #endif
34 
35 #ifdef _WIN32
36 #include <windows.h>
37 #endif
38 
39 #include <iostream>
40 #include <utility>
41 #include <cmath>
42 #include <cassert>
43 #include <fxkeys.h>
44 #include <GL/gl.h>
45 #include <GL/glu.h>
47 #include <foreign/gl2ps/gl2ps.h>
51 #include <utils/common/RGBColor.h>
52 #include <utils/common/ToString.h>
59 #include <utils/gui/div/GLHelper.h>
69 
70 #include "GUISUMOAbstractView.h"
71 #include "GUIMainWindow.h"
72 #include "GUIGlChildWindow.h"
74 #include "GUIDialog_EditViewport.h"
75 
76 #ifdef WIN32
77 #include <windows.h>
78 #endif
79 
80 #ifdef CHECK_MEMORY_LEAKS
81 #include <foreign/nvwa/debug_new.h>
82 #endif // CHECK_MEMORY_LEAKS
83 
84 
85 // ===========================================================================
86 // member method definitions
87 // ===========================================================================
88 /* -------------------------------------------------------------------------
89  * GUISUMOAbstractView - FOX callback mapping
90  * ----------------------------------------------------------------------- */
91 FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[] = {
92  FXMAPFUNC(SEL_CONFIGURE, 0, GUISUMOAbstractView::onConfigure),
93  FXMAPFUNC(SEL_PAINT, 0, GUISUMOAbstractView::onPaint),
94  FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, GUISUMOAbstractView::onLeftBtnPress),
95  FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, GUISUMOAbstractView::onLeftBtnRelease),
96  FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 0, GUISUMOAbstractView::onRightBtnPress),
97  FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, GUISUMOAbstractView::onRightBtnRelease),
98  FXMAPFUNC(SEL_MOUSEWHEEL, 0, GUISUMOAbstractView::onMouseWheel),
99  FXMAPFUNC(SEL_MOTION, 0, GUISUMOAbstractView::onMouseMove),
100  FXMAPFUNC(SEL_LEAVE, 0, GUISUMOAbstractView::onMouseLeft),
101  FXMAPFUNC(SEL_KEYPRESS, 0, GUISUMOAbstractView::onKeyPress),
102  FXMAPFUNC(SEL_KEYRELEASE, 0, GUISUMOAbstractView::onKeyRelease),
103 
104 };
105 
106 
107 FXIMPLEMENT_ABSTRACT(GUISUMOAbstractView, FXGLCanvas, GUISUMOAbstractViewMap, ARRAYNUMBER(GUISUMOAbstractViewMap))
108 
109 
110 /* -------------------------------------------------------------------------
111  * GUISUMOAbstractView - methods
112  * ----------------------------------------------------------------------- */
114  GUIMainWindow& app,
115  GUIGlChildWindow* parent,
116  const SUMORTree& grid,
117  FXGLVisual* glVis, FXGLCanvas* share)
118  : FXGLCanvas(p, glVis, share, p, MID_GLCANVAS,
119  LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0),
120  myApp(&app),
121  myParent(parent),
122  myGrid(&((SUMORTree&)grid)),
123  myChanger(0),
124  myMouseHotspotX(app.getDefaultCursor()->getHotX()),
125  myMouseHotspotY(app.getDefaultCursor()->getHotY()),
126  myPopup(0),
127  myUseToolTips(false),
128  myAmInitialised(false),
129  myViewportChooser(0),
130  myVisualizationChanger(0) {
131  setTarget(this);
132  enable();
133  flags |= FLAG_ENABLED;
134  myInEditMode = false;
135  // show the middle at the beginning
136  myChanger = new GUIDanielPerspectiveChanger(*this, *myGrid);
137  myVisualizationSettings = &gSchemeStorage.getDefault();
138  myVisualizationSettings->gaming = myApp->isGaming();
140 }
141 
142 
146  delete myPopup;
147  delete myChanger;
148  delete myViewportChooser;
149  delete myVisualizationChanger;
150 }
151 
152 
153 bool
155  return myInEditMode;
156 }
157 
158 
159 void
161  if (!myUseToolTips) {
162  return;
163  }
164  update();
165 }
166 
167 
168 Position
170  Boundary bound = myChanger->getViewport();
171  SUMOReal x = bound.xmin() + bound.getWidth() * myWindowCursorPositionX / getWidth();
172  // cursor origin is in the top-left corner
173  SUMOReal y = bound.ymin() + bound.getHeight() * (getHeight() - myWindowCursorPositionY) / getHeight();
174  return Position(x, y);
175 }
176 
177 
178 void
181  std::string text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y());
182  myApp->getCartesianLabel().setText(text.c_str());
184  if (GeoConvHelper::getFinal().usingGeoProjection()) {
185  text = "lat:" + toString(pos.y(), GEO_OUTPUT_ACCURACY) + ", lon:" + toString(pos.x(), GEO_OUTPUT_ACCURACY);
186  } else {
187  text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y());
188  }
189  myApp->getGeoLabel().setText(text.c_str());
190 }
191 
192 
193 Boundary
195  return myChanger->getViewport();
196 }
197 
198 void
200  if (getWidth() == 0 || getHeight() == 0) {
201  return;
202  }
203 
204  if (getTrackedID() > 0) {
205  centerTo(getTrackedID(), false);
206  }
207 
208  unsigned int id = 0;
209  if (myUseToolTips) {
210  id = getObjectUnderCursor();
211  }
212 
213  // draw
214  glClearColor(
218  1);
219  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
220  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
221 
223  glEnable(GL_DITHER);
224  } else {
225  glDisable(GL_DITHER);
226  }
228  glEnable(GL_BLEND);
229  glEnable(GL_POLYGON_SMOOTH);
230  glEnable(GL_LINE_SMOOTH);
231  } else {
232  glDisable(GL_BLEND);
233  glDisable(GL_POLYGON_SMOOTH);
234  glDisable(GL_LINE_SMOOTH);
235  }
236 
238  doPaintGL(GL_RENDER, myChanger->getViewport());
240  displayLegend();
241  }
242  // check whether the select mode /tooltips)
243  // shall be computed, too
244  if (myUseToolTips && id != 0) {
245  showToolTipFor(id);
246  }
247  swapBuffers();
248 }
249 
250 
251 GUIGlID
254 }
255 
256 
257 GUIGlID
259  const SUMOReal SENSITIVITY = 0.1; // meters
260  Boundary selection;
261  selection.add(pos);
262  selection.grow(SENSITIVITY);
263  const std::vector<GUIGlID> ids = getObjectsInBoundary(selection);
264  // Interpret results
265  unsigned int idMax = 0;
266  int prevLayer = -1000;
267  for (std::vector<GUIGlID>::const_iterator it = ids.begin(); it != ids.end(); it++) {
268  GUIGlID id = *it;
270  if (o == 0) {
271  continue;
272  }
273  if (o->getGlID() == 0) {
274  continue;
275  }
276  //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
277  GUIGlObjectType type = o->getType();
278  if (type != 0) {
279  int clayer = (int) type;
280  // determine an "abstract" layer for shapes
281  // this "layer" resembles the layer of the shape
282  // taking into account the stac of other objects
283  if (type == GLO_SHAPE) {
284  if (dynamic_cast<GUIPolygon*>(o) != 0) {
285  if (dynamic_cast<GUIPolygon*>(o)->getLayer() > 0) {
286  clayer = GLO_MAX + dynamic_cast<GUIPolygon*>(o)->getLayer();
287  }
288  if (dynamic_cast<GUIPolygon*>(o)->getLayer() < 0) {
289  clayer = dynamic_cast<GUIPolygon*>(o)->getLayer();
290  }
291  }
292  if (dynamic_cast<GUIPointOfInterest*>(o) != 0) {
293  if (dynamic_cast<GUIPointOfInterest*>(o)->getLayer() > 0) {
294  clayer = GLO_MAX + dynamic_cast<GUIPointOfInterest*>(o)->getLayer();
295  }
296  if (dynamic_cast<GUIPointOfInterest*>(o)->getLayer() < 0) {
297  clayer = dynamic_cast<GUIPointOfInterest*>(o)->getLayer();
298  }
299  }
300  }
301  // check whether the current object is above a previous one
302  if (prevLayer == -1000 || prevLayer < clayer) {
303  idMax = id;
304  prevLayer = clayer;
305  }
306  }
308  }
309  return idMax;
310 }
311 
312 
313 std::vector<GUIGlID>
315  const int NB_HITS_MAX = 1024 * 1024;
316  // Prepare the selection mode
317  static GUIGlID hits[NB_HITS_MAX];
318  static GLint nb_hits = 0;
319  glSelectBuffer(NB_HITS_MAX, hits);
320  glInitNames();
321 
322  Boundary oldViewPort = myChanger->getViewport(false); // backup the actual viewPort
323  myChanger->setViewport(bound);
324  applyGLTransform(false);
325 
326  // paint in select mode
327  int hits2 = doPaintGL(GL_SELECT, bound);
328  // Get the results
329  nb_hits = glRenderMode(GL_RENDER);
330  if (nb_hits == -1) {
331  myApp->setStatusBarText("Selection in boundary failed. Try to select fewer than " + toString(hits2) + " items");
332  }
333  std::vector<GUIGlID> result;
334  for (int i = 0; i < nb_hits; ++i) {
335  assert(i * 4 + 3 < NB_HITS_MAX);
336  result.push_back(hits[i * 4 + 3]);
337  }
338  // switch viewport back to normal
339  myChanger->setViewport(oldViewPort);
340  return result;
341 }
342 
343 
344 void
346  if (id != 0) {
348  if (object != 0) {
350  pos.add(0, p2m(15));
351  GLHelper::drawTextBox(object->getFullName(), pos, GLO_MAX - 1, p2m(20), RGBColor(0, 0, 0), RGBColor(1, 0.7, 0));
353  }
354  }
355 }
356 
357 
358 void
360  glEnable(GL_DEPTH_TEST);
361  glLineWidth(1);
362 
363  SUMOReal xmin = myGrid->xmin();
364  SUMOReal ymin = myGrid->ymin();
365  SUMOReal ypos = ymin;
366  SUMOReal xpos = xmin;
367  SUMOReal xend = myGrid->xmax();
368  SUMOReal yend = myGrid->ymax();
369 
370  glTranslated(0, 0, .55);
371  glColor3d(0.5, 0.5, 0.5);
372  // draw horizontal lines
373  glBegin(GL_LINES);
374  for (; ypos < yend;) {
375  glVertex2d(xmin, ypos);
376  glVertex2d(xend, ypos);
378  }
379  // draw vertical lines
380  for (; xpos < xend;) {
381  glVertex2d(xpos, ymin);
382  glVertex2d(xpos, yend);
384  }
385  glEnd();
386  glTranslated(0, 0, -.55);
387 }
388 
389 
390 void
392  // compute the scale bar length
393  size_t length = 1;
394  const std::string text("10000000000");
395  size_t noDigits = 1;
396  size_t pixelSize = 0;
397  while (true) {
398  pixelSize = (size_t) m2p((SUMOReal) length);
399  if (pixelSize > 20) {
400  break;
401  }
402  length *= 10;
403  noDigits++;
404  if (noDigits > text.length()) {
405  return;
406  }
407  }
408  SUMOReal lineWidth = 1.0;
409  glLineWidth((SUMOReal) lineWidth);
410 
411  glMatrixMode(GL_PROJECTION);
412  glPushMatrix();
413  glLoadIdentity();
414  glMatrixMode(GL_MODELVIEW);
415  glPushMatrix();
416  glLoadIdentity();
417 
418  // draw the scale bar
419  glDisable(GL_TEXTURE_2D);
420  glDisable(GL_ALPHA_TEST);
421  glDisable(GL_BLEND);
422  glEnable(GL_DEPTH_TEST);
423 
424  SUMOReal len = (SUMOReal) pixelSize / (SUMOReal)(getWidth() - 1) * (SUMOReal) 2.0;
425  glColor3d(0, 0, 0);
426  double o = double(15) / double(getHeight());
427  double o2 = o + o;
428  double oo = double(5) / double(getHeight());
429  glBegin(GL_LINES);
430  // vertical
431  glVertex2d(-.98, -1. + o);
432  glVertex2d(-.98 + len, -1. + o);
433  // tick at begin
434  glVertex2d(-.98, -1. + o);
435  glVertex2d(-.98, -1. + o2);
436  // tick at end
437  glVertex2d(-.98 + len, -1. + o);
438  glVertex2d(-.98 + len, -1. + o2);
439  glEnd();
440 
441  SUMOReal w = SUMOReal(35) / SUMOReal(getWidth());
442  SUMOReal h = SUMOReal(35) / SUMOReal(getHeight());
443  pfSetPosition(SUMOReal(-0.99), SUMOReal(1. - o2 - oo));
444  pfSetScaleXY(w, h);
445  glRotated(180, 1, 0, 0);
446  pfDrawString("0m");
447  glRotated(-180, 1, 0, 0);
448 
449  pfSetPosition(SUMOReal(-.99 + len), SUMOReal(1. - o2 - oo));
450  glRotated(180, 1, 0, 0);
451  pfDrawString((text.substr(0, noDigits) + "m").c_str());
452  glRotated(-180, 1, 0, 0);
453 
454  // restore matrices
455  glMatrixMode(GL_PROJECTION);
456  glPopMatrix();
457  glMatrixMode(GL_MODELVIEW);
458  glPopMatrix();
459 }
460 
461 
462 SUMOReal
464  return meter * getWidth() / myChanger->getViewport().getWidth();
465 }
466 
467 
468 SUMOReal
470  return pixel * myChanger->getViewport().getWidth() / getWidth();
471 }
472 
473 
474 void
477 }
478 
479 
480 void
481 GUISUMOAbstractView::centerTo(GUIGlID id, bool applyZoom, SUMOReal zoomDist) {
483  if (o != 0 && dynamic_cast<GUIGlObject*>(o) != 0) {
484  if (applyZoom && zoomDist < 0) {
486  } else {
487  myChanger->centerTo(o->getCenteringBoundary().getCenter(), zoomDist, applyZoom);
488  }
489  }
491 }
492 
493 
494 void
496  myChanger->setViewport(bound);
497  update();
498 }
499 
500 /*
501 bool
502 GUISUMOAbstractView::allowRotation() const
503 {
504  return myParent->allowRotation();
505 }
506 */
507 
508 void
512 }
513 
514 
515 FXbool
517  FXbool ret = FXGLCanvas::makeCurrent();
518  return ret;
519 }
520 
521 
522 long
524  if (makeCurrent()) {
525  glViewport(0, 0, getWidth() - 1, getHeight() - 1);
526  glClearColor(
530  1);
531  doInit();
532  myAmInitialised = true;
533  makeNonCurrent();
534  checkSnapshots();
535  }
536  return 1;
537 }
538 
539 
540 long
542  if (!isEnabled() || !myAmInitialised) {
543  return 1;
544  }
545  if (makeCurrent()) {
546  paintGL();
547  makeNonCurrent();
548  }
549  return 1;
550 }
551 
552 
553 void
555  delete myPopup;
556  myPopup = 0;
557 }
558 
559 
560 long
561 GUISUMOAbstractView::onLeftBtnPress(FXObject*, FXSelector , void* data) {
562  destroyPopup();
563  FXEvent* e = (FXEvent*) data;
564  // check whether the selection-mode is activated
565  if (e->state & CONTROLMASK) {
566  // try to get the object-id if so
567  if (makeCurrent()) {
568  unsigned int id = getObjectUnderCursor();
569  if (id != 0) {
571  }
572  makeNonCurrent();
573  if (id != 0) {
574  // possibly, the selection-colouring is used,
575  // so we should update the screen again...
576  update();
577  }
578  }
579  }
580  myChanger->onLeftBtnPress(data);
581  grab();
582  return 1;
583 }
584 
585 
586 long
588  destroyPopup();
590  if (myApp->isGaming()) {
592  }
593  ungrab();
594  return 1;
595 }
596 
597 
598 long
599 GUISUMOAbstractView::onRightBtnPress(FXObject*, FXSelector , void* data) {
600  destroyPopup();
601  myChanger->onRightBtnPress(data);
602  grab();
603  return 1;
604 }
605 
606 
607 long
609  destroyPopup();
610  if (!myChanger->onRightBtnRelease(data) && !myApp->isGaming()) {
612  }
613  ungrab();
614  return 1;
615 }
616 
617 
618 long
619 GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector , void* data) {
620  myChanger->onMouseWheel(data);
621  return 1;
622 }
623 
624 
625 long
626 GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector , void* data) {
627  SUMOReal xpos = myChanger->getXPos();
628  SUMOReal ypos = myChanger->getYPos();
629  SUMOReal zoom = myChanger->getZoom();
631  myChanger->onMouseMove(data);
632  }
633  if (myViewportChooser != 0 &&
634  (xpos != myChanger->getXPos() || ypos != myChanger->getYPos() || zoom != myChanger->getZoom())) {
635 
638 
639  }
641  return 1;
642 }
643 
644 
645 long
646 GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector , void* /*data*/) {
647  return 1;
648 }
649 
650 
651 void
653  ungrab();
654  if (!isEnabled() || !myAmInitialised) {
655  return;
656  }
657  if (makeCurrent()) {
658  // initialise the select mode
659  unsigned int id = getObjectUnderCursor();
660  GUIGlObject* o = 0;
661  if (id != 0) {
663  } else {
665  }
666  if (o != 0) {
667  myPopup = o->getPopUpMenu(*myApp, *this);
668  int x, y;
669  FXuint b;
670  myApp->getCursorPosition(x, y, b);
671  myPopup->setX(x + myApp->getX());
672  myPopup->setY(y + myApp->getY());
673  myPopup->create();
674  myPopup->show();
677  }
678  makeNonCurrent();
679  }
680 }
681 
682 
683 long
684 GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* data) {
685  FXEvent* e = (FXEvent*) data;
686  if ((e->state & ALTMASK) != 0) {
687  setDefaultCursor(getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR));
688  grabKeyboard();
689  }
690  /*
691  switch(e->code) {
692  case KEY_Left:
693  myChanger->move((SUMOReal) -p2m((SUMOReal) getWidth()/10), 0);
694  break;
695  case KEY_Right:
696  myChanger->move((SUMOReal) p2m((SUMOReal) getWidth()/10), 0);
697  break;
698  case KEY_Up:
699  myChanger->move(0, (SUMOReal) -p2m((SUMOReal) getHeight()/10));
700  break;
701  case KEY_Down:
702  myChanger->move(0, (SUMOReal) p2m((SUMOReal) getHeight()/10));
703  break;
704  default:
705  break;
706  }
707  */
708  return FXGLCanvas::onKeyPress(o, sel, data);
709 }
710 
711 
712 long
713 GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* data) {
714  FXEvent* e = (FXEvent*) data;
715  if ((e->state & ALTMASK) == 0) {
716  ungrabKeyboard();
717  setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
718  }
719  return FXGLCanvas::onKeyRelease(o, sel, data);
720 }
721 
722 
723 // ------------ Dealing with snapshots
724 void
725 GUISUMOAbstractView::setSnapshots(std::map<SUMOTime, std::string> snaps) {
726  mySnapshots.insert(snaps.begin(), snaps.end());
727 }
728 
729 
730 std::string
731 GUISUMOAbstractView::makeSnapshot(const std::string& destFile) {
732  std::string errorMessage;
733  FXString ext = FXPath::extension(destFile.c_str());
734  bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
735 
736  for (int i = 0; i < 10 && !makeCurrent(); ++i) {
738  }
739  // draw
740  glClearColor(
744  1);
745  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
746  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
747 
749  glEnable(GL_DITHER);
750  } else {
751  glDisable(GL_DITHER);
752  }
754  glEnable(GL_BLEND);
755  glEnable(GL_POLYGON_SMOOTH);
756  glEnable(GL_LINE_SMOOTH);
757  } else {
758  glDisable(GL_BLEND);
759  glDisable(GL_POLYGON_SMOOTH);
760  glDisable(GL_LINE_SMOOTH);
761  }
762 
764 
765  if (useGL2PS) {
766  GLint format = GL2PS_PS;
767  if (ext == "ps") {
768  format = GL2PS_PS;
769  } else if (ext == "eps") {
770  format = GL2PS_EPS;
771  } else if (ext == "pdf") {
772  format = GL2PS_PDF;
773  } else if (ext == "tex") {
774  format = GL2PS_TEX;
775  } else if (ext == "svg") {
776  format = GL2PS_SVG;
777  } else if (ext == "pgf") {
778  format = GL2PS_PGF;
779  } else {
780  return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
781  }
782  FILE* fp = fopen(destFile.c_str(), "wb");
783  if (fp == 0) {
784  return "Could not save '" + destFile + "'.\n Could not open file for writing";
785  }
786  GLint buffsize = 0, state = GL2PS_OVERFLOW;
787  GLint viewport[4];
788  glGetIntegerv(GL_VIEWPORT, viewport);
789  while (state == GL2PS_OVERFLOW) {
790  buffsize += 1024 * 1024;
791  gl2psBeginPage(destFile.c_str(), "sumo-gui; http://sumo.sf.net", viewport, format, GL2PS_SIMPLE_SORT,
793  GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
794  glMatrixMode(GL_MODELVIEW);
795  glPushMatrix();
796  glDisable(GL_TEXTURE_2D);
797  glDisable(GL_ALPHA_TEST);
798  glDisable(GL_BLEND);
799  glEnable(GL_DEPTH_TEST);
800  // compute lane width
801  // draw decals (if not in grabbing mode)
802  if (!myUseToolTips) {
803  drawDecals();
805  paintGLGrid();
806  }
807  }
808  glLineWidth(1);
809  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
810  Boundary viewPort = myChanger->getViewport();
811  float minB[2];
812  float maxB[2];
813  minB[0] = viewPort.xmin();
814  minB[1] = viewPort.ymin();
815  maxB[0] = viewPort.xmax();
816  maxB[1] = viewPort.ymax();
818  glEnable(GL_POLYGON_OFFSET_FILL);
819  glEnable(GL_POLYGON_OFFSET_LINE);
820  myGrid->Search(minB, maxB, *myVisualizationSettings);
821 
823  displayLegend();
824  }
825  state = gl2psEndPage();
826  glFinish();
827  }
828  fclose(fp);
829  } else {
830  doPaintGL(GL_RENDER, myChanger->getViewport());
832  displayLegend();
833  }
834  swapBuffers();
835  glFinish();
836  FXColor* buf;
837  FXMALLOC(&buf, FXColor, getWidth()*getHeight());
838  // read from the back buffer
839  glReadBuffer(GL_BACK);
840  // Read the pixels
841  glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
842  makeNonCurrent();
843  update();
844  // mirror
845  size_t mwidth = getWidth();
846  size_t mheight = getHeight();
847  FXColor* paa = buf;
848  FXColor* pbb = buf + mwidth * (mheight - 1);
849  do {
850  FXColor* pa = paa;
851  paa += mwidth;
852  FXColor* pb = pbb;
853  pbb -= mwidth;
854  do {
855  FXColor t = *pa;
856  *pa++ = *pb;
857  *pb++ = t;
858  } while (pa < paa);
859  } while (paa < pbb);
860  try {
861  if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
862  errorMessage = "Could not save '" + destFile + "'.";
863  }
864  } catch (InvalidArgument& e) {
865  errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
866  }
867  FXFREE(&buf);
868  }
869  return errorMessage;
870 }
871 
872 
873 void
875  std::map<SUMOTime, std::string>::iterator snapIt = mySnapshots.find(getCurrentTimeStep());
876  if (snapIt != mySnapshots.end()) {
877  std::string error = makeSnapshot(snapIt->second);
878  if (error != "") {
879  WRITE_WARNING(error);
880  }
881  }
882 }
883 
884 
885 void
887  if (myViewportChooser == 0) {
889  new GUIDialog_EditViewport(this, "Edit Viewport...",
891  0, 0);
892  myViewportChooser->create();
893  }
896  myViewportChooser->show();
897 }
898 
899 
900 void
902  myChanger->setViewport(zoom, xPos, yPos);
903  update();
904 }
905 
906 
907 void
909  myUseToolTips = val;
910 }
911 
912 
913 
914 SUMOReal
916  return myGrid->getWidth();
917 }
918 
919 
920 SUMOReal
922  return myGrid->getHeight();
923 }
924 
925 
926 FXComboBox&
929 }
930 
931 
932 void
934  glTranslated(0, 0, .99);
935  myDecalsLock.lock();
936  for (std::vector<GUISUMOAbstractView::Decal>::iterator l = myDecals.begin(); l != myDecals.end();) {
938  if (!d.initialised) {
939  try {
940  FXImage* i = MFXImageHelper::loadImage(getApp(), d.filename);
942  WRITE_WARNING("Scaling '" + d.filename + "'.");
943  }
945  d.initialised = true;
946  } catch (InvalidArgument& e) {
947  WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what());
948  l = myDecals.erase(l);
949  continue;
950  }
951  }
952  glPushMatrix();
953  glTranslated(d.centerX, d.centerY, 0);
954  glRotated(d.rot, 0, 0, 1);
955  glColor3d(1, 1, 1);
956  SUMOReal halfWidth((d.width / 2.));
957  SUMOReal halfHeight((d.height / 2.));
958  GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
959  glPopMatrix();
960  ++l;
961  }
963  glTranslated(0, 0, -.99);
964 }
965 
966 
967 // ------------ Additional visualisations
968 bool
970  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
971  myAdditionallyDrawn[which] = 1;
972  } else {
973  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
974  }
975  update();
976  return true;
977 }
978 
979 
980 bool
982  if (getTrackedID() == static_cast<int>(which->getGlID())) {
983  stopTrack();
984  }
985  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
986  return false;
987  }
988  int cnt = myAdditionallyDrawn[which];
989  if (cnt == 1) {
990  myAdditionallyDrawn.erase(which);
991  } else {
992  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
993  }
994  update();
995  return true;
996 }
997 
998 
999 void
1001  Boundary bound = myChanger->getViewport(fixRatio);
1002  glMatrixMode(GL_PROJECTION);
1003  glLoadIdentity();
1004  // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
1005  // thus, objects with a higher value will be closer (drawn on top)
1006  // // @todo last param should be 0 after modifying all glDraw methods
1007  glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
1008  glMatrixMode(GL_MODELVIEW);
1009  glLoadIdentity();
1010  SUMOReal scaleX = (SUMOReal)getWidth() / bound.getWidth();
1011  SUMOReal scaleY = (SUMOReal)getHeight() / bound.getHeight();
1012  glScaled(scaleX, scaleY, 1);
1013  glTranslated(-bound.xmin(), -bound.ymin(), 0);
1014 }
1015 
1016 /****************************************************************************/
1017