LCOV - code coverage report
Current view: top level - src/utils/gui/windows - GUISUMOAbstractView.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 35.3 % 1094 386
Test Date: 2026-03-02 16:00:03 Functions: 33.3 % 117 39

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

Generated by: LCOV version 2.0-1