LCOV - code coverage report
Current view: top level - src/guisim - GUILane.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 53.4 % 934 499
Test Date: 2025-11-14 15:59:05 Functions: 69.0 % 58 40

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

Generated by: LCOV version 2.0-1