LCOV - code coverage report
Current view: top level - src/utils/gui/windows - GUISUMOAbstractView.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 328 999 32.8 %
Date: 2024-05-03 15:29:52 Functions: 34 112 30.4 %

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

Generated by: LCOV version 1.14