LCOV - code coverage report
Current view: top level - src/guisim - GUILane.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 53.6 % 937 502
Test Date: 2026-03-02 16:00:03 Functions: 69.5 % 59 41

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    GUILane.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Jakob Erdmann
      17              : /// @author  Michael Behrisch
      18              : /// @date    Sept 2002
      19              : ///
      20              : // Representation of a lane in the micro simulation (gui-version)
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #include <string>
      25              : #include <utility>
      26              : #include <utils/foxtools/fxheader.h>
      27              : #include <utils/geom/GeomHelper.h>
      28              : #include <utils/geom/Position.h>
      29              : #include <microsim/logging/FunctionBinding.h>
      30              : #include <utils/options/OptionsCont.h>
      31              : #include <utils/common/MsgHandler.h>
      32              : #include <utils/common/StdDefs.h>
      33              : #include <utils/geom/GeomHelper.h>
      34              : #include <utils/gui/div/GLHelper.h>
      35              : #include <utils/gui/div/GUIParameterTableWindow.h>
      36              : #include <utils/gui/div/GUIGlobalSelection.h>
      37              : #include <utils/gui/globjects/GLIncludes.h>
      38              : #include <utils/gui/globjects/GUIPolygon.h>
      39              : #include <utils/gui/images/VClassIcons.h>
      40              : #include <utils/gui/windows/GUISUMOAbstractView.h>
      41              : #include <utils/gui/windows/GUIAppEnum.h>
      42              : #include <gui/GUIGlobals.h>
      43              : #include <microsim/MSGlobals.h>
      44              : #include <microsim/MSLane.h>
      45              : #include <microsim/MSLink.h>
      46              : #include <microsim/MSVehicleControl.h>
      47              : #include <microsim/MSInsertionControl.h>
      48              : #include <microsim/MSVehicleTransfer.h>
      49              : #include <microsim/MSNet.h>
      50              : #include <microsim/MSEdgeWeightsStorage.h>
      51              : #include <microsim/MSParkingArea.h>
      52              : #include <microsim/devices/MSDevice_Routing.h>
      53              : #include <microsim/traffic_lights/MSRailSignal.h>
      54              : #include <microsim/traffic_lights/MSDriveWay.h>
      55              : #include <mesosim/MELoop.h>
      56              : #include <mesosim/MESegment.h>
      57              : #include "GUILane.h"
      58              : #include "GUIEdge.h"
      59              : #include "GUIVehicle.h"
      60              : #include "GUINet.h"
      61              : #include <utils/gui/div/GUIDesigns.h>
      62              : 
      63              : #include <osgview/GUIOSGHeader.h>
      64              : 
      65              : #define RENDERING_BUFFER 10
      66              : 
      67              : //#define GUILane_DEBUG_DRAW_FOE_INTERSECTIONS
      68              : //#define GUILane_DEBUG_DRAW_CROSSING_OUTLINE
      69              : 
      70              : // ===========================================================================
      71              : // static member declaration
      72              : // ===========================================================================
      73              : const RGBColor GUILane::MESO_USE_LANE_COLOR(0, 0, 0, 0);
      74              : GUIVisualizationSettings* GUILane::myCachedGUISettings(nullptr);
      75              : 
      76              : 
      77              : // ===========================================================================
      78              : // method definitions
      79              : // ===========================================================================
      80       418975 : GUILane::GUILane(const std::string& id, double maxSpeed, double friction, double length,
      81              :                  MSEdge* const edge, int numericalID,
      82              :                  const PositionVector& shape, double width,
      83              :                  SVCPermissions permissions,
      84              :                  SVCPermissions changeLeft, SVCPermissions changeRight,
      85              :                  int index, bool isRampAccel,
      86              :                  const std::string& type,
      87       418975 :                  const PositionVector& outlineShape) :
      88              :     MSLane(id, maxSpeed, friction, length, edge, numericalID, shape, width, permissions, changeLeft, changeRight, index, isRampAccel, type, outlineShape),
      89              :     GUIGlObject(GLO_LANE, id, GUIIconSubSys::getIcon(GUIIcon::LANE)),
      90       418975 :     myParkingAreas(nullptr),
      91       418975 :     myTesselation(nullptr),
      92              : #ifdef HAVE_OSG
      93       418975 :     myGeom(0),
      94              : #endif
      95       418975 :     myAmClosed(false),
      96       418975 :     myLengthGeometryFactor2(myLengthGeometryFactor),
      97       418975 :     myLock(true) {
      98       418975 :     initRotations(myShape, myShapeRotations, myShapeLengths, myShapeColors);
      99              :     //
     100       418975 :     myHalfLaneWidth = myWidth / 2.;
     101       418975 :     myQuarterLaneWidth = myWidth / 4.;
     102       418975 : }
     103              : 
     104              : 
     105       836452 : GUILane::~GUILane() {
     106              :     // just to quit cleanly on a failure
     107       418226 :     if (myLock.locked()) {
     108            0 :         myLock.unlock();
     109              :     }
     110       418226 :     delete myParkingAreas;
     111       418226 :     delete myTesselation;
     112       836452 : }
     113              : 
     114              : 
     115              : void
     116       140221 : GUILane::updateMesoGUISegments() {
     117              : #ifdef _DEBUG
     118              :     const double origLength = myShape.length();
     119              : #endif
     120       280442 :     myShape = splitAtSegments(myShape);
     121              :     assert(fabs(myShape.length() - origLength) < POSITION_EPS);
     122              :     assert(myShapeSegments.size() == myShape.size());
     123       140221 :     initRotations(myShape, myShapeRotations, myShapeLengths, myShapeColors);
     124       140221 : }
     125              : 
     126              : 
     127              : void
     128       559196 : GUILane::initRotations(const PositionVector& shape,
     129              :                        std::vector<double>& rotations,
     130              :                        std::vector<double>& lengths,
     131              :                        std::vector<RGBColor>& colors) {
     132              :     rotations.clear();
     133              :     lengths.clear();
     134              :     colors.clear();
     135       559196 :     rotations.reserve(shape.size() - 1);
     136       559196 :     lengths.reserve(shape.size() - 1);
     137       559196 :     colors.reserve(shape.size() - 1);
     138       559196 :     int e = (int) shape.size() - 1;
     139      1811517 :     for (int i = 0; i < e; ++i) {
     140      1252321 :         const Position& f = shape[i];
     141      1252321 :         const Position& s = shape[i + 1];
     142      1252321 :         lengths.push_back(f.distanceTo2D(s));
     143      1252321 :         rotations.push_back(RAD2DEG(atan2(s.x() - f.x(), f.y() - s.y())));
     144              :     }
     145       559196 : }
     146              : 
     147              : 
     148              : void
     149            0 : GUILane::addSecondaryShape(const PositionVector& shape) {
     150              :     myShape2 = shape;
     151            0 :     initRotations(myShape2, myShapeRotations2, myShapeLengths2, myShapeColors2);
     152            0 :     myLengthGeometryFactor2 = MAX2(POSITION_EPS, myShape2.length()) / myLength;
     153            0 : }
     154              : 
     155              : 
     156              : // ------ Vehicle insertion ------
     157              : void
     158       494608 : GUILane::incorporateVehicle(MSVehicle* veh, double pos, double speed, double posLat,
     159              :                             const MSLane::VehCont::iterator& at,
     160              :                             MSMoveReminder::Notification notification) {
     161       494608 :     FXMutexLock locker(myLock);
     162       494608 :     MSLane::incorporateVehicle(veh, pos, speed, posLat, at, notification);
     163       494608 : }
     164              : 
     165              : 
     166              : // ------ Access to vehicles ------
     167              : const MSLane::VehCont&
     168    129852497 : GUILane::getVehiclesSecure() const {
     169    129852497 :     myLock.lock();
     170    129852497 :     return myVehicles;
     171              : }
     172              : 
     173              : 
     174              : void
     175    129852497 : GUILane::releaseVehicles() const {
     176    129852497 :     myLock.unlock();
     177    129852497 : }
     178              : 
     179              : 
     180              : void
     181     15058591 : GUILane::planMovements(const SUMOTime t) {
     182     15058591 :     FXMutexLock locker(myLock);
     183     15058591 :     MSLane::planMovements(t);
     184     15058591 : }
     185              : 
     186              : void
     187     15058591 : GUILane::setJunctionApproaches() const {
     188     15058591 :     FXMutexLock locker(myLock);
     189     15058591 :     MSLane::setJunctionApproaches();
     190     15058591 : }
     191              : 
     192              : 
     193              : void
     194     15058591 : GUILane::executeMovements(const SUMOTime t) {
     195     15058591 :     FXMutexLock locker(myLock);
     196     15058591 :     MSLane::executeMovements(t);
     197     15058590 : }
     198              : 
     199              : 
     200              : MSVehicle*
     201         6130 : GUILane::removeVehicle(MSVehicle* remVehicle, MSMoveReminder::Notification notification, bool notify) {
     202         6130 :     FXMutexLock locker(myLock);
     203        12260 :     return MSLane::removeVehicle(remVehicle, notification, notify);
     204              : }
     205              : 
     206              : 
     207              : void
     208         2560 : GUILane::removeParking(MSBaseVehicle* remVehicle) {
     209         2560 :     FXMutexLock locker(myLock);
     210         5120 :     return MSLane::removeParking(remVehicle);
     211              : }
     212              : 
     213              : 
     214              : void
     215     11062238 : GUILane::swapAfterLaneChange(SUMOTime t) {
     216     11062238 :     FXMutexLock locker(myLock);
     217     11062238 :     MSLane::swapAfterLaneChange(t);
     218     11062238 : }
     219              : 
     220              : 
     221              : void
     222      4134815 : GUILane::integrateNewVehicles() {
     223      4134815 :     FXMutexLock locker(myLock);
     224      4134815 :     MSLane::integrateNewVehicles();
     225      4134815 : }
     226              : 
     227              : 
     228              : void
     229     16403807 : GUILane::detectCollisions(SUMOTime timestep, const std::string& stage) {
     230     16403807 :     FXMutexLock locker(myLock);
     231     16403807 :     MSLane::detectCollisions(timestep, stage);
     232     16403807 : }
     233              : 
     234              : 
     235              : double
     236      2789418 : GUILane::setPartialOccupation(MSVehicle* v) {
     237      2789418 :     FXMutexLock locker(myLock);
     238      5578836 :     return MSLane::setPartialOccupation(v);
     239              : }
     240              : 
     241              : 
     242              : void
     243      2789429 : GUILane::resetPartialOccupation(MSVehicle* v) {
     244      2789429 :     FXMutexLock locker(myLock);
     245      2789429 :     MSLane::resetPartialOccupation(v);
     246      2789429 : }
     247              : 
     248              : 
     249              : // ------ Drawing methods ------
     250              : void
     251            0 : GUILane::drawLinkNo(const GUIVisualizationSettings& s) const {
     252            0 :     int noLinks = (int)myLinks.size();
     253            0 :     if (noLinks == 0) {
     254              :         return;
     255              :     }
     256              :     // draw all links
     257            0 :     if (isCrossing()) {
     258              :         // draw indices at the start and end of the crossing
     259            0 :         const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
     260            0 :         PositionVector shape = getShape(s.secondaryShape);
     261            0 :         shape.extrapolate(0.5); // draw on top of the walking area
     262            0 :         GLHelper::drawTextAtEnd(toString(link->getIndex()), shape, 0, s.drawLinkJunctionIndex, s.scale);
     263            0 :         GLHelper::drawTextAtEnd(toString(link->getIndex()), shape.reverse(), 0, s.drawLinkJunctionIndex, s.scale);
     264              :         return;
     265            0 :     }
     266              :     // draw all links
     267            0 :     double w = myWidth / (double) noLinks;
     268            0 :     double x1 = myHalfLaneWidth;
     269            0 :     for (int i = noLinks; --i >= 0;) {
     270            0 :         double x2 = x1 - (double)(w / 2.);
     271            0 :         GLHelper::drawTextAtEnd(toString(myLinks[MSGlobals::gLefthand ? noLinks - 1 - i : i]->getIndex()), getShape(s.secondaryShape), x2, s.drawLinkJunctionIndex, s.scale);
     272            0 :         x1 -= w;
     273              :     }
     274              : }
     275              : 
     276              : 
     277              : void
     278            0 : GUILane::drawTLSLinkNo(const GUIVisualizationSettings& s, const GUINet& net) const {
     279            0 :     int noLinks = (int)myLinks.size();
     280            0 :     if (noLinks == 0) {
     281              :         return;
     282              :     }
     283            0 :     if (isCrossing()) {
     284              :         // draw indices at the start and end of the crossing
     285            0 :         const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
     286            0 :         int linkNo = net.getLinkTLIndex(link);
     287              :         // maybe the reverse link is controlled separately
     288            0 :         int linkNo2 = net.getLinkTLIndex(myLinks.front());
     289              :         // otherwise, use the same index as the forward link
     290            0 :         if (linkNo2 < 0) {
     291            0 :             linkNo2 = linkNo;
     292              :         }
     293            0 :         if (linkNo >= 0) {
     294            0 :             PositionVector shape = getShape(s.secondaryShape);
     295            0 :             shape.extrapolate(0.5); // draw on top of the walking area
     296            0 :             GLHelper::drawTextAtEnd(toString(linkNo2), shape, 0, s.drawLinkTLIndex, s.scale);
     297            0 :             GLHelper::drawTextAtEnd(toString(linkNo), shape.reverse(), 0, s.drawLinkTLIndex, s.scale);
     298            0 :         }
     299              :         return;
     300              :     }
     301              :     // draw all links
     302            0 :     double w = myWidth / (double) noLinks;
     303            0 :     double x1 = myHalfLaneWidth;
     304            0 :     for (int i = noLinks; --i >= 0;) {
     305            0 :         double x2 = x1 - (double)(w / 2.);
     306            0 :         int linkNo = net.getLinkTLIndex(myLinks[MSGlobals::gLefthand ? noLinks - 1 - i : i]);
     307            0 :         if (linkNo < 0) {
     308            0 :             continue;
     309              :         }
     310            0 :         GLHelper::drawTextAtEnd(toString(linkNo), getShape(s.secondaryShape), x2, s.drawLinkTLIndex, s.scale);
     311            0 :         x1 -= w;
     312              :     }
     313              : }
     314              : 
     315              : 
     316              : void
     317       455449 : GUILane::drawLinkRules(const GUIVisualizationSettings& s, const GUINet& net) const {
     318       455449 :     int noLinks = (int)myLinks.size();
     319       455449 :     const PositionVector& shape = getShape(s.secondaryShape);
     320       455449 :     if (noLinks == 0) {
     321       175289 :         drawLinkRule(s, net, nullptr, shape, 0, 0);
     322       175289 :         return;
     323              :     }
     324       280160 :     if (isCrossing()) {
     325              :         // draw rules at the start and end of the crossing
     326        10227 :         const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
     327        10227 :         const MSLink* link2 = myLinks.front();
     328        10227 :         if (link2->getTLLogic() == nullptr) {
     329              :             link2 = link;
     330              :         }
     331              :         PositionVector tmp = shape;
     332        10227 :         tmp.extrapolate(0.5); // draw on top of the walking area
     333        10227 :         drawLinkRule(s, net, link2, tmp, 0, myWidth);
     334        10227 :         drawLinkRule(s, net, link, tmp.reverse(), 0, myWidth);
     335              :         return;
     336        10227 :     }
     337              :     // draw all links
     338       269933 :     const double isRailSignal = myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL;
     339       269933 :     double w = myWidth / (double) noLinks;
     340       269933 :     if (isRailSignal && noLinks > 1 && myLinks.back()->isTurnaround() && s.showRails) {
     341         1266 :         w = myWidth / (double)(noLinks - 1);
     342              :     }
     343       269933 :     double x1 = isRailSignal ? -myWidth * 0.5 : 0;
     344       603964 :     for (int i = 0; i < noLinks; ++i) {
     345       334031 :         double x2 = x1 + w;
     346       334031 :         drawLinkRule(s, net, myLinks[MSGlobals::gLefthand ? noLinks - 1 - i : i], shape, x1, x2);
     347              :         x1 = x2;
     348              :     }
     349              :     // draw stopOffset for passenger cars
     350       269933 :     if (myLaneStopOffset.isDefined() && (myLaneStopOffset.getPermissions() & SVC_PASSENGER) != 0) {
     351          324 :         const double stopOffsetPassenger = myLaneStopOffset.getOffset();
     352              :         const Position& end = shape.back();
     353          324 :         const Position& f = shape[-2];
     354          324 :         const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
     355          324 :         GLHelper::setColor(s.getLinkColor(LINKSTATE_MAJOR));
     356          324 :         GLHelper::pushMatrix();
     357          324 :         glTranslated(end.x(), end.y(), 0);
     358          324 :         glRotated(rot, 0, 0, 1);
     359          324 :         glTranslated(0, stopOffsetPassenger, 0);
     360          324 :         glBegin(GL_QUADS);
     361          324 :         glVertex2d(-myHalfLaneWidth, 0.0);
     362          324 :         glVertex2d(-myHalfLaneWidth, 0.2);
     363          324 :         glVertex2d(myHalfLaneWidth, 0.2);
     364          324 :         glVertex2d(myHalfLaneWidth, 0.0);
     365          324 :         glEnd();
     366          324 :         GLHelper::popMatrix();
     367              :     }
     368              : }
     369              : 
     370              : 
     371              : void
     372       529774 : GUILane::drawLinkRule(const GUIVisualizationSettings& s, const GUINet& net, const MSLink* link, const PositionVector& shape, double x1, double x2) const {
     373              :     const Position& end = shape.back();
     374       529774 :     const Position& f = shape[-2];
     375       529774 :     const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
     376       529774 :     if (link == nullptr) {
     377       175289 :         if (static_cast<GUIEdge*>(myEdge)->showDeadEnd()) {
     378           89 :             GLHelper::setColor(GUIVisualizationColorSettings::SUMO_color_DEADEND_SHOW);
     379              :         } else {
     380       175200 :             GLHelper::setColor(GUIVisualizationSettings::getLinkColor(LINKSTATE_DEADEND));
     381              :         }
     382       175289 :         GLHelper::pushMatrix();
     383       175289 :         glTranslated(end.x(), end.y(), 0);
     384       175289 :         glRotated(rot, 0, 0, 1);
     385       175289 :         glBegin(GL_QUADS);
     386       175289 :         glVertex2d(-myHalfLaneWidth, 0.0);
     387       175289 :         glVertex2d(-myHalfLaneWidth, 0.5);
     388       175289 :         glVertex2d(myHalfLaneWidth, 0.5);
     389       175289 :         glVertex2d(myHalfLaneWidth, 0.0);
     390       175289 :         glEnd();
     391       175289 :         GLHelper::popMatrix();
     392              :     } else {
     393       354485 :         GLHelper::pushMatrix();
     394       354485 :         glTranslated(end.x(), end.y(), 0);
     395       354485 :         glRotated(rot, 0, 0, 1);
     396              :         // select glID
     397              : 
     398       354485 :         switch (link->getState()) {
     399           18 :             case LINKSTATE_ALLWAY_STOP:
     400              :             case LINKSTATE_STOP: {
     401              :                 // might be a traffic light link
     402           18 :                 int tlID = net.getLinkTLID(link);
     403           36 :                 GLHelper::pushName(tlID != 0 ? tlID : getGlID());
     404           18 :                 break;
     405              :             }
     406        85497 :             case LINKSTATE_TL_GREEN_MAJOR:
     407              :             case LINKSTATE_TL_GREEN_MINOR:
     408              :             case LINKSTATE_TL_RED:
     409              :             case LINKSTATE_TL_REDYELLOW:
     410              :             case LINKSTATE_TL_YELLOW_MAJOR:
     411              :             case LINKSTATE_TL_YELLOW_MINOR:
     412              :             case LINKSTATE_TL_OFF_BLINKING:
     413              :             case LINKSTATE_TL_OFF_NOSIGNAL:
     414        85497 :                 GLHelper::pushName(net.getLinkTLID(link));
     415        85497 :                 break;
     416       268970 :             case LINKSTATE_MAJOR:
     417              :             case LINKSTATE_MINOR:
     418              :             case LINKSTATE_EQUAL:
     419              :             default:
     420       268970 :                 GLHelper::pushName(getGlID());
     421       268970 :                 break;
     422              :         }
     423       354485 :         GLHelper::setColor(GUIVisualizationSettings::getLinkColor(link->getState(), s.realisticLinkRules));
     424       354485 :         if (!(drawAsRailway(s) || drawAsWaterway(s)) || link->getState() != LINKSTATE_MAJOR) {
     425              :             // the white bar should be the default for most railway
     426              :             // links and looks ugly so we do not draw it
     427       350891 :             double scale = isInternal() ? 0.5 : 1;
     428       701782 :             if (myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
     429         9848 :                 scale *= MAX2(s.laneWidthExaggeration, s.junctionSize.getExaggeration(s, this, 10));
     430              :             }
     431       350891 :             glScaled(scale, scale, 1);
     432       350891 :             glBegin(GL_QUADS);
     433       350891 :             glVertex2d(x1 - myHalfLaneWidth, 0.0);
     434       350891 :             glVertex2d(x1 - myHalfLaneWidth, 0.5);
     435       350891 :             glVertex2d(x2 - myHalfLaneWidth, 0.5);
     436       350891 :             glVertex2d(x2 - myHalfLaneWidth, 0.0);
     437       350891 :             glEnd();
     438       350891 :             if (s.gaming && link->haveGreen()) {
     439              :                 const MSLane* lane = link->getLane();
     440              :                 // exaggerate green signals for railway game
     441            0 :                 if (isRailway(lane->getPermissions())) {
     442            0 :                     GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, 90, 270);
     443              :                 }
     444              :             }
     445              :         }
     446       354485 :         GLHelper::popName();
     447       354485 :         GLHelper::popMatrix();
     448              :     }
     449       529774 : }
     450              : 
     451              : void
     452       393594 : GUILane::drawArrows(bool secondaryShape) const {
     453       393594 :     if (myLinks.size() == 0) {
     454              :         return;
     455              :     }
     456              :     // draw all links
     457       222430 :     const Position& end = getShape(secondaryShape).back();
     458       222430 :     const Position& f = getShape(secondaryShape)[-2];
     459       222430 :     const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
     460       222430 :     GLHelper::pushMatrix();
     461       222430 :     glColor3d(1, 1, 1);
     462       222430 :     glTranslated(end.x(), end.y(), 0);
     463       222430 :     glRotated(rot, 0, 0, 1);
     464       222430 :     if (myWidth < SUMO_const_laneWidth) {
     465         3793 :         glScaled(myWidth / SUMO_const_laneWidth, 1, 1);
     466              :     }
     467       507096 :     for (const MSLink* const link : myLinks) {
     468              :         LinkDirection dir = link->getDirection();
     469              :         LinkState state = link->getState();
     470       284666 :         if (state == LINKSTATE_DEADEND || dir == LinkDirection::NODIR) {
     471            0 :             continue;
     472              :         }
     473       284666 :         switch (dir) {
     474              :             case LinkDirection::STRAIGHT:
     475       196963 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 2, .05);
     476       196963 :                 GLHelper::drawTriangleAtEnd(Position(0, 4), Position(0, 1), (double) 1, (double) .25);
     477       196963 :                 break;
     478              :             case LinkDirection::TURN:
     479        10750 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     480        10750 :                 GLHelper::drawBoxLine(Position(0, 2.5), 90, .5, .05);
     481        10750 :                 GLHelper::drawBoxLine(Position(0.5, 2.5), 180, 1, .05);
     482        10750 :                 GLHelper::drawTriangleAtEnd(Position(0.5, 2.5), Position(0.5, 4), (double) 1, (double) .25);
     483        10750 :                 break;
     484              :             case LinkDirection::TURN_LEFTHAND:
     485            0 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     486            0 :                 GLHelper::drawBoxLine(Position(0, 2.5), -90, .5, .05);
     487            0 :                 GLHelper::drawBoxLine(Position(-0.5, 2.5), -180, 1, .05);
     488            0 :                 GLHelper::drawTriangleAtEnd(Position(-0.5, 2.5), Position(-0.5, 4), (double) 1, (double) .25);
     489            0 :                 break;
     490              :             case LinkDirection::LEFT:
     491        24714 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     492        24714 :                 GLHelper::drawBoxLine(Position(0, 2.5), 90, 1, .05);
     493        24714 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.5, 2.5), (double) 1, (double) .25);
     494        24714 :                 break;
     495              :             case LinkDirection::RIGHT:
     496        33284 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     497        33284 :                 GLHelper::drawBoxLine(Position(0, 2.5), -90, 1, .05);
     498        33284 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.5, 2.5), (double) 1, (double) .25);
     499        33284 :                 break;
     500              :             case LinkDirection::PARTLEFT:
     501          201 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     502          201 :                 GLHelper::drawBoxLine(Position(0, 2.5), 45, .7, .05);
     503          201 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.2, 1.3), (double) 1, (double) .25);
     504          201 :                 break;
     505              :             case LinkDirection::PARTRIGHT:
     506        18754 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     507        18754 :                 GLHelper::drawBoxLine(Position(0, 2.5), -45, .7, .05);
     508        18754 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.2, 1.3), (double) 1, (double) .25);
     509        18754 :                 break;
     510              :             default:
     511              :                 break;
     512              :         }
     513              :     }
     514       222430 :     GLHelper::popMatrix();
     515              : }
     516              : 
     517              : 
     518              : void
     519            0 : GUILane::drawLane2LaneConnections(double exaggeration, bool s2) const {
     520              :     Position centroid;
     521            0 :     if (exaggeration > 1) {
     522            0 :         centroid = myEdge->getToJunction()->getShape().getCentroid();
     523              :     }
     524            0 :     for (const MSLink* const link : myLinks) {
     525            0 :         const GUILane* connected = dynamic_cast<GUILane*>(link->getLane());
     526            0 :         if (connected == nullptr) {
     527            0 :             continue;
     528              :         }
     529            0 :         GLHelper::setColor(GUIVisualizationSettings::getLinkColor(link->getState()));
     530            0 :         glBegin(GL_LINES);
     531            0 :         Position p1 = myEdge->isWalkingArea() ? getShape(s2).getCentroid() : getShape(s2)[-1];
     532            0 :         Position p2 = connected->isWalkingArea() ? connected->getShape(s2).getCentroid() : connected->getShape(s2)[0];
     533            0 :         if (exaggeration > 1) {
     534            0 :             p1 = centroid + ((p1 - centroid) * exaggeration);
     535            0 :             p2 = centroid + ((p2 - centroid) * exaggeration);
     536              :         }
     537            0 :         glVertex2d(p1.x(), p1.y());
     538            0 :         glVertex2d(p2.x(), p2.y());
     539            0 :         glEnd();
     540            0 :         GLHelper::drawTriangleAtEnd(p1, p2, (double) .4, (double) .2);
     541              :     }
     542            0 : }
     543              : 
     544              : 
     545              : void
     546     48347698 : GUILane::drawGL(const GUIVisualizationSettings& s) const {
     547     48347698 :     GLHelper::pushMatrix();
     548     48347698 :     GLHelper::pushName(getGlID());
     549     48347698 :     const bool s2 = s.secondaryShape;
     550     48347698 :     double exaggeration = s.laneWidthExaggeration;
     551     48347698 :     if (MSGlobals::gUseMesoSim) {
     552      4590647 :         GUIEdge* myGUIEdge = dynamic_cast<GUIEdge*>(myEdge);
     553      4590647 :         exaggeration *= s.edgeScaler.getScheme().getColor(myGUIEdge->getScaleValue(s, s.edgeScaler.getActive()));
     554              :     } else {
     555     43757051 :         exaggeration *= s.laneScaler.getScheme().getColor(getScaleValue(s, s.laneScaler.getActive(), s2));
     556              :     }
     557              :     // set lane color
     558     48347698 :     const RGBColor color = setColor(s);
     559              :     // recognize full transparency and simply don't draw
     560     48347698 :     if (color.alpha() != 0 && s.scale * exaggeration > s.laneMinSize) {
     561              : 
     562     48243221 :         const bool isCrossing = myEdge->isCrossing();
     563              :         const bool isWalkingArea = myEdge->isWalkingArea();
     564     48243221 :         const bool isInternal = isCrossing || isWalkingArea || myEdge->isInternal();
     565     48243221 :         const PositionVector& baseShape = getShape(s2);
     566     48243221 :         const bool hasRailSignal = myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL;
     567     48243221 :         if (s.trueZ) {
     568          288 :             glTranslated(0, 0, baseShape.getMinZ());
     569              :         } else {
     570     48242933 :             if (isCrossing) {
     571              :                 // draw internal lanes on top of junctions
     572       162270 :                 glTranslated(0, 0, GLO_JUNCTION + 0.1);
     573     48080663 :             } else if (isWalkingArea) {
     574              :                 // draw internal lanes on top of junctions
     575       374888 :                 glTranslated(0, 0, GLO_JUNCTION + 0.3);
     576     47705775 :             } else if (isWaterway(myPermissions)) {
     577              :                 // draw waterways below normal roads
     578          500 :                 glTranslated(0, 0, getType() - 0.2);
     579     47705275 :             } else if (myPermissions == SVC_SUBWAY) {
     580              :                 // draw subways further below
     581            0 :                 glTranslated(0, 0, getType() - 0.4);
     582              :             } else {
     583     47705275 :                 glTranslated(0, 0, getType());
     584              :             }
     585              :         }
     586     48243221 :         auto& shapeColors = getShapeColors(s2);
     587     48243221 :         if (MSGlobals::gUseMesoSim) {
     588              :             shapeColors.clear();
     589      4588392 :             const std::vector<RGBColor>& segmentColors = static_cast<const GUIEdge*>(myEdge)->getSegmentColors();
     590      4588392 :             if (segmentColors.size() > 0) {
     591              :                 // apply segment specific shape colors
     592              :                 //std::cout << getID() << " shape=" << myShape << " shapeSegs=" << toString(myShapeSegments) << "\n";
     593            0 :                 for (int ii = 0; ii < (int)baseShape.size() - 1; ++ii) {
     594            0 :                     shapeColors.push_back(segmentColors[myShapeSegments[ii]]);
     595              :                 }
     596              :             }
     597              :         }
     598              : 
     599              :         // scale tls-controlled lane2lane-arrows along with their junction shapes
     600              :         double junctionExaggeration = 1;
     601              :         if (!isInternal
     602     19425664 :                 && myEdge->getToJunction()->getType() <= SumoXMLNodeType::RAIL_CROSSING
     603     54136554 :                 && (s.junctionSize.constantSize || s.junctionSize.exaggeration > 1)) {
     604            0 :             junctionExaggeration = MAX2(1.001, s.junctionSize.getExaggeration(s, this, 4));
     605              :         }
     606              :         // draw lane
     607              :         // check whether it is not too small
     608     48243221 :         if (s.scale * exaggeration < 1. && junctionExaggeration == 1 && s.junctionSize.minSize != 0) {
     609     31254310 :             if (!isInternal || hasRailSignal) {
     610     13412902 :                 if (shapeColors.size() > 0) {
     611            0 :                     GLHelper::drawLine(baseShape, shapeColors);
     612              :                 } else {
     613     13412902 :                     GLHelper::drawLine(baseShape);
     614              :                 }
     615              :             }
     616     31254310 :             GLHelper::popMatrix();
     617              : 
     618              :         } else {
     619              : 
     620     16988911 :             GUINet* net = (GUINet*) MSNet::getInstance();
     621              :             bool mustDrawMarkings = false;
     622     16988911 :             bool hiddenBidi = getBidiLane() != nullptr && myEdge->getNumericalID() > myEdge->getBidiEdge()->getNumericalID();
     623     16988911 :             const bool detailZoom = s.scale * exaggeration > 5;
     624     16988911 :             const bool drawDetails = (detailZoom || s.junctionSize.minSize == 0 || hasRailSignal);
     625     16988911 :             const bool drawRails = drawAsRailway(s);
     626     16988911 :             const bool spreadSuperposed = s.spreadSuperposed && myBidiLane != nullptr;
     627     16988911 :             if (hiddenBidi && !spreadSuperposed) {
     628              :                 // do not draw shape
     629        36410 :                 mustDrawMarkings = !isInternal && myPermissions != 0 && myPermissions != SVC_PEDESTRIAN && exaggeration == 1.0 && !isWaterway(myPermissions) && neighLaneNotBidi();
     630     16952501 :             } else if (drawRails) {
     631              :                 // draw as railway: assume standard gauge of 1435mm when lane width is not set
     632              :                 // draw foot width 150mm, assume that distance between rail feet inner sides is reduced on both sides by 39mm with regard to the gauge
     633              :                 // assume crosstie length of 181% gauge (2600mm for standard gauge)
     634              :                 PositionVector shape = baseShape;
     635        44870 :                 const double width = myWidth;
     636        44870 :                 double halfGauge = 0.5 * (width == SUMO_const_laneWidth ?  1.4350 : width) * exaggeration;
     637        44870 :                 if (spreadSuperposed) {
     638              :                     try {
     639            0 :                         shape.move2side(halfGauge * 0.8);
     640            0 :                     } catch (InvalidArgument&) {}
     641            0 :                     halfGauge *= 0.4;
     642              :                 }
     643        44870 :                 const double halfInnerFeetWidth = halfGauge - 0.039 * exaggeration;
     644        44870 :                 const double halfRailWidth = detailZoom ? (halfInnerFeetWidth + 0.15 * exaggeration) : SUMO_const_halfLaneWidth * exaggeration;
     645        44870 :                 const double halfCrossTieWidth = halfGauge * 1.81;
     646        44870 :                 if (shapeColors.size() > 0) {
     647            0 :                     GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), getShapeColors(s2), halfRailWidth);
     648              :                 } else {
     649        44870 :                     GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), halfRailWidth);
     650              :                 }
     651              :                 // Draw white on top with reduced width (the area between the two tracks)
     652        44870 :                 if (detailZoom) {
     653         2148 :                     glColor3d(1, 1, 1);
     654         2148 :                     glTranslated(0, 0, .1);
     655         2148 :                     GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), halfInnerFeetWidth);
     656         2148 :                     setColor(s);
     657         2148 :                     GLHelper::drawCrossTies(shape, getShapeRotations(s2), getShapeLengths(s2), 0.26 * exaggeration, 0.6 * exaggeration,
     658         2148 :                                             halfCrossTieWidth, 0, s.forceDrawForRectangleSelection);
     659              :                 }
     660     16952501 :             } else if (isCrossing) {
     661       160642 :                 if (s.drawCrossingsAndWalkingareas && (s.scale > 3.0 || s.junctionSize.minSize == 0)) {
     662        50472 :                     glTranslated(0, 0, .2);
     663        50472 :                     GLHelper::drawCrossTies(baseShape, getShapeRotations(s2), getShapeLengths(s2), 0.5, 1.0, getWidth() * 0.5,
     664        50472 :                                             0, s.drawForRectangleSelection);
     665              : #ifdef GUILane_DEBUG_DRAW_CROSSING_OUTLINE
     666              :                     if (myOutlineShape != nullptr) {
     667              :                         GLHelper::setColor(RGBColor::BLUE);
     668              :                         glTranslated(0, 0, 0.4);
     669              :                         GLHelper::drawBoxLines(*myOutlineShape, 0.1);
     670              :                         glTranslated(0, 0, -0.4);
     671              :                         if (s.geometryIndices.show(this)) {
     672              :                             GLHelper::debugVertices(*myOutlineShape, s.geometryIndices, s.scale);
     673              :                         }
     674              :                     }
     675              : #endif
     676        50472 :                     glTranslated(0, 0, -.2);
     677              :                 }
     678     16746989 :             } else if (isWalkingArea) {
     679       363222 :                 if (s.drawCrossingsAndWalkingareas && (s.scale > 3.0 || s.junctionSize.minSize == 0)) {
     680       138262 :                     glTranslated(0, 0, .2);
     681       138262 :                     if (myTesselation == nullptr) {
     682         4708 :                         myTesselation = new TesselatedPolygon(getID(), "", RGBColor::MAGENTA, PositionVector(), false, true, 0);
     683              :                     }
     684       138262 :                     myTesselation->drawTesselation(baseShape);
     685       138262 :                     glTranslated(0, 0, -.2);
     686       138262 :                     if (s.geometryIndices.show(this)) {
     687            0 :                         GLHelper::debugVertices(baseShape, s.geometryIndices, s.scale);
     688              :                     }
     689              :                 }
     690              :             } else {
     691              :                 // we draw the lanes with reduced width so that the lane markings below are visible
     692              :                 // (this avoids artifacts at geometry corners without having to
     693              :                 // compute lane-marking intersection points)
     694     16383767 :                 double halfWidth = isInternal ? myQuarterLaneWidth : (myHalfLaneWidth - SUMO_const_laneMarkWidth / 2);
     695     16383767 :                 mustDrawMarkings = !isInternal && myPermissions != 0 && myPermissions != SVC_PEDESTRIAN && exaggeration == 1.0 && !isWaterway(myPermissions) && !isAirway(myPermissions);
     696     16383767 :                 const int cornerDetail = drawDetails && !isInternal ? (s.drawForRectangleSelection ? 4 : MIN2(32, (int)(s.scale * exaggeration))) : 0;
     697     32767534 :                 double offset = halfWidth * MAX2(0., (exaggeration - 1)) * (MSGlobals::gLefthand ? -1 : 1);
     698     16383767 :                 if (spreadSuperposed) {
     699        77000 :                     offset += halfWidth * 0.5 * (MSGlobals::gLefthand ? -1 : 1);
     700        77000 :                     halfWidth *= 0.4; // create visible gap
     701              :                 }
     702     16383767 :                 if (shapeColors.size() > 0) {
     703            0 :                     GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), shapeColors, halfWidth * exaggeration, cornerDetail, offset);
     704              :                 } else {
     705     16383767 :                     GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), halfWidth * exaggeration, cornerDetail, offset);
     706              :                 }
     707              :             }
     708     16988911 :             GLHelper::popMatrix();
     709              : #ifdef GUILane_DEBUG_DRAW_FOE_INTERSECTIONS
     710              :             if (myEdge->isInternal() && gSelected.isSelected(getType(), getGlID())) {
     711              :                 debugDrawFoeIntersections();
     712              :             }
     713              : #endif
     714     16988911 :             if (s.geometryIndices.show(this)) {
     715            0 :                 GLHelper::debugVertices(baseShape, s.geometryIndices, s.scale);
     716              :             }
     717              :             // draw details
     718     16988911 :             if ((!isInternal || isCrossing || !s.drawJunctionShape) && (drawDetails || junctionExaggeration > 1)) {
     719       455449 :                 GLHelper::pushMatrix();
     720       455449 :                 glTranslated(0, 0, GLO_JUNCTION); // must draw on top of junction shape
     721       455449 :                 glTranslated(0, 0, .5);
     722       455449 :                 if (drawDetails) {
     723       455449 :                     if (s.showLaneDirection) {
     724            0 :                         if (drawRails) {
     725              :                             // improve visibility of superposed rail edges
     726            0 :                             GLHelper::setColor(setColor(s).changedBrightness(100));
     727              :                         } else {
     728            0 :                             glColor3d(0.3, 0.3, 0.3);
     729              :                         }
     730            0 :                         if (!isCrossing || s.drawCrossingsAndWalkingareas) {
     731            0 :                             drawDirectionIndicators(exaggeration, spreadSuperposed, s.secondaryShape);
     732              :                         }
     733              :                     }
     734              :                     if (!isInternal || isCrossing
     735              :                             // controlled internal junction
     736       455449 :                             || (getLinkCont().size() != 0 && getLinkCont()[0]->isInternalJunctionLink() && getLinkCont()[0]->getTLLogic() != nullptr)) {
     737       455449 :                         if (MSGlobals::gLateralResolution > 0 && s.showSublanes && !hiddenBidi && (myPermissions & ~(SVC_PEDESTRIAN | SVC_RAIL_CLASSES)) != 0) {
     738              :                             // draw sublane-borders
     739       120292 :                             const double offsetSign = MSGlobals::gLefthand ? -1 : 1;
     740       120292 :                             GLHelper::setColor(color.changedBrightness(51));
     741       682250 :                             for (double offset = -myHalfLaneWidth; offset < myHalfLaneWidth; offset += MSGlobals::gLateralResolution) {
     742       561958 :                                 GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), 0.01, 0, -offset * offsetSign);
     743              :                             }
     744              :                         }
     745       455449 :                         if (MSGlobals::gUseMesoSim && mySegmentStartIndex.size() > 0 && (myPermissions & ~SVC_PEDESTRIAN) != 0) {
     746              :                             // draw segment borders
     747        32328 :                             GLHelper::setColor(color.changedBrightness(51));
     748        65527 :                             for (int i : mySegmentStartIndex) {
     749        33199 :                                 if (shapeColors.size() > 0) {
     750            0 :                                     GLHelper::setColor(shapeColors[i].changedBrightness(51));
     751              :                                 }
     752        33199 :                                 GLHelper::drawBoxLine(baseShape[i], getShapeRotations(s2)[i] + 90, myWidth / 3, 0.2, 0);
     753        33199 :                                 GLHelper::drawBoxLine(baseShape[i], getShapeRotations(s2)[i] - 90, myWidth / 3, 0.2, 0);
     754              :                             }
     755              :                         }
     756       455449 :                         if (s.showLinkDecals && !drawRails && !drawAsWaterway(s) && myPermissions != SVC_PEDESTRIAN) {
     757       393594 :                             drawArrows(s.secondaryShape);
     758              :                         }
     759       455449 :                         glTranslated(0, 0, 1000);
     760       455449 :                         if (s.drawLinkJunctionIndex.show(nullptr)) {
     761            0 :                             drawLinkNo(s);
     762              :                         }
     763       455449 :                         if (s.drawLinkTLIndex.show(nullptr)) {
     764            0 :                             drawTLSLinkNo(s, *net);
     765              :                         }
     766       455449 :                         glTranslated(0, 0, -1000);
     767              :                     }
     768       455449 :                     glTranslated(0, 0, .1);
     769              :                 }
     770       455449 :                 if ((drawDetails || junctionExaggeration > 1) && s.showLane2Lane) {
     771              :                     //  draw from end of first to the begin of second but respect junction scaling
     772            0 :                     drawLane2LaneConnections(junctionExaggeration, s.secondaryShape);
     773              :                 }
     774       455449 :                 GLHelper::popMatrix();
     775              :                 // make sure link rules are drawn so tls can be selected via right-click
     776       455449 :                 if (s.showLinkRules && drawDetails && !isWalkingArea &&
     777       455449 :                         (!myEdge->isInternal() || (getLinkCont().size() > 0 && getLinkCont()[0]->isInternalJunctionLink()))) {
     778       455449 :                     GLHelper::pushMatrix();
     779       455449 :                     glTranslated(0, 0, GLO_SHAPE); // must draw on top of junction shape and additionals
     780       455449 :                     drawLinkRules(s, *net);
     781       455449 :                     GLHelper::popMatrix();
     782              :                 }
     783              :             }
     784     16988911 :             if (mustDrawMarkings && drawDetails && s.laneShowBorders) { // needs matrix reset
     785       383991 :                 drawMarkings(s, exaggeration);
     786              :             }
     787       365639 :             if (drawDetails && isInternal && s.showBikeMarkings && myPermissions == SVC_BICYCLE && exaggeration == 1.0 && s.showLinkDecals && s.laneShowBorders && !hiddenBidi
     788         2966 :                     && MSGlobals::gUsingInternalLanes
     789     16991665 :                     && getNormalSuccessorLane()->getPermissions() == SVC_BICYCLE && getNormalPredecessorLane()->getPermissions() == SVC_BICYCLE) {
     790          895 :                 drawBikeMarkings();
     791              :             }
     792       365639 :             if (drawDetails && isInternal && exaggeration == 1.0 && s.showLinkDecals && s.laneShowBorders && !hiddenBidi && myIndex > 0
     793     17044471 :                     && !(myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER) && allowsChangingRight(SVC_PASSENGER))) {
     794              :                 // draw lane changing prohibitions on junction
     795           20 :                 drawJunctionChangeProhibitions();
     796              :             }
     797              :         }
     798              :     } else {
     799       104477 :         GLHelper::popMatrix();
     800              :     }
     801              :     // draw vehicles
     802     48347698 :     if (s.scale * s.vehicleSize.getExaggeration(s, nullptr) > s.vehicleSize.minSize) {
     803              :         // retrieve vehicles from lane; disallow simulation
     804     17093380 :         const MSLane::VehCont& vehicles = getVehiclesSecure();
     805     31512953 :         for (MSLane::VehCont::const_iterator v = vehicles.begin(); v != vehicles.end(); ++v) {
     806     14419573 :             if ((*v)->getLane() == this) {
     807     14419573 :                 static_cast<const GUIVehicle*>(*v)->drawGL(s);
     808              :             } // else: this is the shadow during a continuous lane change
     809              :         }
     810              :         // draw long partial vehicles (#14342)
     811     17956959 :         for (const MSVehicle* veh : myPartialVehicles) {
     812       863579 :             if (veh->getLength() > RENDERING_BUFFER) {
     813              :                 // potential double rendering taken into account
     814        16769 :                 static_cast<const GUIVehicle*>(veh)->drawGL(s);
     815              :             }
     816              :         }
     817              :         // draw parking vehicles
     818     17127150 :         for (const MSBaseVehicle* const v : myParkingVehicles) {
     819        33770 :             dynamic_cast<const GUIBaseVehicle*>(v)->drawGL(s);
     820              :         }
     821              :         // allow lane simulation
     822     17093380 :         releaseVehicles();
     823              :     }
     824     48347698 :     GLHelper::popName();
     825     48347698 : }
     826              : 
     827              : bool
     828        20833 : GUILane::neighLaneNotBidi() const {
     829        20833 :     const MSLane* right = getParallelLane(-1, false);
     830        20833 :     if (right && right->getBidiLane() == nullptr) {
     831              :         return true;
     832              :     }
     833        10221 :     const MSLane* left = getParallelLane(1, false);
     834        10221 :     if (left && left->getBidiLane() == nullptr) {
     835              :         return true;
     836              :     }
     837              :     return false;
     838              : }
     839              : 
     840              : void
     841       383991 : GUILane::drawMarkings(const GUIVisualizationSettings& s, double scale) const {
     842       383991 :     GLHelper::pushMatrix();
     843       383991 :     glTranslated(0, 0, GLO_EDGE);
     844       383991 :     setColor(s);
     845              :     // optionally draw inverse markings
     846       383991 :     const bool s2 = s.secondaryShape;
     847       383991 :     if (myIndex > 0 && (myEdge->getLanes()[myIndex - 1]->getPermissions() & myPermissions) != 0) {
     848              :         const bool cl = myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER);
     849              :         const bool cr = allowsChangingRight(SVC_PASSENGER);
     850       110180 :         GLHelper::drawInverseMarkings(getShape(s2), getShapeRotations(s2), getShapeLengths(s2), 3, 6, myHalfLaneWidth, cl, cr, MSGlobals::gLefthand, scale);
     851              :     }
     852              :     // draw white boundings and white markings
     853       383991 :     glColor3d(1, 1, 1);
     854       767982 :     GLHelper::drawBoxLines(
     855       383991 :         getShape(s2),
     856              :         getShapeRotations(s2),
     857              :         getShapeLengths(s2),
     858       383991 :         (myHalfLaneWidth + SUMO_const_laneMarkWidth) * scale);
     859       383991 :     GLHelper::popMatrix();
     860       383991 : }
     861              : 
     862              : 
     863              : void
     864          895 : GUILane::drawBikeMarkings() const {
     865              :     // draw bike lane markings onto the intersection
     866          895 :     glColor3d(1, 1, 1);
     867              :     /// fixme
     868              :     const bool s2 = false;
     869          895 :     const int e = (int) getShape(s2).size() - 1;
     870              :     const double markWidth = 0.1;
     871          895 :     const double mw = myHalfLaneWidth;
     872         2834 :     for (int i = 0; i < e; ++i) {
     873         1939 :         GLHelper::pushMatrix();
     874         1939 :         glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), GLO_JUNCTION + 0.4);
     875         1939 :         glRotated(getShapeRotations(s2)[i], 0, 0, 1);
     876        16077 :         for (double t = 0; t < getShapeLengths(s2)[i]; t += 0.5) {
     877              :             // left and right marking
     878        42414 :             for (int side = -1; side <= 1; side += 2) {
     879        28276 :                 glBegin(GL_QUADS);
     880        28276 :                 glVertex2d(side * mw, -t);
     881        28276 :                 glVertex2d(side * mw, -t - 0.35);
     882        28276 :                 glVertex2d(side * (mw + markWidth), -t - 0.35);
     883        28276 :                 glVertex2d(side * (mw + markWidth), -t);
     884        28276 :                 glEnd();
     885              :             }
     886              :         }
     887         1939 :         GLHelper::popMatrix();
     888              :     }
     889          895 : }
     890              : 
     891              : 
     892              : void
     893           20 : GUILane::drawJunctionChangeProhibitions() const {
     894              :     // fixme
     895              :     const bool s2 = false;
     896              :     // draw white markings
     897           20 :     if (myIndex > 0 && (myEdge->getLanes()[myIndex - 1]->getPermissions() & myPermissions) != 0) {
     898           20 :         glColor3d(1, 1, 1);
     899           20 :         const bool cl = myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER);
     900              :         const bool cr = allowsChangingRight(SVC_PASSENGER);
     901              :         // solid line marking
     902              :         double mw, mw2;
     903              :         // optional broken line marking
     904              :         double mw3, mw4;
     905           20 :         if (!cl && !cr) {
     906              :             // draw a single solid line
     907            6 :             mw = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.4;
     908            6 :             mw2 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.4;
     909              :             mw3 = myHalfLaneWidth;
     910              :             mw4 = myHalfLaneWidth;
     911              :         } else {
     912              :             // draw one solid and one broken line
     913           14 :             if (cl) {
     914            6 :                 mw = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.2;
     915            6 :                 mw2 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.6;
     916            6 :                 mw3 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.2;
     917            6 :                 mw4 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.6;
     918              :             } else {
     919            8 :                 mw = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.2;
     920            8 :                 mw2 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.6;
     921            8 :                 mw3 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.2;
     922            8 :                 mw4 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.6;
     923              :             }
     924              :         }
     925           20 :         if (MSGlobals::gLefthand) {
     926            0 :             mw *= -1;
     927            0 :             mw2 *= -1;
     928              :         }
     929           20 :         int e = (int) getShape(s2).size() - 1;
     930           40 :         for (int i = 0; i < e; ++i) {
     931           20 :             GLHelper::pushMatrix();
     932           20 :             glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), GLO_JUNCTION + 0.4);
     933           20 :             glRotated(getShapeRotations(s2)[i], 0, 0, 1);
     934          420 :             for (double t = 0; t < getShapeLengths(s2)[i]; t += 6) {
     935          400 :                 const double lengthSolid = MIN2(6.0, getShapeLengths(s2)[i] - t);
     936          400 :                 glBegin(GL_QUADS);
     937          400 :                 glVertex2d(-mw, -t);
     938          400 :                 glVertex2d(-mw, -t - lengthSolid);
     939          400 :                 glVertex2d(-mw2, -t - lengthSolid);
     940          400 :                 glVertex2d(-mw2, -t);
     941          400 :                 glEnd();
     942          400 :                 if (cl || cr) {
     943          280 :                     const double lengthBroken = MIN2(3.0, getShapeLengths(s2)[i] - t);
     944          280 :                     glBegin(GL_QUADS);
     945          280 :                     glVertex2d(-mw3, -t);
     946          280 :                     glVertex2d(-mw3, -t - lengthBroken);
     947          280 :                     glVertex2d(-mw4, -t - lengthBroken);
     948          280 :                     glVertex2d(-mw4, -t);
     949          280 :                     glEnd();
     950              :                 }
     951              :             }
     952           20 :             GLHelper::popMatrix();
     953              :         }
     954              :     }
     955           20 : }
     956              : 
     957              : void
     958            0 : GUILane::drawDirectionIndicators(double exaggeration, bool spreadSuperposed, bool s2) const {
     959            0 :     GLHelper::pushMatrix();
     960            0 :     glTranslated(0, 0, GLO_EDGE);
     961            0 :     int e = (int) getShape(s2).size() - 1;
     962            0 :     const double widthFactor = spreadSuperposed ? 0.4 : 1;
     963            0 :     const double w = MAX2(POSITION_EPS, myWidth * widthFactor);
     964            0 :     const double w2 = MAX2(POSITION_EPS, myHalfLaneWidth * widthFactor);
     965            0 :     const double w4 = MAX2(POSITION_EPS, myQuarterLaneWidth * widthFactor);
     966            0 :     const double sideOffset = spreadSuperposed ? w * -0.5 : 0;
     967            0 :     for (int i = 0; i < e; ++i) {
     968            0 :         GLHelper::pushMatrix();
     969            0 :         glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), 0.1);
     970            0 :         glRotated(getShapeRotations(s2)[i], 0, 0, 1);
     971            0 :         for (double t = 0; t < getShapeLengths(s2)[i]; t += w) {
     972            0 :             const double length = MIN2(w2, getShapeLengths(s2)[i] - t) * exaggeration;
     973            0 :             glBegin(GL_TRIANGLES);
     974            0 :             glVertex2d(sideOffset, -t - length);
     975            0 :             glVertex2d(sideOffset - w4 * exaggeration, -t);
     976            0 :             glVertex2d(sideOffset + w4 * exaggeration, -t);
     977            0 :             glEnd();
     978              :         }
     979            0 :         GLHelper::popMatrix();
     980              :     }
     981            0 :     GLHelper::popMatrix();
     982            0 : }
     983              : 
     984              : 
     985              : void
     986            0 : GUILane::debugDrawFoeIntersections() const {
     987            0 :     GLHelper::pushMatrix();
     988            0 :     glTranslated(0, 0, 5);
     989            0 :     glColor3d(1.0, 0.3, 0.3);
     990              :     const double orthoLength = 0.5;
     991            0 :     const MSLink* link = getLinkCont().front();
     992              :     const std::vector<const MSLane*>& foeLanes = link->getFoeLanes();
     993              :     const auto& conflicts = link->getConflicts();
     994            0 :     if (foeLanes.size() == conflicts.size()) {
     995            0 :         for (int i = 0; i < (int)foeLanes.size(); ++i) {
     996            0 :             const MSLane* l = foeLanes[i];
     997            0 :             Position pos = l->geometryPositionAtOffset(l->getLength() - conflicts[i].lengthBehindCrossing);
     998            0 :             PositionVector ortho = l->getShape().getOrthogonal(pos, 10, true, orthoLength);
     999            0 :             if (ortho.length() < orthoLength) {
    1000            0 :                 ortho.extrapolate(orthoLength - ortho.length(), false, true);
    1001              :             }
    1002            0 :             GLHelper::drawLine(ortho);
    1003              :             //std::cout << "foe=" << l->getID() << " lanePos=" << l->getLength() - conflicts[i].lengthBehindCrossing << " pos=" << pos << "\n";
    1004            0 :         }
    1005              :     }
    1006            0 :     GLHelper::popMatrix();
    1007            0 : }
    1008              : 
    1009              : 
    1010              : // ------ inherited from GUIGlObject
    1011              : GUIGLObjectPopupMenu*
    1012            0 : GUILane::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
    1013            0 :     GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
    1014            0 :     buildPopupHeader(ret, app);
    1015            0 :     buildCenterPopupEntry(ret);
    1016              :     //
    1017            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Copy edge name to clipboard"), nullptr, ret, MID_COPY_EDGE_NAME);
    1018            0 :     buildNameCopyPopupEntry(ret);
    1019            0 :     buildSelectionPopupEntry(ret);
    1020              :     //
    1021            0 :     buildShowParamsPopupEntry(ret, false);
    1022            0 :     const PositionVector& baseShape = getShape(parent.getVisualisationSettings().secondaryShape);
    1023            0 :     const double pos = interpolateGeometryPosToLanePos(baseShape.nearest_offset_to_point25D(parent.getPositionInformation()));
    1024            0 :     const double height = baseShape.positionAtOffset(pos).z();
    1025            0 :     GUIDesigns::buildFXMenuCommand(ret, (TL("pos: ") + toString(pos) + " " + TL("height: ") + toString(height)).c_str(), nullptr, nullptr, 0);
    1026            0 :     if (getEdge().hasDistance()) {
    1027            0 :         GUIDesigns::buildFXMenuCommand(ret, ("distance: " + toString(getEdge().getDistanceAt(pos))).c_str(), nullptr, nullptr, 0);
    1028              :     }
    1029            0 :     new FXMenuSeparator(ret);
    1030            0 :     buildPositionCopyEntry(ret, app);
    1031            0 :     new FXMenuSeparator(ret);
    1032            0 :     if (myAmClosed) {
    1033            0 :         if (myPermissionChanges.empty()) {
    1034            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen lane"), nullptr, &parent, MID_CLOSE_LANE);
    1035            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen edge"), nullptr, &parent, MID_CLOSE_EDGE);
    1036              :         } else {
    1037            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen lane (override rerouter)"), nullptr, &parent, MID_CLOSE_LANE);
    1038            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen edge (override rerouter)"), nullptr, &parent, MID_CLOSE_EDGE);
    1039              :         }
    1040              :     } else {
    1041            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Close lane"), nullptr, &parent, MID_CLOSE_LANE);
    1042            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Close edge"), nullptr, &parent, MID_CLOSE_EDGE);
    1043              :     }
    1044            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Add rerouter"), nullptr, &parent, MID_ADD_REROUTER);
    1045            0 :     new FXMenuSeparator(ret);
    1046              :     // reachability menu
    1047            0 :     FXMenuPane* reachableByClass = new FXMenuPane(ret);
    1048            0 :     ret->insertMenuPaneChild(reachableByClass);
    1049            0 :     new FXMenuCascade(ret, TL("Select reachable"), GUIIconSubSys::getIcon(GUIIcon::FLAG), reachableByClass);
    1050            0 :     for (auto i : SumoVehicleClassStrings.getStrings()) {
    1051            0 :         GUIDesigns::buildFXMenuCommand(reachableByClass, i.c_str(), VClassIcons::getVClassIcon(SumoVehicleClassStrings.get(i)), &parent, MID_REACHABILITY);
    1052            0 :     }
    1053            0 :     return ret;
    1054              : }
    1055              : 
    1056              : 
    1057              : GUIParameterTableWindow*
    1058            0 : GUILane::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView& view) {
    1059            0 :     myCachedGUISettings = view.editVisualisationSettings();
    1060            0 :     GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
    1061              :     // add items
    1062            0 :     ret->mkItem(TL("allowed speed [m/s]"), false, getSpeedLimit());
    1063            0 :     const std::map<SUMOVehicleClass, double>* restrictions = MSNet::getInstance()->getRestrictions(myEdge->getEdgeType());
    1064            0 :     if (restrictions != nullptr) {
    1065            0 :         for (const auto& elem : *restrictions) {
    1066            0 :             ret->mkItem((std::string("   ") + TL("allowed speed [m/s]") + std::string(": ") + toString(elem.first)).c_str(), false, elem.second);
    1067              :         }
    1068              :     }
    1069            0 :     ret->mkItem(TL("length [m]"), false, myLength);
    1070            0 :     ret->mkItem(TL("width [m]"), false, myWidth);
    1071            0 :     ret->mkItem(TL("street name"), false, myEdge->getStreetName());
    1072            0 :     ret->mkItem(TL("stored travel time [s]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getStoredEdgeTravelTime));
    1073            0 :     ret->mkItem(TL("loaded weight"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getLoadedEdgeWeight));
    1074            0 :     ret->mkItem(TL("routing speed [m/s]"), true, new FunctionBinding<MSEdge, double>(myEdge, &MSEdge::getRoutingSpeed));
    1075            0 :     ret->mkItem(TL("lane friction coefficient [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getFrictionCoefficient));
    1076            0 :     ret->mkItem(TL("time penalty [s]"), true, new FunctionBinding<MSEdge, double>(myEdge, &MSEdge::getTimePenalty));
    1077            0 :     ret->mkItem(TL("brutto occupancy [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getBruttoOccupancy, 100.));
    1078            0 :     ret->mkItem(TL("netto occupancy [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getNettoOccupancy, 100.));
    1079            0 :     ret->mkItem(TL("pending insertions [#]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getPendingEmits));
    1080            0 :     ret->mkItem(TL("edge type"), false, myEdge->getEdgeType());
    1081            0 :     ret->mkItem(TL("routing type"), false, myEdge->getRoutingType());
    1082            0 :     ret->mkItem(TL("type"), false, myLaneType);
    1083            0 :     ret->mkItem(TL("priority"), false, myEdge->getPriority());
    1084            0 :     ret->mkItem(TL("distance [km]"), false, myEdge->getDistance() / 1000);
    1085            0 :     ret->mkItem(TL("allowed vehicle class"), false, StringUtils::wrapText(getVehicleClassNames(myPermissions), 60));
    1086            0 :     ret->mkItem(TL("disallowed vehicle class"), false, StringUtils::wrapText(getVehicleClassNames(~myPermissions), 60));
    1087            0 :     ret->mkItem(TL("permission code"), false, myPermissions);
    1088            0 :     ret->mkItem(TL("color value"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getColorValueForTracker));
    1089            0 :     if (myBidiLane != nullptr) {
    1090            0 :         ret->mkItem(TL("bidi-lane"), false, myBidiLane->getID());
    1091              :     }
    1092              :     // info for blocked departDriveWay
    1093            0 :     for (auto item : getParametersMap()) {
    1094            0 :         if (StringUtils::startsWith(item.first, "insertionBlocked:")) {
    1095            0 :             const MSDriveWay* dw = MSDriveWay::retrieveDepartDriveWay(myEdge, item.second);
    1096            0 :             if (dw != nullptr) {
    1097            0 :                 ret->mkItem(("blocking " + dw->getID()).c_str(), false, toString(MSRailSignal::getBlockingVehicles(dw)));
    1098            0 :                 ret->mkItem(("driveWays blocking " + dw->getID()).c_str(), false, toString(MSRailSignal::getBlockingDriveWays(dw)));
    1099              :             }
    1100              :         }
    1101              :     }
    1102              : 
    1103            0 :     for (const auto& kv : myEdge->getParametersMap()) {
    1104            0 :         ret->mkItem(("edgeParam:" + kv.first).c_str(), false, kv.second);
    1105              :     }
    1106            0 :     ret->checkFont(myEdge->getStreetName());
    1107            0 :     ret->closeBuilding();
    1108            0 :     return ret;
    1109              : }
    1110              : 
    1111              : 
    1112              : Boundary
    1113            0 : GUILane::getCenteringBoundary() const {
    1114            0 :     const PositionVector& shape = GUIGlobals::gSecondaryShape && myShape2.size() > 0 ? myShape2 : myShape;
    1115            0 :     Boundary b;
    1116            0 :     b.add(shape[0]);
    1117            0 :     b.add(shape[-1]);
    1118            0 :     b.grow(RENDERING_BUFFER);
    1119              :     // ensure that vehicles and persons on the side are drawn even if the edge
    1120              :     // is outside the view
    1121            0 :     return b;
    1122              : }
    1123              : 
    1124              : 
    1125              : const PositionVector&
    1126     99809046 : GUILane::getShape(bool secondary) const {
    1127     99809046 :     return secondary && myShape2.size() > 0 ? myShape2 : myShape;
    1128              : }
    1129              : 
    1130              : 
    1131              : const std::vector<double>&
    1132     17607891 : GUILane::getShapeRotations(bool secondary) const {
    1133     17607891 :     return secondary && myShapeRotations2.size() > 0 ? myShapeRotations2 : myShapeRotations;
    1134              : }
    1135              : 
    1136              : 
    1137              : const std::vector<double>&
    1138     17556711 : GUILane::getShapeLengths(bool secondary) const {
    1139     17556711 :     return secondary && myShapeLengths2.size() > 0 ? myShapeLengths2 : myShapeLengths;
    1140              : }
    1141              : 
    1142              : 
    1143              : std::vector<RGBColor>&
    1144     97036332 : GUILane::getShapeColors(bool secondary) const {
    1145     97036332 :     return secondary && myShapeColors2.size() > 0 ? myShapeColors2 : myShapeColors;
    1146              : }
    1147              : 
    1148              : 
    1149              : double
    1150            0 : GUILane::firstWaitingTime() const {
    1151            0 :     return myVehicles.size() == 0 ? 0 : myVehicles.back()->getWaitingSeconds();
    1152              : }
    1153              : 
    1154              : 
    1155              : double
    1156            0 : GUILane::getEdgeLaneNumber() const {
    1157            0 :     return (double) myEdge->getLanes().size();
    1158              : }
    1159              : 
    1160              : 
    1161              : double
    1162            0 : GUILane::getStoredEdgeTravelTime() const {
    1163            0 :     MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1164            0 :     if (!ews.knowsTravelTime(myEdge)) {
    1165              :         return -1;
    1166              :     } else {
    1167            0 :         double value(0);
    1168            0 :         ews.retrieveExistingTravelTime(myEdge, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()), value);
    1169            0 :         return value;
    1170              :     }
    1171              : }
    1172              : 
    1173              : 
    1174              : double
    1175            0 : GUILane::getLoadedEdgeWeight() const {
    1176            0 :     MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1177            0 :     if (!ews.knowsEffort(myEdge)) {
    1178              :         return -1;
    1179              :     } else {
    1180            0 :         double value(-1);
    1181            0 :         ews.retrieveExistingEffort(myEdge, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()), value);
    1182            0 :         return value;
    1183              :     }
    1184              : }
    1185              : 
    1186              : 
    1187              : double
    1188            0 : GUILane::getColorValueWithFunctional(const GUIVisualizationSettings& s, int activeScheme) const {
    1189            0 :     switch (activeScheme) {
    1190            0 :         case 18: {
    1191            0 :             return GeomHelper::naviDegree(getShape(s.secondaryShape).beginEndAngle()); // [0-360]
    1192              :         }
    1193            0 :         default:
    1194            0 :             return getColorValue(s, activeScheme);
    1195              :     }
    1196              : 
    1197              : }
    1198              : 
    1199              : 
    1200              : RGBColor
    1201     48955613 : GUILane::setColor(const GUIVisualizationSettings& s) const {
    1202              :     // setting and retrieving the color does not work in OSGView so we return it explicitliy
    1203     48955613 :     RGBColor col;
    1204     48955613 :     if (MSGlobals::gUseMesoSim && static_cast<const GUIEdge*>(myEdge)->getMesoColor() != MESO_USE_LANE_COLOR) {
    1205            0 :         col = static_cast<const GUIEdge*>(myEdge)->getMesoColor();
    1206              :     } else {
    1207     48955613 :         const GUIColorer& c = s.laneColorer;
    1208     48955613 :         if (!setFunctionalColor(c, col) && !setMultiColor(s, c, col)) {
    1209     48793111 :             col = c.getScheme().getColor(getColorValue(s, c.getActive()));
    1210              :         }
    1211              :     }
    1212     48955613 :     GLHelper::setColor(col);
    1213     48955613 :     return col;
    1214              : }
    1215              : 
    1216              : 
    1217              : bool
    1218     52506896 : GUILane::setFunctionalColor(const GUIColorer& c, RGBColor& col, int activeScheme) const {
    1219     52506896 :     if (activeScheme < 0) {
    1220              :         activeScheme = c.getActive();
    1221              :     }
    1222     52506896 :     switch (activeScheme) {
    1223     52497456 :         case 0:
    1224     52497456 :             if (myEdge->isCrossing()) {
    1225              :                 // determine priority to decide color
    1226       162502 :                 const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
    1227       162502 :                 if (link->havePriority() || link->getTLLogic() != nullptr) {
    1228        75686 :                     col = RGBColor(230, 230, 230);
    1229              :                 } else {
    1230        86816 :                     col = RGBColor(26, 26, 26);
    1231              :                 }
    1232       162502 :                 GLHelper::setColor(col);
    1233       162502 :                 return true;
    1234              :             } else {
    1235              :                 return false;
    1236              :             }
    1237            0 :         case 18: {
    1238            0 :             double hue = GeomHelper::naviDegree(myShape.beginEndAngle()); // [0-360]
    1239            0 :             col = RGBColor::fromHSV(hue, 1., 1.);
    1240            0 :             GLHelper::setColor(col);
    1241            0 :             return true;
    1242              :         }
    1243              :         case 30: { // taz color
    1244            0 :             col = c.getScheme().getColor(0);
    1245              :             std::vector<RGBColor> tazColors;
    1246            0 :             for (MSEdge* e : myEdge->getPredecessors()) {
    1247            0 :                 if (e->isTazConnector() && e->hasParameter("tazColor")) {
    1248            0 :                     tazColors.push_back(RGBColor::parseColor(e->getParameter("tazColor")));
    1249              :                 }
    1250              :             }
    1251            0 :             for (MSEdge* e : myEdge->getSuccessors()) {
    1252            0 :                 if (e->isTazConnector() && e->hasParameter("tazColor")) {
    1253            0 :                     tazColors.push_back(RGBColor::parseColor(e->getParameter("tazColor")));
    1254              :                 }
    1255              :             }
    1256            0 :             if (tazColors.size() > 0) {
    1257            0 :                 int randColor = RandHelper::rand((int)tazColors.size(), RGBColor::getColorRNG());
    1258            0 :                 col = tazColors[randColor];
    1259              :             }
    1260            0 :             GLHelper::setColor(col);
    1261              :             return true;
    1262            0 :         }
    1263              :         default:
    1264              :             return false;
    1265              :     }
    1266              : }
    1267              : 
    1268              : 
    1269              : bool
    1270     48793111 : GUILane::setMultiColor(const GUIVisualizationSettings& s, const GUIColorer& c, RGBColor& col) const {
    1271              :     const int activeScheme = c.getActive();
    1272     48793111 :     auto& shapeColors = getShapeColors(s.secondaryShape);
    1273     48793111 :     const PositionVector& shape = getShape(s.secondaryShape);
    1274              :     shapeColors.clear();
    1275     48793111 :     switch (activeScheme) {
    1276            0 :         case 22: // color by height at segment start
    1277            0 :             for (PositionVector::const_iterator ii = shape.begin(); ii != shape.end() - 1; ++ii) {
    1278            0 :                 shapeColors.push_back(c.getScheme().getColor(ii->z()));
    1279              :             }
    1280              :             // osg fallback (edge height at start)
    1281            0 :             col = c.getScheme().getColor(getColorValue(s, 21));
    1282            0 :             return true;
    1283              :         case 24: // color by inclination  at segment start
    1284            0 :             for (int ii = 1; ii < (int)shape.size(); ++ii) {
    1285            0 :                 const double inc = (shape[ii].z() - shape[ii - 1].z()) / MAX2(POSITION_EPS, shape[ii].distanceTo2D(shape[ii - 1]));
    1286            0 :                 shapeColors.push_back(c.getScheme().getColor(inc));
    1287              :             }
    1288            0 :             col = c.getScheme().getColor(getColorValue(s, 23));
    1289            0 :             return true;
    1290              :         default:
    1291              :             return false;
    1292              :     }
    1293              : }
    1294              : 
    1295              : double
    1296            0 : GUILane::getColorValueForTracker() const {
    1297            0 :     if (myCachedGUISettings != nullptr) {
    1298              :         const GUIVisualizationSettings& s = *myCachedGUISettings;
    1299              :         const GUIColorer& c = s.laneColorer;
    1300            0 :         double val = getColorValueWithFunctional(s, c.getActive());
    1301            0 :         if (val == GUIVisualizationSettings::MISSING_DATA) {
    1302              :             // blowing up the dialog or plot isn't helpful. At least 0 may be understood as neutral
    1303              :             return 0;
    1304              :         } else {
    1305              :             return val;
    1306              :         }
    1307              :     } else {
    1308              :         return 0;
    1309              :     }
    1310              : }
    1311              : 
    1312              : 
    1313              : double
    1314     48793111 : GUILane::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {
    1315     48793111 :     switch (activeScheme) {
    1316     48783671 :         case 0:
    1317     48783671 :             switch (myPermissions) {
    1318              :                 case SVC_PEDESTRIAN:
    1319              :                     return 1;
    1320              :                 case SVC_BICYCLE:
    1321              :                     return 2;
    1322       107425 :                 case 0:
    1323              :                     // forbidden road or green verge
    1324       107425 :                     return myEdge->getPermissions() == 0 ? 10 : 3;
    1325          707 :                 case SVC_SHIP:
    1326          707 :                     return 4;
    1327         2709 :                 case SVC_AUTHORITY:
    1328         2709 :                     return 8;
    1329            0 :                 case SVC_AIRCRAFT:
    1330              :                 case SVC_DRONE:
    1331            0 :                     return 11;
    1332              :                 default:
    1333              :                     break;
    1334              :             }
    1335     47606371 :             if (myEdge->isTazConnector()) {
    1336              :                 return 9;
    1337     47606371 :             } else if (isRailway(myPermissions)) {
    1338              :                 return 5;
    1339     47297834 :             } else if ((myPermissions & SVC_PASSENGER) != 0) {
    1340     47186314 :                 if ((myPermissions & (SVC_RAIL_CLASSES & ~SVC_RAIL_FAST)) != 0 && (myPermissions & SVC_SHIP) == 0) {
    1341              :                     return 6;
    1342              :                 } else {
    1343              :                     return 0;
    1344              :                 }
    1345              :             } else {
    1346       111520 :                 if ((myPermissions & SVC_RAIL_CLASSES) != 0 && (myPermissions & SVC_SHIP) == 0) {
    1347              :                     return 6;
    1348              :                 } else {
    1349       111226 :                     return 7;
    1350              :                 }
    1351              :             }
    1352         9440 :         case 1:
    1353         9440 :             return isLaneOrEdgeSelected();
    1354            0 :         case 2:
    1355            0 :             return (double)myPermissions;
    1356            0 :         case 3:
    1357            0 :             return getSpeedLimit();
    1358            0 :         case 4:
    1359            0 :             return getBruttoOccupancy();
    1360            0 :         case 5:
    1361            0 :             return getNettoOccupancy();
    1362            0 :         case 6:
    1363            0 :             return firstWaitingTime();
    1364            0 :         case 7:
    1365            0 :             return getEdgeLaneNumber();
    1366            0 :         case 8:
    1367            0 :             return getEmissions<PollutantsInterface::CO2>() / myLength;
    1368            0 :         case 9:
    1369            0 :             return getEmissions<PollutantsInterface::CO>() / myLength;
    1370            0 :         case 10:
    1371            0 :             return getEmissions<PollutantsInterface::PM_X>() / myLength;
    1372            0 :         case 11:
    1373            0 :             return getEmissions<PollutantsInterface::NO_X>() / myLength;
    1374            0 :         case 12:
    1375            0 :             return getEmissions<PollutantsInterface::HC>() / myLength;
    1376            0 :         case 13:
    1377            0 :             return getEmissions<PollutantsInterface::FUEL>() / myLength;
    1378            0 :         case 14:
    1379            0 :             return getHarmonoise_NoiseEmissions();
    1380            0 :         case 15: {
    1381            0 :             return getStoredEdgeTravelTime();
    1382              :         }
    1383            0 :         case 16: {
    1384            0 :             MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1385            0 :             if (!ews.knowsTravelTime(myEdge)) {
    1386              :                 return -1;
    1387              :             } else {
    1388            0 :                 double value(0);
    1389            0 :                 ews.retrieveExistingTravelTime(myEdge, 0, value);
    1390            0 :                 return 100 * myLength / value / getSpeedLimit();
    1391              :             }
    1392              :         }
    1393            0 :         case 17: {
    1394              :             // geometrical length has no meaning for walkingAreas since it describes the outer boundary
    1395            0 :             return myEdge->isWalkingArea() ? 1 :  1 / getLengthGeometryFactor(s.secondaryShape);
    1396              :         }
    1397            0 :         case 19: {
    1398            0 :             return getLoadedEdgeWeight();
    1399              :         }
    1400            0 :         case 20: {
    1401            0 :             return myEdge->getPriority();
    1402              :         }
    1403            0 :         case 21: {
    1404              :             // color by z of first shape point
    1405            0 :             return getShape(s.secondaryShape)[0].z();
    1406              :         }
    1407            0 :         case 23: {
    1408              :             // color by incline
    1409            0 :             return (getShape(s.secondaryShape)[-1].z() - getShape(s.secondaryShape)[0].z()) / getLength();
    1410              :         }
    1411            0 :         case 25: {
    1412              :             // color by average speed
    1413            0 :             return getMeanSpeed();
    1414              :         }
    1415            0 :         case 26: {
    1416              :             // color by average relative speed
    1417            0 :             return getMeanSpeed() / myMaxSpeed;
    1418              :         }
    1419            0 :         case 27: {
    1420              :             // color by routing device assumed speed
    1421            0 :             return myEdge->getRoutingSpeed();
    1422              :         }
    1423            0 :         case 28:
    1424            0 :             return getEmissions<PollutantsInterface::ELEC>() / myLength;
    1425            0 :         case 29:
    1426            0 :             return getPendingEmits();
    1427            0 :         case 31: {
    1428              :             // by numerical edge param value
    1429            0 :             if (myEdge->hasParameter(s.edgeParam)) {
    1430              :                 try {
    1431            0 :                     return StringUtils::toDouble(myEdge->getParameter(s.edgeParam, "0"));
    1432            0 :                 } catch (NumberFormatException&) {
    1433              :                     try {
    1434            0 :                         return StringUtils::toBool(myEdge->getParameter(s.edgeParam, "0"));
    1435            0 :                     } catch (BoolFormatException&) {
    1436            0 :                         return GUIVisualizationSettings::MISSING_DATA;
    1437            0 :                     }
    1438            0 :                 }
    1439              :             } else {
    1440            0 :                 return GUIVisualizationSettings::MISSING_DATA;
    1441              :             }
    1442              :         }
    1443            0 :         case 32: {
    1444              :             // by numerical lane param value
    1445            0 :             if (hasParameter(s.laneParam)) {
    1446              :                 try {
    1447            0 :                     return StringUtils::toDouble(getParameter(s.laneParam, "0"));
    1448            0 :                 } catch (NumberFormatException&) {
    1449              :                     try {
    1450            0 :                         return StringUtils::toBool(getParameter(s.laneParam, "0"));
    1451            0 :                     } catch (BoolFormatException&) {
    1452            0 :                         return GUIVisualizationSettings::MISSING_DATA;
    1453            0 :                     }
    1454            0 :                 }
    1455              :             } else {
    1456            0 :                 return GUIVisualizationSettings::MISSING_DATA;
    1457              :             }
    1458              :         }
    1459            0 :         case 33: {
    1460              :             // by edge data value
    1461            0 :             return GUINet::getGUIInstance()->getEdgeData(myEdge, s.edgeData);
    1462              :         }
    1463            0 :         case 34: {
    1464            0 :             return myEdge->getDistance();
    1465              :         }
    1466            0 :         case 35: {
    1467            0 :             return fabs(myEdge->getDistance());
    1468              :         }
    1469            0 :         case 36: {
    1470            0 :             return myReachability;
    1471              :         }
    1472            0 :         case 37: {
    1473            0 :             return myRNGIndex % MSGlobals::gNumSimThreads;
    1474              :         }
    1475            0 :         case 38: {
    1476            0 :             if (myParkingAreas == nullptr) {
    1477              :                 // init
    1478            0 :                 myParkingAreas = new std::vector<MSParkingArea*>();
    1479            0 :                 for (auto& item : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_PARKING_AREA)) {
    1480            0 :                     if (&item.second->getLane().getEdge() == myEdge) {
    1481            0 :                         myParkingAreas->push_back(dynamic_cast<MSParkingArea*>(item.second));
    1482              :                     }
    1483              :                 }
    1484              :             }
    1485              :             int capacity = 0;
    1486            0 :             for (MSParkingArea* pa : *myParkingAreas) {
    1487            0 :                 capacity += pa->getCapacity() - pa->getOccupancy();
    1488              :             }
    1489            0 :             return capacity;
    1490              :         }
    1491            0 :         case 39: {
    1492              :             // by live edge data value
    1493            0 :             return GUINet::getGUIInstance()->getMeanData(this, s.edgeDataID, s.edgeData);
    1494              :         }
    1495              :     }
    1496              :     return 0;
    1497              : }
    1498              : 
    1499              : 
    1500              : double
    1501     43757051 : GUILane::getScaleValue(const GUIVisualizationSettings& s, int activeScheme, bool s2) const {
    1502     43757051 :     switch (activeScheme) {
    1503              :         case 0:
    1504              :             return 0;
    1505            0 :         case 1:
    1506            0 :             return isLaneOrEdgeSelected();
    1507            0 :         case 2:
    1508            0 :             return getSpeedLimit();
    1509            0 :         case 3:
    1510            0 :             return getBruttoOccupancy();
    1511            0 :         case 4:
    1512            0 :             return getNettoOccupancy();
    1513            0 :         case 5:
    1514            0 :             return firstWaitingTime();
    1515            0 :         case 6:
    1516            0 :             return getEdgeLaneNumber();
    1517            0 :         case 7:
    1518            0 :             return getEmissions<PollutantsInterface::CO2>() / myLength;
    1519            0 :         case 8:
    1520            0 :             return getEmissions<PollutantsInterface::CO>() / myLength;
    1521            0 :         case 9:
    1522            0 :             return getEmissions<PollutantsInterface::PM_X>() / myLength;
    1523            0 :         case 10:
    1524            0 :             return getEmissions<PollutantsInterface::NO_X>() / myLength;
    1525            0 :         case 11:
    1526            0 :             return getEmissions<PollutantsInterface::HC>() / myLength;
    1527            0 :         case 12:
    1528            0 :             return getEmissions<PollutantsInterface::FUEL>() / myLength;
    1529            0 :         case 13:
    1530            0 :             return getHarmonoise_NoiseEmissions();
    1531            0 :         case 14: {
    1532            0 :             return getStoredEdgeTravelTime();
    1533              :         }
    1534            0 :         case 15: {
    1535            0 :             MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1536            0 :             if (!ews.knowsTravelTime(myEdge)) {
    1537              :                 return -1;
    1538              :             } else {
    1539            0 :                 double value(0);
    1540            0 :                 ews.retrieveExistingTravelTime(myEdge, 0, value);
    1541            0 :                 return 100 * myLength / value / getSpeedLimit();
    1542              :             }
    1543              :         }
    1544            0 :         case 16: {
    1545            0 :             return 1 / getLengthGeometryFactor(s2);
    1546              :         }
    1547            0 :         case 17: {
    1548            0 :             return getLoadedEdgeWeight();
    1549              :         }
    1550            0 :         case 18: {
    1551            0 :             return myEdge->getPriority();
    1552              :         }
    1553            0 :         case 19: {
    1554              :             // scale by average speed
    1555            0 :             return getMeanSpeed();
    1556              :         }
    1557            0 :         case 20: {
    1558              :             // scale by average relative speed
    1559            0 :             return getMeanSpeed() / myMaxSpeed;
    1560              :         }
    1561            0 :         case 21:
    1562            0 :             return getEmissions<PollutantsInterface::ELEC>() / myLength;
    1563            0 :         case 22:
    1564            0 :             return MSNet::getInstance()->getInsertionControl().getPendingEmits(this);
    1565            0 :         case 23:
    1566              :             // by edge data value
    1567            0 :             return GUINet::getGUIInstance()->getEdgeData(myEdge, s.edgeDataScaling);
    1568              :     }
    1569              :     return 0;
    1570              : }
    1571              : 
    1572              : 
    1573              : bool
    1574     17343396 : GUILane::drawAsRailway(const GUIVisualizationSettings& s) const {
    1575     17343396 :     return isRailway(myPermissions) && ((myPermissions & SVC_BUS) == 0) && s.showRails;
    1576              : }
    1577              : 
    1578              : 
    1579              : bool
    1580       794208 : GUILane::drawAsWaterway(const GUIVisualizationSettings& s) const {
    1581       794208 :     return isWaterway(myPermissions) && s.showRails; // reusing the showRails setting
    1582              : }
    1583              : 
    1584              : 
    1585              : #ifdef HAVE_OSG
    1586              : void
    1587       221776 : GUILane::updateColor(const GUIVisualizationSettings& s) {
    1588       221776 :     if (myGeom == 0) {
    1589              :         // not drawn
    1590            0 :         return;
    1591              :     }
    1592       221776 :     const RGBColor col = setColor(s);
    1593       221776 :     osg::Vec4ubArray* colors = dynamic_cast<osg::Vec4ubArray*>(myGeom->getColorArray());
    1594       221776 :     (*colors)[0].set(col.red(), col.green(), col.blue(), col.alpha());
    1595       221776 :     myGeom->setColorArray(colors);
    1596              : }
    1597              : #endif
    1598              : 
    1599              : 
    1600              : void
    1601            0 : GUILane::closeTraffic(bool rebuildAllowed) {
    1602            0 :     MSGlobals::gCheckRoutes = false;
    1603            0 :     if (myAmClosed) {
    1604              :         myPermissionChanges.clear(); // reset rerouters
    1605            0 :         resetPermissions(CHANGE_PERMISSIONS_GUI);
    1606              :     } else {
    1607            0 :         setPermissions(SVC_AUTHORITY, CHANGE_PERMISSIONS_GUI);
    1608              :     }
    1609            0 :     myAmClosed = !myAmClosed;
    1610            0 :     if (rebuildAllowed) {
    1611            0 :         getEdge().rebuildAllowedLanes();
    1612              :     }
    1613            0 : }
    1614              : 
    1615              : 
    1616              : PositionVector
    1617       140221 : GUILane::splitAtSegments(const PositionVector& shape) {
    1618              :     assert(MSGlobals::gUseMesoSim);
    1619       140221 :     const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdge().getEdgeType());
    1620       140221 :     int no = MELoop::numSegmentsFor(myLength, edgeType.edgeLength);
    1621       140221 :     const double slength = myLength / no;
    1622              :     PositionVector result = shape;
    1623              :     double offset = 0;
    1624       441898 :     for (int i = 0; i < no; ++i) {
    1625       301677 :         offset += slength;
    1626       301677 :         Position pos = shape.positionAtOffset(offset);
    1627       301677 :         int index = result.indexOfClosest(pos);
    1628       301677 :         if (pos.distanceTo(result[index]) > POSITION_EPS) {
    1629       162029 :             index = result.insertAtClosest(pos, false);
    1630              :         }
    1631       301677 :         if (i != no - 1) {
    1632       161456 :             mySegmentStartIndex.push_back(index);
    1633              :         }
    1634       722171 :         while ((int)myShapeSegments.size() < index) {
    1635       420494 :             myShapeSegments.push_back(i);
    1636              :         }
    1637              :         //std::cout << "splitAtSegments " << getID() << " no=" << no << " i=" << i << " offset=" << offset << " index=" << index << " segs=" << toString(myShapeSegments) << " resultSize=" << result.size() << " result=" << toString(result) << "\n";
    1638              :     }
    1639       284627 :     while (myShapeSegments.size() < result.size()) {
    1640       144406 :         myShapeSegments.push_back(no - 1);
    1641              :     }
    1642       140221 :     return result;
    1643            0 : }
    1644              : 
    1645              : bool
    1646       306918 : GUILane::isSelected() const {
    1647       306918 :     return gSelected.isSelected(GLO_LANE, getGlID());
    1648              : }
    1649              : 
    1650              : bool
    1651         9440 : GUILane::isLaneOrEdgeSelected() const {
    1652         9440 :     return isSelected() || gSelected.isSelected(GLO_EDGE, dynamic_cast<GUIEdge*>(myEdge)->getGlID());
    1653              : }
    1654              : 
    1655              : double
    1656            0 : GUILane::getPendingEmits() const {
    1657            0 :     return MSNet::getInstance()->getInsertionControl().getPendingEmits(this);
    1658              : }
    1659              : 
    1660              : double
    1661            0 : GUILane::getClickPriority() const {
    1662            0 :     if (MSGlobals::gUseMesoSim) {
    1663              :         // do not select lanes in meso mode
    1664            0 :         return INVALID_PRIORITY;
    1665              :     }
    1666            0 :     if (myEdge->isCrossing()) {
    1667            0 :         return GLO_CROSSING;
    1668              :     }
    1669              :     return GLO_LANE;
    1670              : }
    1671              : 
    1672              : 
    1673              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1