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-2014 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  Boundary selection;
302  selection.add(pos);
303  selection.grow(radius);
304  const std::vector<GUIGlID> ids = getObjectsInBoundary(selection);
305  std::vector<GUIGlID> result;
306  // Interpret results
307  for (std::vector<GUIGlID>::const_iterator it = ids.begin(); it != ids.end(); it++) {
308  GUIGlID id = *it;
310  if (o == 0) {
311  continue;
312  }
313  if (o->getGlID() == 0) {
314  continue;
315  }
316  //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
317  GUIGlObjectType type = o->getType();
318  if (type != 0) {
319  result.push_back(id);
320  }
322  }
323  return result;
324 }
325 
326 
327 std::vector<GUIGlID>
329  const int NB_HITS_MAX = 1024 * 1024;
330  // Prepare the selection mode
331  static GUIGlID hits[NB_HITS_MAX];
332  static GLint nb_hits = 0;
333  glSelectBuffer(NB_HITS_MAX, hits);
334  glInitNames();
335 
336  Boundary oldViewPort = myChanger->getViewport(false); // backup the actual viewPort
337  myChanger->setViewport(bound);
338  applyGLTransform(false);
339 
340  // paint in select mode
341  int hits2 = doPaintGL(GL_SELECT, bound);
342  // Get the results
343  nb_hits = glRenderMode(GL_RENDER);
344  if (nb_hits == -1) {
345  myApp->setStatusBarText("Selection in boundary failed. Try to select fewer than " + toString(hits2) + " items");
346  }
347  std::vector<GUIGlID> result;
348  for (int i = 0; i < nb_hits; ++i) {
349  assert(i * 4 + 3 < NB_HITS_MAX);
350  result.push_back(hits[i * 4 + 3]);
351  }
352  // switch viewport back to normal
353  myChanger->setViewport(oldViewPort);
354  return result;
355 }
356 
357 
358 void
360  if (id != 0) {
362  if (object != 0) {
364  pos.add(0, p2m(15));
365  GLHelper::drawTextBox(object->getFullName(), pos, GLO_MAX - 1, p2m(20), RGBColor::BLACK, RGBColor(255, 179, 0, 255));
367  }
368  }
369 }
370 
371 
372 void
374  glEnable(GL_DEPTH_TEST);
375  glLineWidth(1);
376 
377  SUMOReal xmin = myGrid->xmin();
378  SUMOReal ymin = myGrid->ymin();
379  SUMOReal ypos = ymin;
380  SUMOReal xpos = xmin;
381  SUMOReal xend = myGrid->xmax();
382  SUMOReal yend = myGrid->ymax();
383 
384  glTranslated(0, 0, .55);
385  glColor3d(0.5, 0.5, 0.5);
386  // draw horizontal lines
387  glBegin(GL_LINES);
388  for (; ypos < yend;) {
389  glVertex2d(xmin, ypos);
390  glVertex2d(xend, ypos);
392  }
393  // draw vertical lines
394  for (; xpos < xend;) {
395  glVertex2d(xpos, ymin);
396  glVertex2d(xpos, yend);
398  }
399  glEnd();
400  glTranslated(0, 0, -.55);
401 }
402 
403 
404 void
406  // compute the scale bar length
407  size_t length = 1;
408  const std::string text("10000000000");
409  size_t noDigits = 1;
410  size_t pixelSize = (size_t) m2p((SUMOReal) length);
411  while (pixelSize <= 20) {
412  length *= 10;
413  noDigits++;
414  if (noDigits > text.length()) {
415  return;
416  }
417  pixelSize = (size_t) m2p((SUMOReal) length);
418  }
419  SUMOReal lineWidth = 1.0;
420  glLineWidth((SUMOReal) lineWidth);
421 
422  glMatrixMode(GL_PROJECTION);
423  glPushMatrix();
424  glLoadIdentity();
425  glMatrixMode(GL_MODELVIEW);
426  glPushMatrix();
427  glLoadIdentity();
428 
429  // draw the scale bar
430  glDisable(GL_TEXTURE_2D);
431  glDisable(GL_ALPHA_TEST);
432  glDisable(GL_BLEND);
433  glEnable(GL_DEPTH_TEST);
434 
435  SUMOReal len = (SUMOReal) pixelSize / (SUMOReal)(getWidth() - 1) * (SUMOReal) 2.0;
436  glColor3d(0, 0, 0);
437  double o = double(15) / double(getHeight());
438  double o2 = o + o;
439  double oo = double(5) / double(getHeight());
440  glBegin(GL_LINES);
441  // vertical
442  glVertex2d(-.98, -1. + o);
443  glVertex2d(-.98 + len, -1. + o);
444  // tick at begin
445  glVertex2d(-.98, -1. + o);
446  glVertex2d(-.98, -1. + o2);
447  // tick at end
448  glVertex2d(-.98 + len, -1. + o);
449  glVertex2d(-.98 + len, -1. + o2);
450  glEnd();
451 
452  SUMOReal w = SUMOReal(35) / SUMOReal(getWidth());
453  SUMOReal h = SUMOReal(35) / SUMOReal(getHeight());
454  pfSetPosition(SUMOReal(-0.99), SUMOReal(1. - o2 - oo));
455  pfSetScaleXY(w, h);
456  glRotated(180, 1, 0, 0);
457  pfDrawString("0m");
458  glRotated(-180, 1, 0, 0);
459 
460  pfSetPosition(SUMOReal(-.99 + len), SUMOReal(1. - o2 - oo));
461  glRotated(180, 1, 0, 0);
462  pfDrawString((text.substr(0, noDigits) + "m").c_str());
463  glRotated(-180, 1, 0, 0);
464 
465  // restore matrices
466  glMatrixMode(GL_PROJECTION);
467  glPopMatrix();
468  glMatrixMode(GL_MODELVIEW);
469  glPopMatrix();
470 }
471 
472 
473 SUMOReal
475  return meter * getWidth() / myChanger->getViewport().getWidth();
476 }
477 
478 
479 SUMOReal
481  return pixel * myChanger->getViewport().getWidth() / getWidth();
482 }
483 
484 
485 void
488 }
489 
490 
491 void
492 GUISUMOAbstractView::centerTo(GUIGlID id, bool applyZoom, SUMOReal zoomDist) {
494  if (o != 0 && dynamic_cast<GUIGlObject*>(o) != 0) {
495  if (applyZoom && zoomDist < 0) {
497  } else {
498  myChanger->centerTo(o->getCenteringBoundary().getCenter(), zoomDist, applyZoom);
499  }
500  }
502 }
503 
504 
505 void
507  myChanger->setViewport(bound);
508  update();
509 }
510 
511 /*
512 bool
513 GUISUMOAbstractView::allowRotation() const
514 {
515  return myParent->allowRotation();
516 }
517 */
518 
519 void
523 }
524 
525 
526 FXbool
528  FXbool ret = FXGLCanvas::makeCurrent();
529  return ret;
530 }
531 
532 
533 long
535  if (makeCurrent()) {
536  glViewport(0, 0, getWidth() - 1, getHeight() - 1);
537  glClearColor(
542  doInit();
543  myAmInitialised = true;
544  makeNonCurrent();
545  checkSnapshots();
546  }
547  return 1;
548 }
549 
550 
551 long
553  if (!isEnabled() || !myAmInitialised) {
554  return 1;
555  }
556  if (makeCurrent()) {
557  paintGL();
558  makeNonCurrent();
559  }
560  return 1;
561 }
562 
563 
564 void
566  delete myPopup;
567  myPopup = 0;
568 }
569 
570 
571 long
572 GUISUMOAbstractView::onLeftBtnPress(FXObject*, FXSelector , void* data) {
573  destroyPopup();
574  FXEvent* e = (FXEvent*) data;
575  // check whether the selection-mode is activated
576  if (e->state & CONTROLMASK) {
577  // try to get the object-id if so
578  if (makeCurrent()) {
579  unsigned int id = getObjectUnderCursor();
580  if (id != 0) {
582  }
583  makeNonCurrent();
584  if (id != 0) {
585  // possibly, the selection-colouring is used,
586  // so we should update the screen again...
587  update();
588  }
589  }
590  }
591  myChanger->onLeftBtnPress(data);
592  grab();
593  return 1;
594 }
595 
596 
597 long
599  destroyPopup();
601  if (myApp->isGaming()) {
603  }
604  ungrab();
605  return 1;
606 }
607 
608 
609 long
610 GUISUMOAbstractView::onRightBtnPress(FXObject*, FXSelector , void* data) {
611  destroyPopup();
612  myChanger->onRightBtnPress(data);
613  grab();
614  return 1;
615 }
616 
617 
618 long
619 GUISUMOAbstractView::onRightBtnRelease(FXObject* o, FXSelector sel, void* data) {
620  destroyPopup();
621  onMouseMove(o, sel, data);
622  if (!myChanger->onRightBtnRelease(data) && !myApp->isGaming()) {
624  }
625  ungrab();
626  return 1;
627 }
628 
629 
630 long
631 GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector , void* data) {
632  if (!myApp->isGaming()) {
633  myChanger->onMouseWheel(data);
634  }
635  return 1;
636 }
637 
638 
639 long
640 GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector , void* data) {
642  myChanger->onMouseMove(data);
643  }
644  const SUMOReal xpos = myChanger->getXPos();
645  const SUMOReal ypos = myChanger->getYPos();
646  const SUMOReal zoom = myChanger->getZoom();
647  if (myViewportChooser != 0 &&
648  (xpos != myChanger->getXPos() || ypos != myChanger->getYPos() || zoom != myChanger->getZoom())) {
650  }
652  return 1;
653 }
654 
655 
656 long
657 GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector , void* /*data*/) {
658  return 1;
659 }
660 
661 
662 void
664  ungrab();
665  if (!isEnabled() || !myAmInitialised) {
666  return;
667  }
668  if (makeCurrent()) {
669  // initialise the select mode
670  unsigned int id = getObjectUnderCursor();
671  GUIGlObject* o = 0;
672  if (id != 0) {
674  } else {
676  }
677  if (o != 0) {
678  myPopup = o->getPopUpMenu(*myApp, *this);
679  int x, y;
680  FXuint b;
681  myApp->getCursorPosition(x, y, b);
682  myPopup->setX(x + myApp->getX());
683  myPopup->setY(y + myApp->getY());
684  myPopup->create();
685  myPopup->show();
688  }
689  makeNonCurrent();
690  }
691 }
692 
693 
694 long
695 GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* data) {
696  FXEvent* e = (FXEvent*) data;
697  if ((e->state & ALTMASK) != 0) {
698  setDefaultCursor(getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR));
699  grabKeyboard();
700  }
701  /*
702  switch(e->code) {
703  case KEY_Left:
704  myChanger->move((SUMOReal) -p2m((SUMOReal) getWidth()/10), 0);
705  break;
706  case KEY_Right:
707  myChanger->move((SUMOReal) p2m((SUMOReal) getWidth()/10), 0);
708  break;
709  case KEY_Up:
710  myChanger->move(0, (SUMOReal) -p2m((SUMOReal) getHeight()/10));
711  break;
712  case KEY_Down:
713  myChanger->move(0, (SUMOReal) p2m((SUMOReal) getHeight()/10));
714  break;
715  default:
716  break;
717  }
718  */
719  return FXGLCanvas::onKeyPress(o, sel, data);
720 }
721 
722 
723 long
724 GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* data) {
725  FXEvent* e = (FXEvent*) data;
726  if ((e->state & ALTMASK) == 0) {
727  ungrabKeyboard();
728  setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
729  }
730  return FXGLCanvas::onKeyRelease(o, sel, data);
731 }
732 
733 
734 // ------------ Dealing with snapshots
735 void
736 GUISUMOAbstractView::setSnapshots(std::map<SUMOTime, std::string> snaps) {
737  mySnapshots.insert(snaps.begin(), snaps.end());
738 }
739 
740 
741 std::string
742 GUISUMOAbstractView::makeSnapshot(const std::string& destFile) {
743  std::string errorMessage;
744  FXString ext = FXPath::extension(destFile.c_str());
745  bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
746 
747  for (int i = 0; i < 10 && !makeCurrent(); ++i) {
749  }
750  // draw
751  glClearColor(
756  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
757  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
758 
760  glEnable(GL_DITHER);
761  } else {
762  glDisable(GL_DITHER);
763  }
765  glEnable(GL_BLEND);
766  glEnable(GL_POLYGON_SMOOTH);
767  glEnable(GL_LINE_SMOOTH);
768  } else {
769  glDisable(GL_BLEND);
770  glDisable(GL_POLYGON_SMOOTH);
771  glDisable(GL_LINE_SMOOTH);
772  }
773 
775 
776  if (useGL2PS) {
777  GLint format = GL2PS_PS;
778  if (ext == "ps") {
779  format = GL2PS_PS;
780  } else if (ext == "eps") {
781  format = GL2PS_EPS;
782  } else if (ext == "pdf") {
783  format = GL2PS_PDF;
784  } else if (ext == "tex") {
785  format = GL2PS_TEX;
786  } else if (ext == "svg") {
787  format = GL2PS_SVG;
788  } else if (ext == "pgf") {
789  format = GL2PS_PGF;
790  } else {
791  return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
792  }
793  FILE* fp = fopen(destFile.c_str(), "wb");
794  if (fp == 0) {
795  return "Could not save '" + destFile + "'.\n Could not open file for writing";
796  }
797  GLint buffsize = 0, state = GL2PS_OVERFLOW;
798  GLint viewport[4];
799  glGetIntegerv(GL_VIEWPORT, viewport);
800  while (state == GL2PS_OVERFLOW) {
801  buffsize += 1024 * 1024;
802  gl2psBeginPage(destFile.c_str(), "sumo-gui; http://sumo-sim.org", viewport, format, GL2PS_SIMPLE_SORT,
804  GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
805  glMatrixMode(GL_MODELVIEW);
806  glPushMatrix();
807  glDisable(GL_TEXTURE_2D);
808  glDisable(GL_ALPHA_TEST);
809  glDisable(GL_BLEND);
810  glEnable(GL_DEPTH_TEST);
811  // compute lane width
812  // draw decals (if not in grabbing mode)
813  if (!myUseToolTips) {
814  drawDecals();
816  paintGLGrid();
817  }
818  }
819  glLineWidth(1);
820  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
821  Boundary viewPort = myChanger->getViewport();
822  float minB[2];
823  float maxB[2];
824  minB[0] = viewPort.xmin();
825  minB[1] = viewPort.ymin();
826  maxB[0] = viewPort.xmax();
827  maxB[1] = viewPort.ymax();
829  glEnable(GL_POLYGON_OFFSET_FILL);
830  glEnable(GL_POLYGON_OFFSET_LINE);
831  myGrid->Search(minB, maxB, *myVisualizationSettings);
832 
834  displayLegend();
835  }
836  state = gl2psEndPage();
837  glFinish();
838  }
839  fclose(fp);
840  } else {
841  doPaintGL(GL_RENDER, myChanger->getViewport());
843  displayLegend();
844  }
845  swapBuffers();
846  glFinish();
847  FXColor* buf;
848  FXMALLOC(&buf, FXColor, getWidth()*getHeight());
849  // read from the back buffer
850  glReadBuffer(GL_BACK);
851  // Read the pixels
852  glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
853  makeNonCurrent();
854  update();
855  // mirror
856  size_t mwidth = getWidth();
857  size_t mheight = getHeight();
858  FXColor* paa = buf;
859  FXColor* pbb = buf + mwidth * (mheight - 1);
860  do {
861  FXColor* pa = paa;
862  paa += mwidth;
863  FXColor* pb = pbb;
864  pbb -= mwidth;
865  do {
866  FXColor t = *pa;
867  *pa++ = *pb;
868  *pb++ = t;
869  } while (pa < paa);
870  } while (paa < pbb);
871  try {
872  if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
873  errorMessage = "Could not save '" + destFile + "'.";
874  }
875  } catch (InvalidArgument& e) {
876  errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
877  }
878  FXFREE(&buf);
879  }
880  return errorMessage;
881 }
882 
883 
884 void
886  std::map<SUMOTime, std::string>::iterator snapIt = mySnapshots.find(getCurrentTimeStep());
887  if (snapIt != mySnapshots.end()) {
888  std::string error = makeSnapshot(snapIt->second);
889  if (error != "") {
890  WRITE_WARNING(error);
891  }
892  }
893 }
894 
895 
896 void
898  if (myVisualizationChanger == 0) {
903  myVisualizationChanger->create();
904  } else {
906  }
907  myVisualizationChanger->show();
908 }
909 
910 
911 void
913  if (myViewportChooser == 0) {
915  new GUIDialog_EditViewport(this, "Edit Viewport...", 0, 0);
916  myViewportChooser->create();
917  }
920  myViewportChooser->show();
921 }
922 
923 
924 void
925 GUISUMOAbstractView::setViewport(const Position& lookFrom, const Position& /* lookAt */) {
926  myChanger->setViewport(lookFrom.z(), lookFrom.x(), lookFrom.y());
927  update();
928 }
929 
930 
931 void
933  myUseToolTips = val;
934 }
935 
936 
937 
938 SUMOReal
940  return myGrid->getWidth();
941 }
942 
943 
944 SUMOReal
946  return myGrid->getHeight();
947 }
948 
949 
950 FXComboBox&
953 }
954 
955 
956 FXImage*
958 #ifdef HAVE_GDAL
959  GDALAllRegister();
960  GDALDataset* poDataset = (GDALDataset*)GDALOpen(d.filename.c_str(), GA_ReadOnly);
961  if (poDataset == 0) {
962  return 0;
963  }
964  const int xSize = poDataset->GetRasterXSize();
965  const int ySize = poDataset->GetRasterYSize();
966  // checking for geodata in the picture and try to adapt position and scale
967  if (d.width <= 0.) {
968  double adfGeoTransform[6];
969  if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
970  Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
971  const double horizontalSize = xSize * adfGeoTransform[1];
972  const double verticalSize = ySize * adfGeoTransform[5];
973  Position bottomRight(topLeft.x() + horizontalSize, topLeft.y() + verticalSize);
975  d.width = bottomRight.x() - topLeft.x();
976  d.height = topLeft.y() - bottomRight.y();
977  d.centerX = (topLeft.x() + bottomRight.x()) / 2;
978  d.centerY = (topLeft.y() + bottomRight.y()) / 2;
979  //WRITE_MESSAGE("proj: " + toString(poDataset->GetProjectionRef()) + " dim: " + toString(d.width) + "," + toString(d.height) + " center: " + toString(d.centerX) + "," + toString(d.centerY));
980  } else {
981  WRITE_WARNING("Could not convert coordinates in " + d.filename + ".");
982  }
983  }
984  }
985 #endif
986  if (d.width <= 0.) {
987  d.width = getGridWidth();
988  d.height = getGridHeight();
989  }
990 
991  // trying to read the picture
992 #ifdef HAVE_GDAL
993  const int picSize = xSize * ySize;
994  FXColor* result;
995  if (!FXMALLOC(&result, FXColor, picSize)) {
996  WRITE_WARNING("Could not allocate memory for " + d.filename + ".");
997  return 0;
998  }
999  for (int j = 0; j < picSize; j++) {
1000  result[j] = FXRGB(0, 0, 0);
1001  }
1002  bool valid = true;
1003  for (int i = 1; i <= poDataset->GetRasterCount(); i++) {
1004  GDALRasterBand* poBand = poDataset->GetRasterBand(i);
1005  int shift = -1;
1006  if (poBand->GetColorInterpretation() == GCI_RedBand) {
1007  shift = 0;
1008  } else if (poBand->GetColorInterpretation() == GCI_GreenBand) {
1009  shift = 1;
1010  } else if (poBand->GetColorInterpretation() == GCI_BlueBand) {
1011  shift = 2;
1012  } else if (poBand->GetColorInterpretation() == GCI_AlphaBand) {
1013  shift = 3;
1014  } else {
1015  WRITE_MESSAGE("Unknown color band in " + d.filename + ", maybe fox can parse it.");
1016  valid = false;
1017  break;
1018  }
1019  assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
1020  if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, ((unsigned char*)result) + shift, xSize, ySize, GDT_Byte, 4, 4 * xSize) == CE_Failure) {
1021  valid = false;
1022  break;
1023  }
1024  }
1025  GDALClose(poDataset);
1026  if (valid) {
1027  return new FXImage(getApp(), result, IMAGE_OWNED | IMAGE_KEEP | IMAGE_SHMI | IMAGE_SHMP, xSize, ySize);
1028  }
1029  FXFREE(&result);
1030 #endif
1031  return 0;
1032 }
1033 
1034 
1035 void
1037  glPushName(0);
1038  myDecalsLock.lock();
1039  for (std::vector<GUISUMOAbstractView::Decal>::iterator l = myDecals.begin(); l != myDecals.end(); ++l) {
1041  if (d.skip2D) {
1042  continue;
1043  }
1044  if (!d.initialised) {
1045  try {
1046  FXImage* img = checkGDALImage(d);
1047  if (img == 0) {
1048  img = MFXImageHelper::loadImage(getApp(), d.filename);
1049  }
1051  WRITE_WARNING("Scaling '" + d.filename + "'.");
1052  }
1053  d.glID = GUITexturesHelper::add(img);
1054  d.initialised = true;
1055  d.image = img;
1056  } catch (InvalidArgument& e) {
1057  WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what());
1058  d.skip2D = true;
1059  }
1060  }
1061  glPushMatrix();
1062  glTranslated(d.centerX, d.centerY, d.layer);
1063  glRotated(d.rot, 0, 0, 1);
1064  glColor3d(1, 1, 1);
1065  const SUMOReal halfWidth = d.width / 2.;
1066  const SUMOReal halfHeight = d.height / 2.;
1067  GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
1068  glPopMatrix();
1069  }
1070  myDecalsLock.unlock();
1071  glPopName();
1072 }
1073 
1074 
1075 // ------------ Additional visualisations
1076 bool
1078  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1079  myAdditionallyDrawn[which] = 1;
1080  } else {
1081  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
1082  }
1083  update();
1084  return true;
1085 }
1086 
1087 
1088 bool
1090  if (getTrackedID() == static_cast<int>(which->getGlID())) {
1091  stopTrack();
1092  }
1093  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1094  return false;
1095  }
1096  int cnt = myAdditionallyDrawn[which];
1097  if (cnt == 1) {
1098  myAdditionallyDrawn.erase(which);
1099  } else {
1100  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
1101  }
1102  update();
1103  return true;
1104 }
1105 
1106 
1107 void
1109  Boundary bound = myChanger->getViewport(fixRatio);
1110  glMatrixMode(GL_PROJECTION);
1111  glLoadIdentity();
1112  // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
1113  // thus, objects with a higher value will be closer (drawn on top)
1114  // // @todo last param should be 0 after modifying all glDraw methods
1115  glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
1116  glMatrixMode(GL_MODELVIEW);
1117  glLoadIdentity();
1118  SUMOReal scaleX = (SUMOReal)getWidth() / bound.getWidth();
1119  SUMOReal scaleY = (SUMOReal)getHeight() / bound.getHeight();
1120  glScaled(scaleX, scaleY, 1);
1121  glTranslated(-bound.xmin(), -bound.ymin(), 0);
1122 }
1123 
1124 /****************************************************************************/
1125