LCOV - code coverage report
Current view: top level - src/guisim - GUILane.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 53.8 % 939 505
Test Date: 2026-09-20 15:45: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       448620 : 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       448620 :                  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       448620 :     myParkingAreas(nullptr),
      91       448620 :     myTesselation(nullptr),
      92              : #ifdef HAVE_OSG
      93       448620 :     myGeom(0),
      94              : #endif
      95       448620 :     myAmClosed(false),
      96       448620 :     myLengthGeometryFactor2(myLengthGeometryFactor),
      97       448620 :     myLock(true) {
      98       448620 :     initRotations(myShape, myShapeRotations, myShapeLengths, myShapeColors);
      99              :     //
     100       448620 :     myHalfLaneWidth = myWidth / 2.;
     101       448620 :     myQuarterLaneWidth = myWidth / 4.;
     102       448620 : }
     103              : 
     104              : 
     105       895124 : GUILane::~GUILane() {
     106              :     // just to quit cleanly on a failure
     107       447562 :     if (myLock.locked()) {
     108            0 :         myLock.unlock();
     109              :     }
     110       447562 :     delete myParkingAreas;
     111       447562 :     delete myTesselation;
     112       895124 : }
     113              : 
     114              : 
     115              : void
     116       162501 : GUILane::updateMesoGUISegments() {
     117              : #ifdef _DEBUG
     118              :     const double origLength = myShape.length();
     119              : #endif
     120       325002 :     myShape = splitAtSegments(myShape);
     121              :     assert(fabs(myShape.length() - origLength) < POSITION_EPS);
     122              :     assert(myShapeSegments.size() == myShape.size());
     123       162501 :     initRotations(myShape, myShapeRotations, myShapeLengths, myShapeColors);
     124       162501 : }
     125              : 
     126              : 
     127              : void
     128       611121 : 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       611121 :     rotations.reserve(shape.size() - 1);
     136       611121 :     lengths.reserve(shape.size() - 1);
     137       611121 :     colors.reserve(shape.size() - 1);
     138       611121 :     int e = (int) shape.size() - 1;
     139      2041330 :     for (int i = 0; i < e; ++i) {
     140      1430209 :         const Position& f = shape[i];
     141      1430209 :         const Position& s = shape[i + 1];
     142      1430209 :         lengths.push_back(f.distanceTo2D(s));
     143      1430209 :         rotations.push_back(RAD2DEG(atan2(s.x() - f.x(), f.y() - s.y())));
     144              :     }
     145       611121 : }
     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       509517 : GUILane::incorporateVehicle(MSVehicle* veh, double pos, double speed, double posLat,
     159              :                             const MSLane::VehCont::iterator& at,
     160              :                             MSMoveReminder::Notification notification) {
     161       509517 :     FXMutexLock locker(myLock);
     162       509517 :     MSLane::incorporateVehicle(veh, pos, speed, posLat, at, notification);
     163       509517 : }
     164              : 
     165              : 
     166              : // ------ Access to vehicles ------
     167              : const MSLane::VehCont&
     168    132566133 : GUILane::getVehiclesSecure() const {
     169    132566133 :     myLock.lock();
     170    132566133 :     return myVehicles;
     171              : }
     172              : 
     173              : 
     174              : void
     175    132566133 : GUILane::releaseVehicles() const {
     176    132566133 :     myLock.unlock();
     177    132566133 : }
     178              : 
     179              : 
     180              : void
     181     15338611 : GUILane::planMovements(const SUMOTime t) {
     182     15338611 :     FXMutexLock locker(myLock);
     183     15338611 :     MSLane::planMovements(t);
     184     15338611 : }
     185              : 
     186              : void
     187     15338611 : GUILane::setJunctionApproaches() const {
     188     15338611 :     FXMutexLock locker(myLock);
     189     15338611 :     MSLane::setJunctionApproaches();
     190     15338611 : }
     191              : 
     192              : 
     193              : void
     194     15338611 : GUILane::executeMovements(const SUMOTime t) {
     195     15338611 :     FXMutexLock locker(myLock);
     196     15338611 :     MSLane::executeMovements(t);
     197     15338610 : }
     198              : 
     199              : 
     200              : MSVehicle*
     201         6121 : GUILane::removeVehicle(MSVehicle* remVehicle, MSMoveReminder::Notification notification, bool notify) {
     202         6121 :     FXMutexLock locker(myLock);
     203        12242 :     return MSLane::removeVehicle(remVehicle, notification, notify);
     204              : }
     205              : 
     206              : 
     207              : void
     208         2581 : GUILane::removeParking(MSBaseVehicle* remVehicle) {
     209         2581 :     FXMutexLock locker(myLock);
     210         5162 :     return MSLane::removeParking(remVehicle);
     211              : }
     212              : 
     213              : 
     214              : void
     215     11339747 : GUILane::swapAfterLaneChange(SUMOTime t) {
     216     11339747 :     FXMutexLock locker(myLock);
     217     11339747 :     MSLane::swapAfterLaneChange(t);
     218     11339747 : }
     219              : 
     220              : 
     221              : void
     222      4332755 : GUILane::integrateNewVehicles() {
     223      4332755 :     FXMutexLock locker(myLock);
     224      4332755 :     MSLane::integrateNewVehicles();
     225      4332755 : }
     226              : 
     227              : 
     228              : void
     229     16767092 : GUILane::detectCollisions(SUMOTime timestep, const std::string& stage) {
     230     16767092 :     FXMutexLock locker(myLock);
     231     16767092 :     MSLane::detectCollisions(timestep, stage);
     232     16767092 : }
     233              : 
     234              : 
     235              : double
     236      2887386 : GUILane::setPartialOccupation(MSVehicle* v) {
     237      2887386 :     FXMutexLock locker(myLock);
     238      5774772 :     return MSLane::setPartialOccupation(v);
     239              : }
     240              : 
     241              : 
     242              : void
     243      2887397 : GUILane::resetPartialOccupation(MSVehicle* v) {
     244      2887397 :     FXMutexLock locker(myLock);
     245      2887397 :     MSLane::resetPartialOccupation(v);
     246      2887397 : }
     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       507077 : GUILane::drawLinkRules(const GUIVisualizationSettings& s, const GUINet& net) const {
     318       507077 :     int noLinks = (int)myLinks.size();
     319       507077 :     const PositionVector& shape = getShape(s.secondaryShape);
     320       507077 :     if (noLinks == 0) {
     321       198051 :         drawLinkRule(s, net, nullptr, shape, 0, 0);
     322       198051 :         return;
     323              :     }
     324       309026 :     if (isCrossing()) {
     325              :         // draw rules at the start and end of the crossing
     326        11100 :         const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
     327        11100 :         const MSLink* link2 = myLinks.front();
     328        11100 :         if (link2->getTLLogic() == nullptr) {
     329              :             link2 = link;
     330              :         }
     331              :         PositionVector tmp = shape;
     332        11100 :         tmp.extrapolate(0.5); // draw on top of the walking area
     333        11100 :         drawLinkRule(s, net, link2, tmp, 0, myWidth);
     334        11100 :         drawLinkRule(s, net, link, tmp.reverse(), 0, myWidth);
     335              :         return;
     336        11100 :     }
     337              :     // draw all links
     338       297926 :     const double isRailSignal = myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL;
     339       297926 :     double w = myWidth / (double) noLinks;
     340       297926 :     if (isRailSignal && noLinks > 1 && myLinks.back()->isTurnaround() && s.showRails) {
     341         1364 :         w = myWidth / (double)(noLinks - 1);
     342              :     }
     343       297926 :     double x1 = isRailSignal && myIndex == 0 ? -myWidth * 0.5 : 0;
     344       671897 :     for (int i = 0; i < noLinks; ++i) {
     345       373971 :         double x2 = x1 + w;
     346       373971 :         drawLinkRule(s, net, myLinks[MSGlobals::gLefthand ? noLinks - 1 - i : i], shape, x1, x2);
     347              :         x1 = x2;
     348              :     }
     349              :     // draw stopOffset for passenger cars
     350       297926 :     if (myLaneStopOffset.isDefined() && (myLaneStopOffset.getPermissions() & SVC_PASSENGER) != 0) {
     351          399 :         const double stopOffsetPassenger = myLaneStopOffset.getOffset();
     352              :         const Position& end = shape.back();
     353          399 :         const Position& f = shape[-2];
     354          399 :         const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
     355          399 :         GLHelper::setColor(s.getLinkColor(LINKSTATE_MAJOR));
     356          399 :         GLHelper::pushMatrix();
     357          399 :         glTranslated(end.x(), end.y(), 0);
     358          399 :         glRotated(rot, 0, 0, 1);
     359          399 :         glTranslated(0, stopOffsetPassenger, 0);
     360          399 :         glBegin(GL_QUADS);
     361          399 :         glVertex2d(-myHalfLaneWidth, 0.0);
     362          399 :         glVertex2d(-myHalfLaneWidth, 0.2);
     363          399 :         glVertex2d(myHalfLaneWidth, 0.2);
     364          399 :         glVertex2d(myHalfLaneWidth, 0.0);
     365          399 :         glEnd();
     366          399 :         GLHelper::popMatrix();
     367              :     }
     368              : }
     369              : 
     370              : 
     371              : void
     372       594222 : 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       594222 :     const Position& f = shape[-2];
     375       594222 :     const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
     376       594222 :     if (link == nullptr) {
     377       198051 :         if (static_cast<GUIEdge*>(myEdge)->showDeadEnd()) {
     378           89 :             GLHelper::setColor(GUIVisualizationColorSettings::SUMO_color_DEADEND_SHOW);
     379              :         } else {
     380       197962 :             GLHelper::setColor(GUIVisualizationSettings::getLinkColor(LINKSTATE_DEADEND));
     381              :         }
     382       198051 :         GLHelper::pushMatrix();
     383       198051 :         glTranslated(end.x(), end.y(), 0);
     384       198051 :         glRotated(rot, 0, 0, 1);
     385       198051 :         glBegin(GL_QUADS);
     386       198051 :         glVertex2d(-myHalfLaneWidth, 0.0);
     387       198051 :         glVertex2d(-myHalfLaneWidth, 0.5);
     388       198051 :         glVertex2d(myHalfLaneWidth, 0.5);
     389       198051 :         glVertex2d(myHalfLaneWidth, 0.0);
     390       198051 :         glEnd();
     391       198051 :         GLHelper::popMatrix();
     392              :     } else {
     393       396171 :         GLHelper::pushMatrix();
     394       396171 :         glTranslated(end.x(), end.y(), 0);
     395       396171 :         glRotated(rot, 0, 0, 1);
     396              :         // select glID
     397              : 
     398       396171 :         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        68339 :             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        68339 :                 GLHelper::pushName(net.getLinkTLID(link));
     415        68339 :                 break;
     416       327814 :             case LINKSTATE_MAJOR:
     417              :             case LINKSTATE_MINOR:
     418              :             case LINKSTATE_EQUAL:
     419              :             default:
     420       327814 :                 GLHelper::pushName(getGlID());
     421       327814 :                 break;
     422              :         }
     423       396171 :         GLHelper::setColor(GUIVisualizationSettings::getLinkColor(link->getState(), s.realisticLinkRules));
     424       396171 :         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       391883 :             double scale = isInternal() ? 0.5 : 1;
     428       783766 :             if (myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
     429        10926 :                 scale *= MAX2(s.laneWidthExaggeration, s.junctionSize.getExaggeration(s, this, 10));
     430              :             }
     431       391883 :             glScaled(scale, scale, 1);
     432       391883 :             glBegin(GL_QUADS);
     433       391883 :             glVertex2d(x1 - myHalfLaneWidth, 0.0);
     434       391883 :             glVertex2d(x1 - myHalfLaneWidth, 0.5);
     435       391883 :             glVertex2d(x2 - myHalfLaneWidth, 0.5);
     436       391883 :             glVertex2d(x2 - myHalfLaneWidth, 0.0);
     437       391883 :             glEnd();
     438       391883 :             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       396171 :         GLHelper::popName();
     447       396171 :         GLHelper::popMatrix();
     448              :     }
     449       594222 : }
     450              : 
     451              : void
     452       439911 : GUILane::drawArrows(bool secondaryShape) const {
     453       439911 :     if (myLinks.size() == 0) {
     454              :         return;
     455              :     }
     456              :     // draw all links
     457       245835 :     const Position& end = getShape(secondaryShape).back();
     458       245835 :     const Position& f = getShape(secondaryShape)[-2];
     459       245835 :     const double rot = RAD2DEG(atan2((end.x() - f.x()), (f.y() - end.y())));
     460       245835 :     GLHelper::pushMatrix();
     461       245835 :     glColor3d(1, 1, 1);
     462       245835 :     glTranslated(end.x(), end.y(), 0);
     463       245835 :     glRotated(rot, 0, 0, 1);
     464       245835 :     if (myWidth < SUMO_const_laneWidth) {
     465         3746 :         glScaled(myWidth / SUMO_const_laneWidth, 1, 1);
     466              :     }
     467       565843 :     for (const MSLink* const link : myLinks) {
     468              :         LinkDirection dir = link->getDirection();
     469              :         LinkState state = link->getState();
     470       320008 :         if (state == LINKSTATE_DEADEND || dir == LinkDirection::NODIR) {
     471            0 :             continue;
     472              :         }
     473       320008 :         switch (dir) {
     474              :             case LinkDirection::STRAIGHT:
     475       216422 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 2, .05);
     476       216422 :                 GLHelper::drawTriangleAtEnd(Position(0, 4), Position(0, 1), (double) 1, (double) .25);
     477       216422 :                 break;
     478              :             case LinkDirection::TURN:
     479         7635 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     480         7635 :                 GLHelper::drawBoxLine(Position(0, 2.5), 90, .5, .05);
     481         7635 :                 GLHelper::drawBoxLine(Position(0.5, 2.5), 180, 1, .05);
     482         7635 :                 GLHelper::drawTriangleAtEnd(Position(0.5, 2.5), Position(0.5, 4), (double) 1, (double) .25);
     483         7635 :                 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        35528 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     492        35528 :                 GLHelper::drawBoxLine(Position(0, 2.5), 90, 1, .05);
     493        35528 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.5, 2.5), (double) 1, (double) .25);
     494        35528 :                 break;
     495              :             case LinkDirection::RIGHT:
     496        43551 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     497        43551 :                 GLHelper::drawBoxLine(Position(0, 2.5), -90, 1, .05);
     498        43551 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.5, 2.5), (double) 1, (double) .25);
     499        43551 :                 break;
     500              :             case LinkDirection::PARTLEFT:
     501          261 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     502          261 :                 GLHelper::drawBoxLine(Position(0, 2.5), 45, .7, .05);
     503          261 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(1.2, 1.3), (double) 1, (double) .25);
     504          261 :                 break;
     505              :             case LinkDirection::PARTRIGHT:
     506        16611 :                 GLHelper::drawBoxLine(Position(0, 4), 0, 1.5, .05);
     507        16611 :                 GLHelper::drawBoxLine(Position(0, 2.5), -45, .7, .05);
     508        16611 :                 GLHelper::drawTriangleAtEnd(Position(0, 2.5), Position(-1.2, 1.3), (double) 1, (double) .25);
     509        16611 :                 break;
     510              :             default:
     511              :                 break;
     512              :         }
     513              :     }
     514       245835 :     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     48440284 : GUILane::drawGL(const GUIVisualizationSettings& s) const {
     547     48440284 :     GLHelper::pushMatrix();
     548     48440284 :     GLHelper::pushName(getGlID());
     549     48440284 :     const bool s2 = s.secondaryShape;
     550     48440284 :     double exaggeration = s.laneWidthExaggeration;
     551     48440284 :     if (MSGlobals::gUseMesoSim) {
     552      6444023 :         GUIEdge* myGUIEdge = dynamic_cast<GUIEdge*>(myEdge);
     553      6444023 :         exaggeration *= s.edgeScaler.getScheme().getColor(myGUIEdge->getScaleValue(s, s.edgeScaler.getActive()));
     554              :     } else {
     555     41996261 :         exaggeration *= s.laneScaler.getScheme().getColor(getScaleValue(s, s.laneScaler.getActive(), s2));
     556              :     }
     557              :     // set lane color
     558     48440284 :     const RGBColor color = setColor(s);
     559              :     // recognize full transparency and simply don't draw
     560     48440284 :     if (color.alpha() != 0 && s.scale * exaggeration > s.laneMinSize) {
     561              : 
     562     48328020 :         const bool isCrossing = myEdge->isCrossing();
     563              :         const bool isWalkingArea = myEdge->isWalkingArea();
     564     48328020 :         const bool isInternal = isCrossing || isWalkingArea || myEdge->isInternal();
     565     48328020 :         const PositionVector& baseShape = getShape(s2);
     566     48328020 :         const bool hasRailSignal = myEdge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL;
     567     48328020 :         if (s.trueZ) {
     568          284 :             glTranslated(0, 0, baseShape.getMinZ());
     569              :         } else {
     570     48327736 :             if (isCrossing) {
     571              :                 // draw internal lanes on top of junctions
     572       168839 :                 glTranslated(0, 0, GLO_JUNCTION + 0.1);
     573     48158897 :             } else if (isWalkingArea) {
     574              :                 // draw internal lanes on top of junctions
     575       434279 :                 glTranslated(0, 0, GLO_JUNCTION + 0.3);
     576     47724618 :             } else if (isWaterway(myPermissions)) {
     577              :                 // draw waterways below normal roads
     578          497 :                 glTranslated(0, 0, getType() - 0.2);
     579     47724121 :             } else if (myPermissions == SVC_SUBWAY) {
     580              :                 // draw subways further below
     581            0 :                 glTranslated(0, 0, getType() - 0.4);
     582              :             } else {
     583     47724121 :                 glTranslated(0, 0, getType());
     584              :             }
     585              :         }
     586     48328020 :         auto& shapeColors = getShapeColors(s2);
     587     48328020 :         if (MSGlobals::gUseMesoSim) {
     588              :             shapeColors.clear();
     589      6431505 :             const std::vector<RGBColor>& segmentColors = static_cast<const GUIEdge*>(myEdge)->getSegmentColors();
     590      6431505 :             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     19642779 :                 && myEdge->getToJunction()->getType() <= SumoXMLNodeType::RAIL_CROSSING
     603     54123296 :                 && (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     48328020 :         if (s.scale * exaggeration < 1. && junctionExaggeration == 1 && s.junctionSize.minSize != 0) {
     609     30241575 :             if (!isInternal || hasRailSignal) {
     610     13205147 :                 if (shapeColors.size() > 0) {
     611            0 :                     GLHelper::drawLine(baseShape, shapeColors);
     612              :                 } else {
     613     13205147 :                     GLHelper::drawLine(baseShape);
     614              :                 }
     615              :             }
     616     30241575 :             GLHelper::popMatrix();
     617              : 
     618              :         } else {
     619              : 
     620     18086445 :             GUINet* net = (GUINet*) MSNet::getInstance();
     621              :             bool mustDrawMarkings = false;
     622     18086445 :             bool hiddenBidi = getBidiLane() != nullptr && myEdge->getNumericalID() > myEdge->getBidiEdge()->getNumericalID();
     623     18086445 :             const bool detailZoom = s.scale * exaggeration > 5;
     624     18086445 :             const bool drawDetails = (detailZoom || s.junctionSize.minSize == 0 || hasRailSignal);
     625     18086445 :             const bool drawRails = drawAsRailway(s);
     626     18086445 :             const bool spreadSuperposed = s.spreadSuperposed && myBidiLane != nullptr;
     627     18086445 :             if (hiddenBidi && !spreadSuperposed) {
     628              :                 // do not draw shape
     629        57779 :                 mustDrawMarkings = !isInternal && myPermissions != 0 && myPermissions != SVC_PEDESTRIAN && exaggeration == 1.0 && !isWaterway(myPermissions) && neighLaneNotBidi();
     630     18028666 :             } 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        55468 :                 const double width = myWidth;
     636        55468 :                 double halfGauge = 0.5 * (width == SUMO_const_laneWidth ?  1.4350 : width) * exaggeration;
     637        55468 :                 if (spreadSuperposed) {
     638              :                     try {
     639            0 :                         shape.move2side(halfGauge * 0.8);
     640            0 :                     } catch (InvalidArgument&) {}
     641            0 :                     halfGauge *= 0.4;
     642              :                 }
     643        55468 :                 const double halfInnerFeetWidth = halfGauge - 0.039 * exaggeration;
     644        55468 :                 const double halfRailWidth = detailZoom ? (halfInnerFeetWidth + 0.15 * exaggeration) : SUMO_const_halfLaneWidth * exaggeration;
     645        55468 :                 const double halfCrossTieWidth = halfGauge * 1.81;
     646        55468 :                 if (shapeColors.size() > 0) {
     647            0 :                     GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), getShapeColors(s2), halfRailWidth);
     648              :                 } else {
     649        55468 :                     GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), halfRailWidth);
     650              :                 }
     651              :                 // Draw white on top with reduced width (the area between the two tracks)
     652        55468 :                 if (detailZoom) {
     653         2425 :                     glColor3d(1, 1, 1);
     654         2425 :                     glTranslated(0, 0, .1);
     655         2425 :                     GLHelper::drawBoxLines(shape, getShapeRotations(s2), getShapeLengths(s2), halfInnerFeetWidth);
     656         2425 :                     setColor(s);
     657         2425 :                     GLHelper::drawCrossTies(shape, getShapeRotations(s2), getShapeLengths(s2), 0.26 * exaggeration, 0.6 * exaggeration,
     658         2425 :                                             halfCrossTieWidth, 0, s.forceDrawForRectangleSelection);
     659              :                 }
     660     18028666 :             } else if (isCrossing) {
     661       165415 :                 if (s.drawCrossingsAndWalkingareas && (s.scale > 3.0 || s.junctionSize.minSize == 0)) {
     662        56931 :                     glTranslated(0, 0, .2);
     663        56931 :                     GLHelper::drawCrossTies(baseShape, getShapeRotations(s2), getShapeLengths(s2), 0.5, 1.0, getWidth() * 0.5,
     664        56931 :                                             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        56931 :                     glTranslated(0, 0, -.2);
     677              :                 }
     678     17807783 :             } else if (isWalkingArea) {
     679       419719 :                 if (s.drawCrossingsAndWalkingareas && (s.scale > 3.0 || s.junctionSize.minSize == 0)) {
     680       165690 :                     glTranslated(0, 0, .2);
     681       165690 :                     if (myTesselation == nullptr) {
     682         6650 :                         myTesselation = new TesselatedPolygon(getID(), "", RGBColor::MAGENTA, PositionVector(), false, true, 0);
     683              :                     }
     684       165690 :                     myTesselation->drawTesselation(baseShape);
     685       165690 :                     glTranslated(0, 0, -.2);
     686       165690 :                     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     17388064 :                 double halfWidth = isInternal ? myQuarterLaneWidth : (myHalfLaneWidth - SUMO_const_laneMarkWidth / 2);
     695     17388064 :                 mustDrawMarkings = !isInternal && myPermissions != 0 && myPermissions != SVC_PEDESTRIAN && exaggeration == 1.0 && !isWaterway(myPermissions) && !isAirway(myPermissions);
     696     17388064 :                 const int cornerDetail = drawDetails && !isInternal ? (s.drawForRectangleSelection ? 4 : MIN2(32, (int)(s.scale * exaggeration))) : 0;
     697     34776128 :                 double offset = halfWidth * MAX2(0., (exaggeration - 1)) * (MSGlobals::gLefthand ? -1 : 1);
     698     17388064 :                 if (spreadSuperposed) {
     699        78456 :                     offset += halfWidth * 0.5 * (MSGlobals::gLefthand ? -1 : 1);
     700        78456 :                     halfWidth *= 0.4; // create visible gap
     701              :                 }
     702     17388064 :                 if (shapeColors.size() > 0) {
     703            0 :                     GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), shapeColors, halfWidth * exaggeration, cornerDetail, offset);
     704              :                 } else {
     705     17388064 :                     GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), halfWidth * exaggeration, cornerDetail, offset);
     706              :                 }
     707              :             }
     708     18086445 :             GLHelper::popMatrix();
     709              : #ifdef GUILane_DEBUG_DRAW_FOE_INTERSECTIONS
     710              :             if (myEdge->isInternal() && gSelected.isSelected(getType(), getGlID())) {
     711              :                 debugDrawFoeIntersections();
     712              :             }
     713              : #endif
     714     18086445 :             if (s.geometryIndices.show(this)) {
     715            0 :                 GLHelper::debugVertices(baseShape, s.geometryIndices, s.scale);
     716              :             }
     717              :             // draw details
     718     18086445 :             if ((!isInternal || isCrossing || !s.drawJunctionShape) && (drawDetails || junctionExaggeration > 1)) {
     719       507077 :                 GLHelper::pushMatrix();
     720       507077 :                 glTranslated(0, 0, GLO_JUNCTION); // must draw on top of junction shape
     721       507077 :                 glTranslated(0, 0, .5);
     722       507077 :                 if (drawDetails) {
     723       507077 :                     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       507077 :                             || (getLinkCont().size() != 0 && getLinkCont()[0]->isInternalJunctionLink() && getLinkCont()[0]->getTLLogic() != nullptr)) {
     737       507077 :                         if (MSGlobals::gLateralResolution > 0 && s.showSublanes && !hiddenBidi && (myPermissions & ~(SVC_PEDESTRIAN | SVC_RAIL_CLASSES)) != 0) {
     738              :                             // draw sublane-borders
     739       159620 :                             const double offsetSign = MSGlobals::gLefthand ? -1 : 1;
     740       159620 :                             GLHelper::setColor(color.changedBrightness(51));
     741       881928 :                             for (double offset = -myHalfLaneWidth; offset < myHalfLaneWidth; offset += MSGlobals::gLateralResolution) {
     742       722308 :                                 GLHelper::drawBoxLines(baseShape, getShapeRotations(s2), getShapeLengths(s2), 0.01, 0, -offset * offsetSign);
     743              :                             }
     744              :                         }
     745       507077 :                         if (MSGlobals::gUseMesoSim && mySegmentStartIndex.size() > 0 && (myPermissions & ~SVC_PEDESTRIAN) != 0) {
     746              :                             // draw segment borders
     747        35821 :                             GLHelper::setColor(color.changedBrightness(51));
     748        72417 :                             for (int i : mySegmentStartIndex) {
     749        36596 :                                 if (shapeColors.size() > 0) {
     750            0 :                                     GLHelper::setColor(shapeColors[i].changedBrightness(51));
     751              :                                 }
     752        36596 :                                 GLHelper::drawBoxLine(baseShape[i], getShapeRotations(s2)[i] + 90, myWidth / 3, 0.2, 0);
     753        36596 :                                 GLHelper::drawBoxLine(baseShape[i], getShapeRotations(s2)[i] - 90, myWidth / 3, 0.2, 0);
     754              :                             }
     755              :                         }
     756       507077 :                         if (s.showLinkDecals && !drawRails && !drawAsWaterway(s) && myPermissions != SVC_PEDESTRIAN) {
     757       439911 :                             drawArrows(s.secondaryShape);
     758              :                         }
     759       507077 :                         glTranslated(0, 0, 1000);
     760       507077 :                         if (s.drawLinkJunctionIndex.show(nullptr)) {
     761            0 :                             drawLinkNo(s);
     762              :                         }
     763       507077 :                         if (s.drawLinkTLIndex.show(nullptr)) {
     764            0 :                             drawTLSLinkNo(s, *net);
     765              :                         }
     766       507077 :                         glTranslated(0, 0, -1000);
     767              :                     }
     768       507077 :                     glTranslated(0, 0, .1);
     769              :                 }
     770       507077 :                 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       507077 :                 GLHelper::popMatrix();
     775              :                 // make sure link rules are drawn so tls can be selected via right-click
     776       507077 :                 if (s.showLinkRules && drawDetails && !isWalkingArea &&
     777       507077 :                         (!myEdge->isInternal() || (getLinkCont().size() > 0 && getLinkCont()[0]->isInternalJunctionLink()))) {
     778       507077 :                     GLHelper::pushMatrix();
     779       507077 :                     glTranslated(0, 0, GLO_SHAPE); // must draw on top of junction shape and additionals
     780       507077 :                     drawLinkRules(s, *net);
     781       507077 :                     GLHelper::popMatrix();
     782              :                 }
     783              :             }
     784     18086445 :             if (mustDrawMarkings && drawDetails && s.laneShowBorders) { // needs matrix reset
     785       430363 :                 drawMarkings(s, exaggeration);
     786              :             }
     787       404784 :             if (drawDetails && isInternal && s.showBikeMarkings && myPermissions == SVC_BICYCLE && exaggeration == 1.0 && s.showLinkDecals && s.laneShowBorders && !hiddenBidi
     788         2864 :                     && MSGlobals::gUsingInternalLanes
     789     18089309 :                     && getNormalSuccessorLane()->getPermissions() == SVC_BICYCLE && getNormalPredecessorLane()->getPermissions() == SVC_BICYCLE) {
     790          928 :                 drawBikeMarkings();
     791              :             }
     792       404784 :             if (drawDetails && isInternal && exaggeration == 1.0 && s.showLinkDecals && s.laneShowBorders && !hiddenBidi && myIndex > 0
     793     18147363 :                     && !(myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER) && allowsChangingRight(SVC_PASSENGER))) {
     794              :                 // draw lane changing prohibitions on junction
     795           12 :                 drawJunctionChangeProhibitions();
     796              :             }
     797              :         }
     798              :     } else {
     799       112264 :         GLHelper::popMatrix();
     800              :     }
     801              :     // draw vehicles
     802     48440284 :     if (s.scale * s.vehicleSize.getExaggeration(s, nullptr) > s.vehicleSize.minSize) {
     803              :         // retrieve vehicles from lane; disallow simulation
     804     18198701 :         const MSLane::VehCont& vehicles = getVehiclesSecure();
     805     32729020 :         for (MSLane::VehCont::const_iterator v = vehicles.begin(); v != vehicles.end(); ++v) {
     806     14530319 :             if ((*v)->getLane() == this) {
     807     14530319 :                 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              :         // must prevent concurrent access via MSVehicle::cleanupFurtherLanes to avoid crash (#18271)
     812     18198701 :         myPartialOccupatorMutex.lock();
     813     19079971 :         for (const MSVehicle* veh : myPartialVehicles) {
     814       881270 :             if (veh->getLength() > RENDERING_BUFFER) {
     815              :                 // potential double rendering taken into account
     816        20888 :                 static_cast<const GUIVehicle*>(veh)->drawGL(s);
     817              :             }
     818              :         }
     819     18198701 :         myPartialOccupatorMutex.unlock();
     820              :         // draw parking vehicles
     821     18232183 :         for (const MSBaseVehicle* const v : myParkingVehicles) {
     822        33482 :             dynamic_cast<const GUIBaseVehicle*>(v)->drawGL(s);
     823              :         }
     824              :         // allow lane simulation
     825     18198701 :         releaseVehicles();
     826              :     }
     827     48440284 :     GLHelper::popName();
     828     48440284 : }
     829              : 
     830              : bool
     831        33383 : GUILane::neighLaneNotBidi() const {
     832        33383 :     const MSLane* right = getParallelLane(-1, false);
     833        33383 :     if (right && right->getBidiLane() == nullptr) {
     834              :         return true;
     835              :     }
     836        11922 :     const MSLane* left = getParallelLane(1, false);
     837        11922 :     if (left && left->getBidiLane() == nullptr) {
     838              :         return true;
     839              :     }
     840              :     return false;
     841              : }
     842              : 
     843              : void
     844       430363 : GUILane::drawMarkings(const GUIVisualizationSettings& s, double scale) const {
     845       430363 :     GLHelper::pushMatrix();
     846       430363 :     glTranslated(0, 0, GLO_EDGE);
     847       430363 :     setColor(s);
     848              :     // optionally draw inverse markings
     849       430363 :     const bool s2 = s.secondaryShape;
     850       430363 :     if (myIndex > 0 && (myEdge->getLanes()[myIndex - 1]->getPermissions() & myPermissions) != 0) {
     851              :         const bool cl = myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER);
     852              :         const bool cr = allowsChangingRight(SVC_PASSENGER);
     853       128691 :         GLHelper::drawInverseMarkings(getShape(s2), getShapeRotations(s2), getShapeLengths(s2), 3, 6, myHalfLaneWidth, cl, cr, MSGlobals::gLefthand, scale);
     854              :     }
     855              :     // draw white boundings and white markings
     856       430363 :     glColor3d(1, 1, 1);
     857       860726 :     GLHelper::drawBoxLines(
     858       430363 :         getShape(s2),
     859              :         getShapeRotations(s2),
     860              :         getShapeLengths(s2),
     861       430363 :         (myHalfLaneWidth + SUMO_const_laneMarkWidth) * scale);
     862       430363 :     GLHelper::popMatrix();
     863       430363 : }
     864              : 
     865              : 
     866              : void
     867          928 : GUILane::drawBikeMarkings() const {
     868              :     // draw bike lane markings onto the intersection
     869          928 :     glColor3d(1, 1, 1);
     870              :     /// fixme
     871              :     const bool s2 = false;
     872          928 :     const int e = (int) getShape(s2).size() - 1;
     873              :     const double markWidth = 0.1;
     874          928 :     const double mw = myHalfLaneWidth;
     875         2972 :     for (int i = 0; i < e; ++i) {
     876         2044 :         GLHelper::pushMatrix();
     877         2044 :         glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), GLO_JUNCTION + 0.4);
     878         2044 :         glRotated(getShapeRotations(s2)[i], 0, 0, 1);
     879        16994 :         for (double t = 0; t < getShapeLengths(s2)[i]; t += 0.5) {
     880              :             // left and right marking
     881        44850 :             for (int side = -1; side <= 1; side += 2) {
     882        29900 :                 glBegin(GL_QUADS);
     883        29900 :                 glVertex2d(side * mw, -t);
     884        29900 :                 glVertex2d(side * mw, -t - 0.35);
     885        29900 :                 glVertex2d(side * (mw + markWidth), -t - 0.35);
     886        29900 :                 glVertex2d(side * (mw + markWidth), -t);
     887        29900 :                 glEnd();
     888              :             }
     889              :         }
     890         2044 :         GLHelper::popMatrix();
     891              :     }
     892          928 : }
     893              : 
     894              : 
     895              : void
     896           12 : GUILane::drawJunctionChangeProhibitions() const {
     897              :     // fixme
     898              :     const bool s2 = false;
     899              :     // draw white markings
     900           12 :     if (myIndex > 0 && (myEdge->getLanes()[myIndex - 1]->getPermissions() & myPermissions) != 0) {
     901           12 :         glColor3d(1, 1, 1);
     902           12 :         const bool cl = myEdge->getLanes()[myIndex - 1]->allowsChangingLeft(SVC_PASSENGER);
     903              :         const bool cr = allowsChangingRight(SVC_PASSENGER);
     904              :         // solid line marking
     905              :         double mw, mw2;
     906              :         // optional broken line marking
     907              :         double mw3, mw4;
     908           12 :         if (!cl && !cr) {
     909              :             // draw a single solid line
     910            4 :             mw = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.4;
     911            4 :             mw2 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.4;
     912              :             mw3 = myHalfLaneWidth;
     913              :             mw4 = myHalfLaneWidth;
     914              :         } else {
     915              :             // draw one solid and one broken line
     916            8 :             if (cl) {
     917            4 :                 mw = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.2;
     918            4 :                 mw2 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.6;
     919            4 :                 mw3 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.2;
     920            4 :                 mw4 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.6;
     921              :             } else {
     922            4 :                 mw = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.2;
     923            4 :                 mw2 = myHalfLaneWidth + SUMO_const_laneMarkWidth * 0.6;
     924            4 :                 mw3 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.2;
     925            4 :                 mw4 = myHalfLaneWidth - SUMO_const_laneMarkWidth * 0.6;
     926              :             }
     927              :         }
     928           12 :         if (MSGlobals::gLefthand) {
     929            0 :             mw *= -1;
     930            0 :             mw2 *= -1;
     931              :         }
     932           12 :         int e = (int) getShape(s2).size() - 1;
     933           24 :         for (int i = 0; i < e; ++i) {
     934           12 :             GLHelper::pushMatrix();
     935           12 :             glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), GLO_JUNCTION + 0.4);
     936           12 :             glRotated(getShapeRotations(s2)[i], 0, 0, 1);
     937          252 :             for (double t = 0; t < getShapeLengths(s2)[i]; t += 6) {
     938          240 :                 const double lengthSolid = MIN2(6.0, getShapeLengths(s2)[i] - t);
     939          240 :                 glBegin(GL_QUADS);
     940          240 :                 glVertex2d(-mw, -t);
     941          240 :                 glVertex2d(-mw, -t - lengthSolid);
     942          240 :                 glVertex2d(-mw2, -t - lengthSolid);
     943          240 :                 glVertex2d(-mw2, -t);
     944          240 :                 glEnd();
     945          240 :                 if (cl || cr) {
     946          160 :                     const double lengthBroken = MIN2(3.0, getShapeLengths(s2)[i] - t);
     947          160 :                     glBegin(GL_QUADS);
     948          160 :                     glVertex2d(-mw3, -t);
     949          160 :                     glVertex2d(-mw3, -t - lengthBroken);
     950          160 :                     glVertex2d(-mw4, -t - lengthBroken);
     951          160 :                     glVertex2d(-mw4, -t);
     952          160 :                     glEnd();
     953              :                 }
     954              :             }
     955           12 :             GLHelper::popMatrix();
     956              :         }
     957              :     }
     958           12 : }
     959              : 
     960              : void
     961            0 : GUILane::drawDirectionIndicators(double exaggeration, bool spreadSuperposed, bool s2) const {
     962            0 :     GLHelper::pushMatrix();
     963            0 :     glTranslated(0, 0, GLO_EDGE);
     964            0 :     int e = (int) getShape(s2).size() - 1;
     965            0 :     const double widthFactor = spreadSuperposed ? 0.4 : 1;
     966            0 :     const double w = MAX2(POSITION_EPS, myWidth * widthFactor);
     967            0 :     const double w2 = MAX2(POSITION_EPS, myHalfLaneWidth * widthFactor);
     968            0 :     const double w4 = MAX2(POSITION_EPS, myQuarterLaneWidth * widthFactor);
     969            0 :     const double sideOffset = spreadSuperposed ? w * -0.5 : 0;
     970            0 :     for (int i = 0; i < e; ++i) {
     971            0 :         GLHelper::pushMatrix();
     972            0 :         glTranslated(getShape(s2)[i].x(), getShape(s2)[i].y(), 0.1);
     973            0 :         glRotated(getShapeRotations(s2)[i], 0, 0, 1);
     974            0 :         for (double t = 0; t < getShapeLengths(s2)[i]; t += w) {
     975            0 :             const double length = MIN2(w2, getShapeLengths(s2)[i] - t) * exaggeration;
     976            0 :             glBegin(GL_TRIANGLES);
     977            0 :             glVertex2d(sideOffset, -t - length);
     978            0 :             glVertex2d(sideOffset - w4 * exaggeration, -t);
     979            0 :             glVertex2d(sideOffset + w4 * exaggeration, -t);
     980            0 :             glEnd();
     981              :         }
     982            0 :         GLHelper::popMatrix();
     983              :     }
     984            0 :     GLHelper::popMatrix();
     985            0 : }
     986              : 
     987              : 
     988              : void
     989            0 : GUILane::debugDrawFoeIntersections() const {
     990            0 :     GLHelper::pushMatrix();
     991            0 :     glTranslated(0, 0, 5);
     992            0 :     glColor3d(1.0, 0.3, 0.3);
     993              :     const double orthoLength = 0.5;
     994            0 :     const MSLink* link = getLinkCont().front();
     995              :     const std::vector<const MSLane*>& foeLanes = link->getFoeLanes();
     996              :     const auto& conflicts = link->getConflicts();
     997            0 :     if (foeLanes.size() == conflicts.size()) {
     998            0 :         for (int i = 0; i < (int)foeLanes.size(); ++i) {
     999            0 :             const MSLane* l = foeLanes[i];
    1000            0 :             Position pos = l->geometryPositionAtOffset(l->getLength() - conflicts[i].lengthBehindCrossing);
    1001            0 :             PositionVector ortho = l->getShape().getOrthogonal(pos, 10, true, orthoLength);
    1002            0 :             if (ortho.length() < orthoLength) {
    1003            0 :                 ortho.extrapolate(orthoLength - ortho.length(), false, true);
    1004              :             }
    1005            0 :             GLHelper::drawLine(ortho);
    1006              :             //std::cout << "foe=" << l->getID() << " lanePos=" << l->getLength() - conflicts[i].lengthBehindCrossing << " pos=" << pos << "\n";
    1007            0 :         }
    1008              :     }
    1009            0 :     GLHelper::popMatrix();
    1010            0 : }
    1011              : 
    1012              : 
    1013              : // ------ inherited from GUIGlObject
    1014              : GUIGLObjectPopupMenu*
    1015            0 : GUILane::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
    1016            0 :     GUIGLObjectPopupMenu* ret = new GUIGLObjectPopupMenu(app, parent, this);
    1017            0 :     buildPopupHeader(ret, app);
    1018            0 :     buildCenterPopupEntry(ret);
    1019              :     //
    1020            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Copy edge name to clipboard"), nullptr, ret, MID_COPY_EDGE_NAME);
    1021            0 :     buildNameCopyPopupEntry(ret);
    1022            0 :     buildSelectionPopupEntry(ret);
    1023              :     //
    1024            0 :     buildShowParamsPopupEntry(ret, false);
    1025            0 :     const PositionVector& baseShape = getShape(parent.getVisualisationSettings().secondaryShape);
    1026            0 :     const double pos = interpolateGeometryPosToLanePos(baseShape.nearest_offset_to_point25D(parent.getPositionInformation()));
    1027            0 :     const double height = baseShape.positionAtOffset(pos).z();
    1028            0 :     GUIDesigns::buildFXMenuCommand(ret, (TL("pos: ") + toString(pos) + " " + TL("height: ") + toString(height)).c_str(), nullptr, nullptr, 0);
    1029            0 :     if (getEdge().hasDistance()) {
    1030            0 :         GUIDesigns::buildFXMenuCommand(ret, ("distance: " + toString(getEdge().getDistanceAt(pos))).c_str(), nullptr, nullptr, 0);
    1031              :     }
    1032            0 :     new FXMenuSeparator(ret);
    1033            0 :     buildPositionCopyEntry(ret, app);
    1034            0 :     new FXMenuSeparator(ret);
    1035            0 :     if (myAmClosed) {
    1036            0 :         if (myPermissionChanges.empty()) {
    1037            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen lane"), nullptr, &parent, MID_CLOSE_LANE);
    1038            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen edge"), nullptr, &parent, MID_CLOSE_EDGE);
    1039              :         } else {
    1040            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen lane (override rerouter)"), nullptr, &parent, MID_CLOSE_LANE);
    1041            0 :             GUIDesigns::buildFXMenuCommand(ret, TL("Reopen edge (override rerouter)"), nullptr, &parent, MID_CLOSE_EDGE);
    1042              :         }
    1043              :     } else {
    1044            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Close lane"), nullptr, &parent, MID_CLOSE_LANE);
    1045            0 :         GUIDesigns::buildFXMenuCommand(ret, TL("Close edge"), nullptr, &parent, MID_CLOSE_EDGE);
    1046              :     }
    1047            0 :     GUIDesigns::buildFXMenuCommand(ret, TL("Add rerouter"), nullptr, &parent, MID_ADD_REROUTER);
    1048            0 :     new FXMenuSeparator(ret);
    1049              :     // reachability menu
    1050            0 :     FXMenuPane* reachableByClass = new FXMenuPane(ret);
    1051            0 :     ret->insertMenuPaneChild(reachableByClass);
    1052            0 :     new FXMenuCascade(ret, TL("Select reachable"), GUIIconSubSys::getIcon(GUIIcon::FLAG), reachableByClass);
    1053            0 :     for (auto i : SumoVehicleClassStrings.getStrings()) {
    1054            0 :         GUIDesigns::buildFXMenuCommand(reachableByClass, i.c_str(), VClassIcons::getVClassIcon(SumoVehicleClassStrings.get(i)), &parent, MID_REACHABILITY);
    1055            0 :     }
    1056            0 :     return ret;
    1057              : }
    1058              : 
    1059              : 
    1060              : GUIParameterTableWindow*
    1061            0 : GUILane::getParameterWindow(GUIMainWindow& app, GUISUMOAbstractView& view) {
    1062            0 :     myCachedGUISettings = view.editVisualisationSettings();
    1063            0 :     GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
    1064              :     // add items
    1065            0 :     ret->mkItem(TL("allowed speed [m/s]"), false, getSpeedLimit());
    1066            0 :     const std::map<SUMOVehicleClass, double>* restrictions = MSNet::getInstance()->getRestrictions(myEdge->getEdgeType());
    1067            0 :     if (restrictions != nullptr) {
    1068            0 :         for (const auto& elem : *restrictions) {
    1069            0 :             ret->mkItem((std::string("   ") + TL("allowed speed [m/s]") + std::string(": ") + toString(elem.first)).c_str(), false, elem.second);
    1070              :         }
    1071              :     }
    1072            0 :     ret->mkItem(TL("length [m]"), false, myLength);
    1073            0 :     ret->mkItem(TL("width [m]"), false, myWidth);
    1074            0 :     ret->mkItem(TL("street name"), false, myEdge->getStreetName());
    1075            0 :     ret->mkItem(TL("stored travel time [s]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getStoredEdgeTravelTime));
    1076            0 :     ret->mkItem(TL("loaded weight"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getLoadedEdgeWeight));
    1077            0 :     ret->mkItem(TL("routing speed [m/s]"), true, new FunctionBinding<MSEdge, double>(myEdge, &MSEdge::getRoutingSpeed));
    1078            0 :     ret->mkItem(TL("lane friction coefficient [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getFrictionCoefficient));
    1079            0 :     ret->mkItem(TL("time penalty [s]"), true, new FunctionBinding<MSEdge, double>(myEdge, &MSEdge::getTimePenalty));
    1080            0 :     ret->mkItem(TL("brutto occupancy [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getBruttoOccupancy, 100.));
    1081            0 :     ret->mkItem(TL("netto occupancy [%]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getNettoOccupancy, 100.));
    1082            0 :     ret->mkItem(TL("pending insertions [#]"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getPendingEmits));
    1083            0 :     ret->mkItem(TL("edge type"), false, myEdge->getEdgeType());
    1084            0 :     ret->mkItem(TL("routing type"), false, myEdge->getRoutingType());
    1085            0 :     ret->mkItem(TL("type"), false, myLaneType);
    1086            0 :     ret->mkItem(TL("priority"), false, myEdge->getPriority());
    1087            0 :     ret->mkItem(TL("distance [km]"), false, myEdge->getDistance() / 1000);
    1088            0 :     ret->mkItem(TL("allowed vehicle class"), false, StringUtils::wrapText(getVehicleClassNames(myPermissions), 60));
    1089            0 :     ret->mkItem(TL("disallowed vehicle class"), false, StringUtils::wrapText(getVehicleClassNames(~myPermissions), 60));
    1090            0 :     ret->mkItem(TL("permission code"), false, myPermissions);
    1091            0 :     ret->mkItem(TL("color value"), true, new FunctionBinding<GUILane, double>(this, &GUILane::getColorValueForTracker));
    1092            0 :     if (myBidiLane != nullptr) {
    1093            0 :         ret->mkItem(TL("bidi-lane"), false, myBidiLane->getID());
    1094              :     }
    1095              :     // info for blocked departDriveWay
    1096            0 :     for (auto item : getParametersMap()) {
    1097            0 :         if (StringUtils::startsWith(item.first, "insertionBlocked:")) {
    1098            0 :             const MSDriveWay* dw = MSDriveWay::retrieveDepartDriveWay(myEdge, item.second);
    1099            0 :             if (dw != nullptr) {
    1100            0 :                 ret->mkItem(("blocking " + dw->getID()).c_str(), false, toString(MSRailSignal::getBlockingVehicles(dw)));
    1101            0 :                 ret->mkItem(("driveWays blocking " + dw->getID()).c_str(), false, toString(MSRailSignal::getBlockingDriveWays(dw)));
    1102              :             }
    1103              :         }
    1104              :     }
    1105              : 
    1106            0 :     for (const auto& kv : myEdge->getParametersMap()) {
    1107            0 :         ret->mkItem(("edgeParam:" + kv.first).c_str(), false, kv.second);
    1108              :     }
    1109            0 :     ret->checkFont(myEdge->getStreetName());
    1110            0 :     ret->closeBuilding();
    1111            0 :     return ret;
    1112              : }
    1113              : 
    1114              : 
    1115              : Boundary
    1116            0 : GUILane::getCenteringBoundary() const {
    1117            0 :     const PositionVector& shape = GUIGlobals::gSecondaryShape && myShape2.size() > 0 ? myShape2 : myShape;
    1118            0 :     Boundary b;
    1119            0 :     b.add(shape[0]);
    1120            0 :     b.add(shape[-1]);
    1121            0 :     b.grow(RENDERING_BUFFER);
    1122              :     // ensure that vehicles and persons on the side are drawn even if the edge
    1123              :     // is outside the view
    1124            0 :     return b;
    1125              : }
    1126              : 
    1127              : 
    1128              : const PositionVector&
    1129    101825332 : GUILane::getShape(bool secondary) const {
    1130    101825332 :     return secondary && myShape2.size() > 0 ? myShape2 : myShape;
    1131              : }
    1132              : 
    1133              : 
    1134              : const std::vector<double>&
    1135     18861923 : GUILane::getShapeRotations(bool secondary) const {
    1136     18861923 :     return secondary && myShapeRotations2.size() > 0 ? myShapeRotations2 : myShapeRotations;
    1137              : }
    1138              : 
    1139              : 
    1140              : const std::vector<double>&
    1141     18804321 : GUILane::getShapeLengths(bool secondary) const {
    1142     18804321 :     return secondary && myShapeLengths2.size() > 0 ? myShapeLengths2 : myShapeLengths;
    1143              : }
    1144              : 
    1145              : 
    1146              : std::vector<RGBColor>&
    1147     97287465 : GUILane::getShapeColors(bool secondary) const {
    1148     97287465 :     return secondary && myShapeColors2.size() > 0 ? myShapeColors2 : myShapeColors;
    1149              : }
    1150              : 
    1151              : 
    1152              : double
    1153            0 : GUILane::firstWaitingTime() const {
    1154            0 :     return myVehicles.size() == 0 ? 0 : myVehicles.back()->getWaitingSeconds();
    1155              : }
    1156              : 
    1157              : 
    1158              : double
    1159            0 : GUILane::getEdgeLaneNumber() const {
    1160            0 :     return (double) myEdge->getLanes().size();
    1161              : }
    1162              : 
    1163              : 
    1164              : double
    1165            0 : GUILane::getStoredEdgeTravelTime() const {
    1166            0 :     MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1167            0 :     if (!ews.knowsTravelTime(myEdge)) {
    1168              :         return -1;
    1169              :     } else {
    1170            0 :         double value(0);
    1171            0 :         ews.retrieveExistingTravelTime(myEdge, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()), value);
    1172            0 :         return value;
    1173              :     }
    1174              : }
    1175              : 
    1176              : 
    1177              : double
    1178            0 : GUILane::getLoadedEdgeWeight() const {
    1179            0 :     MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1180            0 :     if (!ews.knowsEffort(myEdge)) {
    1181              :         return -1;
    1182              :     } else {
    1183            0 :         double value(-1);
    1184            0 :         ews.retrieveExistingEffort(myEdge, STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()), value);
    1185            0 :         return value;
    1186              :     }
    1187              : }
    1188              : 
    1189              : 
    1190              : double
    1191            0 : GUILane::getColorValueWithFunctional(const GUIVisualizationSettings& s, int activeScheme) const {
    1192            0 :     switch (activeScheme) {
    1193            0 :         case 18: {
    1194            0 :             return GeomHelper::naviDegree(getShape(s.secondaryShape).beginEndAngle()); // [0-360]
    1195              :         }
    1196            0 :         default:
    1197            0 :             return getColorValue(s, activeScheme);
    1198              :     }
    1199              : 
    1200              : }
    1201              : 
    1202              : 
    1203              : RGBColor
    1204     49128580 : GUILane::setColor(const GUIVisualizationSettings& s) const {
    1205              :     // setting and retrieving the color does not work in OSGView so we return it explicitliy
    1206     49128580 :     RGBColor col;
    1207     49128580 :     if (MSGlobals::gUseMesoSim && static_cast<const GUIEdge*>(myEdge)->getMesoColor() != MESO_USE_LANE_COLOR) {
    1208         8699 :         col = static_cast<const GUIEdge*>(myEdge)->getMesoColor();
    1209              :     } else {
    1210     49119881 :         const GUIColorer& c = s.laneColorer;
    1211     49119881 :         if (!setFunctionalColor(c, col) && !setMultiColor(s, c, col)) {
    1212     48959445 :             col = c.getScheme().getColor(getColorValue(s, c.getActive()));
    1213              :         }
    1214              :     }
    1215     49128580 :     GLHelper::setColor(col);
    1216     49128580 :     return col;
    1217              : }
    1218              : 
    1219              : 
    1220              : bool
    1221     54204157 : GUILane::setFunctionalColor(const GUIColorer& c, RGBColor& col, int activeScheme) const {
    1222     54204157 :     if (activeScheme < 0) {
    1223              :         activeScheme = c.getActive();
    1224              :     }
    1225     54204157 :     switch (activeScheme) {
    1226     54194777 :         case 0:
    1227     54194777 :             if (myEdge->isCrossing()) {
    1228              :                 // determine priority to decide color
    1229       169135 :                 const MSLink* const link = getLogicalPredecessorLane()->getLinkTo(this);
    1230       169135 :                 if (link->havePriority() || link->getTLLogic() != nullptr) {
    1231        75996 :                     col = RGBColor(230, 230, 230);
    1232              :                 } else {
    1233        93139 :                     col = RGBColor(26, 26, 26);
    1234              :                 }
    1235       169135 :                 GLHelper::setColor(col);
    1236       169135 :                 return true;
    1237              :             } else {
    1238              :                 return false;
    1239              :             }
    1240            0 :         case 18: {
    1241            0 :             double hue = GeomHelper::naviDegree(myShape.beginEndAngle()); // [0-360]
    1242            0 :             col = RGBColor::fromHSV(hue, 1., 1.);
    1243            0 :             GLHelper::setColor(col);
    1244            0 :             return true;
    1245              :         }
    1246              :         case 30: { // taz color
    1247            0 :             col = c.getScheme().getColor(0);
    1248              :             std::vector<RGBColor> tazColors;
    1249            0 :             for (MSEdge* e : myEdge->getPredecessors()) {
    1250            0 :                 if (e->isTazConnector() && e->hasParameter("tazColor")) {
    1251            0 :                     tazColors.push_back(RGBColor::parseColor(e->getParameter("tazColor")));
    1252              :                 }
    1253              :             }
    1254            0 :             for (MSEdge* e : myEdge->getSuccessors()) {
    1255            0 :                 if (e->isTazConnector() && e->hasParameter("tazColor")) {
    1256            0 :                     tazColors.push_back(RGBColor::parseColor(e->getParameter("tazColor")));
    1257              :                 }
    1258              :             }
    1259            0 :             if (tazColors.size() > 0) {
    1260            0 :                 int randColor = RandHelper::rand((int)tazColors.size(), RGBColor::getColorRNG());
    1261            0 :                 col = tazColors[randColor];
    1262              :             }
    1263            0 :             GLHelper::setColor(col);
    1264              :             return true;
    1265            0 :         }
    1266              :         default:
    1267              :             return false;
    1268              :     }
    1269              : }
    1270              : 
    1271              : 
    1272              : bool
    1273     48959445 : GUILane::setMultiColor(const GUIVisualizationSettings& s, const GUIColorer& c, RGBColor& col) const {
    1274              :     const int activeScheme = c.getActive();
    1275     48959445 :     auto& shapeColors = getShapeColors(s.secondaryShape);
    1276     48959445 :     const PositionVector& shape = getShape(s.secondaryShape);
    1277              :     shapeColors.clear();
    1278     48959445 :     switch (activeScheme) {
    1279            0 :         case 22: // color by height at segment start
    1280            0 :             for (PositionVector::const_iterator ii = shape.begin(); ii != shape.end() - 1; ++ii) {
    1281            0 :                 shapeColors.push_back(c.getScheme().getColor(ii->z()));
    1282              :             }
    1283              :             // osg fallback (edge height at start)
    1284            0 :             col = c.getScheme().getColor(getColorValue(s, 21));
    1285            0 :             return true;
    1286              :         case 24: // color by inclination  at segment start
    1287            0 :             for (int ii = 1; ii < (int)shape.size(); ++ii) {
    1288            0 :                 const double inc = (shape[ii].z() - shape[ii - 1].z()) / MAX2(POSITION_EPS, shape[ii].distanceTo2D(shape[ii - 1]));
    1289            0 :                 shapeColors.push_back(c.getScheme().getColor(inc));
    1290              :             }
    1291            0 :             col = c.getScheme().getColor(getColorValue(s, 23));
    1292            0 :             return true;
    1293              :         default:
    1294              :             return false;
    1295              :     }
    1296              : }
    1297              : 
    1298              : double
    1299            0 : GUILane::getColorValueForTracker() const {
    1300            0 :     if (myCachedGUISettings != nullptr) {
    1301              :         const GUIVisualizationSettings& s = *myCachedGUISettings;
    1302              :         const GUIColorer& c = s.laneColorer;
    1303            0 :         double val = getColorValueWithFunctional(s, c.getActive());
    1304            0 :         if (val == GUIVisualizationSettings::MISSING_DATA) {
    1305              :             // blowing up the dialog or plot isn't helpful. At least 0 may be understood as neutral
    1306              :             return 0;
    1307              :         } else {
    1308              :             return val;
    1309              :         }
    1310              :     } else {
    1311              :         return 0;
    1312              :     }
    1313              : }
    1314              : 
    1315              : 
    1316              : double
    1317     48959445 : GUILane::getColorValue(const GUIVisualizationSettings& s, int activeScheme) const {
    1318     48959445 :     switch (activeScheme) {
    1319     48950065 :         case 0:
    1320     48950065 :             switch (myPermissions) {
    1321              :                 case SVC_PEDESTRIAN:
    1322              :                     return 1;
    1323              :                 case SVC_BICYCLE:
    1324              :                     return 2;
    1325       115383 :                 case 0:
    1326              :                     // forbidden road or green verge
    1327       115383 :                     return myEdge->getPermissions() == 0 ? 10 : 3;
    1328          712 :                 case SVC_SHIP:
    1329          712 :                     return 4;
    1330         2670 :                 case SVC_AUTHORITY:
    1331         2670 :                     return 8;
    1332            0 :                 case SVC_AIRCRAFT:
    1333              :                 case SVC_DRONE:
    1334            0 :                     return 11;
    1335              :                 default:
    1336              :                     break;
    1337              :             }
    1338     47620057 :             if (myEdge->isTazConnector()) {
    1339              :                 return 9;
    1340     47620057 :             } else if (isRailway(myPermissions)) {
    1341              :                 return 5;
    1342     47275209 :             } else if ((myPermissions & SVC_PASSENGER) != 0) {
    1343     47170122 :                 if ((myPermissions & (SVC_RAIL_CLASSES & ~SVC_RAIL_FAST)) != 0 && (myPermissions & SVC_SHIP) == 0) {
    1344              :                     return 6;
    1345              :                 } else {
    1346              :                     return 0;
    1347              :                 }
    1348              :             } else {
    1349       105087 :                 if ((myPermissions & SVC_RAIL_CLASSES) != 0 && (myPermissions & SVC_SHIP) == 0) {
    1350              :                     return 6;
    1351              :                 } else {
    1352       104771 :                     return 7;
    1353              :                 }
    1354              :             }
    1355         9380 :         case 1:
    1356         9380 :             return isLaneOrEdgeSelected();
    1357            0 :         case 2:
    1358            0 :             return (double)myPermissions;
    1359            0 :         case 3:
    1360            0 :             return getSpeedLimit();
    1361            0 :         case 4:
    1362            0 :             return getBruttoOccupancy();
    1363            0 :         case 5:
    1364            0 :             return getNettoOccupancy();
    1365            0 :         case 6:
    1366            0 :             return firstWaitingTime();
    1367            0 :         case 7:
    1368            0 :             return getEdgeLaneNumber();
    1369            0 :         case 8:
    1370            0 :             return getEmissions<PollutantsInterface::CO2>() / myLength;
    1371            0 :         case 9:
    1372            0 :             return getEmissions<PollutantsInterface::CO>() / myLength;
    1373            0 :         case 10:
    1374            0 :             return getEmissions<PollutantsInterface::PM_X>() / myLength;
    1375            0 :         case 11:
    1376            0 :             return getEmissions<PollutantsInterface::NO_X>() / myLength;
    1377            0 :         case 12:
    1378            0 :             return getEmissions<PollutantsInterface::HC>() / myLength;
    1379            0 :         case 13:
    1380            0 :             return getEmissions<PollutantsInterface::FUEL>() / myLength;
    1381            0 :         case 14:
    1382            0 :             return getHarmonoise_NoiseEmissions();
    1383            0 :         case 15: {
    1384            0 :             return getStoredEdgeTravelTime();
    1385              :         }
    1386            0 :         case 16: {
    1387            0 :             MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1388            0 :             if (!ews.knowsTravelTime(myEdge)) {
    1389              :                 return -1;
    1390              :             } else {
    1391            0 :                 double value(0);
    1392            0 :                 ews.retrieveExistingTravelTime(myEdge, 0, value);
    1393            0 :                 return 100 * myLength / value / getSpeedLimit();
    1394              :             }
    1395              :         }
    1396            0 :         case 17: {
    1397              :             // geometrical length has no meaning for walkingAreas since it describes the outer boundary
    1398            0 :             return myEdge->isWalkingArea() ? 1 :  1 / getLengthGeometryFactor(s.secondaryShape);
    1399              :         }
    1400            0 :         case 19: {
    1401            0 :             return getLoadedEdgeWeight();
    1402              :         }
    1403            0 :         case 20: {
    1404            0 :             return myEdge->getPriority();
    1405              :         }
    1406            0 :         case 21: {
    1407              :             // color by z of first shape point
    1408            0 :             return getShape(s.secondaryShape)[0].z();
    1409              :         }
    1410            0 :         case 23: {
    1411              :             // color by incline
    1412            0 :             return (getShape(s.secondaryShape)[-1].z() - getShape(s.secondaryShape)[0].z()) / getLength();
    1413              :         }
    1414            0 :         case 25: {
    1415              :             // color by average speed
    1416            0 :             return getMeanSpeed();
    1417              :         }
    1418            0 :         case 26: {
    1419              :             // color by average relative speed
    1420            0 :             return getMeanSpeed() / myMaxSpeed;
    1421              :         }
    1422            0 :         case 27: {
    1423              :             // color by routing device assumed speed
    1424            0 :             return myEdge->getRoutingSpeed();
    1425              :         }
    1426            0 :         case 28:
    1427            0 :             return getEmissions<PollutantsInterface::ELEC>() / myLength;
    1428            0 :         case 29:
    1429            0 :             return getPendingEmits();
    1430            0 :         case 31: {
    1431              :             // by numerical edge param value
    1432            0 :             if (myEdge->hasParameter(s.edgeParam)) {
    1433              :                 try {
    1434            0 :                     return StringUtils::toDouble(myEdge->getParameter(s.edgeParam, "0"));
    1435            0 :                 } catch (NumberFormatException&) {
    1436              :                     try {
    1437            0 :                         return StringUtils::toBool(myEdge->getParameter(s.edgeParam, "0"));
    1438            0 :                     } catch (BoolFormatException&) {
    1439            0 :                         return GUIVisualizationSettings::MISSING_DATA;
    1440            0 :                     }
    1441            0 :                 }
    1442              :             } else {
    1443            0 :                 return GUIVisualizationSettings::MISSING_DATA;
    1444              :             }
    1445              :         }
    1446            0 :         case 32: {
    1447              :             // by numerical lane param value
    1448            0 :             if (hasParameter(s.laneParam)) {
    1449              :                 try {
    1450            0 :                     return StringUtils::toDouble(getParameter(s.laneParam, "0"));
    1451            0 :                 } catch (NumberFormatException&) {
    1452              :                     try {
    1453            0 :                         return StringUtils::toBool(getParameter(s.laneParam, "0"));
    1454            0 :                     } catch (BoolFormatException&) {
    1455            0 :                         return GUIVisualizationSettings::MISSING_DATA;
    1456            0 :                     }
    1457            0 :                 }
    1458              :             } else {
    1459            0 :                 return GUIVisualizationSettings::MISSING_DATA;
    1460              :             }
    1461              :         }
    1462            0 :         case 33: {
    1463              :             // by edge data value
    1464            0 :             return GUINet::getGUIInstance()->getEdgeData(myEdge, s.edgeData);
    1465              :         }
    1466            0 :         case 34: {
    1467            0 :             return myEdge->getDistance();
    1468              :         }
    1469            0 :         case 35: {
    1470            0 :             return fabs(myEdge->getDistance());
    1471              :         }
    1472            0 :         case 36: {
    1473            0 :             return myReachability;
    1474              :         }
    1475            0 :         case 37: {
    1476            0 :             return myRNGIndex % MSGlobals::gNumSimThreads;
    1477              :         }
    1478            0 :         case 38: {
    1479            0 :             if (myParkingAreas == nullptr) {
    1480              :                 // init
    1481            0 :                 myParkingAreas = new std::vector<MSParkingArea*>();
    1482            0 :                 for (auto& item : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_PARKING_AREA)) {
    1483            0 :                     if (&item.second->getLane().getEdge() == myEdge) {
    1484            0 :                         myParkingAreas->push_back(dynamic_cast<MSParkingArea*>(item.second));
    1485              :                     }
    1486              :                 }
    1487              :             }
    1488              :             int capacity = 0;
    1489            0 :             for (MSParkingArea* pa : *myParkingAreas) {
    1490            0 :                 capacity += pa->getCapacity() - pa->getOccupancy();
    1491              :             }
    1492            0 :             return capacity;
    1493              :         }
    1494            0 :         case 39: {
    1495              :             // by live edge data value
    1496            0 :             return GUINet::getGUIInstance()->getMeanData(this, s.edgeDataID, s.edgeData);
    1497              :         }
    1498              :     }
    1499              :     return 0;
    1500              : }
    1501              : 
    1502              : 
    1503              : double
    1504     41996261 : GUILane::getScaleValue(const GUIVisualizationSettings& s, int activeScheme, bool s2) const {
    1505     41996261 :     switch (activeScheme) {
    1506              :         case 0:
    1507              :             return 0;
    1508            0 :         case 1:
    1509            0 :             return isLaneOrEdgeSelected();
    1510            0 :         case 2:
    1511            0 :             return getSpeedLimit();
    1512            0 :         case 3:
    1513            0 :             return getBruttoOccupancy();
    1514            0 :         case 4:
    1515            0 :             return getNettoOccupancy();
    1516            0 :         case 5:
    1517            0 :             return firstWaitingTime();
    1518            0 :         case 6:
    1519            0 :             return getEdgeLaneNumber();
    1520            0 :         case 7:
    1521            0 :             return getEmissions<PollutantsInterface::CO2>() / myLength;
    1522            0 :         case 8:
    1523            0 :             return getEmissions<PollutantsInterface::CO>() / myLength;
    1524            0 :         case 9:
    1525            0 :             return getEmissions<PollutantsInterface::PM_X>() / myLength;
    1526            0 :         case 10:
    1527            0 :             return getEmissions<PollutantsInterface::NO_X>() / myLength;
    1528            0 :         case 11:
    1529            0 :             return getEmissions<PollutantsInterface::HC>() / myLength;
    1530            0 :         case 12:
    1531            0 :             return getEmissions<PollutantsInterface::FUEL>() / myLength;
    1532            0 :         case 13:
    1533            0 :             return getHarmonoise_NoiseEmissions();
    1534            0 :         case 14: {
    1535            0 :             return getStoredEdgeTravelTime();
    1536              :         }
    1537            0 :         case 15: {
    1538            0 :             MSEdgeWeightsStorage& ews = MSNet::getInstance()->getWeightsStorage();
    1539            0 :             if (!ews.knowsTravelTime(myEdge)) {
    1540              :                 return -1;
    1541              :             } else {
    1542            0 :                 double value(0);
    1543            0 :                 ews.retrieveExistingTravelTime(myEdge, 0, value);
    1544            0 :                 return 100 * myLength / value / getSpeedLimit();
    1545              :             }
    1546              :         }
    1547            0 :         case 16: {
    1548            0 :             return 1 / getLengthGeometryFactor(s2);
    1549              :         }
    1550            0 :         case 17: {
    1551            0 :             return getLoadedEdgeWeight();
    1552              :         }
    1553            0 :         case 18: {
    1554            0 :             return myEdge->getPriority();
    1555              :         }
    1556            0 :         case 19: {
    1557              :             // scale by average speed
    1558            0 :             return getMeanSpeed();
    1559              :         }
    1560            0 :         case 20: {
    1561              :             // scale by average relative speed
    1562            0 :             return getMeanSpeed() / myMaxSpeed;
    1563              :         }
    1564            0 :         case 21:
    1565            0 :             return getEmissions<PollutantsInterface::ELEC>() / myLength;
    1566            0 :         case 22:
    1567            0 :             return MSNet::getInstance()->getInsertionControl().getPendingEmits(this);
    1568            0 :         case 23:
    1569              :             // by edge data value
    1570            0 :             return GUINet::getGUIInstance()->getEdgeData(myEdge, s.edgeDataScaling);
    1571              :     }
    1572              :     return 0;
    1573              : }
    1574              : 
    1575              : 
    1576              : bool
    1577     18482616 : GUILane::drawAsRailway(const GUIVisualizationSettings& s) const {
    1578     18482616 :     return isRailway(myPermissions) && ((myPermissions & SVC_BUS) == 0) && s.showRails;
    1579              : }
    1580              : 
    1581              : 
    1582              : bool
    1583       885119 : GUILane::drawAsWaterway(const GUIVisualizationSettings& s) const {
    1584       885119 :     return isWaterway(myPermissions) && s.showRails; // reusing the showRails setting
    1585              : }
    1586              : 
    1587              : 
    1588              : #ifdef HAVE_OSG
    1589              : void
    1590       255508 : GUILane::updateColor(const GUIVisualizationSettings& s) {
    1591       255508 :     if (myGeom == 0) {
    1592              :         // not drawn
    1593            0 :         return;
    1594              :     }
    1595       255508 :     const RGBColor col = setColor(s);
    1596       255508 :     osg::Vec4ubArray* colors = dynamic_cast<osg::Vec4ubArray*>(myGeom->getColorArray());
    1597       255508 :     (*colors)[0].set(col.red(), col.green(), col.blue(), col.alpha());
    1598       255508 :     myGeom->setColorArray(colors);
    1599              : }
    1600              : #endif
    1601              : 
    1602              : 
    1603              : void
    1604            0 : GUILane::closeTraffic(bool rebuildAllowed) {
    1605            0 :     MSGlobals::gCheckRoutes = false;
    1606            0 :     if (myAmClosed) {
    1607              :         myPermissionChanges.clear(); // reset rerouters
    1608            0 :         resetPermissions(CHANGE_PERMISSIONS_GUI);
    1609              :     } else {
    1610            0 :         setPermissions(SVC_AUTHORITY, CHANGE_PERMISSIONS_GUI);
    1611              :     }
    1612            0 :     myAmClosed = !myAmClosed;
    1613            0 :     if (rebuildAllowed) {
    1614            0 :         getEdge().rebuildAllowedLanes();
    1615              :     }
    1616            0 : }
    1617              : 
    1618              : 
    1619              : PositionVector
    1620       162501 : GUILane::splitAtSegments(const PositionVector& shape) {
    1621              :     assert(MSGlobals::gUseMesoSim);
    1622       162501 :     const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdge().getEdgeType());
    1623       162501 :     int no = MELoop::numSegmentsFor(myLength, edgeType.edgeLength);
    1624       162501 :     const double slength = myLength / no;
    1625              :     PositionVector result = shape;
    1626              :     double offset = 0;
    1627       500249 :     for (int i = 0; i < no; ++i) {
    1628       337748 :         offset += slength;
    1629       337748 :         Position pos = shape.positionAtOffset(interpolateLanePosToGeometryPos(offset));
    1630       337748 :         int index = result.indexOfClosest(pos);
    1631       337748 :         if (pos.distanceTo(result[index]) > POSITION_EPS) {
    1632       175244 :             index = result.insertAtClosest(pos, false);
    1633              :         }
    1634       337748 :         if (i != no - 1) {
    1635       175247 :             mySegmentStartIndex.push_back(index);
    1636              :         }
    1637       846355 :         while ((int)myShapeSegments.size() < index) {
    1638       508607 :             myShapeSegments.push_back(i);
    1639              :         }
    1640              :         //std::cout << "splitAtSegments " << getID() << " no=" << no << " i=" << i << " offset=" << offset << " index=" << index << " segs=" << toString(myShapeSegments) << " resultSize=" << result.size() << " result=" << toString(result) << "\n";
    1641              :     }
    1642       327618 :     while (myShapeSegments.size() < result.size()) {
    1643       165117 :         myShapeSegments.push_back(no - 1);
    1644              :     }
    1645       162501 :     return result;
    1646            0 : }
    1647              : 
    1648              : bool
    1649     48746064 : GUILane::isSelected() const {
    1650     48746064 :     return gSelected.isSelected(GLO_LANE, getGlID());
    1651              : }
    1652              : 
    1653              : bool
    1654         9380 : GUILane::isLaneOrEdgeSelected() const {
    1655         9380 :     return isSelected() || gSelected.isSelected(GLO_EDGE, dynamic_cast<GUIEdge*>(myEdge)->getGlID());
    1656              : }
    1657              : 
    1658              : double
    1659            0 : GUILane::getPendingEmits() const {
    1660            0 :     return MSNet::getInstance()->getInsertionControl().getPendingEmits(this);
    1661              : }
    1662              : 
    1663              : double
    1664            0 : GUILane::getClickPriority() const {
    1665            0 :     if (MSGlobals::gUseMesoSim) {
    1666              :         // do not select lanes in meso mode
    1667            0 :         return INVALID_PRIORITY;
    1668              :     }
    1669            0 :     if (myEdge->isCrossing()) {
    1670            0 :         return GLO_CROSSING;
    1671              :     }
    1672              :     return GLO_LANE;
    1673              : }
    1674              : 
    1675              : 
    1676              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1