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