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

Generated by: LCOV version 2.0-1