LCOV - code coverage report
Current view: top level - src/utils/gui/windows - GUISUMOAbstractView.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 32.7 % 1090 356
Test Date: 2026-04-16 16:39:47 Functions: 32.5 % 117 38

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    GUISUMOAbstractView.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @author  Laura Bieker
      19              : /// @author  Andreas Gaubatz
      20              : /// @date    Sept 2002
      21              : ///
      22              : // The base class for a view
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include <iostream>
      27              : #include <utility>
      28              : #include <cmath>
      29              : #include <cassert>
      30              : #include <limits>
      31              : #include <fxkeys.h>
      32              : #ifdef HAVE_GL2PS
      33              : #include <gl2ps.h>
      34              : #endif
      35              : #include <foreign/fontstash/fontstash.h>
      36              : #include <utils/common/MsgHandler.h>
      37              : #include <utils/common/RGBColor.h>
      38              : #include <utils/common/StringUtils.h>
      39              : #include <utils/common/SysUtils.h>
      40              : #include <utils/common/ToString.h>
      41              : #include <utils/foxtools/MFXCheckableButton.h>
      42              : #include <utils/foxtools/MFXImageHelper.h>
      43              : #include <utils/foxtools/MFXSingleEventThread.h>
      44              : #include <utils/foxtools/MFXStaticToolTip.h>
      45              : #include <utils/geom/GeoConvHelper.h>
      46              : #include <utils/geom/GeomHelper.h>
      47              : #include <utils/gui/cursors/GUICursorSubSys.h>
      48              : #include <utils/gui/div/GLHelper.h>
      49              : #include <utils/gui/div/GUIDesigns.h>
      50              : #include <utils/gui/div/GUIGlobalSelection.h>
      51              : #include <utils/gui/globjects/GLIncludes.h>
      52              : #include <utils/gui/globjects/GUICursorDialog.h>
      53              : #include <utils/gui/globjects/GUIGlObject.h>
      54              : #include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
      55              : #include <utils/gui/globjects/GUIGlObjectStorage.h>
      56              : #include <utils/gui/globjects/GUIPointOfInterest.h>
      57              : #include <utils/gui/globjects/GUIPolygon.h>
      58              : #include <utils/gui/images/GUITexturesHelper.h>
      59              : #include <utils/gui/settings/GUICompleteSchemeStorage.h>
      60              : #include <utils/gui/settings/GUIVisualizationSettings.h>
      61              : #include <utils/gui/windows/GUIAppEnum.h>
      62              : #include <utils/gui/windows/GUIDialog_ViewSettings.h>
      63              : #include <utils/options/OptionsCont.h>
      64              : #include <utils/shapes/PointOfInterest.h>
      65              : 
      66              : #include <unordered_set>
      67              : 
      68              : #include "GUISUMOAbstractView.h"
      69              : #include "GUIMainWindow.h"
      70              : #include "GUIGlChildWindow.h"
      71              : #include "GUIDanielPerspectiveChanger.h"
      72              : #include "GUIDialog_EditViewport.h"
      73              : 
      74              : #ifdef HAVE_GDAL
      75              : #ifdef _MSC_VER
      76              : #pragma warning(push)
      77              : #pragma warning(disable: 4435 5219 5220)
      78              : #endif
      79              : #if __GNUC__ > 3
      80              : #pragma GCC diagnostic push
      81              : #pragma GCC diagnostic ignored "-Wpedantic"
      82              : #endif
      83              : #include <gdal_priv.h>
      84              : #if __GNUC__ > 3
      85              : #pragma GCC diagnostic pop
      86              : #endif
      87              : #ifdef _MSC_VER
      88              : #pragma warning(pop)
      89              : #endif
      90              : #endif
      91              : 
      92              : // ===========================================================================
      93              : // debug constants
      94              : // ===========================================================================
      95              : //#define DEBUG_SNAPSHOT
      96              : 
      97              : // ===========================================================================
      98              : // static members
      99              : // ===========================================================================
     100              : 
     101              : const double GUISUMOAbstractView::SENSITIVITY = 0.1; // meters
     102              : 
     103              : // ===========================================================================
     104              : // FOX callback mapping
     105              : // ===========================================================================
     106              : 
     107              : FXDEFMAP(GUISUMOAbstractView) GUISUMOAbstractViewMap[] = {
     108              :     FXMAPFUNC(SEL_CONFIGURE,            0,                              GUISUMOAbstractView::onConfigure),
     109              :     FXMAPFUNC(SEL_PAINT,                0,                              GUISUMOAbstractView::onPaint),
     110              :     FXMAPFUNC(SEL_LEFTBUTTONPRESS,      0,                              GUISUMOAbstractView::onLeftBtnPress),
     111              :     FXMAPFUNC(SEL_LEFTBUTTONRELEASE,    0,                              GUISUMOAbstractView::onLeftBtnRelease),
     112              :     FXMAPFUNC(SEL_MIDDLEBUTTONPRESS,    0,                              GUISUMOAbstractView::onMiddleBtnPress),
     113              :     FXMAPFUNC(SEL_MIDDLEBUTTONRELEASE,  0,                              GUISUMOAbstractView::onMiddleBtnRelease),
     114              :     FXMAPFUNC(SEL_RIGHTBUTTONPRESS,     0,                              GUISUMOAbstractView::onRightBtnPress),
     115              :     FXMAPFUNC(SEL_RIGHTBUTTONRELEASE,   0,                              GUISUMOAbstractView::onRightBtnRelease),
     116              :     FXMAPFUNC(SEL_DOUBLECLICKED,        0,                              GUISUMOAbstractView::onDoubleClicked),
     117              :     FXMAPFUNC(SEL_MOUSEWHEEL,           0,                              GUISUMOAbstractView::onMouseWheel),
     118              :     FXMAPFUNC(SEL_MOTION,               0,                              GUISUMOAbstractView::onMouseMove),
     119              :     FXMAPFUNC(SEL_LEAVE,                0,                              GUISUMOAbstractView::onMouseLeft),
     120              :     FXMAPFUNC(SEL_KEYPRESS,             0,                              GUISUMOAbstractView::onKeyPress),
     121              :     FXMAPFUNC(SEL_KEYRELEASE,           0,                              GUISUMOAbstractView::onKeyRelease),
     122              :     FXMAPFUNC(SEL_COMMAND,              MID_CLOSE_LANE,                 GUISUMOAbstractView::onCmdCloseLane),
     123              :     FXMAPFUNC(SEL_COMMAND,              MID_CLOSE_EDGE,                 GUISUMOAbstractView::onCmdCloseEdge),
     124              :     FXMAPFUNC(SEL_COMMAND,              MID_ADD_REROUTER,               GUISUMOAbstractView::onCmdAddRerouter),
     125              :     FXMAPFUNC(SEL_COMMAND,              MID_REACHABILITY,               GUISUMOAbstractView::onCmdShowReachability),
     126              :     FXMAPFUNC(SEL_COMMAND,              MID_REACHABILITY,               GUISUMOAbstractView::onCmdShowReachability),
     127              :     FXMAPFUNC(SEL_CHANGED,              MID_SIMPLE_VIEW_COLORCHANGE,    GUISUMOAbstractView::onVisualizationChange),
     128              : };
     129              : 
     130      3325311 : FXIMPLEMENT_ABSTRACT(GUISUMOAbstractView, FXGLCanvas, GUISUMOAbstractViewMap, ARRAYNUMBER(GUISUMOAbstractViewMap))
     131              : 
     132              : // ===========================================================================
     133              : // member method definitions
     134              : // ===========================================================================
     135              : 
     136         8116 : GUISUMOAbstractView::GUISUMOAbstractView(FXComposite* p, GUIMainWindow& app, GUIGlChildWindow* parent, const SUMORTree& grid, FXGLVisual* glVis, FXGLCanvas* share) :
     137              :     FXGLCanvas(p, glVis, share, p, MID_GLCANVAS, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0),
     138         8116 :     myApp(&app),
     139         8116 :     myGlChildWindowParent(parent),
     140         8116 :     myGrid(&grid),
     141         8116 :     myMouseHotspotX(app.getDefaultCursor()->getHotX()),
     142         8116 :     myMouseHotspotY(app.getDefaultCursor()->getHotY()),
     143         8116 :     myWindowCursorPositionX(getWidth() / 2),
     144         8116 :     myWindowCursorPositionY(getHeight() / 2) {
     145         8116 :     setTarget(this);
     146         8116 :     enable();
     147         8116 :     flags |= FLAG_ENABLED;
     148         8116 :     myChanger = new GUIDanielPerspectiveChanger(*this, *myGrid);
     149         8116 :     myVisualizationSettings = &gSchemeStorage.getDefault();
     150         8116 :     myVisualizationSettings->gaming = myApp->isGaming();
     151         8116 :     gSchemeStorage.setViewport(this);
     152         8116 :     myDecals = gSchemeStorage.getDecals();
     153         8116 : }
     154              : 
     155              : 
     156         8087 : GUISUMOAbstractView::~GUISUMOAbstractView() {
     157         8087 :     gSchemeStorage.setDefault(myVisualizationSettings->name);
     158         8087 :     delete myPopup;
     159         8087 :     delete myChanger;
     160         8087 :     delete myGUIDialogEditViewport;
     161         8087 :     delete myGUIDialogViewSettings;
     162              : 
     163              :     // release GPU textures
     164         8087 :     if (makeCurrent()) {
     165         8087 :         for (auto& decal : myDecals) {
     166            0 :             if (decal.glID > 0) {
     167            0 :                 queueTextureDelete(static_cast<unsigned int>(decal.glID));
     168              :             }
     169              :         }
     170         8087 :         processPendingTextureDeletes();
     171         8087 :         makeNonCurrent();
     172              :     }
     173              : 
     174              :     // remove all elements
     175         8087 :     for (auto& additional : myAdditionallyDrawn) {
     176            0 :         additional.first->removeActiveAddVisualisation(this, ~0);
     177              :     }
     178        16174 : }
     179              : 
     180              : 
     181              : bool
     182            0 : GUISUMOAbstractView::isInEditMode() {
     183            0 :     return myInEditMode;
     184              : }
     185              : 
     186              : 
     187              : GUIPerspectiveChanger&
     188        32369 : GUISUMOAbstractView::getChanger() const {
     189        32369 :     return *myChanger;
     190              : }
     191              : 
     192              : 
     193              : void
     194            0 : GUISUMOAbstractView::updateToolTip() {
     195            0 :     if (myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->isStaticToolTipEnabled()) {
     196            0 :         update();
     197              :     }
     198            0 : }
     199              : 
     200              : 
     201              : Position
     202          472 : GUISUMOAbstractView::getPositionInformation() const {
     203          472 :     return screenPos2NetPos(myWindowCursorPositionX, myWindowCursorPositionY);
     204              : }
     205              : 
     206              : 
     207              : Position
     208            0 : GUISUMOAbstractView::snapToActiveGrid(const Position& pos, bool snapXY) const {
     209            0 :     Position result = pos;
     210            0 :     if (myVisualizationSettings->showGrid) {
     211            0 :         if (snapXY) {
     212            0 :             const double xRest = std::fmod(pos.x(), myVisualizationSettings->gridXSize) + (pos.x() < 0 ? myVisualizationSettings->gridXSize : 0);
     213            0 :             const double yRest = std::fmod(pos.y(), myVisualizationSettings->gridYSize) + (pos.y() < 0 ? myVisualizationSettings->gridYSize : 0);
     214            0 :             result.setx(pos.x() - xRest + (xRest < myVisualizationSettings->gridXSize * 0.5 ? 0 : myVisualizationSettings->gridXSize));
     215            0 :             result.sety(pos.y() - yRest + (yRest < myVisualizationSettings->gridYSize * 0.5 ? 0 : myVisualizationSettings->gridYSize));
     216              :         } else {
     217              :             // snapZToActiveGrid uses grid Y Size
     218            0 :             const double zRest = std::fmod(pos.z(), myVisualizationSettings->gridYSize) + (pos.z() < 0 ? myVisualizationSettings->gridYSize : 0);
     219            0 :             result.setz(pos.z() - zRest + (zRest < myVisualizationSettings->gridYSize * 0.5 ? 0 : myVisualizationSettings->gridYSize));
     220              :         }
     221              :     }
     222            0 :     return result;
     223              : }
     224              : 
     225              : 
     226              : Position
     227          472 : GUISUMOAbstractView::screenPos2NetPos(int x, int y) const {
     228          472 :     Boundary bound = myChanger->getViewport();
     229          472 :     double xNet = bound.xmin() + bound.getWidth() * x / getWidth();
     230              :     // cursor origin is in the top-left corner
     231          472 :     double yNet = bound.ymin() + bound.getHeight() * (getHeight() - y) / getHeight();
     232              :     // rotate around the viewport center
     233          472 :     if (myChanger->getRotation() != 0) {
     234            0 :         return Position(xNet, yNet).rotateAround2D(-DEG2RAD(myChanger->getRotation()), bound.getCenter());
     235              :     } else {
     236              :         return Position(xNet, yNet);
     237              :     }
     238              : }
     239              : 
     240              : 
     241              : void
     242           37 : GUISUMOAbstractView::addDecals(const std::vector<Decal>& decals) {
     243              :     // insert decals but avoid duplicates
     244           37 :     FXMutexLock lock(myDecalsLockMutex);
     245           44 :     for (const auto& d : decals) {
     246              :         bool found = false;
     247           13 :         for (const auto& existing : myDecals) {
     248            6 :             if (existing.filename == d.filename &&
     249            0 :                     existing.centerX == d.centerX &&
     250            6 :                     existing.centerY == d.centerY &&
     251            0 :                     existing.centerZ == d.centerZ) {
     252              :                 found = true;
     253              :                 break;
     254              :             }
     255              :         }
     256            7 :         if (!found) {
     257            7 :             myDecals.push_back(d);
     258            7 :             myDecals.back().initialised = false;
     259              :         }
     260              :     }
     261           37 : }
     262              : 
     263              : 
     264              : void
     265          472 : GUISUMOAbstractView::updatePositionInformationLabel() const {
     266          472 :     Position pos = getPositionInformation();
     267              :     // set cartesian position
     268         1416 :     myApp->getCartesianLabel()->setText(("x:" + toString(pos.x()) + ", y:" + toString(pos.y())).c_str());
     269              :     // set geo position
     270          472 :     GeoConvHelper::getFinal().cartesian2geo(pos);
     271          472 :     if (GeoConvHelper::getFinal().usingGeoProjection()) {
     272            0 :         myApp->getGeoLabel()->setText(("lat:" + toString(pos.y(), gPrecisionGeo) + ", lon:" + toString(pos.x(), gPrecisionGeo)).c_str());
     273              :     } else {
     274          472 :         myApp->getGeoLabel()->setText(TL("(No projection defined)"));
     275              :     }
     276              :     // if enabled, set test position
     277          472 :     if (myApp->getTestFrame()) {
     278            0 :         if (OptionsCont::getOptions().getBool("gui-testing")) {
     279            0 :             myApp->getTestFrame()->show();
     280              :             // adjust cursor position (24,25) to show exactly the same position as in function netedit.leftClick(match, X, Y)
     281            0 :             myApp->getTestLabel()->setText(("Test: x:" + toString(getWindowCursorPosition().x() - 24.0) + " y:" + toString(getWindowCursorPosition().y() - 25.0)).c_str());
     282              :         } else {
     283            0 :             myApp->getTestFrame()->hide();
     284              :         }
     285              :     }
     286          472 : }
     287              : 
     288              : 
     289              : int
     290            0 : GUISUMOAbstractView::doPaintGL(int /*mode*/, const Boundary& /*boundary*/) {
     291            0 :     return 0;
     292              : }
     293              : 
     294              : 
     295              : void
     296         7517 : GUISUMOAbstractView::doInit() {
     297         7517 : }
     298              : 
     299              : 
     300              : Boundary
     301            3 : GUISUMOAbstractView::getVisibleBoundary() const {
     302            3 :     return myChanger->getViewport();
     303              : }
     304              : 
     305              : 
     306              : bool
     307           18 : GUISUMOAbstractView::is3DView() const {
     308           18 :     return false;
     309              : }
     310              : 
     311              : 
     312            0 : void GUISUMOAbstractView::zoom2Pos(Position& /* camera */, Position& /* lookAt */, double /* zoom */) {
     313            0 : }
     314              : 
     315              : 
     316              : void
     317       744721 : GUISUMOAbstractView::paintGL() {
     318              :     // reset debug counters
     319       744721 :     GLHelper::resetMatrixCounter();
     320       744721 :     GLHelper::resetVertexCounter();
     321       744721 :     if (getWidth() == 0 || getHeight() == 0) {
     322            0 :         return;
     323              :     }
     324              : 
     325              :     // process pending texture deletions
     326       744721 :     processPendingTextureDeletes();
     327              : 
     328       744721 :     const long start = SysUtils::getCurrentMillis();
     329              : 
     330       744721 :     if (getTrackedID() != GUIGlObject::INVALID_ID) {
     331          472 :         centerTo(getTrackedID(), false);
     332              :     }
     333              :     // draw
     334      2978884 :     glClearColor(
     335       744721 :         myVisualizationSettings->backgroundColor.red() / 255.f,
     336       744721 :         myVisualizationSettings->backgroundColor.green() / 255.f,
     337       744721 :         myVisualizationSettings->backgroundColor.blue() / 255.f,
     338       744721 :         myVisualizationSettings->backgroundColor.alpha() / 255.f);
     339       744721 :     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
     340       744721 :     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     341              : 
     342       744721 :     if (myVisualizationSettings->dither) {
     343            0 :         glEnable(GL_DITHER);
     344              :     } else {
     345       744721 :         glDisable(GL_DITHER);
     346              :     }
     347       744721 :     glEnable(GL_BLEND);
     348       744721 :     glDisable(GL_LINE_SMOOTH);
     349              : 
     350       744721 :     Boundary bound = applyGLTransform();
     351       744721 :     doPaintGL(GL_RENDER, bound);
     352       744721 :     GLHelper::checkCounterMatrix();
     353       744721 :     GLHelper::checkCounterName();
     354       744721 :     displayLegends();
     355       744721 :     const long end = SysUtils::getCurrentMillis();
     356       744721 :     myFrameDrawTime = end - start;
     357       744721 :     if (myVisualizationSettings->fps) {
     358            0 :         drawFPS();
     359              :     }
     360              :     // check if show tooltip
     361       744721 :     if (myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->isStaticToolTipEnabled()) {
     362            0 :         showToolTipFor(getToolTipID());
     363              :     } else {
     364       744721 :         myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->hideStaticToolTip();
     365              :     }
     366       744721 :     swapBuffers();
     367              : }
     368              : 
     369              : 
     370              : long
     371            0 : GUISUMOAbstractView::onCmdCloseLane(FXObject*, FXSelector, void*) {
     372            0 :     return 1;
     373              : }
     374              : 
     375              : 
     376              : long
     377            0 : GUISUMOAbstractView::onCmdCloseEdge(FXObject*, FXSelector, void*) {
     378            0 :     return 1;
     379              : }
     380              : 
     381              : 
     382              : long
     383            0 : GUISUMOAbstractView::onCmdAddRerouter(FXObject*, FXSelector, void*) {
     384            0 :     return 1;
     385              : }
     386              : 
     387              : 
     388              : long
     389            0 : GUISUMOAbstractView::onCmdShowReachability(FXObject*, FXSelector, void*) {
     390            0 :     return 1;
     391              : }
     392              : 
     393              : 
     394              : long
     395            0 : GUISUMOAbstractView::onVisualizationChange(FXObject*, FXSelector, void*) {
     396            0 :     return 1;
     397              : }
     398              : 
     399              : 
     400              : GUILane*
     401            0 : GUISUMOAbstractView::getLaneUnderCursor() {
     402            0 :     return nullptr;
     403              : }
     404              : 
     405              : 
     406              : GUIGlID
     407            0 : GUISUMOAbstractView::getToolTipID() {
     408            0 :     return getObjectUnderCursor();
     409              : }
     410              : 
     411              : 
     412              : GUIGlID
     413            0 : GUISUMOAbstractView::getObjectUnderCursor(double sensitivity) {
     414            0 :     return getObjectAtPosition(getPositionInformation(), sensitivity);
     415              : }
     416              : 
     417              : 
     418              : std::vector<GUIGlID>
     419            0 : GUISUMOAbstractView::getObjectsUnderCursor() {
     420            0 :     return getObjectsAtPosition(getPositionInformation(), SENSITIVITY);
     421              : }
     422              : 
     423              : 
     424              : 
     425              : std::vector<GUIGlObject*>
     426            0 : GUISUMOAbstractView::getGUIGlObjectsUnderCursor() {
     427            0 :     return getGUIGlObjectsAtPosition(getPositionInformation(), SENSITIVITY);
     428              : }
     429              : 
     430              : 
     431              : std::vector<GUIGlObject*>
     432            0 : GUISUMOAbstractView::getGUIGlObjectsUnderSnappedCursor() {
     433            0 :     return getGUIGlObjectsAtPosition(snapToActiveGrid(getPositionInformation()), SENSITIVITY);
     434              : }
     435              : 
     436              : 
     437              : GUIGlID
     438            0 : GUISUMOAbstractView::getObjectAtPosition(Position pos, double sensitivity) {
     439              :     // calculate a boundary for the given position
     440            0 :     Boundary positionBoundary;
     441            0 :     positionBoundary.add(pos);
     442            0 :     positionBoundary.grow(sensitivity);
     443            0 :     const std::vector<GUIGlID> ids = getObjectsInBoundary(positionBoundary);
     444              :     // Interpret results
     445              :     int idMax = 0;
     446              :     double maxLayer = -std::numeric_limits<double>::max();
     447              :     double minDist = std::numeric_limits<double>::max();
     448              :     // iterate over obtained GUIGlIDs
     449            0 :     for (const auto& i : ids) {
     450              :         // obtain GUIGlObject
     451            0 :         GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);
     452              :         // check that GUIGlObject exist
     453            0 :         if (o == nullptr) {
     454            0 :             continue;
     455              :         }
     456              :         // check that GUIGlObject isn't the network
     457            0 :         if (o->getGlID() == 0) {
     458            0 :             continue;
     459              :         }
     460              :         //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
     461            0 :         double layer = o->getClickPriority();
     462            0 :         double dist = o->getCenter().distanceTo2D(pos);
     463              :         // check whether the current object is above a previous one
     464            0 :         if (layer > maxLayer) {
     465            0 :             idMax = i;
     466              :             maxLayer = layer;
     467              :             minDist = dist;
     468            0 :         } else if (layer == maxLayer && dist < minDist) {
     469            0 :             idMax = i;
     470              :             minDist = dist;
     471              :         }
     472              :         // unblock object
     473            0 :         GUIGlObjectStorage::gIDStorage.unblockObject(i);
     474              :     }
     475            0 :     return idMax;
     476            0 : }
     477              : 
     478              : 
     479              : std::vector<GUIGlID>
     480            0 : GUISUMOAbstractView::getObjectsAtPosition(Position pos, double radius) {
     481              :     // declare result vector
     482              :     std::vector<GUIGlID> result;
     483              :     // calculate boundary
     484            0 :     Boundary selection;
     485            0 :     selection.add(pos);
     486            0 :     selection.grow(radius);
     487              :     // obtain GUIGlID of objects in boundary
     488            0 :     const std::vector<GUIGlID> ids = getObjectsInBoundary(selection);
     489              :     // iterate over obtained GUIGlIDs
     490            0 :     for (const auto& i : ids) {
     491              :         // obtain GUIGlObject
     492            0 :         GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);
     493              :         // check that GUIGlObject exist
     494            0 :         if (o == nullptr) {
     495            0 :             continue;
     496              :         }
     497              :         // check that GUIGlObject isn't the network
     498            0 :         if (o->getGlID() == 0) {
     499            0 :             continue;
     500              :         }
     501              :         //std::cout << "point selection hit " << o->getMicrosimID() << "\n";
     502              :         GUIGlObjectType type = o->getType();
     503              :         // avoid network
     504            0 :         if (type != GLO_NETWORK) {
     505            0 :             result.push_back(i);
     506              :         }
     507              :         // unblock object
     508            0 :         GUIGlObjectStorage::gIDStorage.unblockObject(i);
     509              :     }
     510            0 :     return result;
     511            0 : }
     512              : 
     513              : 
     514              : std::vector<GUIGlObject*>
     515            0 : GUISUMOAbstractView::getGUIGlObjectsAtPosition(Position pos, double radius) {
     516              :     // declare result vector
     517              :     std::vector<GUIGlObject*> result;
     518              :     // calculate boundary
     519            0 :     Boundary selection;
     520            0 :     selection.add(pos);
     521            0 :     selection.grow(radius);
     522              :     // obtain GUIGlID of objects in boundary
     523            0 :     const std::vector<GUIGlID> ids = getObjectsInBoundary(selection);
     524              :     // iterate over obtained GUIGlIDs
     525            0 :     for (const auto& i : ids) {
     526              :         // obtain GUIGlObject
     527            0 :         GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(i);
     528              :         // check that GUIGlObject exist
     529            0 :         if (o == nullptr) {
     530            0 :             continue;
     531              :         }
     532              :         // check that GUIGlObject isn't the network
     533            0 :         if (o->getGlID() == 0) {
     534            0 :             continue;
     535              :         }
     536            0 :         result.push_back(o);
     537              :         // unblock object
     538            0 :         GUIGlObjectStorage::gIDStorage.unblockObject(i);
     539              :     }
     540            0 :     return result;
     541            0 : }
     542              : 
     543              : 
     544              : std::vector<GUIGlID>
     545            0 : GUISUMOAbstractView::getObjectsInBoundary(Boundary bound) {
     546              :     const int NB_HITS_MAX = 1024 * 1024;
     547              :     // Prepare the selection mode
     548              :     static GUIGlID hits[NB_HITS_MAX];
     549              :     static GLint nb_hits = 0;
     550            0 :     glSelectBuffer(NB_HITS_MAX, hits);
     551            0 :     glInitNames();
     552              : 
     553            0 :     myVisualizationSettings->scale = m2p(SUMO_const_laneWidth);
     554            0 :     Boundary oldViewPort = myChanger->getViewport(false); // backup the actual viewPort
     555            0 :     myChanger->setViewport(bound);
     556            0 :     bound = applyGLTransform(false);
     557              :     // enable draw for selecting (to draw objects with less details)
     558            0 :     myVisualizationSettings->drawForRectangleSelection = true;
     559            0 :     int hits2 = doPaintGL(GL_SELECT, bound);
     560              :     // reset flags
     561            0 :     myVisualizationSettings->drawForRectangleSelection = false;
     562              :     // Get the results
     563            0 :     nb_hits = glRenderMode(GL_RENDER);
     564            0 :     if (nb_hits == -1) {
     565            0 :         myApp->setStatusBarText("Selection in boundary failed. Try to select fewer than " + toString(hits2) + " items");
     566              :     }
     567              :     std::vector<GUIGlID> result;
     568              :     GLuint numNames;
     569              :     GLuint* ptr = hits;
     570            0 :     for (int i = 0; i < nb_hits; ++i) {
     571            0 :         numNames = *ptr;
     572            0 :         ptr += 3;
     573            0 :         for (int j = 0; j < (int)numNames; j++) {
     574            0 :             result.push_back(*ptr);
     575            0 :             ptr++;
     576              :         }
     577              :     }
     578              :     // switch viewport back to normal
     579            0 :     myChanger->setViewport(oldViewPort);
     580            0 :     return result;
     581            0 : }
     582              : 
     583              : 
     584              : std::vector<GUIGlObject*>
     585            0 : GUISUMOAbstractView::filterInternalLanes(const std::vector<GUIGlObject*>& objects) const {
     586              :     // count number of internal lanes
     587              :     size_t internalLanes = 0;
     588            0 :     for (const auto& object : objects) {
     589            0 :         if ((object->getType() == GLO_LANE) && (object->getMicrosimID().find(':') != std::string::npos)) {
     590            0 :             internalLanes++;
     591              :         }
     592              :     }
     593              :     // if all objects are internal lanes, return it all
     594            0 :     if (objects.size() == internalLanes || !myVisualizationSettings->drawJunctionShape) {
     595            0 :         return objects;
     596              :     }
     597              :     // in other case filter internal lanes
     598              :     std::vector<GUIGlObject*> filteredObjects;
     599            0 :     for (const auto& object : objects) {
     600            0 :         if ((object->getType() == GLO_LANE) && (object->getMicrosimID().find(':') != std::string::npos)) {
     601            0 :             continue;
     602              :         }
     603            0 :         filteredObjects.push_back(object);
     604              :     }
     605              :     return filteredObjects;
     606            0 : }
     607              : 
     608              : 
     609              : bool
     610            0 : GUISUMOAbstractView::showToolTipFor(const GUIGlID idToolTip) {
     611            0 :     if (idToolTip != GUIGlObject::INVALID_ID) {
     612            0 :         const GUIGlObject* object = GUIGlObjectStorage::gIDStorage.getObjectBlocking(idToolTip);
     613            0 :         if (object != nullptr) {
     614            0 :             myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->showStaticToolTip(object->getFullName().c_str());
     615            0 :             return true;
     616              :         }
     617              :     }
     618              :     // nothing to show
     619            0 :     myGlChildWindowParent->getGUIMainWindowParent()->getStaticTooltipView()->hideStaticToolTip();
     620            0 :     return false;
     621              : }
     622              : 
     623              : 
     624              : void
     625            0 : GUISUMOAbstractView::paintGLGrid() const {
     626              :     // obtain minimum grid
     627            0 :     const double minimumSizeGrid = (myVisualizationSettings->gridXSize < myVisualizationSettings->gridYSize) ? myVisualizationSettings->gridXSize : myVisualizationSettings->gridYSize;
     628              :     // Check if the distance is enough to draw grid
     629            0 :     if (myVisualizationSettings->scale * myVisualizationSettings->addSize.getExaggeration(*myVisualizationSettings, nullptr) >= (25 / minimumSizeGrid)) {
     630            0 :         glEnable(GL_DEPTH_TEST);
     631            0 :         glLineWidth(1);
     632              :         // get multiplication values (2 is the margin)
     633            0 :         const int multXmin = (int)(myChanger->getViewport().xmin() / myVisualizationSettings->gridXSize) - 2;
     634            0 :         const int multYmin = (int)(myChanger->getViewport().ymin() / myVisualizationSettings->gridYSize) - 2;
     635            0 :         const int multXmax = (int)(myChanger->getViewport().xmax() / myVisualizationSettings->gridXSize) + 2;
     636            0 :         const int multYmax = (int)(myChanger->getViewport().ymax() / myVisualizationSettings->gridYSize) + 2;
     637              :         // obtain references
     638            0 :         const double xmin = myVisualizationSettings->gridXSize * multXmin;
     639            0 :         const double ymin = myVisualizationSettings->gridYSize * multYmin;
     640            0 :         const double xmax = myVisualizationSettings->gridXSize * multXmax;
     641            0 :         const double ymax = myVisualizationSettings->gridYSize * multYmax;
     642              :         double xp = xmin;
     643              :         double yp = ymin;
     644              :         // move drawing matrix
     645            0 :         glTranslated(0, 0, .55);
     646            0 :         glColor3d(0.5, 0.5, 0.5);
     647              :         // draw horizontal lines
     648            0 :         glBegin(GL_LINES);
     649            0 :         while (yp <= ymax) {
     650            0 :             glVertex2d(xmin, yp);
     651            0 :             glVertex2d(xmax, yp);
     652            0 :             yp += myVisualizationSettings->gridYSize;
     653              :         }
     654              :         // draw vertical lines
     655            0 :         while (xp <= xmax) {
     656            0 :             glVertex2d(xp, ymin);
     657            0 :             glVertex2d(xp, ymax);
     658            0 :             xp += myVisualizationSettings->gridXSize;
     659              :         }
     660            0 :         glEnd();
     661            0 :         glTranslated(0, 0, -.55);
     662              :     }
     663            0 : }
     664              : 
     665              : 
     666              : void
     667       745029 : GUISUMOAbstractView::displayLegend() {
     668              :     // compute the scale bar length
     669              :     int length = 1;
     670       745029 :     const std::string text("10000000000");
     671              :     int noDigits = 1;
     672       745029 :     int pixelSize = (int) m2p((double) length);
     673      2441813 :     while (pixelSize <= 20) {
     674      1696784 :         length *= 10;
     675      1696784 :         noDigits++;
     676      1696784 :         if (noDigits > (int)text.length()) {
     677              :             return;
     678              :         }
     679      1696784 :         pixelSize = (int) m2p((double) length);
     680              :     }
     681       745029 :     glLineWidth(1.0);
     682              : 
     683       745029 :     glMatrixMode(GL_PROJECTION);
     684       745029 :     GLHelper::pushMatrix();
     685       745029 :     glLoadIdentity();
     686       745029 :     glMatrixMode(GL_MODELVIEW);
     687       745029 :     GLHelper::pushMatrix();
     688       745029 :     glLoadIdentity();
     689              : 
     690              :     // draw the scale bar
     691              :     const double z = -1;
     692       745029 :     glDisable(GL_TEXTURE_2D);
     693       745029 :     glDisable(GL_ALPHA_TEST);
     694       745029 :     glDisable(GL_BLEND);
     695       745029 :     glEnable(GL_DEPTH_TEST);
     696       745029 :     GLHelper::pushMatrix();
     697       745029 :     glTranslated(0, 0, z);
     698              : 
     699       745029 :     double len = (double) pixelSize / (double)(getWidth() - 1) * (double) 2.0;
     700       745029 :     glColor3d(0, 0, 0);
     701       745029 :     double o = double(15) / double(getHeight());
     702       745029 :     double o2 = o + o;
     703       745029 :     double oo = double(5) / double(getHeight());
     704       745029 :     glBegin(GL_LINES);
     705              :     // vertical
     706       745029 :     glVertex2d(-.98, -1. + o);
     707       745029 :     glVertex2d(-.98 + len, -1. + o);
     708              :     // tick at begin
     709       745029 :     glVertex2d(-.98, -1. + o);
     710       745029 :     glVertex2d(-.98, -1. + o2);
     711              :     // tick at end
     712       745029 :     glVertex2d(-.98 + len, -1. + o);
     713       745029 :     glVertex2d(-.98 + len, -1. + o2);
     714       745029 :     glEnd();
     715       745029 :     GLHelper::popMatrix();
     716              : 
     717       745029 :     const double fontHeight = 0.1 * 300. / getHeight();
     718       745029 :     const double fontWidth = 0.1 * 300. / getWidth();
     719              :     // draw 0
     720       745029 :     GLHelper::drawText("0", Position(-.99, -0.99 + o2 + oo), z, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT, fontWidth);
     721              : 
     722              :     // draw current scale
     723      1490058 :     GLHelper::drawText((text.substr(0, noDigits) + "m").c_str(), Position(-.99 + len, -0.99 + o2 + oo), z, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT, fontWidth);
     724              : 
     725              :     // restore matrices
     726       745029 :     glMatrixMode(GL_PROJECTION);
     727       745029 :     GLHelper::popMatrix();
     728       745029 :     glMatrixMode(GL_MODELVIEW);
     729       745029 :     GLHelper::popMatrix();
     730              : }
     731              : 
     732              : void
     733       745029 : GUISUMOAbstractView::displayLegends() {
     734       745029 :     if (myVisualizationSettings->showSizeLegend) {
     735       745029 :         displayLegend();
     736              :     }
     737       745029 :     std::string key = "";
     738       745029 :     if (myVisualizationSettings->showColorLegend) {
     739            0 :         auto const& scheme = myVisualizationSettings->getLaneEdgeScheme();
     740            0 :         if (scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_EDGEDATA_NUMERICAL) {
     741            0 :             key = myVisualizationSettings->edgeData;
     742            0 :         } else if (scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_EDGE_PARAM_NUMERICAL) {
     743            0 :             key = myVisualizationSettings->edgeParam;
     744            0 :         } else if (scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_LANE_PARAM_NUMERICAL) {
     745            0 :             key = myVisualizationSettings->laneParam;
     746              :         }
     747            0 :         displayColorLegend(scheme, false, key);
     748              :     }
     749       745029 :     if (myVisualizationSettings->showVehicleColorLegend) {
     750              :         auto const& scheme = myVisualizationSettings->vehicleColorer.getScheme();
     751            0 :         if (scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_PARAM_NUMERICAL) {
     752            0 :             key = myVisualizationSettings->vehicleParam;
     753              :         }
     754            0 :         displayColorLegend(myVisualizationSettings->vehicleColorer.getScheme(), true, key);
     755              :     }
     756       745029 : }
     757              : 
     758              : void
     759            0 : GUISUMOAbstractView::displayColorLegend(const GUIColorScheme& scheme, bool leftSide, const std::string& key) {
     760              :     // compute the scale bar length
     761            0 :     glLineWidth(1.0);
     762            0 :     glMatrixMode(GL_PROJECTION);
     763            0 :     GLHelper::pushMatrix();
     764            0 :     glLoadIdentity();
     765            0 :     glMatrixMode(GL_MODELVIEW);
     766            0 :     GLHelper::pushMatrix();
     767            0 :     glLoadIdentity();
     768              : 
     769              :     const double z = -1;
     770            0 :     glEnable(GL_DEPTH_TEST);
     771            0 :     glEnable(GL_BLEND);
     772            0 :     GLHelper::pushMatrix();
     773            0 :     glTranslated(0, 0, z);
     774              : 
     775              :     const bool fixed = scheme.isFixed();
     776            0 :     const int numColors = (int)scheme.getColors().size();
     777              : 
     778              :     // vertical
     779              :     double right = 0.98;
     780              :     double left = 0.95;
     781              :     double textX = left - 0.01;
     782              :     double textDir = 1;
     783              :     FONSalign textAlign = FONS_ALIGN_RIGHT;
     784              :     const double top = -0.7;
     785              :     const double bot = 0.9;
     786            0 :     const double dy = (top - bot) / numColors;
     787            0 :     const double bot2 = fixed ? bot : bot + dy / 2;
     788              :     // legend placement
     789            0 :     if (leftSide) {
     790              :         right = -right;
     791              :         left = -left;
     792              :         std::swap(right, left);
     793              :         textX = right + 0.01;
     794              :         textDir *= -1;
     795              :         textAlign = FONS_ALIGN_LEFT;
     796              :     }
     797              :     // draw black boundary around legend colors
     798            0 :     glColor3d(0, 0, 0);
     799            0 :     glBegin(GL_LINES);
     800            0 :     glVertex2d(right, top);
     801            0 :     glVertex2d(right, bot2);
     802            0 :     glVertex2d(left, bot2);
     803            0 :     glVertex2d(left, top);
     804            0 :     glVertex2d(right, top);
     805            0 :     glVertex2d(left, top);
     806            0 :     glVertex2d(right, bot2);
     807            0 :     glVertex2d(left, bot2);
     808            0 :     glEnd();
     809              : 
     810            0 :     const double fontHeight = 0.20 * 300. / getHeight();
     811            0 :     const double fontWidth = 0.20 * 300. / getWidth();
     812              : 
     813            0 :     const int fadeSteps = fixed ? 1 : 10;
     814            0 :     double colorStep = dy / fadeSteps;
     815            0 :     for (int i = 0; i < numColors; i++) {
     816            0 :         RGBColor col = scheme.getColors()[i];
     817            0 :         const double topi = top - i * dy;
     818              :         //const double boti = top - (i + 1) * dy;
     819              :         //std::cout << " col=" << scheme.getColors()[i] << " i=" << i << " topi=" << topi << " boti=" << boti << "\n";
     820            0 :         if (i + 1 < numColors) {
     821              :             // fade
     822            0 :             RGBColor col2 = scheme.getColors()[i + 1];
     823            0 :             double thresh2 = scheme.getThresholds()[i + 1];
     824            0 :             if (!fixed && thresh2 == GUIVisualizationSettings::MISSING_DATA) {
     825              :                 // draw scale end before missing data
     826            0 :                 GLHelper::setColor(col);
     827            0 :                 glBegin(GL_QUADS);
     828            0 :                 glVertex2d(left, topi);
     829            0 :                 glVertex2d(right, topi);
     830            0 :                 glVertex2d(right, topi - 5 * colorStep);
     831            0 :                 glVertex2d(left, topi - 5 * colorStep);
     832            0 :                 glEnd();
     833            0 :                 glColor3d(0, 0, 0);
     834            0 :                 glBegin(GL_LINES);
     835            0 :                 glVertex2d(right, topi - 10 * colorStep);
     836            0 :                 glVertex2d(left, topi - 10 * colorStep);
     837            0 :                 glEnd();
     838            0 :                 glBegin(GL_LINES);
     839            0 :                 glVertex2d(right, topi - 5 * colorStep);
     840            0 :                 glVertex2d(left, topi - 5 * colorStep);
     841            0 :                 glEnd();
     842              :             } else {
     843              :                 // fade colors
     844            0 :                 for (double j = 0.0; j < fadeSteps; j++) {
     845            0 :                     GLHelper::setColor(RGBColor::interpolate(col, col2, j / fadeSteps));
     846            0 :                     glBegin(GL_QUADS);
     847            0 :                     glVertex2d(left, topi - j * colorStep);
     848            0 :                     glVertex2d(right, topi - j * colorStep);
     849            0 :                     glVertex2d(right, topi - (j + 1) * colorStep);
     850            0 :                     glVertex2d(left, topi - (j + 1) * colorStep);
     851            0 :                     glEnd();
     852              :                 }
     853              :             }
     854              :         } else {
     855            0 :             GLHelper::setColor(col);
     856            0 :             glBegin(GL_QUADS);
     857            0 :             glVertex2d(left, topi);
     858            0 :             glVertex2d(right, topi);
     859            0 :             glVertex2d(right, bot2);
     860            0 :             glVertex2d(left, bot2);
     861            0 :             glEnd();
     862              :         }
     863              : 
     864            0 :         const double threshold = scheme.getThresholds()[i];
     865              :         std::string name = scheme.getNames()[i];
     866            0 :         std::string text = fixed || threshold == GUIVisualizationSettings::MISSING_DATA ? name : toString(threshold);
     867              : 
     868              :         const double bgShift = 0.0;
     869              :         const double textShift = 0.01;
     870              :         const double textXShift = -0.005;
     871              : 
     872            0 :         GLHelper::setColor(RGBColor::WHITE);
     873            0 :         glTranslated(0, 0, 0.1);
     874            0 :         glBegin(GL_QUADS);
     875            0 :         glVertex2d(textX, topi + fontHeight * bgShift);
     876            0 :         glVertex2d(textX - textDir * fontWidth * (double)text.size() / 2.1, topi + fontHeight * bgShift);
     877            0 :         glVertex2d(textX - textDir * fontWidth * (double)text.size() / 2.1, topi + fontHeight * (0.8 + bgShift));
     878            0 :         glVertex2d(textX, topi + fontHeight * (0.8 + bgShift));
     879            0 :         glEnd();
     880            0 :         glTranslated(0, 0, -0.1);
     881            0 :         GLHelper::drawText(text, Position(textX + textDir * textXShift, topi + textShift), 0, fontHeight, RGBColor::BLACK, 0, textAlign, fontWidth);
     882              :     }
     883              :     // draw scheme name
     884              :     std::string name = scheme.getName();
     885            0 :     if (name == GUIVisualizationSettings::SCHEME_NAME_EDGEDATA_NUMERICAL) {
     886            0 :         name = "edgeData (" + key + ")";
     887            0 :     } else if (name == GUIVisualizationSettings::SCHEME_NAME_EDGE_PARAM_NUMERICAL) {
     888            0 :         name = "edgeParam (" + key + ")";
     889            0 :     } else if (name == GUIVisualizationSettings::SCHEME_NAME_LANE_PARAM_NUMERICAL) {
     890            0 :         name = "laneParam (" + key + ")";
     891            0 :     } else if (name == GUIVisualizationSettings::SCHEME_NAME_PARAM_NUMERICAL) {
     892            0 :         name = "param (" + key + ")";
     893            0 :     } else if (name == GUIVisualizationSettings::SCHEME_NAME_DATA_ATTRIBUTE_NUMERICAL) {
     894            0 :         name = "attribute (" + key + ")";
     895            0 :     } else if (StringUtils::startsWith(name, "by ")) {
     896            0 :         name = name.substr(3);
     897              :     }
     898              :     const double topN = -0.8;
     899              :     const double bgShift = 0.0;
     900            0 :     GLHelper::setColor(RGBColor::WHITE);
     901            0 :     glTranslated(0, 0, 0.1);
     902            0 :     glBegin(GL_QUADS);
     903            0 :     glVertex2d(textX + textDir * 0.04,                                                   topN + fontHeight * bgShift - 0.01);
     904            0 :     glVertex2d(textX + textDir * 0.04 - textDir * fontWidth * (double)name.size() / 2.3, topN + fontHeight * bgShift - 0.01);
     905            0 :     glVertex2d(textX + textDir * 0.04 - textDir * fontWidth * (double)name.size() / 2.3, topN + fontHeight * (0.8 + bgShift));
     906            0 :     glVertex2d(textX + textDir * 0.04,                                                   topN + fontHeight * (0.8 + bgShift));
     907            0 :     glEnd();
     908            0 :     glTranslated(0, 0, -0.1);
     909            0 :     GLHelper::drawText(name, Position(textX + textDir * 0.04, topN), 0, fontHeight, RGBColor::BLACK, 0, textAlign, fontWidth);
     910              : 
     911            0 :     GLHelper::popMatrix();
     912              :     // restore matrices
     913            0 :     glMatrixMode(GL_PROJECTION);
     914            0 :     GLHelper::popMatrix();
     915            0 :     glMatrixMode(GL_MODELVIEW);
     916            0 :     GLHelper::popMatrix();
     917            0 : }
     918              : 
     919              : 
     920              : double
     921            0 : GUISUMOAbstractView::getFPS() const {
     922            0 :     return 1000.0 / MAX2((long)1, myFrameDrawTime);
     923              : }
     924              : 
     925              : 
     926              : GUIGlChildWindow*
     927            0 : GUISUMOAbstractView::getGUIGlChildWindow() {
     928            0 :     return myGlChildWindowParent;
     929              : }
     930              : 
     931              : 
     932              : void
     933            0 : GUISUMOAbstractView::drawFPS() {
     934            0 :     glMatrixMode(GL_PROJECTION);
     935            0 :     GLHelper::pushMatrix();
     936            0 :     glLoadIdentity();
     937            0 :     glMatrixMode(GL_MODELVIEW);
     938            0 :     GLHelper::pushMatrix();
     939            0 :     glLoadIdentity();
     940            0 :     const double fontHeight = 0.2 * 300. / getHeight();
     941            0 :     const double fontWidth = 0.2 * 300. / getWidth();
     942            0 :     GLHelper::drawText(toString((int)getFPS()) + " FPS", Position(0.82, 0.88), -1, fontHeight, RGBColor::RED, 0, FONS_ALIGN_LEFT, fontWidth);
     943              : #ifdef CHECK_ELEMENTCOUNTER
     944              :     GLHelper::drawText(toString(GLHelper::getMatrixCounter()) + " matrix", Position(0.82, 0.79), -1, fontHeight, RGBColor::RED, 0, FONS_ALIGN_LEFT, fontWidth);
     945              :     GLHelper::drawText(toString(GLHelper::getVertexCounter()) + " vertex", Position(0.82, 0.71), -1, fontHeight, RGBColor::RED, 0, FONS_ALIGN_LEFT, fontWidth);
     946              : #endif
     947              :     // restore matrices
     948            0 :     glMatrixMode(GL_PROJECTION);
     949            0 :     GLHelper::popMatrix();
     950            0 :     glMatrixMode(GL_MODELVIEW);
     951            0 :     GLHelper::popMatrix();
     952            0 : }
     953              : 
     954              : 
     955              : double
     956      3186842 : GUISUMOAbstractView::m2p(double meter) const {
     957      3186842 :     return  meter * getWidth() / myChanger->getViewport().getWidth();
     958              : }
     959              : 
     960              : 
     961              : double
     962            0 : GUISUMOAbstractView::p2m(double pixel) const {
     963            0 :     return pixel * myChanger->getViewport().getWidth() / getWidth();
     964              : }
     965              : 
     966              : 
     967              : void
     968         8116 : GUISUMOAbstractView::recenterView() {
     969         8116 :     myChanger->setViewport(*myGrid);
     970         8116 : }
     971              : 
     972              : 
     973              : void
     974          472 : GUISUMOAbstractView::centerTo(GUIGlID id, bool applyZoom, double zoomDist) {
     975          472 :     GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
     976          472 :     if (o != nullptr && dynamic_cast<GUIGlObject*>(o) != nullptr) {
     977          472 :         const Boundary& b = o->getCenteringBoundary();
     978          472 :         if (b.getCenter() != Position::INVALID) {
     979          472 :             if (applyZoom && zoomDist < 0) {
     980            0 :                 myChanger->setViewport(b);
     981            0 :                 update(); // only update when centering onto an object once
     982              :             } else {
     983              :                 // called during tracking. update is triggered somewhere else
     984          472 :                 myChanger->centerTo(b.getCenter(), zoomDist, applyZoom);
     985          472 :                 updatePositionInformationLabel();
     986              :             }
     987              :         }
     988              :     }
     989          472 :     GUIGlObjectStorage::gIDStorage.unblockObject(id);
     990          472 : }
     991              : 
     992              : 
     993              : void
     994            0 : GUISUMOAbstractView::centerTo(const Position& pos, bool applyZoom, double zoomDist) {
     995              :     // called during tracking. update is triggered somewhere else
     996            0 :     myChanger->centerTo(pos, zoomDist, applyZoom);
     997            0 :     updatePositionInformationLabel();
     998            0 : }
     999              : 
    1000              : 
    1001              : void
    1002            3 : GUISUMOAbstractView::centerTo(const Boundary& bound) {
    1003            3 :     myChanger->setViewport(bound);
    1004            3 :     update();
    1005            3 : }
    1006              : 
    1007              : 
    1008              : GUIMainWindow*
    1009            0 : GUISUMOAbstractView::getMainWindow() const {
    1010            0 :     return myApp;
    1011              : }
    1012              : 
    1013              : 
    1014              : Position
    1015            0 : GUISUMOAbstractView::getWindowCursorPosition() const {
    1016            0 :     return Position(myWindowCursorPositionX, myWindowCursorPositionY);
    1017              : }
    1018              : 
    1019              : 
    1020              : void
    1021            0 : GUISUMOAbstractView::setWindowCursorPosition(FXint x, FXint y) {
    1022            0 :     myWindowCursorPositionX = x + myMouseHotspotX;
    1023            0 :     myWindowCursorPositionY = y + myMouseHotspotY;
    1024            0 : }
    1025              : 
    1026              : 
    1027              : FXbool
    1028       788544 : GUISUMOAbstractView::makeCurrent() {
    1029       788544 :     FXbool ret = FXGLCanvas::makeCurrent();
    1030       788544 :     return ret;
    1031              : }
    1032              : 
    1033              : 
    1034              : long
    1035         7517 : GUISUMOAbstractView::onConfigure(FXObject*, FXSelector, void*) {
    1036         7517 :     if (makeCurrent()) {
    1037         7517 :         glViewport(0, 0, getWidth() - 1, getHeight() - 1);
    1038        30068 :         glClearColor(
    1039         7517 :             myVisualizationSettings->backgroundColor.red() / 255.f,
    1040         7517 :             myVisualizationSettings->backgroundColor.green() / 255.f,
    1041         7517 :             myVisualizationSettings->backgroundColor.blue() / 255.f,
    1042         7517 :             myVisualizationSettings->backgroundColor.alpha() / 255.f);
    1043         7517 :         doInit();
    1044         7517 :         myAmInitialised = true;
    1045         7517 :         makeNonCurrent();
    1046         7517 :         checkSnapshots();
    1047              :     }
    1048         7517 :     return 1;
    1049              : }
    1050              : 
    1051              : 
    1052              : long
    1053       752299 : GUISUMOAbstractView::onPaint(FXObject*, FXSelector, void*) {
    1054       752299 :     if (!isEnabled() || !myAmInitialised) {
    1055              :         return 1;
    1056              :     }
    1057       744721 :     if (makeCurrent()) {
    1058       744721 :         paintGL();
    1059       744721 :         makeNonCurrent();
    1060              :     }
    1061              :     // run tests
    1062       744721 :     myApp->handle(this, FXSEL(SEL_COMMAND, MID_RUNTESTS), nullptr);
    1063       744721 :     return 1;
    1064              : }
    1065              : 
    1066              : 
    1067              : GUIGLObjectPopupMenu*
    1068            0 : GUISUMOAbstractView::getPopup() const {
    1069            0 :     return myPopup;
    1070              : }
    1071              : 
    1072              : 
    1073              : const Position&
    1074            0 : GUISUMOAbstractView::getPopupPosition() const {
    1075            0 :     return myPopupPosition;
    1076              : }
    1077              : 
    1078              : 
    1079              : void
    1080            0 : GUISUMOAbstractView::destroyPopup() {
    1081            0 :     if (myPopup != nullptr) {
    1082            0 :         myPopup->removePopupFromObject();
    1083            0 :         delete myPopup;
    1084              :         myPopupPosition.set(0, 0);
    1085            0 :         myPopup = nullptr;
    1086              :         myCurrentObjectsDialog.clear();
    1087              :     }
    1088            0 : }
    1089              : 
    1090              : 
    1091              : void
    1092            0 : GUISUMOAbstractView::replacePopup(GUIGLObjectPopupMenu* popUp) {
    1093              :     // use the same position of old popUp
    1094            0 :     popUp->move(myPopup->getX(), myPopup->getY());
    1095              :     // delete and replace popup
    1096            0 :     myPopup->removePopupFromObject();
    1097            0 :     delete myPopup;
    1098            0 :     myPopup = popUp;
    1099              :     // create and show popUp
    1100            0 :     myPopup->create();
    1101            0 :     myPopup->show();
    1102            0 :     myChanger->onRightBtnRelease(nullptr);
    1103            0 :     setFocus();
    1104            0 : }
    1105              : 
    1106              : 
    1107              : long
    1108            0 : GUISUMOAbstractView::onLeftBtnPress(FXObject*, FXSelector, void* ptr) {
    1109            0 :     destroyPopup();
    1110            0 :     setFocus();
    1111              :     FXEvent* e = (FXEvent*) ptr;
    1112              :     // check whether the selection-mode is activated
    1113            0 :     if ((e->state & CONTROLMASK) != 0) {
    1114              :         // toggle selection of object under cursor
    1115            0 :         if (makeCurrent()) {
    1116            0 :             int id = getObjectUnderCursor();
    1117            0 :             if (id != 0) {
    1118            0 :                 gSelected.toggleSelection(id);
    1119              :             }
    1120            0 :             makeNonCurrent();
    1121            0 :             if (id != 0) {
    1122              :                 // possibly, the selection-coloring is used,
    1123              :                 //  so we should update the screen again...
    1124            0 :                 update();
    1125              :             }
    1126              :         }
    1127              :     }
    1128            0 :     if ((e->state & SHIFTMASK) != 0) {
    1129              :         // track vehicle or person under cursor
    1130            0 :         if (makeCurrent()) {
    1131            0 :             int id = getObjectUnderCursor();
    1132            0 :             if (id != 0) {
    1133            0 :                 GUIGlObject* o = GUIGlObjectStorage::gIDStorage.getObjectBlocking(id);
    1134            0 :                 if (o != nullptr) {
    1135            0 :                     if (!myApp->isGaming() && (o->getType() == GLO_VEHICLE || o->getType() == GLO_PERSON)) {
    1136            0 :                         startTrack(id);
    1137              :                     }
    1138              :                 }
    1139              :             }
    1140            0 :             makeNonCurrent();
    1141              :         }
    1142              :     }
    1143            0 :     myChanger->onLeftBtnPress(ptr);
    1144            0 :     grab();
    1145              :     // Check there are double click
    1146            0 :     if (e->click_count == 2) {
    1147            0 :         handle(this, FXSEL(SEL_DOUBLECLICKED, 0), ptr);
    1148              :     }
    1149            0 :     return 1;
    1150              : }
    1151              : 
    1152              : 
    1153              : long
    1154            0 : GUISUMOAbstractView::onLeftBtnRelease(FXObject*, FXSelector, void* ptr) {
    1155            0 :     destroyPopup();
    1156            0 :     myChanger->onLeftBtnRelease(ptr);
    1157            0 :     if (myApp->isGaming()) {
    1158            0 :         onGamingClick(getPositionInformation());
    1159              :     }
    1160            0 :     ungrab();
    1161            0 :     return 1;
    1162              : }
    1163              : 
    1164              : 
    1165              : long
    1166            0 : GUISUMOAbstractView::onMiddleBtnPress(FXObject*, FXSelector, void* ptr) {
    1167            0 :     destroyPopup();
    1168            0 :     setFocus();
    1169            0 :     if (!myApp->isGaming()) {
    1170            0 :         myChanger->onMiddleBtnPress(ptr);
    1171              :     }
    1172            0 :     grab();
    1173              :     // enable panning
    1174            0 :     myPanning = true;
    1175              :     // set cursors
    1176            0 :     setDefaultCursor(GUICursorSubSys::getCursor(GUICursor::MOVEVIEW));
    1177            0 :     setDragCursor(GUICursorSubSys::getCursor(GUICursor::MOVEVIEW));
    1178            0 :     return 1;
    1179              : }
    1180              : 
    1181              : 
    1182              : long
    1183            0 : GUISUMOAbstractView::onMiddleBtnRelease(FXObject*, FXSelector, void* ptr) {
    1184            0 :     destroyPopup();
    1185            0 :     if (!myApp->isGaming()) {
    1186            0 :         myChanger->onMiddleBtnRelease(ptr);
    1187              :     }
    1188            0 :     ungrab();
    1189              :     // disable panning
    1190            0 :     myPanning = false;
    1191              :     // restore cursors
    1192            0 :     setDefaultCursor(GUICursorSubSys::getCursor(GUICursor::DEFAULT));
    1193            0 :     setDragCursor(GUICursorSubSys::getCursor(GUICursor::DEFAULT));
    1194            0 :     return 1;
    1195              : }
    1196              : 
    1197              : 
    1198              : long
    1199            0 : GUISUMOAbstractView::onRightBtnPress(FXObject*, FXSelector, void* ptr) {
    1200            0 :     destroyPopup();
    1201            0 :     if (!myApp->isGaming()) {
    1202            0 :         myChanger->onRightBtnPress(ptr);
    1203              :     }
    1204            0 :     grab();
    1205            0 :     return 1;
    1206              : }
    1207              : 
    1208              : 
    1209              : long
    1210            0 : GUISUMOAbstractView::onRightBtnRelease(FXObject* o, FXSelector sel, void* ptr) {
    1211            0 :     destroyPopup();
    1212            0 :     onMouseMove(o, sel, ptr);
    1213            0 :     if (!myChanger->onRightBtnRelease(ptr) && !myApp->isGaming()) {
    1214            0 :         openObjectDialogAtCursor((FXEvent*)ptr);
    1215              :     }
    1216            0 :     if (myApp->isGaming()) {
    1217            0 :         onGamingRightClick(getPositionInformation());
    1218              :     }
    1219            0 :     ungrab();
    1220            0 :     return 1;
    1221              : }
    1222              : 
    1223              : 
    1224              : long
    1225            0 : GUISUMOAbstractView::onDoubleClicked(FXObject*, FXSelector, void*) {
    1226            0 :     return 1;
    1227              : }
    1228              : 
    1229              : 
    1230              : long
    1231            0 : GUISUMOAbstractView::onMouseWheel(FXObject*, FXSelector, void* ptr) {
    1232            0 :     if (!myApp->isGaming()) {
    1233            0 :         myChanger->onMouseWheel(ptr);
    1234              :         // upddate viewport
    1235            0 :         if (myGUIDialogEditViewport != nullptr) {
    1236            0 :             myGUIDialogEditViewport->setValues(myChanger->getZoom(),
    1237            0 :                                                myChanger->getXPos(), myChanger->getYPos(),
    1238            0 :                                                myChanger->getRotation());
    1239              :         }
    1240            0 :         updatePositionInformationLabel();
    1241              :     }
    1242            0 :     return 1;
    1243              : }
    1244              : 
    1245              : 
    1246              : long
    1247            0 : GUISUMOAbstractView::onMouseMove(FXObject*, FXSelector, void* ptr) {
    1248              :     // check if popup exist
    1249            0 :     if (myPopup) {
    1250              :         // check if handle front element
    1251            0 :         if (myPopupPosition == getPositionInformation()) {
    1252            0 :             myPopupPosition = Position::INVALID;
    1253            0 :             myPopup->handle(this, FXSEL(SEL_COMMAND, MID_CURSORDIALOG_FRONT), nullptr);
    1254            0 :             destroyPopup();
    1255            0 :         } else if (!myPopup->shown()) {
    1256            0 :             destroyPopup();
    1257              :         }
    1258              :     }
    1259            0 :     if (myPopup == nullptr) {
    1260            0 :         if (myGUIDialogEditViewport == nullptr || !myGUIDialogEditViewport->haveGrabbed()) {
    1261            0 :             myChanger->onMouseMove(ptr);
    1262              :         }
    1263            0 :         if (myGUIDialogEditViewport != nullptr) {
    1264            0 :             myGUIDialogEditViewport->setValues(myChanger->getZoom(),
    1265            0 :                                                myChanger->getXPos(), myChanger->getYPos(),
    1266            0 :                                                myChanger->getRotation());
    1267              :         }
    1268            0 :         updatePositionInformationLabel();
    1269              :     }
    1270            0 :     return 1;
    1271              : }
    1272              : 
    1273              : 
    1274              : long
    1275            0 : GUISUMOAbstractView::onMouseLeft(FXObject*, FXSelector, void* /*data*/) {
    1276            0 :     return 1;
    1277              : }
    1278              : 
    1279              : std::vector<GUIGlObject*>
    1280            0 : GUISUMOAbstractView::filterContextObjects(const std::vector<GUIGlObject*>& objects) {
    1281              :     // assume input is sorted with ComparatorClickPriority
    1282              :     std::vector<GUIGlObject*> result;
    1283            0 :     for (GUIGlObject* o : objects) {
    1284            0 :         if (o->getClickPriority() != GUIGlObject::INVALID_PRIORITY && (result.empty() || result.back() != o)) {
    1285            0 :             result.push_back(o);
    1286              :         }
    1287              :     }
    1288            0 :     return result;
    1289            0 : }
    1290              : 
    1291              : 
    1292              : void
    1293            0 : GUISUMOAbstractView::openObjectDialogAtCursor(const FXEvent* ev) {
    1294              :     // release the mouse grab
    1295            0 :     ungrab();
    1296              :     // check if alt key is pressed
    1297            0 :     const bool altKeyPressed = ((ev->state & ALTMASK) != 0);
    1298              :     // check if SUMO is enabled, initialised and Make OpenGL context current
    1299            0 :     if (isEnabled() && myAmInitialised && makeCurrent()) {
    1300            0 :         auto objectsUnderCursor = getGUIGlObjectsUnderCursor();
    1301            0 :         if (objectsUnderCursor.empty()) {
    1302            0 :             myPopup = GUIGlObjectStorage::gIDStorage.getNetObject()->getPopUpMenu(*myApp, *this);
    1303              :         } else {
    1304            0 :             std::sort(objectsUnderCursor.begin(), objectsUnderCursor.end(), ComparatorClickPriority());
    1305            0 :             std::vector<GUIGlObject*> filtered = filterContextObjects(objectsUnderCursor);
    1306            0 :             if (filtered.size() > 1 && (altKeyPressed
    1307            0 :                                         || filtered[0]->getClickPriority() == filtered[1]->getClickPriority())) {
    1308              :                 // open dialog for picking among objects (without duplicates)
    1309            0 :                 myPopup = new GUICursorDialog(GUIGLObjectPopupMenu::PopupType::PROPERTIES, this, filtered);
    1310              :             } else {
    1311            0 :                 myPopup = objectsUnderCursor.front()->getPopUpMenu(*myApp, *this);
    1312              :             }
    1313            0 :         }
    1314            0 :         openPopupDialog();
    1315            0 :         makeNonCurrent();
    1316            0 :     }
    1317            0 : }
    1318              : 
    1319              : 
    1320              : void
    1321            0 : GUISUMOAbstractView::openObjectDialog(const std::vector<GUIGlObject*>& objects, const bool filter) {
    1322            0 :     if (objects.size() > 0) {
    1323              :         // create cursor popup dialog
    1324            0 :         if (objects.size() == 1) {
    1325            0 :             myCurrentObjectsDialog = objects;
    1326            0 :         } else if (filter) {
    1327              :             // declare filtered objects
    1328              :             std::vector<GUIGlObject*> filteredGLObjects;
    1329              :             // fill filtered objects
    1330            0 :             for (const auto& glObject : objects) {
    1331              :                 // compare type with first element type
    1332            0 :                 if (glObject->getType() == objects.front()->getType()) {
    1333            0 :                     filteredGLObjects.push_back(glObject);
    1334              :                 }
    1335              :             }
    1336            0 :             myCurrentObjectsDialog = filteredGLObjects;
    1337            0 :         } else {
    1338            0 :             myCurrentObjectsDialog = objects;
    1339              :         }
    1340            0 :         if (myCurrentObjectsDialog.size() > 1) {
    1341            0 :             myPopup = new GUICursorDialog(GUIGLObjectPopupMenu::PopupType::PROPERTIES, this, myCurrentObjectsDialog);
    1342              :         } else {
    1343            0 :             myPopup = myCurrentObjectsDialog.front()->getPopUpMenu(*myApp, *this);
    1344              :         }
    1345              :         // open popup dialog
    1346            0 :         openPopupDialog();
    1347              :     }
    1348            0 : }
    1349              : 
    1350              : 
    1351              : long
    1352            0 : GUISUMOAbstractView::onKeyPress(FXObject* o, FXSelector sel, void* ptr) {
    1353              :     const FXEvent* e = (FXEvent*) ptr;
    1354              :     // check if process canvas or popup
    1355            0 :     if (myPopup != nullptr) {
    1356            0 :         return myPopup->onKeyPress(o, sel, ptr);
    1357              :     } else {
    1358            0 :         if (e->state & CONTROLMASK) {
    1359            0 :             if (e->code == FX::KEY_Page_Up) {
    1360            0 :                 myVisualizationSettings->gridXSize *= 2;
    1361            0 :                 myVisualizationSettings->gridYSize *= 2;
    1362            0 :                 update();
    1363            0 :                 return 1;
    1364            0 :             } else if (e->code == FX::KEY_Page_Down) {
    1365            0 :                 myVisualizationSettings->gridXSize /= 2;
    1366            0 :                 myVisualizationSettings->gridYSize /= 2;
    1367            0 :                 update();
    1368            0 :                 return 1;
    1369              :             }
    1370              :         }
    1371            0 :         FXGLCanvas::onKeyPress(o, sel, ptr);
    1372            0 :         return myChanger->onKeyPress(ptr);
    1373              :     }
    1374              : }
    1375              : 
    1376              : 
    1377              : long
    1378            0 : GUISUMOAbstractView::onKeyRelease(FXObject* o, FXSelector sel, void* ptr) {
    1379              :     // check if process canvas or popup
    1380            0 :     if (myPopup != nullptr) {
    1381            0 :         return myPopup->onKeyRelease(o, sel, ptr);
    1382              :     } else {
    1383            0 :         FXGLCanvas::onKeyRelease(o, sel, ptr);
    1384            0 :         return myChanger->onKeyRelease(ptr);
    1385              :     }
    1386              : }
    1387              : 
    1388              : // ------------ Dealing with snapshots
    1389              : 
    1390              : void
    1391          308 : GUISUMOAbstractView::addSnapshot(SUMOTime time, const std::string& file, const int w, const int h) {
    1392              : #ifdef DEBUG_SNAPSHOT
    1393              :     std::cout << "add snapshot time=" << time << " file=" << file << "\n";
    1394              : #endif
    1395          308 :     FXMutexLock lock(mySnapshotsMutex);
    1396          616 :     mySnapshots[time].push_back(std::make_tuple(file, w, h));
    1397          308 : }
    1398              : 
    1399              : 
    1400              : std::string
    1401          308 : GUISUMOAbstractView::makeSnapshot(const std::string& destFile, const int w, const int h) {
    1402          308 :     if (w >= 0) {
    1403            3 :         resize(w, h);
    1404            3 :         repaint();
    1405              :     }
    1406              :     std::string errorMessage;
    1407          308 :     FXString ext = FXPath::extension(destFile.c_str());
    1408          308 :     const bool useGL2PS = ext == "ps" || ext == "eps" || ext == "pdf" || ext == "svg" || ext == "tex" || ext == "pgf";
    1409              : #ifdef HAVE_FFMPEG
    1410          308 :     const bool useVideo = destFile == "" || ext == "h264" || ext == "hevc" || ext == "mp4";
    1411              : #endif
    1412          308 :     for (int i = 0; i < 10 && !makeCurrent(); ++i) {
    1413            0 :         MFXSingleEventThread::sleep(100);
    1414              :     }
    1415              :     // draw
    1416         1232 :     glClearColor(
    1417          308 :         myVisualizationSettings->backgroundColor.red() / 255.f,
    1418          308 :         myVisualizationSettings->backgroundColor.green() / 255.f,
    1419          308 :         myVisualizationSettings->backgroundColor.blue() / 255.f,
    1420          308 :         myVisualizationSettings->backgroundColor.alpha() / 255.f);
    1421          308 :     glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    1422          308 :     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    1423              : 
    1424          308 :     if (myVisualizationSettings->dither) {
    1425            0 :         glEnable(GL_DITHER);
    1426              :     } else {
    1427          308 :         glDisable(GL_DITHER);
    1428              :     }
    1429          308 :     glEnable(GL_BLEND);
    1430          308 :     glDisable(GL_LINE_SMOOTH);
    1431              : 
    1432          308 :     applyGLTransform();
    1433              : 
    1434          308 :     if (useGL2PS) {
    1435              : #ifdef HAVE_GL2PS
    1436              :         GLint format = GL2PS_PS;
    1437            0 :         if (ext == "ps") {
    1438              :             format = GL2PS_PS;
    1439            0 :         } else if (ext == "eps") {
    1440              :             format = GL2PS_EPS;
    1441            0 :         } else if (ext == "pdf") {
    1442              :             format = GL2PS_PDF;
    1443            0 :         } else if (ext == "tex") {
    1444              :             format = GL2PS_TEX;
    1445            0 :         } else if (ext == "svg") {
    1446              :             format = GL2PS_SVG;
    1447            0 :         } else if (ext == "pgf") {
    1448              :             format = GL2PS_PGF;
    1449              :         } else {
    1450            0 :             return "Could not save '" + destFile + "'.\n Unrecognized format '" + std::string(ext.text()) + "'.";
    1451              :         }
    1452            0 :         FILE* fp = fopen(destFile.c_str(), "wb");
    1453            0 :         if (fp == 0) {
    1454            0 :             return "Could not save '" + destFile + "'.\n Could not open file for writing";
    1455              :         }
    1456            0 :         GLHelper::setGL2PS();
    1457              :         GLint buffsize = 0, state = GL2PS_OVERFLOW;
    1458              :         GLint viewport[4];
    1459            0 :         glGetIntegerv(GL_VIEWPORT, viewport);
    1460            0 :         while (state == GL2PS_OVERFLOW) {
    1461            0 :             buffsize += 1024 * 1024;
    1462            0 :             gl2psBeginPage(destFile.c_str(), "sumo-gui; https://sumo.dlr.de", viewport, format, GL2PS_SIMPLE_SORT,
    1463              :                            GL2PS_DRAW_BACKGROUND | GL2PS_USE_CURRENT_VIEWPORT,
    1464              :                            GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, "out.eps");
    1465            0 :             glMatrixMode(GL_MODELVIEW);
    1466            0 :             GLHelper::pushMatrix();
    1467            0 :             glDisable(GL_TEXTURE_2D);
    1468            0 :             glDisable(GL_ALPHA_TEST);
    1469            0 :             glDisable(GL_BLEND);
    1470            0 :             glEnable(GL_DEPTH_TEST);
    1471              :             // draw decals (if not in grabbing mode)
    1472              : 
    1473            0 :             drawDecals();
    1474            0 :             if (myVisualizationSettings->showGrid) {
    1475            0 :                 paintGLGrid();
    1476              :             }
    1477              : 
    1478            0 :             glLineWidth(1);
    1479            0 :             glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    1480            0 :             Boundary viewPort = myChanger->getViewport();
    1481            0 :             const float minB[2] = { (float)viewPort.xmin(), (float)viewPort.ymin() };
    1482            0 :             const float maxB[2] = { (float)viewPort.xmax(), (float)viewPort.ymax() };
    1483            0 :             myVisualizationSettings->scale = m2p(SUMO_const_laneWidth);
    1484            0 :             glEnable(GL_POLYGON_OFFSET_FILL);
    1485            0 :             glEnable(GL_POLYGON_OFFSET_LINE);
    1486            0 :             myGrid->Search(minB, maxB, *myVisualizationSettings);
    1487              : 
    1488            0 :             displayLegends();
    1489            0 :             state = gl2psEndPage();
    1490            0 :             glFinish();
    1491              :         }
    1492            0 :         GLHelper::setGL2PS(false);
    1493            0 :         fclose(fp);
    1494              : #else
    1495              :         return "Could not save '" + destFile + "', gl2ps was not enabled at compile time.";
    1496              : #endif
    1497              :     } else {
    1498          308 :         doPaintGL(GL_RENDER, myChanger->getViewport());
    1499          308 :         displayLegends();
    1500          308 :         swapBuffers();
    1501          308 :         glFinish();
    1502              :         FXColor* buf;
    1503          308 :         FXMALLOC(&buf, FXColor, getWidth()*getHeight());
    1504              :         // read from the back buffer
    1505          308 :         glReadBuffer(GL_BACK);
    1506              :         // Read the pixels
    1507          308 :         glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)buf);
    1508          308 :         makeNonCurrent();
    1509          308 :         update();
    1510              :         // mirror
    1511              :         int mwidth = getWidth();
    1512              :         int mheight = getHeight();
    1513          308 :         FXColor* paa = buf;
    1514          308 :         FXColor* pbb = buf + mwidth * (mheight - 1);
    1515              :         do {
    1516              :             FXColor* pa = paa;
    1517        40156 :             paa += mwidth;
    1518              :             FXColor* pb = pbb;
    1519        40156 :             pbb -= mwidth;
    1520              :             do {
    1521     19691440 :                 FXColor t = *pa;
    1522     19691440 :                 *pa++ = *pb;
    1523     19691440 :                 *pb++ = t;
    1524     19691440 :             } while (pa < paa);
    1525        40156 :         } while (paa < pbb);
    1526              :         try {
    1527              : #ifdef HAVE_FFMPEG
    1528          308 :             if (useVideo) {
    1529              :                 try {
    1530            0 :                     saveFrame(destFile, buf);
    1531              :                     errorMessage = "video";
    1532            0 :                 } catch (std::runtime_error& err) {
    1533            0 :                     errorMessage = err.what();
    1534            0 :                 }
    1535              :             } else
    1536              : #endif
    1537          308 :                 if (!MFXImageHelper::saveImage(destFile, getWidth(), getHeight(), buf)) {
    1538            0 :                     errorMessage = "Could not save '" + destFile + "'.";
    1539              :                 }
    1540            3 :         } catch (InvalidArgument& e) {
    1541            6 :             errorMessage = "Could not save '" + destFile + "'.\n" + e.what();
    1542            3 :         }
    1543          308 :         FXFREE(&buf);
    1544              :     }
    1545          308 :     return errorMessage;
    1546          308 : }
    1547              : 
    1548              : 
    1549              : void
    1550            0 : GUISUMOAbstractView::saveFrame(const std::string& destFile, FXColor* buf) {
    1551              :     UNUSED_PARAMETER(destFile);
    1552              :     UNUSED_PARAMETER(buf);
    1553            0 : }
    1554              : 
    1555              : 
    1556              : void
    1557      9736478 : GUISUMOAbstractView::checkSnapshots() {
    1558      9736478 :     const SUMOTime time = getCurrentTimeStep() - DELTA_T;
    1559              : #ifdef DEBUG_SNAPSHOT
    1560              :     std::cout << "check snapshots time=" << time << " registeredTimes=" << mySnapshots.size() << "\n";
    1561              : #endif
    1562      9736478 :     FXMutexLock lock(mySnapshotsMutex);
    1563              :     const auto snapIt = mySnapshots.find(time);
    1564      9736478 :     if (snapIt == mySnapshots.end()) {
    1565              :         return;
    1566              :     }
    1567           34 :     std::vector<std::tuple<std::string, int, int> > files = snapIt->second;
    1568              :     lock.unlock();
    1569              :     // decouple map access and painting to avoid deadlock
    1570          342 :     for (const auto& entry : files) {
    1571              : #ifdef DEBUG_SNAPSHOT
    1572              :         std::cout << "make snapshot time=" << time << " file=" << file << "\n";
    1573              : #endif
    1574          308 :         const std::string& error = makeSnapshot(std::get<0>(entry), std::get<1>(entry), std::get<2>(entry));
    1575          308 :         if (error != "" && error != "video") {
    1576            9 :             WRITE_WARNING(error);
    1577              :         }
    1578              :     }
    1579              :     // synchronization with a waiting run thread
    1580              :     lock.lock();
    1581              :     mySnapshots.erase(time);
    1582           34 :     mySnapshotCondition.signal();
    1583              : #ifdef DEBUG_SNAPSHOT
    1584              :     std::cout << "  files=" << toString(files) << " myApplicationSnapshots=" << joinToString(*myApplicationSnapshots, ",") << "\n";
    1585              : #endif
    1586           34 : }
    1587              : 
    1588              : 
    1589              : void
    1590      9736526 : GUISUMOAbstractView::waitForSnapshots(const SUMOTime snapshotTime) {
    1591      9736526 :     FXMutexLock lock(mySnapshotsMutex);
    1592              :     if (mySnapshots.count(snapshotTime) > 0) {
    1593           34 :         mySnapshotCondition.wait(mySnapshotsMutex);
    1594              :     }
    1595      9736526 : }
    1596              : 
    1597              : 
    1598              : SUMOTime
    1599            0 : GUISUMOAbstractView::getCurrentTimeStep() const {
    1600            0 :     return 0;
    1601              : }
    1602              : 
    1603              : 
    1604              : void
    1605            0 : GUISUMOAbstractView::showViewschemeEditor() {
    1606            0 :     if (myGUIDialogViewSettings == nullptr) {
    1607            0 :         myGUIDialogViewSettings = new GUIDialog_ViewSettings(this, myVisualizationSettings);
    1608            0 :         myGUIDialogViewSettings->create();
    1609              :     } else {
    1610            0 :         myGUIDialogViewSettings->setCurrent(myVisualizationSettings);
    1611              :     }
    1612            0 :     setFocus();
    1613            0 :     myGUIDialogViewSettings->show();
    1614            0 : }
    1615              : 
    1616              : 
    1617              : GUIDialog_EditViewport*
    1618            0 : GUISUMOAbstractView::getViewportEditor() {
    1619            0 :     if (myGUIDialogEditViewport == nullptr) {
    1620            0 :         myGUIDialogEditViewport = new GUIDialog_EditViewport(this, TLC("Labels", "Edit Viewport"));
    1621            0 :         myGUIDialogEditViewport->create();
    1622              :     }
    1623            0 :     updateViewportValues();
    1624            0 :     return myGUIDialogEditViewport;
    1625              : }
    1626              : 
    1627              : 
    1628            0 : void GUISUMOAbstractView::updateViewportValues() {
    1629            0 :     myGUIDialogEditViewport->setValues(myChanger->getZoom(),
    1630            0 :                                        myChanger->getXPos(), myChanger->getYPos(),
    1631            0 :                                        myChanger->getRotation());
    1632            0 : }
    1633              : 
    1634              : 
    1635              : void
    1636            0 : GUISUMOAbstractView::showViewportEditor() {
    1637            0 :     getViewportEditor(); // make sure it exists;
    1638            0 :     Position p(myChanger->getXPos(), myChanger->getYPos(), myChanger->getZPos());
    1639            0 :     myGUIDialogEditViewport->setOldValues(p, Position::INVALID, myChanger->getRotation());
    1640            0 :     myGUIDialogEditViewport->show();
    1641            0 : }
    1642              : 
    1643              : 
    1644              : void
    1645           16 : GUISUMOAbstractView::setViewportFromToRot(const Position& lookFrom, const Position& /* lookAt */, double rotation) {
    1646           16 :     myChanger->setViewportFrom(lookFrom.x(), lookFrom.y(), lookFrom.z());
    1647           16 :     myChanger->setRotation(rotation);
    1648           16 :     update();
    1649           16 : }
    1650              : 
    1651              : 
    1652              : void
    1653            4 : GUISUMOAbstractView::copyViewportTo(GUISUMOAbstractView* view) {
    1654              :     // look straight down
    1655            4 :     view->setViewportFromToRot(Position(myChanger->getXPos(), myChanger->getYPos(), myChanger->getZPos()),
    1656            4 :                                Position(myChanger->getXPos(), myChanger->getYPos(), 0),
    1657            4 :                                myChanger->getRotation());
    1658            4 : }
    1659              : 
    1660              : 
    1661              : bool
    1662            0 : GUISUMOAbstractView::setColorScheme(const std::string&) {
    1663            0 :     return true;
    1664              : }
    1665              : 
    1666              : 
    1667              : const GUIVisualizationSettings&
    1668            3 : GUISUMOAbstractView::getVisualisationSettings() const {
    1669            3 :     return *myVisualizationSettings;
    1670              : }
    1671              : 
    1672              : 
    1673              : GUIVisualizationSettings*
    1674            0 : GUISUMOAbstractView::editVisualisationSettings() const {
    1675            0 :     return myVisualizationSettings;
    1676              : }
    1677              : 
    1678              : 
    1679              : void
    1680            0 : GUISUMOAbstractView::remove(GUIDialog_EditViewport*) {
    1681            0 :     myGUIDialogEditViewport = nullptr;
    1682            0 : }
    1683              : 
    1684              : 
    1685              : void
    1686            0 : GUISUMOAbstractView::remove(GUIDialog_ViewSettings*) {
    1687            0 :     myGUIDialogViewSettings = nullptr;
    1688            0 : }
    1689              : 
    1690              : 
    1691              : double
    1692            0 : GUISUMOAbstractView::getGridWidth() const {
    1693            0 :     return myGrid->getWidth();
    1694              : }
    1695              : 
    1696              : 
    1697              : double
    1698            0 : GUISUMOAbstractView::getGridHeight() const {
    1699            0 :     return myGrid->getHeight();
    1700              : }
    1701              : 
    1702              : 
    1703              : void
    1704            0 : GUISUMOAbstractView::startTrack(int /*id*/) {
    1705            0 : }
    1706              : 
    1707              : 
    1708              : void
    1709            0 : GUISUMOAbstractView::stopTrack() {
    1710            0 : }
    1711              : 
    1712              : 
    1713              : GUIGlID
    1714            0 : GUISUMOAbstractView::getTrackedID() const {
    1715            0 :     return GUIGlObject::INVALID_ID;
    1716              : }
    1717              : 
    1718              : 
    1719              : void
    1720            0 : GUISUMOAbstractView::onGamingClick(Position /*pos*/) {
    1721            0 : }
    1722              : 
    1723              : void
    1724            0 : GUISUMOAbstractView::onGamingRightClick(Position /*pos*/) {
    1725            0 : }
    1726              : 
    1727              : 
    1728              : std::vector<GUISUMOAbstractView::Decal>&
    1729         8084 : GUISUMOAbstractView::getDecals() {
    1730         8084 :     return myDecals;
    1731              : }
    1732              : 
    1733              : 
    1734              : FXMutex&
    1735            0 : GUISUMOAbstractView::getDecalsLockMutex() {
    1736            0 :     return myDecalsLockMutex;
    1737              : }
    1738              : 
    1739              : 
    1740              : void
    1741            7 : GUISUMOAbstractView::queueTextureDelete(unsigned int textureId) {
    1742            7 :     FXMutexLock lock(myTextureDeleteMutex);
    1743            7 :     myPendingTextureDeletes.push_back(textureId);
    1744            7 : }
    1745              : 
    1746              : 
    1747              : void
    1748       760892 : GUISUMOAbstractView::processPendingTextureDeletes() {
    1749       760892 :     FXMutexLock lock(myTextureDeleteMutex);
    1750       760892 :     if (!myPendingTextureDeletes.empty()) {
    1751            4 :         glDeleteTextures(
    1752              :             static_cast<GLsizei>(myPendingTextureDeletes.size()),
    1753              :             myPendingTextureDeletes.data()
    1754              :         );
    1755              :         myPendingTextureDeletes.clear();
    1756              :     }
    1757       760892 : }
    1758              : 
    1759              : 
    1760              : void
    1761         8084 : GUISUMOAbstractView::clearDecals() {
    1762         8084 :     FXMutexLock lock(myDecalsLockMutex);
    1763         8091 :     for (auto& decal : myDecals) {
    1764            7 :         if (decal.glID > 0) {
    1765            7 :             queueTextureDelete(static_cast<unsigned int>(decal.glID));
    1766            7 :             decal.glID = -1;
    1767              :         }
    1768            7 :         decal.initialised = false;
    1769              :     }
    1770              :     myDecals.clear();
    1771         8084 : }
    1772              : 
    1773              : 
    1774              : MFXComboBoxIcon*
    1775           40 : GUISUMOAbstractView::getColoringSchemesCombo() {
    1776           40 :     return myGlChildWindowParent->getColoringSchemesCombo();
    1777              : }
    1778              : 
    1779              : 
    1780              : FXImage*
    1781            7 : GUISUMOAbstractView::checkGDALImage(Decal& d) {
    1782              : #ifdef HAVE_GDAL
    1783            7 :     GDALAllRegister();
    1784            7 :     GDALDataset* poDataset = (GDALDataset*)GDALOpen(d.filename.c_str(), GA_ReadOnly);
    1785            7 :     if (poDataset == 0) {
    1786              :         return 0;
    1787              :     }
    1788            7 :     const int xSize = poDataset->GetRasterXSize();
    1789            7 :     const int ySize = poDataset->GetRasterYSize();
    1790              :     // checking for geodata in the picture and try to adapt position and scale
    1791            7 :     if (d.width <= 0.) {
    1792              :         double adfGeoTransform[6];
    1793            0 :         if (poDataset->GetGeoTransform(adfGeoTransform) == CE_None) {
    1794            0 :             Position topLeft(adfGeoTransform[0], adfGeoTransform[3]);
    1795            0 :             const double horizontalSize = xSize * adfGeoTransform[1];
    1796            0 :             const double verticalSize = ySize * adfGeoTransform[5];
    1797            0 :             Position bottomRight(topLeft.x() + horizontalSize, topLeft.y() + verticalSize);
    1798            0 :             if (GeoConvHelper::getFinal().usingGeoProjection() && GeoConvHelper::getFinal().x2cartesian_const(topLeft) && GeoConvHelper::getFinal().x2cartesian_const(bottomRight)) {
    1799              :                 //WRITE_MESSAGE("proj: " + toString(poDataset->GetProjectionRef()) + " dim: " + toString(d.width) + "," + toString(d.height) + " center: " + toString(d.centerX) + "," + toString(d.centerY));
    1800              :             } else {
    1801            0 :                 WRITE_WARNINGF(TL("Could not transform coordinates from WGS84 in decal %, assuming UTM."), d.filename);
    1802            0 :                 topLeft = topLeft + GeoConvHelper::getFinal().getOffset();
    1803            0 :                 bottomRight = bottomRight + GeoConvHelper::getFinal().getOffset();
    1804              :             }
    1805            0 :             d.width = bottomRight.x() - topLeft.x();
    1806            0 :             d.height = topLeft.y() - bottomRight.y();
    1807            0 :             d.centerX = (topLeft.x() + bottomRight.x()) / 2;
    1808            0 :             d.centerY = (topLeft.y() + bottomRight.y()) / 2;
    1809              :         }
    1810              :     }
    1811              : #endif
    1812            7 :     if (d.width <= 0.) {
    1813            0 :         d.width = getGridWidth();
    1814            0 :         d.height = getGridHeight();
    1815              :     }
    1816              : 
    1817              :     // trying to read the picture
    1818              : #ifdef HAVE_GDAL
    1819            7 :     const int picSize = xSize * ySize;
    1820              :     FXColor* result;
    1821            7 :     if (!FXMALLOC(&result, FXColor, picSize)) {
    1822            0 :         WRITE_WARNINGF("Could not allocate memory for %.", d.filename);
    1823            0 :         return 0;
    1824              :     }
    1825       544775 :     for (int j = 0; j < picSize; j++) {
    1826       544768 :         result[j] = GUIDesignTextColorBlack;
    1827              :     }
    1828              :     bool valid = true;
    1829            7 :     for (int i = 1; i <= poDataset->GetRasterCount(); i++) {
    1830            7 :         GDALRasterBand* poBand = poDataset->GetRasterBand(i);
    1831              :         int shift = -1;
    1832            7 :         if (poBand->GetColorInterpretation() == GCI_RedBand) {
    1833              :             shift = 0;
    1834            7 :         } else if (poBand->GetColorInterpretation() == GCI_GreenBand) {
    1835              :             shift = 1;
    1836            7 :         } else if (poBand->GetColorInterpretation() == GCI_BlueBand) {
    1837              :             shift = 2;
    1838            7 :         } else if (poBand->GetColorInterpretation() == GCI_AlphaBand) {
    1839              :             shift = 3;
    1840              :         } else {
    1841              :             valid = false;
    1842              :             break;
    1843              :         }
    1844              :         assert(xSize == poBand->GetXSize() && ySize == poBand->GetYSize());
    1845            0 :         if (poBand->RasterIO(GF_Read, 0, 0, xSize, ySize, ((unsigned char*)result) + shift, xSize, ySize, GDT_Byte, 4, 4 * xSize) == CE_Failure) {
    1846              :             valid = false;
    1847              :             break;
    1848              :         }
    1849              :     }
    1850            7 :     GDALClose(poDataset);
    1851            7 :     if (valid) {
    1852            0 :         return new FXImage(getApp(), result, IMAGE_OWNED | IMAGE_KEEP | IMAGE_SHMI | IMAGE_SHMP, xSize, ySize);
    1853              :     }
    1854            7 :     FXFREE(&result);
    1855              : #endif
    1856              :     return nullptr;
    1857              : }
    1858              : 
    1859              : 
    1860              : void
    1861       745029 : GUISUMOAbstractView::drawDecals() {
    1862       745029 :     GLHelper::pushName(0);
    1863       745029 :     myDecalsLockMutex.lock();
    1864       747381 :     for (auto& decal : myDecals) {
    1865         2352 :         if (decal.skip2D || decal.filename.empty()) {
    1866            0 :             continue;
    1867              :         }
    1868         2352 :         if (!decal.initialised) {
    1869              :             try {
    1870            7 :                 FXImage* img = checkGDALImage(decal);
    1871            7 :                 if (img == nullptr) {
    1872            7 :                     img = MFXImageHelper::loadImage(getApp(), decal.filename);
    1873              :                 }
    1874            7 :                 MFXImageHelper::scalePower2(img, GUITexturesHelper::getMaxTextureSize());
    1875            7 :                 decal.glID = GUITexturesHelper::add(img);
    1876            7 :                 delete img;
    1877            7 :                 decal.initialised = true;
    1878            0 :             } catch (InvalidArgument& e) {
    1879            0 :                 WRITE_ERROR("Could not load '" + decal.filename + "'.\n" + e.what());
    1880            0 :                 decal.skip2D = true;
    1881            0 :             }
    1882              :         }
    1883         2352 :         GLHelper::pushMatrix();
    1884         2352 :         if (decal.screenRelative) {
    1885            0 :             Position center = screenPos2NetPos((int)decal.centerX, (int)decal.centerY);
    1886            0 :             glTranslated(center.x(), center.y(), decal.layer);
    1887              :         } else {
    1888         2352 :             glTranslated(decal.centerX, decal.centerY, decal.layer);
    1889              :         }
    1890         2352 :         glRotated(decal.rot, 0, 0, 1);
    1891         2352 :         glColor3d(1, 1, 1);
    1892         2352 :         double halfWidth = decal.width / 2.;
    1893         2352 :         double halfHeight = decal.height / 2.;
    1894         2352 :         if (decal.screenRelative) {
    1895            0 :             halfWidth = p2m(halfWidth);
    1896            0 :             halfHeight = p2m(halfHeight);
    1897              :         }
    1898         2352 :         GUITexturesHelper::drawTexturedBox(decal.glID, -halfWidth, -halfHeight, halfWidth, halfHeight);
    1899         2352 :         GLHelper::popMatrix();
    1900              :     }
    1901       745029 :     myDecalsLockMutex.unlock();
    1902       745029 :     GLHelper::popName();
    1903       745029 : }
    1904              : 
    1905              : 
    1906              : void
    1907            0 : GUISUMOAbstractView::openPopupDialog() {
    1908              :     int x, y;
    1909              :     FXuint b;
    1910            0 :     myApp->getCursorPosition(x, y, b);
    1911            0 :     int appX = myApp->getX();
    1912            0 :     int popX = x + appX;
    1913            0 :     int popY = y + myApp->getY();
    1914            0 :     myPopup->setX(popX);
    1915            0 :     myPopup->setY(popY);
    1916            0 :     myPopup->create();
    1917            0 :     myPopup->show();
    1918              :     // TODO: try to stay on screen even on a right secondary screen in multi-monitor setup
    1919              :     const int rootWidth = getApp()->getRootWindow()->getWidth();
    1920              :     const int rootHeight = getApp()->getRootWindow()->getHeight();
    1921            0 :     if (popX <= rootWidth) {
    1922            0 :         const int maxX = (appX < 0) ? 0 : rootWidth;
    1923            0 :         popX = MIN2(popX, maxX - myPopup->getWidth() - 10);
    1924              :     }
    1925            0 :     popY = MIN2(popY, rootHeight - myPopup->getHeight() - 50);
    1926            0 :     myPopup->move(popX, popY);
    1927            0 :     myPopupPosition = getPositionInformation();
    1928            0 :     myChanger->onRightBtnRelease(nullptr);
    1929            0 :     setFocus();
    1930            0 : }
    1931              : 
    1932              : // ------------ Additional visualisations
    1933              : 
    1934              : bool
    1935            9 : GUISUMOAbstractView::addAdditionalGLVisualisation(GUIGlObject* const which) {
    1936            9 :     if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
    1937            9 :         myAdditionallyDrawn[which] = 1;
    1938              :     } else {
    1939            0 :         myAdditionallyDrawn[which] = myAdditionallyDrawn[which] + 1;
    1940              :     }
    1941            9 :     update();
    1942            9 :     return true;
    1943              : }
    1944              : 
    1945              : 
    1946              : bool
    1947           34 : GUISUMOAbstractView::removeAdditionalGLVisualisation(GUIGlObject* const which) {
    1948           34 :     if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
    1949              :         return false;
    1950              :     }
    1951            9 :     int cnt = myAdditionallyDrawn[which];
    1952            9 :     if (cnt == 1) {
    1953              :         myAdditionallyDrawn.erase(which);
    1954              :     } else {
    1955            0 :         myAdditionallyDrawn[which] = myAdditionallyDrawn[which] - 1;
    1956              :     }
    1957            9 :     update();
    1958            9 :     return true;
    1959              : }
    1960              : 
    1961              : 
    1962              : bool
    1963            0 : GUISUMOAbstractView::isAdditionalGLVisualisationEnabled(GUIGlObject* const which) const {
    1964            0 :     if (myAdditionallyDrawn.find(which) == myAdditionallyDrawn.end()) {
    1965              :         return false;
    1966              :     } else {
    1967            0 :         return true;
    1968              :     }
    1969              : }
    1970              : 
    1971              : 
    1972              : Boundary
    1973       745029 : GUISUMOAbstractView::applyGLTransform(bool fixRatio) {
    1974       745029 :     Boundary bound = myChanger->getViewport(fixRatio);
    1975       745029 :     glMatrixMode(GL_PROJECTION);
    1976       745029 :     glLoadIdentity();
    1977              :     // as a rough rule, each GLObject is drawn at z = -GUIGlObjectType
    1978              :     // thus, objects with a higher value will be closer (drawn on top)
    1979              :     // // @todo last param should be 0 after modifying all glDraw methods
    1980       745029 :     glOrtho(0, getWidth(), 0, getHeight(), -GLO_MAX - 1, GLO_MAX + 1);
    1981       745029 :     glMatrixMode(GL_MODELVIEW);
    1982       745029 :     glLoadIdentity();
    1983       745029 :     double scaleX = (double)getWidth() / bound.getWidth();
    1984       745029 :     double scaleY = (double)getHeight() / bound.getHeight();
    1985       745029 :     glScaled(scaleX, scaleY, 1);
    1986       745029 :     glTranslated(-bound.xmin(), -bound.ymin(), 0);
    1987              :     // rotate around the center of the screen
    1988              :     //double angle = -90;
    1989       745029 :     if (myChanger->getRotation() != 0) {
    1990            0 :         glTranslated(bound.getCenter().x(), bound.getCenter().y(), 0);
    1991            0 :         glRotated(myChanger->getRotation(), 0, 0, 1);
    1992            0 :         glTranslated(-bound.getCenter().x(), -bound.getCenter().y(), 0);
    1993            0 :         Boundary rotBound;
    1994            0 :         double rad = -DEG2RAD(myChanger->getRotation());
    1995            0 :         rotBound.add(Position(bound.xmin(), bound.ymin()).rotateAround2D(rad, bound.getCenter()));
    1996            0 :         rotBound.add(Position(bound.xmin(), bound.ymax()).rotateAround2D(rad, bound.getCenter()));
    1997            0 :         rotBound.add(Position(bound.xmax(), bound.ymin()).rotateAround2D(rad, bound.getCenter()));
    1998            0 :         rotBound.add(Position(bound.xmax(), bound.ymax()).rotateAround2D(rad, bound.getCenter()));
    1999              :         bound = rotBound;
    2000              :     }
    2001       745029 :     myVisualizationSettings->angle = myChanger->getRotation();
    2002       745029 :     return bound;
    2003              : }
    2004              : 
    2005              : 
    2006              : double
    2007            0 : GUISUMOAbstractView::getDelay() const {
    2008            0 :     return myApp->getDelay();
    2009              : }
    2010              : 
    2011              : 
    2012              : void
    2013            0 : GUISUMOAbstractView::setDelay(double delay) {
    2014            0 :     myApp->setDelay(delay);
    2015            0 : }
    2016              : 
    2017              : 
    2018              : void
    2019            0 : GUISUMOAbstractView::setBreakpoints(const std::vector<SUMOTime>& breakpoints) {
    2020            0 :     myApp->setBreakpoints(breakpoints);
    2021            0 : }
    2022              : 
    2023              : 
    2024              : void
    2025            0 : GUISUMOAbstractView::buildMinMaxRainbow(const GUIVisualizationSettings& s, GUIColorScheme& scheme,
    2026              :                                         const GUIVisualizationRainbowSettings& rs, double minValue, double maxValue, bool hasMissingData) {
    2027            0 :     if (rs.hideMin && rs.hideMax && minValue == std::numeric_limits<double>::infinity()) {
    2028            0 :         minValue = rs.minThreshold;
    2029            0 :         maxValue = rs.maxThreshold;
    2030              :     }
    2031            0 :     if (rs.fixRange) {
    2032            0 :         if (rs.hideMin) {
    2033            0 :             minValue = rs.minThreshold;
    2034              :         }
    2035            0 :         if (rs.hideMax) {
    2036            0 :             maxValue = rs.maxThreshold;
    2037              :         }
    2038              :     }
    2039            0 :     if (minValue != std::numeric_limits<double>::infinity()) {
    2040            0 :         scheme.clear();
    2041              :         // add new thresholds
    2042            0 :         if (scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_EDGEDATA_NUMERICAL
    2043            0 :                 || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_EDGE_PARAM_NUMERICAL
    2044            0 :                 || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_LANE_PARAM_NUMERICAL
    2045            0 :                 || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_DATA_ATTRIBUTE_NUMERICAL
    2046            0 :                 || scheme.getName() == GUIVisualizationSettings::SCHEME_NAME_PARAM_NUMERICAL
    2047            0 :                 || hasMissingData) {
    2048            0 :             scheme.addColor(s.COL_MISSING_DATA, s.MISSING_DATA, "missing data");
    2049              :         }
    2050            0 :         if (rs.hideMin && !rs.fixRange) {
    2051            0 :             const double rawRange = maxValue - minValue;
    2052            0 :             minValue = MAX2(rs.minThreshold + MIN2(1.0, rawRange / 100.0), minValue);
    2053            0 :             scheme.addColor(RGBColor(204, 204, 204), rs.minThreshold);
    2054              :         }
    2055            0 :         if (rs.hideMax && !rs.fixRange) {
    2056            0 :             const double rawRange = maxValue - minValue;
    2057            0 :             maxValue = MIN2(rs.maxThreshold - MIN2(1.0, rawRange / 100.0), maxValue);
    2058            0 :             scheme.addColor(RGBColor(204, 204, 204), rs.maxThreshold);
    2059              :         }
    2060            0 :         const double range = maxValue - minValue;
    2061            0 :         scheme.addColor(rs.colors.front(), minValue);
    2062            0 :         const int steps = (int)rs.colors.size() - 1;
    2063            0 :         if (rs.setNeutral) {
    2064            0 :             const int steps1 = steps / 2;
    2065            0 :             const int steps2 = steps - steps1;
    2066            0 :             const double range1 = rs.neutralThreshold - minValue;
    2067            0 :             const double range2 = maxValue - rs.neutralThreshold;
    2068            0 :             for (int i = 1; i < steps1; i++) {
    2069            0 :                 scheme.addColor(rs.colors[i], (minValue + range1 * i / steps1));
    2070              :             }
    2071            0 :             scheme.addColor(rs.colors[steps1], rs.neutralThreshold);
    2072            0 :             for (int i = 1; i < steps2; i++) {
    2073            0 :                 scheme.addColor(rs.colors[steps1 + i], (rs.neutralThreshold + range2 * i / steps2));
    2074              :             }
    2075              :         } else {
    2076            0 :             for (int i = 1; i < steps; i++) {
    2077            0 :                 scheme.addColor(rs.colors[i], (minValue + range * i / steps));
    2078              :             }
    2079              :         }
    2080            0 :         scheme.addColor(rs.colors.back(), maxValue);
    2081              :     }
    2082            0 : }
    2083              : 
    2084              : 
    2085            0 : GUISUMOAbstractView::LayerObject::LayerObject(double layer, GUIGlObject* object) :
    2086            0 :     myGLObject(object) {
    2087            0 :     first = layer;
    2088            0 :     second.first = object->getType();
    2089            0 :     second.second = object->getMicrosimID();
    2090            0 : }
    2091              : 
    2092              : 
    2093            0 : GUISUMOAbstractView::LayerObject::LayerObject(GUIGlObject* object) :
    2094            0 :     myGLObject(object) {
    2095            0 :     first = object->getType();
    2096            0 :     second.first = object->getType();
    2097            0 :     second.second = object->getMicrosimID();
    2098            0 : }
    2099              : 
    2100              : 
    2101              : GUIGlObject*
    2102            0 : GUISUMOAbstractView::LayerObject::getGLObject() const {
    2103            0 :     return myGLObject;
    2104              : }
    2105              : 
    2106              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1