LCOV - code coverage report
Current view: top level - src/utils/gui/windows - GUISUMOAbstractView.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 27.6 % 1041 287
Test Date: 2024-12-21 15:45:41 Functions: 23.9 % 113 27

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

Generated by: LCOV version 2.0-1