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 #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(
216  1);
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(0, 0, 0), RGBColor(1, 0.7, 0));
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  update();
470  }
472 }
473 
474 
475 void
477  myChanger->setViewport(bound);
478  update();
479 }
480 
481 /*
482 bool
483 GUISUMOAbstractView::allowRotation() const
484 {
485  return myParent->allowRotation();
486 }
487 */
488 
489 void
493 }
494 
495 
496 FXbool
498  FXbool ret = FXGLCanvas::makeCurrent();
499  return ret;
500 }
501 
502 
503 long
505  if (makeCurrent()) {
506  glViewport(0, 0, getWidth() - 1, getHeight() - 1);
507  glClearColor(
511  1);
512  doInit();
513  myAmInitialised = true;
514  makeNonCurrent();
515  checkSnapshots();
516  }
517  return 1;
518 }
519 
520 
521 long
523  if (!isEnabled() || !myAmInitialised) {
524  return 1;
525  }
526  if (makeCurrent()) {
527  paintGL();
528  makeNonCurrent();
529  }
530  return 1;
531 }
532 
533 
534 void
536  delete myPopup;
537  myPopup = 0;
538 }
539 
540 
541 long
542 GUISUMOAbstractView::onLeftBtnPress(FXObject*, FXSelector , void* data) {
543  destroyPopup();
544  FXEvent* e = (FXEvent*) data;
545  // check whether the selection-mode is activated
546  if (e->state & CONTROLMASK) {
547  // try to get the object-id if so
548  if (makeCurrent()) {
549  unsigned int id = getObjectUnderCursor();
550  if (id != 0) {
552  }
553  makeNonCurrent();
554  if (id != 0) {
555  // possibly, the selection-colouring is used,
556  // so we should update the screen again...
557  update();
558  }
559  }
560  }
561  myChanger->onLeftBtnPress(data);
562  grab();
563  return 1;
564 }
565 
566 
567 long
569  destroyPopup();
571  if (myApp->isGaming()) {
573  }
574  ungrab();
575  return 1;
576 }
577 
578 
579 long
580 GUISUMOAbstractView::onRightBtnPress(FXObject*, FXSelector , void* data) {
581  destroyPopup();
582  myChanger->onRightBtnPress(data);
583  grab();
584  return 1;
585 }
586 
587 
588 long
590  destroyPopup();
591  if (!myChanger->onRightBtnRelease(data) && !myApp->isGaming()) {
593  }
594  ungrab();
595  return 1;
596 }
597 
598 
599 long
600 GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector , void* data) {
601  myChanger->onMouseWheel(data);
602  return 1;
603 }
604 
605 
606 long
607 GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector , void* data) {
608  SUMOReal xpos = myChanger->getXPos();
609  SUMOReal ypos = myChanger->getYPos();
610  SUMOReal zoom = myChanger->getZoom();
612  myChanger->onMouseMove(data);
613  }
614  if (myViewportChooser != 0 &&
615  (xpos != myChanger->getXPos() || ypos != myChanger->getYPos() || zoom != myChanger->getZoom())) {
616 
619 
620  }
622  return 1;
623 }
624 
625 
626 long
627 GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector , void* /*data*/) {
628  return 1;
629 }
630 
631 
632 void
634  ungrab();
635  if (!isEnabled() || !myAmInitialised) {
636  return;
637  }
638  if (makeCurrent()) {
639  // initialise the select mode
640  unsigned int id = getObjectUnderCursor();
641  GUIGlObject* o = 0;
642  if (id != 0) {
644  } else {
646  }
647  if (o != 0) {
648  myPopup = o->getPopUpMenu(*myApp, *this);
649  int x, y;
650  FXuint b;
651  myApp->getCursorPosition(x, y, b);
652  myPopup->setX(x + myApp->getX());
653  myPopup->setY(y + myApp->getY());
654  myPopup->create();
655  myPopup->show();
658  }
659  makeNonCurrent();
660  }
661 }
662 
663 
664 long
665 GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* data) {
666  FXEvent* e = (FXEvent*) data;
667  if ((e->state & ALTMASK) != 0) {
668  setDefaultCursor(getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR));
669  grabKeyboard();
670  }
671  /*
672  switch(e->code) {
673  case KEY_Left:
674  myChanger->move((SUMOReal) -p2m((SUMOReal) getWidth()/10), 0);
675  break;
676  case KEY_Right:
677  myChanger->move((SUMOReal) p2m((SUMOReal) getWidth()/10), 0);
678  break;
679  case KEY_Up:
680  myChanger->move(0, (SUMOReal) -p2m((SUMOReal) getHeight()/10));
681  break;
682  case KEY_Down:
683  myChanger->move(0, (SUMOReal) p2m((SUMOReal) getHeight()/10));
684  break;
685  default:
686  break;
687  }
688  */
689  return FXGLCanvas::onKeyPress(o, sel, data);
690 }
691 
692 
693 long
694 GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* data) {
695  FXEvent* e = (FXEvent*) data;
696  if ((e->state & ALTMASK) == 0) {
697  ungrabKeyboard();
698  setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
699  }
700  return FXGLCanvas::onKeyRelease(o, sel, data);
701 }
702 
703 
704 // ------------ Dealing with snapshots
705 void
706 GUISUMOAbstractView::setSnapshots(std::map<SUMOTime, std::string> snaps) {
707  mySnapshots.insert(snaps.begin(), snaps.end());
708 }
709 
710 
711 std::string
712 GUISUMOAbstractView::makeSnapshot(const std::string& destFile) {
713  std::string errorMessage;
714  FXString ext = FXPath::extension(destFile.c_str());
715  bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
716 
717  for (int i = 0; i < 10 && !makeCurrent(); ++i) {
719  }
720  // draw
721  glClearColor(
725  1);
726  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
727  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
728 
730  glEnable(GL_DITHER);
731  } else {
732  glDisable(GL_DITHER);
733  }
735  glEnable(GL_BLEND);
736  glEnable(GL_POLYGON_SMOOTH);
737  glEnable(GL_LINE_SMOOTH);
738  } else {
739  glDisable(GL_BLEND);
740  glDisable(GL_POLYGON_SMOOTH);
741  glDisable(GL_LINE_SMOOTH);
742  }
743 
745 
746  if (useGL2PS) {
747  GLint format = GL2PS_PS;
748  if (ext == "ps") {
749  format = GL2PS_PS;
750  } else if (ext == "eps") {
751  format = GL2PS_EPS;
752  } else if (ext == "pdf") {
753  format = GL2PS_PDF;
754  } else if (ext == "tex") {
755  format = GL2PS_TEX;
756  } else if (ext == "svg") {
757  format = GL2PS_SVG;
758  } else if (ext == "pgf") {
759  format = GL2PS_PGF;
760  } else {
761  return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
762  }
763  FILE* fp = fopen(destFile.c_str(), "wb");
764  if (fp == 0) {
765  return "Could not save '" + destFile + "'.\n Could not open file for writing";
766  }
767  GLint buffsize = 0, state = GL2PS_OVERFLOW;
768  GLint viewport[4];
769  glGetIntegerv(GL_VIEWPORT, viewport);
770  while (state == GL2PS_OVERFLOW) {
771  buffsize += 1024 * 1024;
772  gl2psBeginPage(destFile.c_str(), "sumo-gui; http://sumo.sf.net", viewport, format, GL2PS_SIMPLE_SORT,
774  GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
775  glMatrixMode(GL_MODELVIEW);
776  glPushMatrix();
777  glDisable(GL_TEXTURE_2D);
778  glDisable(GL_ALPHA_TEST);
779  glDisable(GL_BLEND);
780  glEnable(GL_DEPTH_TEST);
781  // compute lane width
782  // draw decals (if not in grabbing mode)
783  if (!myUseToolTips) {
784  drawDecals();
786  paintGLGrid();
787  }
788  }
789  glLineWidth(1);
790  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
791  Boundary viewPort = myChanger->getViewport();
792  float minB[2];
793  float maxB[2];
794  minB[0] = viewPort.xmin();
795  minB[1] = viewPort.ymin();
796  maxB[0] = viewPort.xmax();
797  maxB[1] = viewPort.ymax();
799  glEnable(GL_POLYGON_OFFSET_FILL);
800  glEnable(GL_POLYGON_OFFSET_LINE);
801  myGrid->Search(minB, maxB, *myVisualizationSettings);
802 
804  displayLegend();
805  }
806  state = gl2psEndPage();
807  glFinish();
808  }
809  fclose(fp);
810  } else {
811  doPaintGL(GL_RENDER, myChanger->getViewport());
813  displayLegend();
814  }
815  swapBuffers();
816  glFinish();
817  FXColor* buf;
818  FXMALLOC(&buf, FXColor, getWidth()*getHeight());
819  // read from the back buffer
820  glReadBuffer(GL_BACK);
821  // Read the pixels
822  glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
823  makeNonCurrent();
824  update();
825  // mirror
826  size_t mwidth = getWidth();
827  size_t mheight = getHeight();
828  FXColor* paa = buf;
829  FXColor* pbb = buf + mwidth * (mheight - 1);
830  do {
831  FXColor* pa = paa;
832  paa += mwidth;
833  FXColor* pb = pbb;
834  pbb -= mwidth;
835  do {
836  FXColor t = *pa;
837  *pa++ = *pb;
838  *pb++ = t;
839  } while (pa < paa);
840  } while (paa < pbb);
841  try {
842  if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
843  errorMessage = "Could not save '" + destFile + "'.";
844  }
845  } catch (InvalidArgument& e) {
846  errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
847  }
848  FXFREE(&buf);
849  }
850  return errorMessage;
851 }
852 
853 
854 void
856  std::map<SUMOTime, std::string>::iterator snapIt = mySnapshots.find(getCurrentTimeStep());
857  if (snapIt != mySnapshots.end()) {
858  std::string error = makeSnapshot(snapIt->second);
859  if (error != "") {
860  WRITE_WARNING(error);
861  }
862  }
863 }
864 
865 
866 void
868  if (myViewportChooser == 0) {
870  new GUIDialog_EditViewport(this, "Edit Viewport...",
872  0, 0);
873  myViewportChooser->create();
874  }
877  myViewportChooser->show();
878 }
879 
880 
881 void
883  myChanger->setViewport(zoom, xPos, yPos);
884  update();
885 }
886 
887 
888 void
890  myUseToolTips = val;
891 }
892 
893 
894 
895 SUMOReal
897  return myGrid->getWidth();
898 }
899 
900 
901 SUMOReal
903  return myGrid->getHeight();
904 }
905 
906 
907 FXComboBox&
910 }
911 
912 
913 void
915  glPushName(0);
916  myDecalsLock.lock();
917  for (std::vector<GUISUMOAbstractView::Decal>::iterator l = myDecals.begin(); l != myDecals.end();) {
919  if (!d.initialised) {
920  try {
921  FXImage* i = MFXImageHelper::loadImage(getApp(), d.filename);
923  WRITE_WARNING("Scaling '" + d.filename + "'.");
924  }
926  d.initialised = true;
927  d.image = i;
928  } catch (InvalidArgument& e) {
929  WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what());
930  l = myDecals.erase(l);
931  continue;
932  }
933  }
934  glPushMatrix();
935  glTranslated(d.centerX, d.centerY, d.layer);
936  glRotated(d.rot, 0, 0, 1);
937  glColor3d(1, 1, 1);
938  SUMOReal halfWidth((d.width / 2.));
939  SUMOReal halfHeight((d.height / 2.));
940  GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
941  glPopMatrix();
942  ++l;
943  }
945  glPopName();
946 }
947 
948 
949 // ------------ Additional visualisations
950 bool
952  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
953  myAdditionallyDrawn[which] = 1;
954  } else {
955  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
956  }
957  update();
958  return true;
959 }
960 
961 
962 bool
964  if (getTrackedID() == static_cast<int>(which->getGlID())) {
965  stopTrack();
966  }
967  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
968  return false;
969  }
970  int cnt = myAdditionallyDrawn[which];
971  if (cnt == 1) {
972  myAdditionallyDrawn.erase(which);
973  } else {
974  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
975  }
976  update();
977  return true;
978 }
979 
980 
981 void
983  Boundary bound = myChanger->getViewport(fixRatio);
984  glMatrixMode(GL_PROJECTION);
985  glLoadIdentity();
986  // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
987  // thus, objects with a higher value will be closer (drawn on top)
988  // // @todo last param should be 0 after modifying all glDraw methods
989  glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
990  glMatrixMode(GL_MODELVIEW);
991  glLoadIdentity();
992  SUMOReal scaleX = (SUMOReal)getWidth() / bound.getWidth();
993  SUMOReal scaleY = (SUMOReal)getHeight() / bound.getHeight();
994  glScaled(scaleX, scaleY, 1);
995  glTranslated(-bound.xmin(), -bound.ymin(), 0);
996 }
997 
998 /****************************************************************************/
999