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-sim.org/
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 <foreign/gl2ps/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 HAVE_GDAL
72 #include <gdal_priv.h>
73 #endif
74 
75 #ifdef CHECK_MEMORY_LEAKS
76 #include <foreign/nvwa/debug_new.h>
77 #endif // CHECK_MEMORY_LEAKS
78 
79 
80 // ===========================================================================
81 // member method definitions
82 // ===========================================================================
83 /* -------------------------------------------------------------------------
84  * GUISUMOAbstractView - FOX callback mapping
85  * ----------------------------------------------------------------------- */
86 FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[] = {
87  FXMAPFUNC(SEL_CONFIGURE, 0, GUISUMOAbstractView::onConfigure),
88  FXMAPFUNC(SEL_PAINT, 0, GUISUMOAbstractView::onPaint),
89  FXMAPFUNC(SEL_LEFTBUTTONPRESS, 0, GUISUMOAbstractView::onLeftBtnPress),
90  FXMAPFUNC(SEL_LEFTBUTTONRELEASE, 0, GUISUMOAbstractView::onLeftBtnRelease),
91  FXMAPFUNC(SEL_MIDDLEBUTTONPRESS, 0, GUISUMOAbstractView::onMiddleBtnPress),
92  FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE, 0, GUISUMOAbstractView::onMiddleBtnRelease),
93  FXMAPFUNC(SEL_RIGHTBUTTONPRESS, 0, GUISUMOAbstractView::onRightBtnPress),
94  FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, 0, GUISUMOAbstractView::onRightBtnRelease),
95  FXMAPFUNC(SEL_MOUSEWHEEL, 0, GUISUMOAbstractView::onMouseWheel),
96  FXMAPFUNC(SEL_MOTION, 0, GUISUMOAbstractView::onMouseMove),
97  FXMAPFUNC(SEL_LEAVE, 0, GUISUMOAbstractView::onMouseLeft),
98  FXMAPFUNC(SEL_KEYPRESS, 0, GUISUMOAbstractView::onKeyPress),
99  FXMAPFUNC(SEL_KEYRELEASE, 0, GUISUMOAbstractView::onKeyRelease),
100 
101 };
102 
103 
104 FXIMPLEMENT_ABSTRACT(GUISUMOAbstractView, FXGLCanvas, GUISUMOAbstractViewMap, ARRAYNUMBER(GUISUMOAbstractViewMap))
105 
106 
107 /* -------------------------------------------------------------------------
108  * GUISUMOAbstractView - methods
109  * ----------------------------------------------------------------------- */
111  GUIMainWindow& app,
112  GUIGlChildWindow* parent,
113  const SUMORTree& grid,
114  FXGLVisual* glVis, FXGLCanvas* share)
115  : FXGLCanvas(p, glVis, share, p, MID_GLCANVAS,
116  LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0),
117  myApp(&app),
118  myParent(parent),
119  myGrid(&((SUMORTree&)grid)),
120  myChanger(0),
121  myMouseHotspotX(app.getDefaultCursor()->getHotX()),
122  myMouseHotspotY(app.getDefaultCursor()->getHotY()),
123  myPopup(0),
124  myUseToolTips(false),
125  myAmInitialised(false),
126  myViewportChooser(0),
127  myVisualizationChanger(0) {
128  setTarget(this);
129  enable();
130  flags |= FLAG_ENABLED;
131  myInEditMode = false;
132  // show the middle at the beginning
133  myChanger = new GUIDanielPerspectiveChanger(*this, *myGrid);
134  myVisualizationSettings = &gSchemeStorage.getDefault();
135  myVisualizationSettings->gaming = myApp->isGaming();
137 }
138 
139 
143  delete myPopup;
144  delete myChanger;
145  delete myViewportChooser;
146  delete myVisualizationChanger;
147  // cleanup decals
148  for (std::vector<GUISUMOAbstractView::Decal>::iterator it = myDecals.begin(); it != myDecals.end(); ++it) {
149  delete it->image;
150  }
151 }
152 
153 
154 bool
156  return myInEditMode;
157 }
158 
159 
160 void
162  if (!myUseToolTips) {
163  return;
164  }
165  update();
166 }
167 
168 
169 Position
171  Boundary bound = myChanger->getViewport();
172  SUMOReal x = bound.xmin() + bound.getWidth() * myWindowCursorPositionX / getWidth();
173  // cursor origin is in the top-left corner
174  SUMOReal y = bound.ymin() + bound.getHeight() * (getHeight() - myWindowCursorPositionY) / getHeight();
175  return Position(x, y);
176 }
177 
178 
179 void
182  std::string text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y());
183  myApp->getCartesianLabel().setText(text.c_str());
185  if (GeoConvHelper::getFinal().usingGeoProjection()) {
186  text = "lat:" + toString(pos.y(), GEO_OUTPUT_ACCURACY) + ", lon:" + toString(pos.x(), GEO_OUTPUT_ACCURACY);
187  } else {
188  text = "x:" + toString(pos.x()) + ", y:" + toString(pos.y());
189  }
190  myApp->getGeoLabel().setText(text.c_str());
191 }
192 
193 
194 Boundary
196  return myChanger->getViewport();
197 }
198 
199 void
201  if (getWidth() == 0 || getHeight() == 0) {
202  return;
203  }
204 
205  if (getTrackedID() > 0) {
206  centerTo(getTrackedID(), false);
207  }
208 
209  unsigned int id = 0;
210  if (myUseToolTips) {
211  id = getObjectUnderCursor();
212  }
213 
214  // draw
215  glClearColor(
220  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
221  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
222 
224  glEnable(GL_DITHER);
225  } else {
226  glDisable(GL_DITHER);
227  }
229  glEnable(GL_BLEND);
230  glEnable(GL_POLYGON_SMOOTH);
231  glEnable(GL_LINE_SMOOTH);
232  } else {
233  glDisable(GL_BLEND);
234  glDisable(GL_POLYGON_SMOOTH);
235  glDisable(GL_LINE_SMOOTH);
236  }
237 
239  doPaintGL(GL_RENDER, myChanger->getViewport());
241  displayLegend();
242  }
243  // check whether the select mode /tooltips)
244  // shall be computed, too
245  if (myUseToolTips && id != 0) {
246  showToolTipFor(id);
247  }
248  swapBuffers();
249 }
250 
251 
252 GUIGlID
255 }
256 
257 
258 GUIGlID
260  const SUMOReal SENSITIVITY = 0.1; // meters
261  Boundary selection;
262  selection.add(pos);
263  selection.grow(SENSITIVITY);
264  const std::vector<GUIGlID> ids = getObjectsInBoundary(selection);
265  // Interpret results
266  unsigned int idMax = 0;
268  for (std::vector<GUIGlID>::const_iterator it = ids.begin(); it != ids.end(); it++) {
269  GUIGlID id = *it;
271  if (o == 0) {
272  continue;
273  }
274  if (o->getGlID() == 0) {
275  continue;
276  }
277  //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
278  GUIGlObjectType type = o->getType();
279  if (type != 0) {
280  SUMOReal layer = (SUMOReal)type;
281  // determine an "abstract" layer for shapes
282  // this "layer" resembles the layer of the shape
283  // taking into account the stac of other objects
284  if (type == GLO_POI || type == GLO_POLYGON) {
285  layer = dynamic_cast<Shape*>(o)->getLayer();
286  }
287  // check whether the current object is above a previous one
288  if (layer > maxLayer) {
289  idMax = id;
290  maxLayer = layer;
291  }
292  }
294  }
295  return idMax;
296 }
297 
298 
299 std::vector<GUIGlID>
301  const int NB_HITS_MAX = 1024 * 1024;
302  // Prepare the selection mode
303  static GUIGlID hits[NB_HITS_MAX];
304  static GLint nb_hits = 0;
305  glSelectBuffer(NB_HITS_MAX, hits);
306  glInitNames();
307 
308  Boundary oldViewPort = myChanger->getViewport(false); // backup the actual viewPort
309  myChanger->setViewport(bound);
310  applyGLTransform(false);
311 
312  // paint in select mode
313  int hits2 = doPaintGL(GL_SELECT, bound);
314  // Get the results
315  nb_hits = glRenderMode(GL_RENDER);
316  if (nb_hits == -1) {
317  myApp->setStatusBarText("Selection in boundary failed. Try to select fewer than " + toString(hits2) + " items");
318  }
319  std::vector<GUIGlID> result;
320  for (int i = 0; i < nb_hits; ++i) {
321  assert(i * 4 + 3 < NB_HITS_MAX);
322  result.push_back(hits[i * 4 + 3]);
323  }
324  // switch viewport back to normal
325  myChanger->setViewport(oldViewPort);
326  return result;
327 }
328 
329 
330 void
332  if (id != 0) {
334  if (object != 0) {
336  pos.add(0, p2m(15));
337  GLHelper::drawTextBox(object->getFullName(), pos, GLO_MAX - 1, p2m(20), RGBColor::BLACK, RGBColor(255, 179, 0, 255));
339  }
340  }
341 }
342 
343 
344 void
346  glEnable(GL_DEPTH_TEST);
347  glLineWidth(1);
348 
349  SUMOReal xmin = myGrid->xmin();
350  SUMOReal ymin = myGrid->ymin();
351  SUMOReal ypos = ymin;
352  SUMOReal xpos = xmin;
353  SUMOReal xend = myGrid->xmax();
354  SUMOReal yend = myGrid->ymax();
355 
356  glTranslated(0, 0, .55);
357  glColor3d(0.5, 0.5, 0.5);
358  // draw horizontal lines
359  glBegin(GL_LINES);
360  for (; ypos < yend;) {
361  glVertex2d(xmin, ypos);
362  glVertex2d(xend, ypos);
364  }
365  // draw vertical lines
366  for (; xpos < xend;) {
367  glVertex2d(xpos, ymin);
368  glVertex2d(xpos, yend);
370  }
371  glEnd();
372  glTranslated(0, 0, -.55);
373 }
374 
375 
376 void
378  // compute the scale bar length
379  size_t length = 1;
380  const std::string text("10000000000");
381  size_t noDigits = 1;
382  size_t pixelSize = (size_t) m2p((SUMOReal) length);
383  while (pixelSize <= 20) {
384  length *= 10;
385  noDigits++;
386  if (noDigits > text.length()) {
387  return;
388  }
389  pixelSize = (size_t) m2p((SUMOReal) length);
390  }
391  SUMOReal lineWidth = 1.0;
392  glLineWidth((SUMOReal) lineWidth);
393 
394  glMatrixMode(GL_PROJECTION);
395  glPushMatrix();
396  glLoadIdentity();
397  glMatrixMode(GL_MODELVIEW);
398  glPushMatrix();
399  glLoadIdentity();
400 
401  // draw the scale bar
402  glDisable(GL_TEXTURE_2D);
403  glDisable(GL_ALPHA_TEST);
404  glDisable(GL_BLEND);
405  glEnable(GL_DEPTH_TEST);
406 
407  SUMOReal len = (SUMOReal) pixelSize / (SUMOReal)(getWidth() - 1) * (SUMOReal) 2.0;
408  glColor3d(0, 0, 0);
409  double o = double(15) / double(getHeight());
410  double o2 = o + o;
411  double oo = double(5) / double(getHeight());
412  glBegin(GL_LINES);
413  // vertical
414  glVertex2d(-.98, -1. + o);
415  glVertex2d(-.98 + len, -1. + o);
416  // tick at begin
417  glVertex2d(-.98, -1. + o);
418  glVertex2d(-.98, -1. + o2);
419  // tick at end
420  glVertex2d(-.98 + len, -1. + o);
421  glVertex2d(-.98 + len, -1. + o2);
422  glEnd();
423 
424  SUMOReal w = SUMOReal(35) / SUMOReal(getWidth());
425  SUMOReal h = SUMOReal(35) / SUMOReal(getHeight());
426  pfSetPosition(SUMOReal(-0.99), SUMOReal(1. - o2 - oo));
427  pfSetScaleXY(w, h);
428  glRotated(180, 1, 0, 0);
429  pfDrawString("0m");
430  glRotated(-180, 1, 0, 0);
431 
432  pfSetPosition(SUMOReal(-.99 + len), SUMOReal(1. - o2 - oo));
433  glRotated(180, 1, 0, 0);
434  pfDrawString((text.substr(0, noDigits) + "m").c_str());
435  glRotated(-180, 1, 0, 0);
436 
437  // restore matrices
438  glMatrixMode(GL_PROJECTION);
439  glPopMatrix();
440  glMatrixMode(GL_MODELVIEW);
441  glPopMatrix();
442 }
443 
444 
445 SUMOReal
447  return meter * getWidth() / myChanger->getViewport().getWidth();
448 }
449 
450 
451 SUMOReal
453  return pixel * myChanger->getViewport().getWidth() / getWidth();
454 }
455 
456 
457 void
460 }
461 
462 
463 void
464 GUISUMOAbstractView::centerTo(GUIGlID id, bool applyZoom, SUMOReal zoomDist) {
466  if (o != 0 && dynamic_cast<GUIGlObject*>(o) != 0) {
467  if (applyZoom && zoomDist < 0) {
469  } else {
470  myChanger->centerTo(o->getCenteringBoundary().getCenter(), zoomDist, applyZoom);
471  }
472  }
474 }
475 
476 
477 void
479  myChanger->setViewport(bound);
480  update();
481 }
482 
483 /*
484 bool
485 GUISUMOAbstractView::allowRotation() const
486 {
487  return myParent->allowRotation();
488 }
489 */
490 
491 void
495 }
496 
497 
498 FXbool
500  FXbool ret = FXGLCanvas::makeCurrent();
501  return ret;
502 }
503 
504 
505 long
507  if (makeCurrent()) {
508  glViewport(0, 0, getWidth() - 1, getHeight() - 1);
509  glClearColor(
514  doInit();
515  myAmInitialised = true;
516  makeNonCurrent();
517  checkSnapshots();
518  }
519  return 1;
520 }
521 
522 
523 long
525  if (!isEnabled() || !myAmInitialised) {
526  return 1;
527  }
528  if (makeCurrent()) {
529  paintGL();
530  makeNonCurrent();
531  }
532  return 1;
533 }
534 
535 
536 void
538  delete myPopup;
539  myPopup = 0;
540 }
541 
542 
543 long
544 GUISUMOAbstractView::onLeftBtnPress(FXObject*, FXSelector , void* data) {
545  destroyPopup();
546  FXEvent* e = (FXEvent*) data;
547  // check whether the selection-mode is activated
548  if (e->state & CONTROLMASK) {
549  // try to get the object-id if so
550  if (makeCurrent()) {
551  unsigned int id = getObjectUnderCursor();
552  if (id != 0) {
554  }
555  makeNonCurrent();
556  if (id != 0) {
557  // possibly, the selection-colouring is used,
558  // so we should update the screen again...
559  update();
560  }
561  }
562  }
563  myChanger->onLeftBtnPress(data);
564  grab();
565  return 1;
566 }
567 
568 
569 long
571  destroyPopup();
573  if (myApp->isGaming()) {
575  }
576  ungrab();
577  return 1;
578 }
579 
580 
581 long
582 GUISUMOAbstractView::onRightBtnPress(FXObject*, FXSelector , void* data) {
583  destroyPopup();
584  myChanger->onRightBtnPress(data);
585  grab();
586  return 1;
587 }
588 
589 
590 long
591 GUISUMOAbstractView::onRightBtnRelease(FXObject* o, FXSelector sel, void* data) {
592  destroyPopup();
593  onMouseMove(o, sel, data);
594  if (!myChanger->onRightBtnRelease(data) && !myApp->isGaming()) {
596  }
597  ungrab();
598  return 1;
599 }
600 
601 
602 long
603 GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector , void* data) {
604  myChanger->onMouseWheel(data);
605  return 1;
606 }
607 
608 
609 long
610 GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector , void* data) {
611  SUMOReal xpos = myChanger->getXPos();
612  SUMOReal ypos = myChanger->getYPos();
613  SUMOReal zoom = myChanger->getZoom();
615  myChanger->onMouseMove(data);
616  }
617  if (myViewportChooser != 0 &&
618  (xpos != myChanger->getXPos() || ypos != myChanger->getYPos() || zoom != myChanger->getZoom())) {
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(
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-sim.org", 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 (myVisualizationChanger == 0) {
873  myVisualizationChanger->create();
874  } else {
876  }
877  myVisualizationChanger->show();
878 }
879 
880 
881 void
883  if (myViewportChooser == 0) {
885  new GUIDialog_EditViewport(this, "Edit Viewport...", 0, 0);
886  myViewportChooser->create();
887  }
890  myViewportChooser->show();
891 }
892 
893 
894 void
895 GUISUMOAbstractView::setViewport(const Position& lookFrom, const Position& /* lookAt */) {
896  myChanger->setViewport(lookFrom.z(), lookFrom.x(), lookFrom.y());
897  update();
898 }
899 
900 
901 void
903  myUseToolTips = val;
904 }
905 
906 
907 
908 SUMOReal
910  return myGrid->getWidth();
911 }
912 
913 
914 SUMOReal
916  return myGrid->getHeight();
917 }
918 
919 
920 FXComboBox&
923 }
924 
925 
926 FXImage*
928 #ifdef HAVE_GDAL
929  GDALAllRegister();
930  GDALDataset* poDataset = (GDALDataset*)GDALOpen(d.filename.c_str(), GA_ReadOnly);
931  if (poDataset == 0) {
932  return 0;
933  }
934  const int xSize = poDataset->GetRasterXSize();
935  const int ySize = poDataset->GetRasterYSize();
936  // checking for geodata in the picture and try to adapt position and scale
937  if (d.width <= 0.) {
938  double adfGeoTransform[6];
939  if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
940  Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
941  const double horizontalSize = xSize * adfGeoTransform[1];
942  const double verticalSize = ySize * adfGeoTransform[5];
943  Position bottomRight(topLeft.x() + horizontalSize, topLeft.y() + verticalSize);
945  d.width = bottomRight.x() - topLeft.x();
946  d.height = topLeft.y() - bottomRight.y();
947  d.centerX = (topLeft.x() + bottomRight.x()) / 2;
948  d.centerY = (topLeft.y() + bottomRight.y()) / 2;
949  //WRITE_MESSAGE("proj: " + toString(poDataset->GetProjectionRef()) + " dim: " + toString(d.width) + "," + toString(d.height) + " center: " + toString(d.centerX) + "," + toString(d.centerY));
950  } else {
951  WRITE_WARNING("Could not convert coordinates in " + d.filename + ".");
952  }
953  }
954  }
955 #endif
956  if (d.width <= 0.) {
957  d.width = getGridWidth();
958  d.height = getGridHeight();
959  }
960 
961  // trying to read the picture
962 #ifdef HAVE_GDAL
963  const int picSize = xSize * ySize;
964  FXColor* result;
965  if (!FXMALLOC(&result, FXColor, picSize)) {
966  WRITE_WARNING("Could not allocate memory for " + d.filename + ".");
967  return 0;
968  }
969  for (int j = 0; j < picSize; j++) {
970  result[j] = FXRGB(0, 0, 0);
971  }
972  bool valid = true;
973  for (int i = 1; i <= poDataset->GetRasterCount(); i++) {
974  GDALRasterBand* poBand = poDataset->GetRasterBand(i);
975  int shift = -1;
976  if (poBand->GetColorInterpretation() == GCI_RedBand) {
977  shift = 0;
978  } else if (poBand->GetColorInterpretation() == GCI_GreenBand) {
979  shift = 1;
980  } else if (poBand->GetColorInterpretation() == GCI_BlueBand) {
981  shift = 2;
982  } else if (poBand->GetColorInterpretation() == GCI_AlphaBand) {
983  shift = 3;
984  } else {
985  WRITE_MESSAGE("Unknown color band in " + d.filename + ", maybe fox can parse it.");
986  valid = false;
987  break;
988  }
989  assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
990  if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, ((unsigned char*)result) + shift, xSize, ySize, GDT_Byte, 4, 4 * xSize) == CE_Failure) {
991  valid = false;
992  break;
993  }
994  }
995  GDALClose(poDataset);
996  if (valid) {
997  return new FXImage(getApp(), result, IMAGE_OWNED | IMAGE_KEEP | IMAGE_SHMI | IMAGE_SHMP, xSize, ySize);
998  }
999  FXFREE(&result);
1000 #endif
1001  return 0;
1002 }
1003 
1004 
1005 void
1007  glPushName(0);
1008  myDecalsLock.lock();
1009  for (std::vector<GUISUMOAbstractView::Decal>::iterator l = myDecals.begin(); l != myDecals.end(); ++l) {
1011  if (d.skip2D) {
1012  continue;
1013  }
1014  if (!d.initialised) {
1015  try {
1016  FXImage* img = checkGDALImage(d);
1017  if (img == 0) {
1018  img = MFXImageHelper::loadImage(getApp(), d.filename);
1019  }
1021  WRITE_WARNING("Scaling '" + d.filename + "'.");
1022  }
1023  d.glID = GUITexturesHelper::add(img);
1024  d.initialised = true;
1025  d.image = img;
1026  } catch (InvalidArgument& e) {
1027  WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what());
1028  d.skip2D = true;
1029  }
1030  }
1031  glPushMatrix();
1032  glTranslated(d.centerX, d.centerY, d.layer);
1033  glRotated(d.rot, 0, 0, 1);
1034  glColor3d(1, 1, 1);
1035  const SUMOReal halfWidth = d.width / 2.;
1036  const SUMOReal halfHeight = d.height / 2.;
1037  GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
1038  glPopMatrix();
1039  }
1040  myDecalsLock.unlock();
1041  glPopName();
1042 }
1043 
1044 
1045 // ------------ Additional visualisations
1046 bool
1048  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1049  myAdditionallyDrawn[which] = 1;
1050  } else {
1051  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
1052  }
1053  update();
1054  return true;
1055 }
1056 
1057 
1058 bool
1060  if (getTrackedID() == static_cast<int>(which->getGlID())) {
1061  stopTrack();
1062  }
1063  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1064  return false;
1065  }
1066  int cnt = myAdditionallyDrawn[which];
1067  if (cnt == 1) {
1068  myAdditionallyDrawn.erase(which);
1069  } else {
1070  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
1071  }
1072  update();
1073  return true;
1074 }
1075 
1076 
1077 void
1079  Boundary bound = myChanger->getViewport(fixRatio);
1080  glMatrixMode(GL_PROJECTION);
1081  glLoadIdentity();
1082  // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
1083  // thus, objects with a higher value will be closer (drawn on top)
1084  // // @todo last param should be 0 after modifying all glDraw methods
1085  glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
1086  glMatrixMode(GL_MODELVIEW);
1087  glLoadIdentity();
1088  SUMOReal scaleX = (SUMOReal)getWidth() / bound.getWidth();
1089  SUMOReal scaleY = (SUMOReal)getHeight() / bound.getHeight();
1090  glScaled(scaleX, scaleY, 1);
1091  glTranslated(-bound.xmin(), -bound.ymin(), 0);
1092 }
1093 
1094 /****************************************************************************/
1095