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  myChanger->onMouseWheel(data);
633  return 1;
634 }
635 
636 
637 long
638 GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector , void* data) {
639  SUMOReal xpos = myChanger->getXPos();
640  SUMOReal ypos = myChanger->getYPos();
641  SUMOReal zoom = myChanger->getZoom();
643  myChanger->onMouseMove(data);
644  }
645  if (myViewportChooser != 0 &&
646  (xpos != myChanger->getXPos() || ypos != myChanger->getYPos() || zoom != myChanger->getZoom())) {
648  }
650  return 1;
651 }
652 
653 
654 long
655 GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector , void* /*data*/) {
656  return 1;
657 }
658 
659 
660 void
662  ungrab();
663  if (!isEnabled() || !myAmInitialised) {
664  return;
665  }
666  if (makeCurrent()) {
667  // initialise the select mode
668  unsigned int id = getObjectUnderCursor();
669  GUIGlObject* o = 0;
670  if (id != 0) {
672  } else {
674  }
675  if (o != 0) {
676  myPopup = o->getPopUpMenu(*myApp, *this);
677  int x, y;
678  FXuint b;
679  myApp->getCursorPosition(x, y, b);
680  myPopup->setX(x + myApp->getX());
681  myPopup->setY(y + myApp->getY());
682  myPopup->create();
683  myPopup->show();
686  }
687  makeNonCurrent();
688  }
689 }
690 
691 
692 long
693 GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* data) {
694  FXEvent* e = (FXEvent*) data;
695  if ((e->state & ALTMASK) != 0) {
696  setDefaultCursor(getApp()->getDefaultCursor(DEF_CROSSHAIR_CURSOR));
697  grabKeyboard();
698  }
699  /*
700  switch(e->code) {
701  case KEY_Left:
702  myChanger->move((SUMOReal) -p2m((SUMOReal) getWidth()/10), 0);
703  break;
704  case KEY_Right:
705  myChanger->move((SUMOReal) p2m((SUMOReal) getWidth()/10), 0);
706  break;
707  case KEY_Up:
708  myChanger->move(0, (SUMOReal) -p2m((SUMOReal) getHeight()/10));
709  break;
710  case KEY_Down:
711  myChanger->move(0, (SUMOReal) p2m((SUMOReal) getHeight()/10));
712  break;
713  default:
714  break;
715  }
716  */
717  return FXGLCanvas::onKeyPress(o, sel, data);
718 }
719 
720 
721 long
722 GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* data) {
723  FXEvent* e = (FXEvent*) data;
724  if ((e->state & ALTMASK) == 0) {
725  ungrabKeyboard();
726  setDefaultCursor(getApp()->getDefaultCursor(DEF_ARROW_CURSOR));
727  }
728  return FXGLCanvas::onKeyRelease(o, sel, data);
729 }
730 
731 
732 // ------------ Dealing with snapshots
733 void
734 GUISUMOAbstractView::setSnapshots(std::map<SUMOTime, std::string> snaps) {
735  mySnapshots.insert(snaps.begin(), snaps.end());
736 }
737 
738 
739 std::string
740 GUISUMOAbstractView::makeSnapshot(const std::string& destFile) {
741  std::string errorMessage;
742  FXString ext = FXPath::extension(destFile.c_str());
743  bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
744 
745  for (int i = 0; i < 10 && !makeCurrent(); ++i) {
747  }
748  // draw
749  glClearColor(
754  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
755  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
756 
758  glEnable(GL_DITHER);
759  } else {
760  glDisable(GL_DITHER);
761  }
763  glEnable(GL_BLEND);
764  glEnable(GL_POLYGON_SMOOTH);
765  glEnable(GL_LINE_SMOOTH);
766  } else {
767  glDisable(GL_BLEND);
768  glDisable(GL_POLYGON_SMOOTH);
769  glDisable(GL_LINE_SMOOTH);
770  }
771 
773 
774  if (useGL2PS) {
775  GLint format = GL2PS_PS;
776  if (ext == "ps") {
777  format = GL2PS_PS;
778  } else if (ext == "eps") {
779  format = GL2PS_EPS;
780  } else if (ext == "pdf") {
781  format = GL2PS_PDF;
782  } else if (ext == "tex") {
783  format = GL2PS_TEX;
784  } else if (ext == "svg") {
785  format = GL2PS_SVG;
786  } else if (ext == "pgf") {
787  format = GL2PS_PGF;
788  } else {
789  return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
790  }
791  FILE* fp = fopen(destFile.c_str(), "wb");
792  if (fp == 0) {
793  return "Could not save '" + destFile + "'.\n Could not open file for writing";
794  }
795  GLint buffsize = 0, state = GL2PS_OVERFLOW;
796  GLint viewport[4];
797  glGetIntegerv(GL_VIEWPORT, viewport);
798  while (state == GL2PS_OVERFLOW) {
799  buffsize += 1024 * 1024;
800  gl2psBeginPage(destFile.c_str(), "sumo-gui; http://sumo-sim.org", viewport, format, GL2PS_SIMPLE_SORT,
802  GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
803  glMatrixMode(GL_MODELVIEW);
804  glPushMatrix();
805  glDisable(GL_TEXTURE_2D);
806  glDisable(GL_ALPHA_TEST);
807  glDisable(GL_BLEND);
808  glEnable(GL_DEPTH_TEST);
809  // compute lane width
810  // draw decals (if not in grabbing mode)
811  if (!myUseToolTips) {
812  drawDecals();
814  paintGLGrid();
815  }
816  }
817  glLineWidth(1);
818  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
819  Boundary viewPort = myChanger->getViewport();
820  float minB[2];
821  float maxB[2];
822  minB[0] = viewPort.xmin();
823  minB[1] = viewPort.ymin();
824  maxB[0] = viewPort.xmax();
825  maxB[1] = viewPort.ymax();
827  glEnable(GL_POLYGON_OFFSET_FILL);
828  glEnable(GL_POLYGON_OFFSET_LINE);
829  myGrid->Search(minB, maxB, *myVisualizationSettings);
830 
832  displayLegend();
833  }
834  state = gl2psEndPage();
835  glFinish();
836  }
837  fclose(fp);
838  } else {
839  doPaintGL(GL_RENDER, myChanger->getViewport());
841  displayLegend();
842  }
843  swapBuffers();
844  glFinish();
845  FXColor* buf;
846  FXMALLOC(&buf, FXColor, getWidth()*getHeight());
847  // read from the back buffer
848  glReadBuffer(GL_BACK);
849  // Read the pixels
850  glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
851  makeNonCurrent();
852  update();
853  // mirror
854  size_t mwidth = getWidth();
855  size_t mheight = getHeight();
856  FXColor* paa = buf;
857  FXColor* pbb = buf + mwidth * (mheight - 1);
858  do {
859  FXColor* pa = paa;
860  paa += mwidth;
861  FXColor* pb = pbb;
862  pbb -= mwidth;
863  do {
864  FXColor t = *pa;
865  *pa++ = *pb;
866  *pb++ = t;
867  } while (pa < paa);
868  } while (paa < pbb);
869  try {
870  if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
871  errorMessage = "Could not save '" + destFile + "'.";
872  }
873  } catch (InvalidArgument& e) {
874  errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
875  }
876  FXFREE(&buf);
877  }
878  return errorMessage;
879 }
880 
881 
882 void
884  std::map<SUMOTime, std::string>::iterator snapIt = mySnapshots.find(getCurrentTimeStep());
885  if (snapIt != mySnapshots.end()) {
886  std::string error = makeSnapshot(snapIt->second);
887  if (error != "") {
888  WRITE_WARNING(error);
889  }
890  }
891 }
892 
893 
894 void
896  if (myVisualizationChanger == 0) {
901  myVisualizationChanger->create();
902  } else {
904  }
905  myVisualizationChanger->show();
906 }
907 
908 
909 void
911  if (myViewportChooser == 0) {
913  new GUIDialog_EditViewport(this, "Edit Viewport...", 0, 0);
914  myViewportChooser->create();
915  }
918  myViewportChooser->show();
919 }
920 
921 
922 void
923 GUISUMOAbstractView::setViewport(const Position& lookFrom, const Position& /* lookAt */) {
924  myChanger->setViewport(lookFrom.z(), lookFrom.x(), lookFrom.y());
925  update();
926 }
927 
928 
929 void
931  myUseToolTips = val;
932 }
933 
934 
935 
936 SUMOReal
938  return myGrid->getWidth();
939 }
940 
941 
942 SUMOReal
944  return myGrid->getHeight();
945 }
946 
947 
948 FXComboBox&
951 }
952 
953 
954 FXImage*
956 #ifdef HAVE_GDAL
957  GDALAllRegister();
958  GDALDataset* poDataset = (GDALDataset*)GDALOpen(d.filename.c_str(), GA_ReadOnly);
959  if (poDataset == 0) {
960  return 0;
961  }
962  const int xSize = poDataset->GetRasterXSize();
963  const int ySize = poDataset->GetRasterYSize();
964  // checking for geodata in the picture and try to adapt position and scale
965  if (d.width <= 0.) {
966  double adfGeoTransform[6];
967  if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
968  Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
969  const double horizontalSize = xSize * adfGeoTransform[1];
970  const double verticalSize = ySize * adfGeoTransform[5];
971  Position bottomRight(topLeft.x() + horizontalSize, topLeft.y() + verticalSize);
973  d.width = bottomRight.x() - topLeft.x();
974  d.height = topLeft.y() - bottomRight.y();
975  d.centerX = (topLeft.x() + bottomRight.x()) / 2;
976  d.centerY = (topLeft.y() + bottomRight.y()) / 2;
977  //WRITE_MESSAGE("proj: " + toString(poDataset->GetProjectionRef()) + " dim: " + toString(d.width) + "," + toString(d.height) + " center: " + toString(d.centerX) + "," + toString(d.centerY));
978  } else {
979  WRITE_WARNING("Could not convert coordinates in " + d.filename + ".");
980  }
981  }
982  }
983 #endif
984  if (d.width <= 0.) {
985  d.width = getGridWidth();
986  d.height = getGridHeight();
987  }
988 
989  // trying to read the picture
990 #ifdef HAVE_GDAL
991  const int picSize = xSize * ySize;
992  FXColor* result;
993  if (!FXMALLOC(&result, FXColor, picSize)) {
994  WRITE_WARNING("Could not allocate memory for " + d.filename + ".");
995  return 0;
996  }
997  for (int j = 0; j < picSize; j++) {
998  result[j] = FXRGB(0, 0, 0);
999  }
1000  bool valid = true;
1001  for (int i = 1; i <= poDataset->GetRasterCount(); i++) {
1002  GDALRasterBand* poBand = poDataset->GetRasterBand(i);
1003  int shift = -1;
1004  if (poBand->GetColorInterpretation() == GCI_RedBand) {
1005  shift = 0;
1006  } else if (poBand->GetColorInterpretation() == GCI_GreenBand) {
1007  shift = 1;
1008  } else if (poBand->GetColorInterpretation() == GCI_BlueBand) {
1009  shift = 2;
1010  } else if (poBand->GetColorInterpretation() == GCI_AlphaBand) {
1011  shift = 3;
1012  } else {
1013  WRITE_MESSAGE("Unknown color band in " + d.filename + ", maybe fox can parse it.");
1014  valid = false;
1015  break;
1016  }
1017  assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
1018  if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, ((unsigned char*)result) + shift, xSize, ySize, GDT_Byte, 4, 4 * xSize) == CE_Failure) {
1019  valid = false;
1020  break;
1021  }
1022  }
1023  GDALClose(poDataset);
1024  if (valid) {
1025  return new FXImage(getApp(), result, IMAGE_OWNED | IMAGE_KEEP | IMAGE_SHMI | IMAGE_SHMP, xSize, ySize);
1026  }
1027  FXFREE(&result);
1028 #endif
1029  return 0;
1030 }
1031 
1032 
1033 void
1035  glPushName(0);
1036  myDecalsLock.lock();
1037  for (std::vector<GUISUMOAbstractView::Decal>::iterator l = myDecals.begin(); l != myDecals.end(); ++l) {
1039  if (d.skip2D) {
1040  continue;
1041  }
1042  if (!d.initialised) {
1043  try {
1044  FXImage* img = checkGDALImage(d);
1045  if (img == 0) {
1046  img = MFXImageHelper::loadImage(getApp(), d.filename);
1047  }
1049  WRITE_WARNING("Scaling '" + d.filename + "'.");
1050  }
1051  d.glID = GUITexturesHelper::add(img);
1052  d.initialised = true;
1053  d.image = img;
1054  } catch (InvalidArgument& e) {
1055  WRITE_ERROR("Could not load '" + d.filename + "'.\n" + e.what());
1056  d.skip2D = true;
1057  }
1058  }
1059  glPushMatrix();
1060  glTranslated(d.centerX, d.centerY, d.layer);
1061  glRotated(d.rot, 0, 0, 1);
1062  glColor3d(1, 1, 1);
1063  const SUMOReal halfWidth = d.width / 2.;
1064  const SUMOReal halfHeight = d.height / 2.;
1065  GUITexturesHelper::drawTexturedBox(d.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
1066  glPopMatrix();
1067  }
1068  myDecalsLock.unlock();
1069  glPopName();
1070 }
1071 
1072 
1073 // ------------ Additional visualisations
1074 bool
1076  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1077  myAdditionallyDrawn[which] = 1;
1078  } else {
1079  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
1080  }
1081  update();
1082  return true;
1083 }
1084 
1085 
1086 bool
1088  if (getTrackedID() == static_cast<int>(which->getGlID())) {
1089  stopTrack();
1090  }
1091  if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
1092  return false;
1093  }
1094  int cnt = myAdditionallyDrawn[which];
1095  if (cnt == 1) {
1096  myAdditionallyDrawn.erase(which);
1097  } else {
1098  myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
1099  }
1100  update();
1101  return true;
1102 }
1103 
1104 
1105 void
1107  Boundary bound = myChanger->getViewport(fixRatio);
1108  glMatrixMode(GL_PROJECTION);
1109  glLoadIdentity();
1110  // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
1111  // thus, objects with a higher value will be closer (drawn on top)
1112  // // @todo last param should be 0 after modifying all glDraw methods
1113  glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
1114  glMatrixMode(GL_MODELVIEW);
1115  glLoadIdentity();
1116  SUMOReal scaleX = (SUMOReal)getWidth() / bound.getWidth();
1117  SUMOReal scaleY = (SUMOReal)getHeight() / bound.getHeight();
1118  glScaled(scaleX, scaleY, 1);
1119  glTranslated(-bound.xmin(), -bound.ymin(), 0);
1120 }
1121 
1122 /****************************************************************************/
1123 
#define GL2PS_PS
Definition: gl2ps.h:100
void paintGLGrid()
paints a grid
A decal (an image) that can be shown.
GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, GLint options, GLint colormode, GLint colorsize, GL2PSrgba *colormap, GLint nr, GLint ng, GLint nb, GLint buffersize, FILE *stream, const char *filename)
Definition: gl2ps.c:5650
virtual long onConfigure(FXObject *, FXSelector, void *)
void setValues(SUMOReal zoom, SUMOReal xoff, SUMOReal yoff)
Sets the given values into the dialog.
int pfDrawString(const char *c)
Definition: polyfonts.c:1070
SUMOReal getHeight() const
Returns the height of the boundary.
Definition: Boundary.cpp:142
GUICompleteSchemeStorage gSchemeStorage
bool showSizeLegend
Information whether the size legend shall be drawn.
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
FXImage * checkGDALImage(Decal &d)
check whether we can read image data or position with gdal
virtual void setViewport(SUMOReal zoom, SUMOReal xPos, SUMOReal yPos)=0
Sets the viewport Used for: Adapting a new viewport.
FXImage * image
The image pointer for later cleanup.
const SUMOReal SUMO_const_laneWidth
Definition: StdDefs.h:45
SUMOReal getWidth() const
Returns the width of the boudary.
Definition: Boundary.cpp:136
a polygon
void showToolTipFor(unsigned int id)
invokes the tooltip for the given object
virtual void setViewport(const Position &lookFrom, const Position &lookAt)
applies the given viewport settings
void setDefault(const std::string &name)
Makes the scheme with the given name the default.
Position getCenter() const
Returns the center of the boundary.
Definition: Boundary.cpp:106
GUIGlObjectType
virtual void centerTo(GUIGlID id, bool applyZoom, SUMOReal zoomDist=20)
centers to the chosen artifact
bool myAmInitialised
Internal information whether doInit() was called.
void add(const Position &pos)
Adds the given position to this one.
Definition: Position.h:119
virtual void recenterView()
recenters the view
SUMORTree * myGrid
The visualization speed-up.
static GUIGlID add(FXImage *i)
Adds a texture to use.
void toggleSelection(GUIGlID id)
Toggles selection of an object.
bool gaming
whether the application is in gaming mode or not
virtual long onMouseMove(FXObject *, FXSelector, void *)
virtual SUMOReal getZoom() const =0
Returns the zoom factor computed stored in this changer.
GLCanvas - ID.
Definition: GUIAppEnum.h:191
SUMOReal ymin() const
Returns minimum y-coordinate.
Definition: Boundary.cpp:124
The dialog to change the view (gui) settings.
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
Definition: GeoConvHelper.h:97
#define GEO_OUTPUT_ACCURACY
Definition: config.h:16
bool x2cartesian(Position &from, bool includeInBoundary=true)
GUIMainWindow * myApp
The application.
#define GL2PS_DRAW_BACKGROUND
Definition: gl2ps.h:126
SUMOReal xmin() const
Returns minimum x-coordinate.
Definition: Boundary.cpp:112
virtual SUMOTime getCurrentTimeStep() const
get the current simulation time
MFXMutex myDecalsLock
The mutex to use before accessing the decals list in order to avoid thread conficts.
void pfSetPosition(SUMOReal x, SUMOReal y)
Definition: polyfonts.c:476
SUMOReal p2m(SUMOReal pixel) const
pixels-to-meters conversion method
bool addAdditionalGLVisualisation(GUIGlObject *const which)
Adds an object to call its additional visualisation method.
virtual long onLeftBtnPress(FXObject *, FXSelector, void *)
bool myInEditMode
Information whether too-tip informations shall be generated.
virtual void openObjectDialog()
virtual Boundary getCenteringBoundary() const =0
Returns the boundary to which the view shall be centered in order to show the object.
virtual long onKeyRelease(FXObject *o, FXSelector sel, void *data)
GUIGlObject * getNetObject() const
Returns the network object.
SUMOReal getGridHeight() const
int glID
The gl-id of the texture that holds this image.
void setSnapshots(std::map< SUMOTime, std::string > snaps)
Sets the snapshot time to file map.
static const RGBColor BLACK
Definition: RGBColor.h:195
SUMOReal width
The width of the image (net coordinates in x-direction, in m)
GUIDialog_ViewSettings * myVisualizationChanger
bool isGaming() const
return whether the gui is in gaming mode
Definition: GUIMainWindow.h:77
GUIDialog_EditViewport * myViewportChooser
A RT-tree for efficient storing of SUMO's GL-objects.
Definition: SUMORTree.h:74
SUMOReal x() const
Returns the x-position.
Definition: Position.h:63
bool dither
Information whether dithering shall be enabled.
GUIGlID getGlID() const
Returns the numerical id of the object.
Definition: GUIGlObject.h:115
SUMOReal xmax() const
Returns maximum x-coordinate.
Definition: Boundary.cpp:118
A class that stores a 2D geometrical boundary.
Definition: Boundary.h:48
int myMouseHotspotX
Offset to the mouse-hotspot from the mouse position.
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:196
SUMOReal scale
information about a lane's width (temporary, used for a single view)
unsigned char blue() const
Returns the blue-amount of the color.
Definition: RGBColor.h:91
virtual int getTrackedID() const
FXLabel & getCartesianLabel()
std::vector< GUIGlID > getObjectsAtPosition(Position pos, SUMOReal radius)
returns the ids of the object at position within the given (rectangular) radius using GL_SELECT ...
std::vector< Decal > myDecals
The list of decals to show.
GUIGlObjectType getType() const
Returns the type of the object as coded in GUIGlObjectType.
Definition: GUIGlObject.h:159
GUIGlID getObjectAtPosition(Position pos)
returns the id of the object at position using GL_SELECT
static FXbool scalePower2(FXImage *image, int maxSize=(2<< 29))
virtual int doPaintGL(int, const Boundary &)
bool removeAdditionalGLVisualisation(GUIGlObject *const which)
Removes an object from the list of objects that show additional things.
#define max(a, b)
Definition: polyfonts.c:61
virtual long onPaint(FXObject *, FXSelector, void *)
std::string name
The name of this setting.
std::map< GUIGlObject *, int > myAdditionallyDrawn
List of objects for which GUIGlObject::drawGLAdditional is called.
Boundary getVisibleBoundary() const
virtual long onMiddleBtnPress(FXObject *, FXSelector, void *)
static void drawTexturedBox(unsigned int which, SUMOReal size)
Draws a named texture as a box with the given size.
virtual void setStatusBarText(const std::string &)
Definition: GUIMainWindow.h:71
virtual long onKeyPress(FXObject *o, FXSelector sel, void *data)
#define GL2PS_PGF
Definition: gl2ps.h:105
virtual SUMOReal getXPos() const =0
Returns the x-offset of the field to show stored in this changer.
virtual long onMiddleBtnRelease(FXObject *, FXSelector, void *)
static void sleep(long ms)
bool isInEditMode()
returns true, if the edit button was pressed
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:46
SUMOReal centerY
The center of the image in y-direction (net coordinates, in m)
#define GL2PS_USE_CURRENT_VIEWPORT
Definition: gl2ps.h:135
virtual GUIGLObjectPopupMenu * getPopUpMenu(GUIMainWindow &app, GUISUMOAbstractView &parent)=0
Returns an own popup-menu.
FXComboBox & getColoringSchemesCombo()
GL2PSDLL_API GLint gl2psEndPage(void)
Definition: gl2ps.c:5817
unsigned char alpha() const
Returns the alpha-amount of the color.
Definition: RGBColor.h:99
static GUIGlObjectStorage gIDStorage
A single static instance of this class.
SUMOReal z() const
Returns the z-position.
Definition: Position.h:73
virtual bool onLeftBtnRelease(void *data)
FXComboBox & getColoringSchemesCombo()
bool initialised
Whether this image was initialised (inserted as a texture)
A 2D- or 3D-Shape.
Definition: Shape.h:45
virtual bool onRightBtnRelease(void *data)
FXLabel & getGeoLabel()
virtual long onMouseWheel(FXObject *, FXSelector, void *)
void checkSnapshots()
Checks whether it is time for a snapshot.
virtual ~GUISUMOAbstractView()
destructor
std::string filename
The path to the file the image is located at.
#define GL2PS_TEX
Definition: gl2ps.h:102
void saveViewport(const SUMOReal x, const SUMOReal y, const SUMOReal zoom)
Makes the given viewport the default.
void pfSetScaleXY(SUMOReal sx, SUMOReal sy)
Definition: polyfonts.c:468
SUMOReal gridXSize
Information about the grid spacings.
std::map< SUMOTime, std::string > mySnapshots
static FXbool saveImage(const std::string &file, int width, int height, FXColor *data)
std::string toString(const T &t, std::streamsize accuracy=OUTPUT_ACCURACY)
Definition: ToString.h:52
void updatePositionInformation() const
#define GL2PS_SIMPLE_SORT
Definition: gl2ps.h:110
static void drawTextBox(const std::string &text, const Position &pos, const SUMOReal layer, const SUMOReal size, const RGBColor &txtColor=RGBColor::BLACK, const RGBColor &bgColor=RGBColor::WHITE, const RGBColor &borderColor=RGBColor::BLACK, const SUMOReal angle=0)
draw Text box with given parameters
Definition: GLHelper.cpp:387
GUIPerspectiveChanger * myChanger
The perspective changer.
std::string makeSnapshot(const std::string &destFile)
Takes a snapshots and writes it into the given file.
virtual void onLeftBtnPress(void *data)
GUIGLObjectPopupMenu * myPopup
The current popup-menu.
RGBColor backgroundColor
The background color to use.
void destroyPopup()
destoys the popup
bool antialiase
Information whether antialiase shall be enabled.
FXint myWindowCursorPositionX
Position of the cursor relative to the window.
Boundary getViewport(bool fixRatio=true)
unsigned int GUIGlID
Definition: GUIGlObject.h:48
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:201
void unlock()
release mutex lock
Definition: MFXMutex.cpp:94
virtual void showViewportEditor()
FXbool makeCurrent()
A reimplementation due to some internal reasons.
SUMOReal height
The height of the image (net coordinates in y-direction, in m)
void applyGLTransform(bool fixRatio=true)
#define GL2PS_PDF
Definition: gl2ps.h:103
virtual long onLeftBtnRelease(FXObject *, FXSelector, void *)
void add(SUMOReal x, SUMOReal y)
Makes the boundary include the given coordinate.
Definition: Boundary.cpp:76
SUMOReal centerX
The center of the image in x-direction (net coordinates, in m)
GUIVisualizationSettings & getDefault()
Returns the default scheme.
Boundary & grow(SUMOReal by)
extends the boundary by the given amount
Definition: Boundary.cpp:200
void setViewport(GUISUMOAbstractView *view)
Sets the default viewport.
GUIVisualizationSettings * myVisualizationSettings
virtual void onMouseWheel(void *data)
SUMOReal m2p(SUMOReal meter) const
meter-to-pixels conversion method
void paintGL()
performs the painting of the simulation
SUMOReal y() const
Returns the y-position.
Definition: Position.h:68
void setWindowCursorPosition(FXint x, FXint y)
Returns the information whether rotation is allowd.
void setCurrent(GUIVisualizationSettings *settings)
Sets current settings (called if reopened)
static FXImage * loadImage(FXApp *a, const std::string &file)
#define GL2PS_SVG
Definition: gl2ps.h:104
SUMOReal getGridWidth() const
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
void lock()
lock mutex
Definition: MFXMutex.cpp:84
bool showGrid
Information whether a grid shall be shown.
void drawDecals()
Draws the stored decals.
static int getMaxTextureSize()
return maximum number of pixels in x and y direction
SUMOReal layer
The layer of the image.
virtual int Search(const float a_min[2], const float a_max[2], const GUIVisualizationSettings &c) const
Find all within search rectangle.
Definition: SUMORTree.h:120
virtual void centerTo(const Position &pos, SUMOReal radius, bool applyZoom=true)=0
Centers the view to the given position, setting it to a size that covers the radius. Used for: Centering of vehicles and junctions.
bool skip2D
Whether this image should be skipped in 2D-views.
unsigned char green() const
Returns the green-amount of the color.
Definition: RGBColor.h:83
#define SUMOReal
Definition: config.h:215
virtual void onMouseMove(void *data)
void updateToolTip()
A method that updates the tooltip.
A dialog to change the viewport.
SUMOReal ymax() const
Returns maximum y-coordinate.
Definition: Boundary.cpp:130
virtual void onRightBtnPress(void *data)
virtual void onGamingClick(Position)
empty max
void unblockObject(GUIGlID id)
Marks an object as unblocked.
virtual SUMOReal getYPos() const =0
Returns the y-offset of the field to show stored in this changer.
virtual long onRightBtnPress(FXObject *, FXSelector, void *)
bool haveGrabbed() const
Returns the information whether one of the spin dialers is grabbed.
virtual long onMouseLeft(FXObject *, FXSelector, void *)
Position getPositionInformation() const
Returns the cursor's x/y position within the network.
GUIGlID getObjectUnderCursor()
returns the id of the object under the cursor using GL_SELECT
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:197
GUIGlObject * getObjectBlocking(GUIGlID id)
Returns the object from the container locking it.
const std::string & getFullName() const
Returns the full name appearing in the tool tip.
Definition: GUIGlObject.h:107
unsigned char red() const
Returns the red-amount of the color.
Definition: RGBColor.h:75
GUISelectedStorage gSelected
A global holder of selected objects.
#define GL2PS_OVERFLOW
Definition: gl2ps.h:120
FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[]
SUMOReal rot
The rotation of the image in the ground plane (in degrees)
GUIGlChildWindow * myParent
The parent window.
virtual long onRightBtnRelease(FXObject *, FXSelector, void *)
static const Position INVALID
Definition: Position.h:252
std::vector< GUIGlID > getObjectsInBoundary(const Boundary &bound)
returns the ids of all objects in the given boundary
void setOldValues(const Position &lookFrom, const Position &lookAt)
Resets old values.
#define GL2PS_EPS
Definition: gl2ps.h:101