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 <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
592  destroyPopup();
593  if (!myChanger->onRightBtnRelease(data) && !myApp->isGaming()) {
595  }
596  ungrab();
597  return 1;
598 }
599 
600 
601 long
602 GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector , void* data) {
603  myChanger->onMouseWheel(data);
604  return 1;
605 }
606 
607 
608 long
609 GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector , void* data) {
610  SUMOReal xpos = myChanger->getXPos();
611  SUMOReal ypos = myChanger->getYPos();
612  SUMOReal zoom = myChanger->getZoom();
614  myChanger->onMouseMove(data);
615  }
616  if (myViewportChooser != 0 &&
617  (xpos != myChanger->getXPos() || ypos != myChanger->getYPos() || zoom != myChanger->getZoom())) {
619  }
621  return 1;
622 }
623 
624 
625 long
626 GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector , void* /*data*/) {
627  return 1;
628 }
629 
630 
631 void
633  ungrab();
634  if (!isEnabled() || !myAmInitialised) {
635  return;
636  }
637  if (makeCurrent()) {
638  // initialise the select mode
639  unsigned int id = getObjectUnderCursor();
640  GUIGlObject* o = 0;
641  if (id != 0) {
643  } else {
645  }
646  if (o != 0) {
647  myPopup = o->getPopUpMenu(*myApp, *this);
648  int x, y;
649  FXuint b;
650  myApp->getCursorPosition(x, y, b);
651  myPopup->setX(x + myApp->getX());
652  myPopup->setY(y + myApp->getY());
653  myPopup->create();
654  myPopup->show();
657  }
658  makeNonCurrent();
659  }
660 }
661 
662 
663 long
664 GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* data) {
665  FXEvent* e = (FXEvent*) data;
666  if ((e->state & ALTMASK) != 0) {
667  setDefaultCursor(getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR));
668  grabKeyboard();
669  }
670  /*
671  switch(e->code) {
672  case KEY_Left:
673  myChanger->move((SUMOReal) -p2m((SUMOReal) getWidth()/10), 0);
674  break;
675  case KEY_Right:
676  myChanger->move((SUMOReal) p2m((SUMOReal) getWidth()/10), 0);
677  break;
678  case KEY_Up:
679  myChanger->move(0, (SUMOReal) -p2m((SUMOReal) getHeight()/10));
680  break;
681  case KEY_Down:
682  myChanger->move(0, (SUMOReal) p2m((SUMOReal) getHeight()/10));
683  break;
684  default:
685  break;
686  }
687  */
688  return FXGLCanvas::onKeyPress(o, sel, data);
689 }
690 
691 
692 long
693 GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* data) {
694  FXEvent* e = (FXEvent*) data;
695  if ((e->state & ALTMASK) == 0) {
696  ungrabKeyboard();
697  setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
698  }
699  return FXGLCanvas::onKeyRelease(o, sel, data);
700 }
701 
702 
703 // ------------ Dealing with snapshots
704 void
705 GUISUMOAbstractView::setSnapshots(std::map<SUMOTime, std::string> snaps) {
706  mySnapshots.insert(snaps.begin(), snaps.end());
707 }
708 
709 
710 std::string
711 GUISUMOAbstractView::makeSnapshot(const std::string& destFile) {
712  std::string errorMessage;
713  FXString ext = FXPath::extension(destFile.c_str());
714  bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
715 
716  for (int i = 0; i < 10 && !makeCurrent(); ++i) {
718  }
719  // draw
720  glClearColor(
725  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
726  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
727 
729  glEnable(GL_DITHER);
730  } else {
731  glDisable(GL_DITHER);
732  }
734  glEnable(GL_BLEND);
735  glEnable(GL_POLYGON_SMOOTH);
736  glEnable(GL_LINE_SMOOTH);
737  } else {
738  glDisable(GL_BLEND);
739  glDisable(GL_POLYGON_SMOOTH);
740  glDisable(GL_LINE_SMOOTH);
741  }
742 
744 
745  if (useGL2PS) {
746  GLint format = GL2PS_PS;
747  if (ext == "ps") {
748  format = GL2PS_PS;
749  } else if (ext == "eps") {
750  format = GL2PS_EPS;
751  } else if (ext == "pdf") {
752  format = GL2PS_PDF;
753  } else if (ext == "tex") {
754  format = GL2PS_TEX;
755  } else if (ext == "svg") {
756  format = GL2PS_SVG;
757  } else if (ext == "pgf") {
758  format = GL2PS_PGF;
759  } else {
760  return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
761  }
762  FILE* fp = fopen(destFile.c_str(), "wb");
763  if (fp == 0) {
764  return "Could not save '" + destFile + "'.\n Could not open file for writing";
765  }
766  GLint buffsize = 0, state = GL2PS_OVERFLOW;
767  GLint viewport[4];
768  glGetIntegerv(GL_VIEWPORT, viewport);
769  while (state == GL2PS_OVERFLOW) {
770  buffsize += 1024 * 1024;
771  gl2psBeginPage(destFile.c_str(), "sumo-gui; http://sumo.sf.net", viewport, format, GL2PS_SIMPLE_SORT,
773  GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
774  glMatrixMode(GL_MODELVIEW);
775  glPushMatrix();
776  glDisable(GL_TEXTURE_2D);
777  glDisable(GL_ALPHA_TEST);
778  glDisable(GL_BLEND);
779  glEnable(GL_DEPTH_TEST);
780  // compute lane width
781  // draw decals (if not in grabbing mode)
782  if (!myUseToolTips) {
783  drawDecals();
785  paintGLGrid();
786  }
787  }
788  glLineWidth(1);
789  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
790  Boundary viewPort = myChanger->getViewport();
791  float minB[2];
792  float maxB[2];
793  minB[0] = viewPort.xmin();
794  minB[1] = viewPort.ymin();
795  maxB[0] = viewPort.xmax();
796  maxB[1] = viewPort.ymax();
798  glEnable(GL_POLYGON_OFFSET_FILL);
799  glEnable(GL_POLYGON_OFFSET_LINE);
800  myGrid->Search(minB, maxB, *myVisualizationSettings);
801 
803  displayLegend();
804  }
805  state = gl2psEndPage();
806  glFinish();
807  }
808  fclose(fp);
809  } else {
810  doPaintGL(GL_RENDER, myChanger->getViewport());
812  displayLegend();
813  }
814  swapBuffers();
815  glFinish();
816  FXColor* buf;
817  FXMALLOC(&buf, FXColor, getWidth()*getHeight());
818  // read from the back buffer
819  glReadBuffer(GL_BACK);
820  // Read the pixels
821  glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
822  makeNonCurrent();
823  update();
824  // mirror
825  size_t mwidth = getWidth();
826  size_t mheight = getHeight();
827  FXColor* paa = buf;
828  FXColor* pbb = buf + mwidth * (mheight - 1);
829  do {
830  FXColor* pa = paa;
831  paa += mwidth;
832  FXColor* pb = pbb;
833  pbb -= mwidth;
834  do {
835  FXColor t = *pa;
836  *pa++ = *pb;
837  *pb++ = t;
838  } while (pa < paa);
839  } while (paa < pbb);
840  try {
841  if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
842  errorMessage = "Could not save '" + destFile + "'.";
843  }
844  } catch (InvalidArgument& e) {
845  errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
846  }
847  FXFREE(&buf);
848  }
849  return errorMessage;
850 }
851 
852 
853 void
855  std::map<SUMOTime, std::string>::iterator snapIt = mySnapshots.find(getCurrentTimeStep());
856  if (snapIt != mySnapshots.end()) {
857  std::string error = makeSnapshot(snapIt->second);
858  if (error != "") {
859  WRITE_WARNING(error);
860  }
861  }
862 }
863 
864 
865 void
867  if (myVisualizationChanger == 0) {
872  myVisualizationChanger->create();
873  } else {
875  }
876  myVisualizationChanger->show();
877 }
878 
879 
880 void
882  if (myViewportChooser == 0) {
884  new GUIDialog_EditViewport(this, "Edit Viewport...", 0, 0);
885  myViewportChooser->create();
886  }
889  myViewportChooser->show();
890 }
891 
892 
893 void
894 GUISUMOAbstractView::setViewport(const Position& lookFrom, const Position& /* lookAt */) {
895  myChanger->setViewport(lookFrom.z(), lookFrom.x(), lookFrom.y());
896  update();
897 }
898 
899 
900 void
902  myUseToolTips = val;
903 }
904 
905 
906 
907 SUMOReal
909  return myGrid->getWidth();
910 }
911 
912 
913 SUMOReal
915  return myGrid->getHeight();
916 }
917 
918 
919 FXComboBox&
922 }
923 
924 
925 FXImage*
927 #ifdef HAVE_GDAL
928  GDALAllRegister();
929  GDALDataset* poDataset = (GDALDataset*)GDALOpen(d.filename.c_str(), GA_ReadOnly);
930  if (poDataset == 0) {
931  return 0;
932  }
933  const int xSize = poDataset->GetRasterXSize();
934  const int ySize = poDataset->GetRasterYSize();
935  // checking for geodata in the picture and try to adapt position and scale
936  if (d.width <= 0.) {
937  double adfGeoTransform[6];
938  if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
939  Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
940  const double horizontalSize = xSize * adfGeoTransform[1];
941  const double verticalSize = ySize * adfGeoTransform[5];
942  Position bottomRight(topLeft.x() + horizontalSize, topLeft.y() + verticalSize);
944  d.width = bottomRight.x() - topLeft.x();
945  d.height = topLeft.y() - bottomRight.y();
946  d.centerX = (topLeft.x() + bottomRight.x()) / 2;
947  d.centerY = (topLeft.y() + bottomRight.y()) / 2;
948  //WRITE_MESSAGE("proj: " + toString(poDataset->GetProjectionRef()) + " dim: " + toString(d.width) + "," + toString(d.height) + " center: " + toString(d.centerX) + "," + toString(d.centerY));
949  } else {
950  WRITE_WARNING("Could not convert coordinates in " + d.filename + ".");
951  }
952  }
953  }
954 #endif
955  if (d.width <= 0.) {
956  d.width = getGridWidth();
957  d.height = getGridHeight();
958  }
959 
960  // trying to read the picture
961 #ifdef HAVE_GDAL
962  const int picSize = xSize * ySize;
963  FXColor* result;
964  if (!FXMALLOC(&result, FXColor, picSize)) {
965  WRITE_WARNING("Could not allocate memory for " + d.filename + ".");
966  return 0;
967  }
968  for (int j = 0; j < picSize; j++) {
969  result[j] = FXRGB(0, 0, 0);
970  }
971  bool valid = true;
972  for (int i = 1; i <= poDataset->GetRasterCount(); i++) {
973  GDALRasterBand* poBand = poDataset->GetRasterBand(i);
974  int shift = -1;
975  if (poBand->GetColorInterpretation() == GCI_RedBand) {
976  shift = 0;
977  } else if (poBand->GetColorInterpretation() == GCI_GreenBand) {
978  shift = 1;
979  } else if (poBand->GetColorInterpretation() == GCI_BlueBand) {
980  shift = 2;
981  } else if (poBand->GetColorInterpretation() == GCI_AlphaBand) {
982  shift = 3;
983  } else {
984  WRITE_MESSAGE("Unknown color band in " + d.filename + ", maybe fox can parse it.");
985  valid = false;
986  break;
987  }
988  assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
989  if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, ((unsigned char*)result) + shift, xSize, ySize, GDT_Byte, 4, 4 * xSize) == CE_Failure) {
990  valid = false;
991  break;
992  }
993  }
994  GDALClose(poDataset);
995  if (valid) {
996  return new FXImage(getApp(), result, IMAGE_OWNED | IMAGE_KEEP | IMAGE_SHMI | IMAGE_SHMP, xSize, ySize);
997  }
998  FXFREE(&result);
999 #endif
1000  return 0;
1001 }
1002 
1003 
1004 void
1006  glPushName(0);
1007  myDecalsLock.lock();
1008  for (std::vector<GUISUMOAbstractView::Decal>::iterator l = myDecals.begin(); l != myDecals.end(); ++l) {
1010  if (d.skip2D) {
1011  continue;
1012  }
1013  if (!d.initialised) {
1014  try {
1015  FXImage* img = checkGDALImage(d);
1016  if (img == 0) {
1017  img = MFXImageHelper::loadImage(getApp(), d.filename);
1018  }
1020  WRITE_WARNING("Scaling '" + d.filename + "'.");
1021  }
1022  d.glID = GUITexturesHelper::add(img);
1023  d.initialised = true;
1024  d.image = img;
1025  } catch (InvalidArgument& e) {
1026  WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what());
1027  d.skip2D = true;
1028  }
1029  }
1030  glPushMatrix();
1031  glTranslated(d.centerX, d.centerY, d.layer);
1032  glRotated(d.rot, 0, 0, 1);
1033  glColor3d(1, 1, 1);
1034  const SUMOReal halfWidth = d.width / 2.;
1035  const SUMOReal halfHeight = d.height / 2.;
1036  GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
1037  glPopMatrix();
1038  }
1039  myDecalsLock.unlock();
1040  glPopName();
1041 }
1042 
1043 
1044 // ------------ Additional visualisations
1045 bool
1047  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1048  myAdditionallyDrawn[which] = 1;
1049  } else {
1050  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
1051  }
1052  update();
1053  return true;
1054 }
1055 
1056 
1057 bool
1059  if (getTrackedID() == static_cast<int>(which->getGlID())) {
1060  stopTrack();
1061  }
1062  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1063  return false;
1064  }
1065  int cnt = myAdditionallyDrawn[which];
1066  if (cnt == 1) {
1067  myAdditionallyDrawn.erase(which);
1068  } else {
1069  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
1070  }
1071  update();
1072  return true;
1073 }
1074 
1075 
1076 void
1078  Boundary bound = myChanger->getViewport(fixRatio);
1079  glMatrixMode(GL_PROJECTION);
1080  glLoadIdentity();
1081  // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
1082  // thus, objects with a higher value will be closer (drawn on top)
1083  // // @todo last param should be 0 after modifying all glDraw methods
1084  glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
1085  glMatrixMode(GL_MODELVIEW);
1086  glLoadIdentity();
1087  SUMOReal scaleX = (SUMOReal)getWidth() / bound.getWidth();
1088  SUMOReal scaleY = (SUMOReal)getHeight() / bound.getHeight();
1089  glScaled(scaleX, scaleY, 1);
1090  glTranslated(-bound.xmin(), -bound.ymin(), 0);
1091 }
1092 
1093 /****************************************************************************/
1094