LCOV - code coverage report
Current view: top level - src/utils/gui/windows - GUISUMOAbstractView.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 31.0 % 1061 329
Test Date: 2025-11-13 15:38:19 Functions: 29.8 % 114 34

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

Generated by: LCOV version 2.0-1