LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSPModel_Striping.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 86.5 % 1310 1133
Test Date: 2024-11-20 15:55:46 Functions: 98.5 % 68 67

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2014-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    MSPModel_Striping.cpp
      15              : /// @author  Jakob Erdmann
      16              : /// @author  Michael Behrisch
      17              : /// @date    Mon, 13 Jan 2014
      18              : ///
      19              : // The pedestrian following model (prototype)
      20              : /****************************************************************************/
      21              : #include <config.h>
      22              : 
      23              : #include <cmath>
      24              : #include <algorithm>
      25              : #include <utils/common/RandHelper.h>
      26              : #include <utils/geom/GeomHelper.h>
      27              : #include <utils/options/OptionsCont.h>
      28              : #include <utils/router/PedestrianRouter.h>
      29              : #include <microsim/MSNet.h>
      30              : #include <microsim/MSEdge.h>
      31              : #include <microsim/MSEventControl.h>
      32              : #include <microsim/MSLane.h>
      33              : #include <microsim/MSLink.h>
      34              : #include <microsim/MSJunction.h>
      35              : #include <microsim/MSStoppingPlace.h>
      36              : #include <microsim/MSVehicleControl.h>
      37              : #include <microsim/MSGlobals.h>
      38              : #include <microsim/transportables/MSStage.h>
      39              : #include <microsim/transportables/MSTransportableControl.h>
      40              : #include "MSPModel_Striping.h"
      41              : 
      42              : 
      43              : // ===========================================================================
      44              : // DEBUGGING HELPERS
      45              : // ===========================================================================
      46              : //
      47              : #define DEBUGID1 ""
      48              : #define DEBUGID2 ""
      49              : //#define DEBUGCOND(PED) (false)
      50              : //#define DEBUGCOND(PED) ((PED).getPerson()->getID() == DEBUGID1 || (PED).getPerson()->getID() == DEBUGID2)
      51              : #define DEBUGCOND(PED) ((PED).getPerson()->isSelected())
      52              : #define DEBUGCOND2(LANE) ((LANE)->isSelected())
      53              : //#define LOG_ALL 1
      54              : //#define DEBUG_MOVETOXY
      55              : 
      56            0 : void MSPModel_Striping::DEBUG_PRINT(const Obstacles& obs) {
      57            0 :     for (int i = 0; i < (int)obs.size(); ++i) {
      58              :         std::cout
      59            0 :                 << "(" << obs[i].description
      60            0 :                 << " x=(" << obs[i].xBack << "," << obs[i].xFwd
      61            0 :                 << ") s=" << obs[i].speed
      62            0 :                 << ")   ";
      63              :     }
      64            0 :     std::cout << "\n";
      65            0 : }
      66              : 
      67              : // ===========================================================================
      68              : // named (internal) constants
      69              : // ===========================================================================
      70              : 
      71              : // distances are comparable with lower values being "more important"
      72              : const double MSPModel_Striping::DIST_FAR_AWAY(10000);
      73              : const double MSPModel_Striping::DIST_BEHIND(1000);
      74              : const double MSPModel_Striping::DIST_OVERLAP(-1);
      75              : 
      76              : // ===========================================================================
      77              : // static members
      78              : // ===========================================================================
      79              : 
      80              : MSPModel_Striping::WalkingAreaPaths MSPModel_Striping::myWalkingAreaPaths;
      81              : std::map<const MSEdge*, std::vector<const MSLane*> >  MSPModel_Striping::myWalkingAreaFoes;
      82              : MSPModel_Striping::MinNextLengths MSPModel_Striping::myMinNextLengths;
      83              : 
      84              : // model parameters (static to simplify access from class PState
      85              : double MSPModel_Striping::stripeWidth;
      86              : double MSPModel_Striping::dawdling;
      87              : double MSPModel_Striping::minGapToVehicle;
      88              : int MSPModel_Striping::myWalkingAreaDetail;
      89              : SUMOTime MSPModel_Striping::jamTime;
      90              : SUMOTime MSPModel_Striping::jamTimeCrossing;
      91              : SUMOTime MSPModel_Striping::jamTimeNarrow;
      92              : double MSPModel_Striping::jamFactor;
      93              : bool MSPModel_Striping::myLegacyPosLat;
      94              : const double MSPModel_Striping::LOOKAHEAD_SAMEDIR(4.0); // seconds
      95              : const double MSPModel_Striping::LOOKAHEAD_ONCOMING(10.0); // seconds
      96              : const double MSPModel_Striping::LOOKAHEAD_ONCOMING_DIST(10.0); // m
      97              : const double MSPModel_Striping::LOOKAROUND_VEHICLES(60.0); // meters
      98              : const double MSPModel_Striping::LATERAL_PENALTY(-1.); // meters
      99              : const double MSPModel_Striping::OBSTRUCTED_PENALTY(-300000.); // meters
     100              : const double MSPModel_Striping::INAPPROPRIATE_PENALTY(-20000.); // meters
     101              : const double MSPModel_Striping::ONCOMING_CONFLICT_PENALTY(-1000.); // meters
     102              : const double MSPModel_Striping::OBSTRUCTION_THRESHOLD(MSPModel_Striping::OBSTRUCTED_PENALTY * 0.5); // despite obstruction, additional utility may have been added
     103              : const double MSPModel_Striping::SQUEEZE(0.7);
     104              : double MSPModel_Striping::RESERVE_FOR_ONCOMING_FACTOR;
     105              : double MSPModel_Striping::RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS;
     106              : double MSPModel_Striping::RESERVE_FOR_ONCOMING_MAX;
     107              : const double MSPModel_Striping::MAX_WAIT_TOLERANCE(120.); // seconds
     108              : const double MSPModel_Striping::LATERAL_SPEED_FACTOR(0.4);
     109              : const double MSPModel_Striping::MIN_STARTUP_DIST(0.4); // meters
     110              : 
     111              : 
     112              : // ===========================================================================
     113              : // MSPModel_Striping method definitions
     114              : // ===========================================================================
     115              : 
     116         5111 : MSPModel_Striping::MSPModel_Striping(const OptionsCont& oc, MSNet* net) {
     117         5111 :     myWalkingAreaDetail = oc.getInt("pedestrian.striping.walkingarea-detail");
     118         5111 :     initWalkingAreaPaths(net);
     119              :     // configurable parameters
     120         5111 :     stripeWidth = oc.getFloat("pedestrian.striping.stripe-width");
     121         5111 :     MSVehicleType* defaultPedType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
     122         5111 :     if (defaultPedType != nullptr && defaultPedType->getWidth() > stripeWidth) {
     123           12 :         WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."),
     124              :                        DEFAULT_PEDTYPE_ID, defaultPedType->getWidth());
     125              :     }
     126              : 
     127         5111 :     dawdling = oc.getFloat("pedestrian.striping.dawdling");
     128         5111 :     minGapToVehicle = oc.getFloat("pedestrian.striping.mingap-to-vehicle");
     129         5111 :     RESERVE_FOR_ONCOMING_FACTOR = oc.getFloat("pedestrian.striping.reserve-oncoming");
     130         5111 :     RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS = oc.getFloat("pedestrian.striping.reserve-oncoming.junctions");
     131         5111 :     RESERVE_FOR_ONCOMING_MAX = oc.getFloat("pedestrian.striping.reserve-oncoming.max");
     132              : 
     133         5111 :     jamTime = string2time(oc.getString("pedestrian.striping.jamtime"));
     134         5111 :     if (jamTime <= 0) {
     135            4 :         jamTime = SUMOTime_MAX;
     136              :     }
     137         5111 :     jamTimeCrossing = string2time(oc.getString("pedestrian.striping.jamtime.crossing"));
     138         5111 :     if (jamTimeCrossing <= 0) {
     139            0 :         jamTimeCrossing = SUMOTime_MAX;
     140              :     }
     141         5111 :     jamTimeNarrow = string2time(oc.getString("pedestrian.striping.jamtime.narrow"));
     142         5111 :     if (jamTimeNarrow <= 0) {
     143            0 :         jamTimeNarrow = SUMOTime_MAX;
     144              :     }
     145         5111 :     jamFactor = oc.getFloat("pedestrian.striping.jamfactor");
     146         5111 :     myLegacyPosLat = oc.getBool("pedestrian.striping.legacy-departposlat");
     147         5111 : }
     148              : 
     149              : 
     150        10210 : MSPModel_Striping::~MSPModel_Striping() {
     151              :     myWalkingAreaPaths.clear(); // need to recompute when lane pointers change
     152              :     myWalkingAreaFoes.clear();
     153              :     myMinNextLengths.clear();
     154        10210 : }
     155              : 
     156              : 
     157              : MSTransportableStateAdapter*
     158       215151 : MSPModel_Striping::add(MSTransportable* transportable, MSStageMoving* stage, SUMOTime) {
     159       215151 :     if (!transportable->isPerson()) {
     160              :         // containers are not supported (TODO add a warning here?)
     161              :         return nullptr;
     162              :     }
     163              :     MSPerson* person = static_cast<MSPerson*>(transportable);
     164       215151 :     MSNet* net = MSNet::getInstance();
     165       215151 :     if (!myAmActive) {
     166         3829 :         net->getBeginOfTimestepEvents()->addEvent(new MovePedestrians(this), net->getCurrentTimeStep() + DELTA_T);
     167         3829 :         myAmActive = true;
     168              :     }
     169              :     assert(person->getCurrentStageType() == MSStageType::WALKING);
     170       215151 :     const MSLane* lane = stage->checkDepartLane(person->getEdge(), person->getVClass(), stage->getDepartLane(), person->getID());
     171       215151 :     if (lane == nullptr) {
     172            8 :         const char* error = TL("Person '%' could not find sidewalk on edge '%', time=%.");
     173           16 :         if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
     174           24 :             WRITE_WARNINGF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep()));
     175            8 :             return nullptr;
     176              :         } else {
     177            0 :             throw ProcessError(TLF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep())));
     178              :         }
     179              :     }
     180       215143 :     PState* ped = new PState(person, stage, lane);
     181       215139 :     myActiveLanes[lane].push_back(ped);
     182       215139 :     myNumActivePedestrians++;
     183       215139 :     return ped;
     184              : }
     185              : 
     186              : 
     187              : MSTransportableStateAdapter*
     188           14 : MSPModel_Striping::loadState(MSTransportable* transportable, MSStageMoving* stage, std::istringstream& in) {
     189              :     MSPerson* person = static_cast<MSPerson*>(transportable);
     190           14 :     MSNet* net = MSNet::getInstance();
     191           14 :     if (!myAmActive) {
     192           12 :         net->getBeginOfTimestepEvents()->addEvent(new MovePedestrians(this), SIMSTEP);
     193           12 :         myAmActive = true;
     194              :     }
     195           14 :     PState* ped = new PState(person, stage, &in);
     196           14 :     myActiveLanes[ped->getLane()].push_back(ped);
     197           14 :     myNumActivePedestrians++;
     198           14 :     return ped;
     199              : }
     200              : 
     201              : 
     202              : int
     203   4931129645 : MSPModel_Striping::numStripes(const MSLane* lane) {
     204   4931129645 :     return MAX2(1, (int)floor(lane->getWidth() / stripeWidth));
     205              : }
     206              : 
     207              : 
     208              : int
     209       812940 : MSPModel_Striping::connectedDirection(const MSLane* from, const MSLane* to) {
     210       812940 :     if (from == nullptr || to == nullptr) {
     211            0 :         return UNDEFINED_DIRECTION;
     212       812940 :     } else if (from->getLinkTo(to) != nullptr) {
     213       545028 :         return FORWARD;
     214       267912 :     } else if (to->getLinkTo(from) != nullptr) {
     215       267912 :         return BACKWARD;
     216              :     } else {
     217            0 :         return UNDEFINED_DIRECTION;
     218              :     }
     219              : }
     220              : 
     221              : 
     222              : void
     223         5111 : MSPModel_Striping::initWalkingAreaPaths(const MSNet*) {
     224         5111 :     if (myWalkingAreaPaths.size() > 0) {
     225              :         return;
     226              :     }
     227              :     // collect vehicle lanes that cross walkingareas
     228       390894 :     for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
     229       385783 :         const MSEdge* edge = *i;
     230       385783 :         if (!edge->isWalkingArea() && !edge->isCrossing()) {
     231       688308 :             for (MSLane* lane : edge->getLanes()) {
     232       801231 :                 for (MSLink* link : lane->getLinkCont()) {
     233       442360 :                     if (link->getWalkingAreaFoe() != nullptr) {
     234              :                         // link is an exit link
     235         2846 :                         myWalkingAreaFoes[&link->getWalkingAreaFoe()->getEdge()].push_back(link->getLaneBefore());
     236              :                         //std::cout << " wa=" << link->getWalkingAreaFoe()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
     237              :                     }
     238       442360 :                     if (link->getWalkingAreaFoeExit() != nullptr) {
     239              :                         // link is an exit link
     240         2932 :                         myWalkingAreaFoes[&link->getWalkingAreaFoeExit()->getEdge()].push_back(link->getLaneBefore());
     241              :                         //std::cout << " wa=" << link->getWalkingAreaFoeExit()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
     242              :                     }
     243              :                 }
     244              :             }
     245              :         }
     246              :     }
     247              : 
     248              :     // build walkingareaPaths
     249       390894 :     for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
     250       385783 :         insertWalkArePaths(*i, myWalkingAreaPaths);
     251              :     }
     252              : }
     253              : 
     254              : 
     255              : void
     256       385783 : MSPModel_Striping::insertWalkArePaths(const MSEdge* edge, WalkingAreaPaths& into) {
     257       385783 :     if (edge->isWalkingArea()) {
     258        48992 :         const MSLane* walkingArea = getSidewalk<MSEdge, MSLane>(edge);
     259        48992 :         myMinNextLengths[walkingArea] = walkingArea->getLength();
     260              :         // build all possible paths across this walkingArea
     261              :         // gather all incident lanes
     262              :         std::vector<const MSLane*> lanes;
     263       128326 :         for (const MSEdge* in : edge->getPredecessors()) {
     264        79334 :             if (!in->isTazConnector()) {
     265        57092 :                 lanes.push_back(getSidewalk<MSEdge, MSLane>(in));
     266        57092 :                 if (lanes.back() == nullptr) {
     267            0 :                     throw ProcessError("Invalid connection from edge '" + in->getID() + "' to walkingarea edge '" + edge->getID() + "'");
     268              :                 }
     269              :             }
     270              :         }
     271       128495 :         for (const MSEdge* out : edge->getSuccessors()) {
     272        79503 :             if (!out->isTazConnector()) {
     273        57261 :                 lanes.push_back(getSidewalk<MSEdge, MSLane>(out));
     274        57261 :                 if (lanes.back() == nullptr) {
     275            0 :                     throw ProcessError("Invalid connection from walkingarea edge '" + edge->getID() + "' to edge '" + out->getID() + "'");
     276              :                 }
     277              :             }
     278              :         }
     279              :         // build all combinations
     280       163345 :         for (int j = 0; j < (int)lanes.size(); ++j) {
     281       405230 :             for (int k = 0; k < (int)lanes.size(); ++k) {
     282       290877 :                 if (j != k) {
     283              :                     // build the walkingArea
     284       176524 :                     const MSLane* const from = lanes[j];
     285       176524 :                     const MSLane* const to = lanes[k];
     286       176524 :                     const int fromDir = from->getLinkTo(walkingArea) != nullptr ? FORWARD : BACKWARD;
     287       176524 :                     const int toDir = walkingArea->getLinkTo(to) != nullptr ? FORWARD : BACKWARD;
     288       176524 :                     PositionVector shape;
     289       265031 :                     Position fromPos = from->getShape()[fromDir == FORWARD ? -1 : 0];
     290       264541 :                     Position toPos = to->getShape()[toDir == FORWARD ? 0 : -1];
     291       176524 :                     const double maxExtent = fromPos.distanceTo2D(toPos) / 4; // prevent sharp corners
     292       176524 :                     const double extrapolateBy = MIN2(maxExtent, walkingArea->getWidth() / 2);
     293              :                     // assemble shape
     294       176524 :                     shape.push_back(fromPos);
     295       176524 :                     if (extrapolateBy > POSITION_EPS) {
     296              :                         PositionVector fromShp = from->getShape();
     297       175544 :                         fromShp.extrapolate(extrapolateBy);
     298       351088 :                         shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
     299              :                         PositionVector nextShp = to->getShape();
     300       175544 :                         nextShp.extrapolate(extrapolateBy);
     301       351088 :                         shape.push_back_noDoublePos(toDir == FORWARD ? nextShp.front() : nextShp.back());
     302       175544 :                     }
     303       176524 :                     shape.push_back_noDoublePos(toPos);
     304       176524 :                     if (shape.size() < 2) {
     305              :                         PositionVector fromShp = from->getShape();
     306          546 :                         fromShp.extrapolate(1.5 * POSITION_EPS); // noDoublePos requires a difference of POSITION_EPS in at least one coordinate
     307         1092 :                         shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
     308              :                         assert(shape.size() == 2);
     309       176524 :                     } else if (myWalkingAreaDetail > 4) {
     310          448 :                         shape = shape.bezier(myWalkingAreaDetail);
     311              :                     }
     312              :                     double angleOverride = INVALID_DOUBLE;
     313       176524 :                     if (shape.size() >= 4 && shape.length() < walkingArea->getWidth()) {
     314        44872 :                         const double aStart = shape.angleAt2D(0);
     315        44872 :                         const double aEnd = shape.angleAt2D((int)shape.size() - 2);
     316        44872 :                         if (fabs(aStart - aEnd) < DEG2RAD(10)) {
     317         7406 :                             angleOverride = (aStart + aEnd) / 2;
     318              :                         }
     319              :                     }
     320       176524 :                     if (fromDir == BACKWARD) {
     321              :                         // will be walking backward on walkingArea
     322       177014 :                         shape = shape.reverse();
     323              :                     }
     324       176524 :                     WalkingAreaPath wap = WalkingAreaPath(from, walkingArea, to, shape, fromDir, angleOverride);
     325            0 :                     into.insert(std::make_pair(std::make_pair(from, to), wap));
     326       353048 :                     myMinNextLengths[walkingArea] = MIN2(myMinNextLengths[walkingArea], wap.length);
     327       176524 :                 }
     328              :             }
     329              :         }
     330        48992 :     }
     331       385783 : }
     332              : 
     333              : 
     334              : const MSPModel_Striping::WalkingAreaPath*
     335            8 : MSPModel_Striping::getArbitraryPath(const MSEdge* walkingArea) {
     336              :     assert(walkingArea->isWalkingArea());
     337              :     std::vector<const MSLane*> lanes;
     338           24 :     for (const MSEdge* const pred : walkingArea->getPredecessors()) {
     339           16 :         lanes.push_back(getSidewalk<MSEdge, MSLane>(pred));
     340              :     }
     341           24 :     for (const MSEdge* const succ : walkingArea->getSuccessors()) {
     342           16 :         lanes.push_back(getSidewalk<MSEdge, MSLane>(succ));
     343              :     }
     344            8 :     if (lanes.size() < 1) {
     345            0 :         throw ProcessError(TLF("Invalid walkingarea '%' does not allow continuation.", walkingArea->getID()));
     346              :     }
     347            8 :     return &myWalkingAreaPaths.find(std::make_pair(lanes.front(), lanes.back()))->second;
     348            8 : }
     349              : 
     350              : const MSPModel_Striping::WalkingAreaPath*
     351           59 : MSPModel_Striping::guessPath(const MSEdge* walkingArea, const MSEdge* before, const MSEdge* after) {
     352              :     assert(walkingArea->isWalkingArea());
     353           59 :     const MSLane* swBefore = getSidewalk<MSEdge, MSLane>(before);
     354           59 :     const MSLane* swAfter = getSidewalk<MSEdge, MSLane>(after);
     355           59 :     const auto pathIt = myWalkingAreaPaths.find(std::make_pair(swBefore, swAfter));
     356           59 :     if (pathIt != myWalkingAreaPaths.end()) {
     357           24 :         return &pathIt->second;
     358              :     }
     359              :     const MSEdgeVector& preds = walkingArea->getPredecessors();
     360           35 :     const MSEdgeVector& succs = walkingArea->getSuccessors();
     361           35 :     bool useBefore = swBefore != nullptr && std::find(preds.begin(), preds.end(), before) != preds.end();
     362           35 :     bool useAfter = swAfter != nullptr && std::find(succs.begin(), succs.end(), after) != succs.end();
     363           35 :     if (useBefore) {
     364           27 :         if (useAfter) {
     365            0 :             return getWalkingAreaPath(walkingArea, swBefore, swAfter);
     366           27 :         } else if (succs.size() > 0) {
     367              :             // could also try to exploit direction
     368           27 :             return getWalkingAreaPath(walkingArea, swBefore, getSidewalk<MSEdge, MSLane>(succs.front()));
     369              :         }
     370            8 :     } else if (useAfter && preds.size() > 0) {
     371              :         // could also try to exploit direction
     372            8 :         return getWalkingAreaPath(walkingArea, getSidewalk<MSEdge, MSLane>(preds.front()), swAfter);
     373              :     }
     374            0 :     return getArbitraryPath(walkingArea);
     375              : }
     376              : 
     377              : 
     378              : const MSPModel_Striping::WalkingAreaPath*
     379       843658 : MSPModel_Striping::getWalkingAreaPath(const MSEdge* walkingArea, const MSLane* before, const MSLane* after) {
     380              :     assert(walkingArea->isWalkingArea());
     381       843658 :     const auto pathIt = myWalkingAreaPaths.find(std::make_pair(before, after));
     382       843658 :     if (pathIt != myWalkingAreaPaths.end()) {
     383       843617 :         return &pathIt->second;
     384              :     } else {
     385              :         // this can happen in case of moveToXY where before can point anywhere
     386              :         const MSEdgeVector& preds = walkingArea->getPredecessors();
     387           41 :         if (preds.size() > 0) {
     388           41 :             const MSEdge* const pred = walkingArea->getPredecessors().front();
     389           41 :             const auto pathIt2 = myWalkingAreaPaths.find(std::make_pair(getSidewalk<MSEdge, MSLane>(pred), after));
     390              :             assert(pathIt2 != myWalkingAreaPaths.end());
     391           41 :             return &pathIt2->second;
     392              :         } else {
     393            0 :             return getArbitraryPath(walkingArea);
     394              :         }
     395              :     }
     396              : }
     397              : 
     398              : 
     399              : 
     400              : MSPModel_Striping::NextLaneInfo
     401      1401251 : MSPModel_Striping::getNextLane(const PState& ped, const MSLane* currentLane, const MSLane* prevLane) {
     402              :     const MSEdge* currentEdge = &currentLane->getEdge();
     403      1401251 :     const MSJunction* junction = ped.getDirection() == FORWARD ? currentEdge->getToJunction() : currentEdge->getFromJunction();
     404      1401251 :     const MSEdge* nextRouteEdge = ped.getStage()->getNextRouteEdge();
     405      1401251 :     const MSLane* nextRouteLane = getSidewalk<MSEdge, MSLane>(nextRouteEdge, ped.getPerson()->getVClass());
     406              :     // result values
     407              :     const MSLane* nextLane = nextRouteLane;
     408      1401251 :     const MSLink* link = nullptr;
     409      1401251 :     int nextDir = UNDEFINED_DIRECTION;
     410              : 
     411              :     //if DEBUGCOND(ped) {
     412              :     //    std::cout << "  nextRouteLane=" << Named::getIDSecure(nextRouteLane) << " junction=" << junction->getID() << "\n";
     413              :     //}
     414      1401251 :     if (nextRouteLane == nullptr && nextRouteEdge != nullptr) {
     415           56 :         std::string error = "Person '" + ped.getPerson()->getID() + "' could not find sidewalk on edge '" + nextRouteEdge->getID() + "', time="
     416           56 :                             + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".";
     417           56 :         if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
     418           76 :             WRITE_WARNING(error);
     419           24 :             nextRouteLane = nextRouteEdge->getLanes().front();
     420              :         } else {
     421            8 :             throw ProcessError(error);
     422              :         }
     423              :     }
     424              : 
     425      1401247 :     if (nextRouteLane != nullptr) {
     426      1205075 :         if (currentEdge->isInternal()) {
     427              :             assert(junction == currentEdge->getFromJunction());
     428        25324 :             nextDir = junction == nextRouteEdge->getFromJunction() ? FORWARD : BACKWARD;
     429        25324 :             if (nextDir == FORWARD) {
     430        24348 :                 nextLane = currentLane->getLinkCont()[0]->getViaLaneOrLane();
     431              :             } else {
     432          976 :                 nextLane = currentLane->getLogicalPredecessorLane();
     433              :             }
     434        25324 :             if DEBUGCOND(ped) {
     435            0 :                 std::cout << "  internal\n";
     436              :             }
     437      1179751 :         } else if (currentEdge->isCrossing()) {
     438        30615 :             nextDir = ped.getDirection();
     439        30615 :             if (nextDir == FORWARD) {
     440        15374 :                 nextLane = currentLane->getLinkCont()[0]->getLane();
     441              :             } else {
     442        15241 :                 nextLane = currentLane->getLogicalPredecessorLane();
     443              :             }
     444        30615 :             if DEBUGCOND(ped) {
     445            0 :                 std::cout << "  crossing\n";
     446              :             }
     447        30615 :             unregisterCrossingApproach(ped, currentLane);
     448      1149136 :         } else if (currentEdge->isWalkingArea())  {
     449              :             ConstMSEdgeVector crossingRoute;
     450              :             // departPos can be 0 because the direction of the walkingArea does not matter
     451              :             // for the arrivalPos, we need to make sure that the route does not deviate across other junctions
     452       812977 :             const int nextRouteEdgeDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
     453       812977 :             const double arrivalPos = (nextRouteEdge == ped.getStage()->getRoute().back()
     454       812977 :                                        ? ped.getStage()->getArrivalPos()
     455       246405 :                                        : (nextRouteEdgeDir == FORWARD ? 0 : nextRouteEdge->getLength()));
     456              :             MSEdgeVector prohibited;
     457       812977 :             if (prevLane != nullptr) {
     458       812918 :                 prohibited.push_back(&prevLane->getEdge());
     459              :             }
     460       812977 :             MSNet::getInstance()->getPedestrianRouter(0, prohibited).compute(currentEdge, nextRouteEdge, 0, arrivalPos, ped.getStage()->getMaxSpeed(ped.getPerson()), 0, junction, crossingRoute, true);
     461       812977 :             if DEBUGCOND(ped) {
     462              :                 std::cout
     463              :                         << "   nre=" << nextRouteEdge->getID()
     464              :                         << "   nreDir=" << nextRouteEdgeDir
     465            0 :                         << "   aPos=" << arrivalPos
     466            0 :                         << " crossingRoute=" << toString(crossingRoute)
     467            0 :                         << "\n";
     468              :             }
     469       812977 :             if (crossingRoute.size() > 1) {
     470       812940 :                 const MSEdge* nextEdge = crossingRoute[1];
     471       812940 :                 nextLane = getSidewalk<MSEdge, MSLane>(crossingRoute[1], ped.getPerson()->getVClass());
     472              :                 assert((nextEdge->getFromJunction() == junction || nextEdge->getToJunction() == junction));
     473              :                 assert(nextLane != prevLane);
     474       812940 :                 nextDir = connectedDirection(currentLane, nextLane);
     475       812940 :                 if DEBUGCOND(ped) {
     476            0 :                     std::cout << " nextDir=" << nextDir << "\n";
     477              :                 }
     478              :                 assert(nextDir != UNDEFINED_DIRECTION);
     479       812940 :                 if (nextDir == FORWARD) {
     480       545028 :                     link = currentLane->getLinkTo(nextLane);
     481              :                 } else {
     482       267912 :                     link = nextLane->getLinkTo(currentLane);
     483       267912 :                     if (nextEdge->isCrossing() && link->getTLLogic() == nullptr) {
     484       220632 :                         const MSLane* oppositeWalkingArea = nextLane->getLogicalPredecessorLane();
     485       220632 :                         link = oppositeWalkingArea->getLinkTo(nextLane);
     486              :                     }
     487              :                 }
     488              :                 assert(link != nullptr);
     489       812940 :                 if (nextLane->isCrossing()) {
     490       537031 :                     registerCrossingApproach(ped, nextLane, prevLane);
     491              :                 }
     492              :             } else {
     493           37 :                 if DEBUGCOND(ped) {
     494            0 :                     std::cout << SIMTIME
     495            0 :                               << " no route from '" << (currentEdge == nullptr ? "NULL" : currentEdge->getID())
     496            0 :                               << "' to '" << (nextRouteEdge == nullptr ? "NULL" : nextRouteEdge->getID())
     497            0 :                               << "\n";
     498              :                 }
     499              :                 // check if a direct connection exists (moving onto the walkingarea was the wrong choice)
     500           37 :                 if (ped.getDirection() == FORWARD) {
     501           24 :                     link = prevLane->getLinkTo(nextRouteLane);
     502              :                 } else {
     503           13 :                     link = nextRouteLane->getLinkTo(prevLane);
     504              :                 }
     505           37 :                 if (link != nullptr) {
     506              :                     // leave direction as UNDEFINED_DIRECTION to signal that currentLane must be changed
     507              :                     nextLane = link->getViaLaneOrLane();
     508              :                 } else {
     509           80 :                     WRITE_WARNING("Person '" + ped.getPerson()->getID() + "' could not find route across junction '" + junction->getID()
     510              :                                   + "' from walkingArea '" + currentEdge->getID()
     511              :                                   + "' to edge '" + nextRouteEdge->getID() + "', time=" +
     512              :                                   time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     513              :                     // error indicated by nextDir == UNDEFINED_DIRECTION
     514              :                     nextLane = nextRouteLane;
     515              :                 }
     516              :             }
     517      1149136 :         } else if (currentEdge == nextRouteEdge) {
     518              :             // strange loop in this route. No need to use walkingArea
     519            8 :             nextDir = -ped.getDirection();
     520              :         } else {
     521              :             // normal edge. by default use next / previous walking area
     522       336151 :             nextDir = ped.getDirection();
     523       336151 :             nextLane = getNextWalkingArea(currentLane, ped.getDirection(), link);
     524       336151 :             if (nextLane != nullptr) {
     525              :                 // walking area found
     526       294842 :                 if DEBUGCOND(ped) {
     527            0 :                     std::cout << "  next walkingArea " << (nextDir == FORWARD ? "forward" : "backward") << "\n";
     528              :                 }
     529              :             } else {
     530              :                 // walk forward by default
     531        41309 :                 if (junction == nextRouteEdge->getToJunction()) {
     532         4026 :                     nextDir = BACKWARD;
     533        37283 :                 } else if (junction == nextRouteEdge->getFromJunction()) {
     534              :                     nextDir = FORWARD;
     535              :                 } else {
     536              :                     // topological disconnect, find a direction that makes sense
     537              :                     // for the future part of the route
     538           56 :                     ConstMSEdgeVector futureRoute = ped.getStage()->getRoute();
     539           56 :                     futureRoute.erase(futureRoute.begin(), futureRoute.begin() + ped.getStage()->getRoutePosition() + 1);
     540           56 :                     int passedFwd = 0;
     541           56 :                     int passedBwd = 0;
     542           56 :                     canTraverse(FORWARD, futureRoute, passedFwd);
     543           56 :                     canTraverse(BACKWARD, futureRoute, passedBwd);
     544           56 :                     nextDir = (passedFwd >= passedBwd) ? FORWARD : BACKWARD;
     545           56 :                     if DEBUGCOND(ped) {
     546            0 :                         std::cout << " nextEdge=" << nextRouteEdge->getID() << " passedFwd=" << passedFwd << " passedBwd=" << passedBwd << " futureRoute=" << toString(futureRoute) << " nextDir=" << nextDir << "\n";
     547              :                     }
     548           56 :                 }
     549              :                 // try to use a direct link as fallback
     550              :                 // direct links only exist if built explicitly. They are used to model tl-controlled links if there are no crossings
     551        41309 :                 if (ped.getDirection() == FORWARD) {
     552        36818 :                     link = currentLane->getLinkTo(nextRouteLane);
     553        36818 :                     if (link != nullptr) {
     554        35246 :                         if DEBUGCOND(ped) {
     555            0 :                             std::cout << "  direct forward\n";
     556              :                         }
     557        35246 :                         nextLane = currentLane->getInternalFollowingLane(nextRouteLane);
     558              :                     }
     559              :                 } else {
     560         4491 :                     link = nextRouteLane->getLinkTo(currentLane);
     561         4491 :                     if (link != nullptr) {
     562         3264 :                         if DEBUGCOND(ped) {
     563            0 :                             std::cout << "  direct backward\n";
     564              :                         }
     565         3264 :                         nextLane = nextRouteLane->getInternalFollowingLane(currentLane);
     566         3264 :                         if (nextLane != nullptr) {
     567              :                             // advance to the end of consecutive internal lanes
     568         5519 :                             while (nextLane->getLinkCont()[0]->getViaLaneOrLane()->isInternal()) {
     569            5 :                                 nextLane = nextLane->getLinkCont()[0]->getViaLaneOrLane();
     570              :                             }
     571              :                         }
     572              :                     }
     573              :                 }
     574              :             }
     575       335644 :             if (nextLane == nullptr) {
     576              :                 // no internal lane found
     577              :                 nextLane = nextRouteLane;
     578         8439 :                 if DEBUGCOND(ped) {
     579            0 :                     std::cout << SIMTIME << " no next lane found for " << currentLane->getID() << " dir=" << ped.getDirection() << "\n";
     580              :                 }
     581         8439 :                 if (usingInternalLanesStatic() && currentLane->getLinkCont().size() > 0) {
     582            0 :                     WRITE_WARNING("Person '" + ped.getPerson()->getID() + "' could not find route across junction '" + junction->getID()
     583              :                                   + "' from edge '" + currentEdge->getID()
     584              :                                   + "' to edge '" + nextRouteEdge->getID() + "', time=" +
     585              :                                   time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     586              :                 }
     587       327712 :             } else if (nextLane->getLength() <= POSITION_EPS) {
     588              :                 // internal lane too short
     589              :                 // most often this is due to a zero-size junction. However, if
     590              :                 // the person needs to pass a crossing we cannot skip ahead
     591        11110 :                 if ((nextLane->getCanonicalSuccessorLane() == nullptr
     592        11102 :                         || !nextLane->getCanonicalSuccessorLane()->getEdge().isCrossing())
     593        33310 :                         && (nextLane->getLogicalPredecessorLane() == nullptr ||
     594        11098 :                             !nextLane->getLogicalPredecessorLane()->getEdge().isCrossing())) {
     595              :                     //WRITE_WARNING("Person '" + ped.getID()
     596              :                     //        + "' skips short lane '" + nextLane->getID()
     597              :                     //        + "' length=" + toString(nextLane->getLength())
     598              :                     //        + " time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     599              :                     nextLane = nextRouteLane;
     600        11110 :                     nextDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
     601              :                 }
     602              :             }
     603              :         }
     604              :     }
     605      1401247 :     if DEBUGCOND(ped) {
     606            0 :         std::cout << SIMTIME
     607              :                   << " p=" << ped.getPerson()->getID()
     608              :                   << " l=" << currentLane->getID()
     609            0 :                   << " nl=" << (nextLane == nullptr ? "NULL" : nextLane->getID())
     610            0 :                   << " nrl=" << (nextRouteLane == nullptr ? "NULL" : nextRouteLane->getID())
     611              :                   << " d=" << nextDir
     612            0 :                   << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
     613            0 :                   << " pedDir=" << ped.getDirection()
     614            0 :                   << "\n";
     615              :     }
     616              :     assert(nextLane != 0 || nextRouteLane == 0);
     617      1401247 :     return NextLaneInfo(nextLane, link, nextDir);
     618              : }
     619              : 
     620              : 
     621              : const MSLane*
     622       336151 : MSPModel_Striping::getNextWalkingArea(const MSLane* currentLane, const int dir, const MSLink*& link) {
     623       336151 :     if (dir == FORWARD) {
     624       343216 :         for (const MSLink* const l : currentLane->getLinkCont()) {
     625       306398 :             if (l->getLane()->getEdge().isWalkingArea()) {
     626       243208 :                 link = l;
     627              :                 return l->getLane();
     628              :             }
     629              :         }
     630              :     } else {
     631              :         const std::vector<MSLane::IncomingLaneInfo>& laneInfos = currentLane->getIncomingLanes();
     632        62774 :         for (std::vector<MSLane::IncomingLaneInfo>::const_iterator it = laneInfos.begin(); it != laneInfos.end(); ++it) {
     633        58283 :             if ((*it).lane->getEdge().isWalkingArea()) {
     634        51634 :                 link = (*it).viaLink;
     635              :                 return (*it).lane;
     636              :             }
     637              :         }
     638              :     }
     639              :     return nullptr;
     640              : }
     641              : 
     642              : 
     643              : MSPModel_Striping::Obstacles
     644     50308437 : MSPModel_Striping::getNeighboringObstacles(const Pedestrians& pedestrians, int egoIndex, int stripes) {
     645     50308437 :     const PState& ego = *static_cast<PState*>(pedestrians[egoIndex]);
     646     50308437 :     const int egoStripe = ego.stripe();
     647     50308437 :     Obstacles obs(stripes, Obstacle(ego.getDirection()));
     648     50308437 :     std::vector<bool> haveBlocker(stripes, false);
     649   6814111257 :     for (int index = egoIndex + 1; index < (int)pedestrians.size(); index++) {
     650   6802617895 :         const PState& p = *static_cast<PState*>(pedestrians[index]);
     651   6802617895 :         if DEBUGCOND(ego) {
     652            0 :             std::cout << SIMTIME << " ped=" << ego.getID() << " cur=" << egoStripe << " checking neighbor " << p.getID()
     653            0 :                       << " nCur=" << p.stripe() << " nOth=" << p.otherStripe();
     654              :         }
     655   6802617895 :         if (!p.isWaitingToEnter() && !p.isJammed()) {
     656     89129024 :             const Obstacle o(p);
     657     89129024 :             if DEBUGCOND(ego) {
     658            0 :                 std::cout << " dist=" << ego.distanceTo(o) << std::endl;
     659              :             }
     660     89129024 :             if (ego.distanceTo(o) == DIST_BEHIND) {
     661              :                 break;
     662              :             }
     663     50313949 :             if (ego.distanceTo(o) == DIST_OVERLAP) {
     664     50313949 :                 if (p.stripe() != egoStripe || p.getDirection() != ego.getDirection()) {
     665     38675265 :                     obs[p.stripe()] = o;
     666     38675265 :                     haveBlocker[p.stripe()] = true;
     667              :                 } else {
     668              :                     //std::cout << SIMTIME << "   ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe=" << egoStripe << "\n";
     669              :                 }
     670     50313949 :                 if (p.otherStripe() != egoStripe || p.getDirection() != ego.getDirection()) {
     671     38675265 :                     obs[p.otherStripe()] = o;
     672     38675265 :                     haveBlocker[p.otherStripe()] = true;
     673              :                 } else {
     674              :                     //std::cout << SIMTIME << "   ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe2=" << egoStripe << "\n";
     675              :                 }
     676              :             } else {
     677            0 :                 if (!haveBlocker[p.stripe()]) {
     678            0 :                     obs[p.stripe()] = o;
     679              :                 }
     680            0 :                 if (!haveBlocker[p.otherStripe()]) {
     681            0 :                     obs[p.otherStripe()] = o;
     682              :                 }
     683              :             }
     684              :         }
     685              :     }
     686     50308437 :     if DEBUGCOND(ego) {
     687            0 :         std::cout << SIMTIME << " ped=" << ego.getPerson()->getID() << "  neighObs=";
     688            0 :         DEBUG_PRINT(obs);
     689              :     }
     690     50308437 :     return obs;
     691            0 : }
     692              : 
     693              : 
     694              : int
     695      2878164 : MSPModel_Striping::getStripeOffset(int origStripes, int destStripes, bool addRemainder) {
     696      2878164 :     int offset = (destStripes - origStripes) / 2;
     697      2878164 :     if (addRemainder) {
     698        12268 :         offset += (destStripes - origStripes) % 2;
     699              :     }
     700      2878164 :     return offset;
     701              : }
     702              : 
     703              : 
     704              : const MSPModel_Striping::Obstacles&
     705     13056254 : MSPModel_Striping::getNextLaneObstacles(NextLanesObstacles& nextLanesObs, const
     706              :                                         MSLane* lane, const MSLane* nextLane, int stripes, int nextDir,
     707              :                                         double currentLength, int currentDir) {
     708              :     if (nextLanesObs.count(nextLane) == 0) {
     709      2198621 :         const double nextLength = nextLane->getEdge().isWalkingArea() ? myMinNextLengths[nextLane] : nextLane->getLength();
     710              :         // figure out the which pedestrians are ahead on the next lane
     711      2198621 :         const int nextStripes = numStripes(nextLane);
     712              :         // do not move past the end of the next lane in a single step
     713      4397242 :         Obstacles obs(stripes, Obstacle(nextDir == FORWARD ? nextLength : 0, 0, OBSTACLE_NEXTEND, "nextEnd", 0));
     714              : 
     715      2198621 :         const int offset = getStripeOffset(nextStripes, stripes, currentDir != nextDir && nextStripes > stripes);
     716              :         //std::cout << SIMTIME << " getNextLaneObstacles"
     717              :         //    << " nextLane=" << nextLane->getID()
     718              :         //    << " nextLength=" << nextLength
     719              :         //    << " nextDir=" << nextDir
     720              :         //    << " currentLength=" << currentLength
     721              :         //    << " currentDir=" << currentDir
     722              :         //    << " stripes=" << stripes
     723              :         //    << " nextStripes=" << nextStripes
     724              :         //    << " offset=" << offset
     725              :         //    << "\n";
     726      2198621 :         if (nextStripes < stripes) {
     727              :             // some stripes do not continue
     728      1860293 :             for (int ii = 0; ii < stripes; ++ii) {
     729      1600066 :                 if (ii < offset || ii >= nextStripes + offset) {
     730      2247393 :                     obs[ii] = Obstacle(nextDir == FORWARD ? 0 : nextLength, 0, OBSTACLE_END, "stripeEnd", 0);
     731              :                 }
     732              :             }
     733              :         }
     734      2198621 :         Pedestrians& pedestrians = getPedestrians(nextLane);
     735      2198621 :         if (nextLane->getEdge().isWalkingArea()) {
     736      1142637 :             transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
     737              :             // complex transformation into the coordinate system of the current lane
     738              :             // (pedestrians on next lane may walk at arbitrary angles relative to the current lane)
     739      1142637 :             double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
     740      1142637 :             if ((stripes - nextStripes) % 2 != 0) {
     741       444154 :                 lateral_offset += 0.5 * stripeWidth;
     742              :             }
     743              :             nextDir = currentDir;
     744              :             // transform pedestrians into the current coordinate system
     745      6324165 :             for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
     746      5181528 :                 const PState& p = *static_cast<PState*>(pedestrians[ii]);
     747      5181528 :                 if (p.isWaitingToEnter() || p.isJammed()) {
     748      1006735 :                     continue;
     749              :                 }
     750      4174793 :                 Position pPos = p.getPosition(*p.getStage(), -1);
     751      4174793 :                 Position relPos = lane->getShape().transformToVectorCoordinates(pPos, true);
     752              :                 if (relPos == Position::INVALID) {
     753            0 :                     WRITE_WARNINGF("Could not map position % onto lane '%'", pPos, lane->getID());
     754              :                 }
     755      4174793 :                 const double newY = relPos.y() + lateral_offset;
     756              :                 //if (p.getPerson()->getID() == "ped200") std::cout << "    ped=" << p.getPerson()->getID() << "  relX=" << relPos.x() << " relY=" << newY << " latOff=" << lateral_offset << " s=" << p.stripe(newY) << " os=" << p.otherStripe(newY) << "\n";
     757      4174793 :                 if ((currentDir == FORWARD && relPos.x() >= lane->getLength()) || (currentDir == BACKWARD && relPos.x() < 0)) {
     758      4170122 :                     addCloserObstacle(obs, relPos.x(), p.stripe(newY), stripes, p.getPerson()->getID(), p.getPerson()->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
     759      4170122 :                     addCloserObstacle(obs, relPos.x(), p.otherStripe(newY), stripes, p.getPerson()->getID(), p.getPerson()->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
     760              :                 }
     761              :             }
     762              :         } else {
     763              :             // simple transformation into the coordinate system of the current lane
     764              :             // (only need to worry about currentDir and nextDir)
     765              :             // XXX consider waitingToEnter on nextLane
     766      1055984 :             sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(nextDir));
     767     24910654 :             for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
     768     23854670 :                 const PState& p = *static_cast<PState*>(pedestrians[ii]);
     769     23854670 :                 if (p.isWaitingToEnter() || p.isJammed()) {
     770     14074785 :                     continue;
     771              :                 }
     772              :                 double newY = p.getPosLat();
     773      9779885 :                 Obstacle pObs(p);
     774      9779885 :                 if (nextDir != currentDir) {
     775       503586 :                     newY = (nextStripes - 1) * stripeWidth - newY;
     776       503586 :                     pObs.speed *= -1;
     777              :                 }
     778      9779885 :                 newY += offset * stripeWidth;
     779      9779885 :                 const int stripe = p.stripe(newY);
     780      9779885 :                 if (stripe >= 0 && stripe < stripes) {
     781      9779882 :                     obs[stripe] = pObs;
     782              :                 }
     783      9779885 :                 const int otherStripe = p.otherStripe(newY);
     784      9779885 :                 if (otherStripe >= 0 && otherStripe < stripes) {
     785      9779882 :                     obs[otherStripe] = pObs;
     786              :                 }
     787              :             }
     788      1055984 :             if (nextLane->getEdge().isCrossing()) {
     789              :                 // add vehicle obstacles
     790       290322 :                 const MSLink* crossingEntryLink = nextLane->getIncomingLanes().front().viaLink;
     791       290322 :                 const bool prio = crossingEntryLink->havePriority() || crossingEntryLink->getTLLogic() != nullptr;
     792       290322 :                 addCrossingVehs(nextLane, stripes, offset, nextDir, obs, prio);
     793              :             }
     794      1055984 :             if (nextLane->getVehicleNumberWithPartials() > 0) {
     795        18456 :                 Obstacles vehObs = getVehicleObstacles(nextLane, nextDir);
     796        18456 :                 PState::mergeObstacles(obs, vehObs, nextDir, offset);
     797        18456 :             }
     798      1055984 :             transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
     799              :         }
     800      2198621 :         nextLanesObs[nextLane] = obs;
     801      2198621 :     }
     802     13056254 :     return nextLanesObs[nextLane];
     803              : }
     804              : 
     805              : void
     806      2198621 : MSPModel_Striping::transformToCurrentLanePositions(Obstacles& obs, int currentDir, int nextDir, double currentLength, double nextLength) {
     807     12346590 :     for (Obstacle& o : obs) {
     808     10147969 :         if (currentDir == FORWARD) {
     809      6690839 :             if (nextDir == FORWARD) {
     810      6451857 :                 o.xFwd += currentLength;
     811      6451857 :                 o.xBack += currentLength;
     812              :             } else {
     813       238982 :                 const double tmp = o.xFwd;
     814       238982 :                 o.xFwd = currentLength + nextLength - o.xBack;
     815       238982 :                 o.xBack = currentLength + nextLength - tmp;
     816              :             }
     817              :         } else {
     818      3457130 :             if (nextDir == FORWARD) {
     819       743311 :                 const double tmp = o.xFwd;
     820       743311 :                 o.xFwd = -o.xBack;
     821       743311 :                 o.xBack = -tmp;
     822              :             } else {
     823      2713819 :                 o.xFwd -= nextLength;
     824      2713819 :                 o.xBack -= nextLength;
     825              :             }
     826              :         }
     827              :     }
     828      2198621 : }
     829              : 
     830              : 
     831              : void
     832      8340244 : MSPModel_Striping::addCloserObstacle(Obstacles& obs, double x, int stripe, int numStripes, const std::string& id, double width, int dir, ObstacleType type) {
     833      8340244 :     if (stripe >= 0 && stripe < numStripes) {
     834      2186800 :         if ((dir == FORWARD && x - width / 2. < obs[stripe].xBack) || (dir == BACKWARD && x + width / 2. > obs[stripe].xFwd)) {
     835      1805832 :             obs[stripe] = Obstacle(x, 0, type, id, width);
     836              :         }
     837              :     }
     838      8340244 : }
     839              : 
     840              : void
     841     17795458 : MSPModel_Striping::moveInDirection(SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
     842    138662215 :     for (ActiveLanes::iterator it_lane = myActiveLanes.begin(); it_lane != myActiveLanes.end(); ++it_lane) {
     843    120866761 :         const MSLane* lane = it_lane->first;
     844    120866761 :         Pedestrians& pedestrians = it_lane->second;
     845    120866761 :         if (pedestrians.size() == 0) {
     846    112114660 :             continue;
     847              :         }
     848              :         //std::cout << SIMTIME << ">>> lane=" << lane->getID() << " numPeds=" << pedestrians.size() << "\n";
     849      8752101 :         if (lane->getEdge().isWalkingArea()) {
     850      1887010 :             const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
     851      1887010 :             const double minY = stripeWidth * - 0.5 + NUMERICAL_EPS;
     852      1887010 :             const double maxY = stripeWidth * (numStripes(lane) - 0.5) - NUMERICAL_EPS;
     853              :             const WalkingAreaPath* debugPath = nullptr;
     854              :             // need to handle each walkingAreaPath separately and transform
     855              :             // coordinates beforehand
     856              :             std::set<const WalkingAreaPath*, walkingarea_path_sorter> paths;
     857     13291180 :             for (Pedestrians::iterator it = pedestrians.begin(); it != pedestrians.end(); ++it) {
     858     11404170 :                 const PState* p = static_cast<PState*>(*it);
     859              :                 assert(p->myWalkingAreaPath != 0);
     860     11404170 :                 if (p->getDirection() == dir) {
     861      5716257 :                     paths.insert(p->myWalkingAreaPath);
     862      5716257 :                     if DEBUGCOND(*p) {
     863            0 :                         debugPath = p->myWalkingAreaPath;
     864            0 :                         std::cout << SIMTIME << " debugging WalkingAreaPath from=" << debugPath->from->getID() << " to=" << debugPath->to->getID() << " minY=" << minY << " maxY=" << maxY << " latOffset=" << lateral_offset << "\n";
     865              :                     }
     866              :                 }
     867              :             }
     868      1887010 :             const double usableWidth = (numStripes(lane) - 1) * stripeWidth;
     869      2909288 :             for (std::set<const WalkingAreaPath*, walkingarea_path_sorter>::iterator it = paths.begin(); it != paths.end(); ++it) {
     870      1022278 :                 const WalkingAreaPath* path = *it;
     871              :                 Pedestrians toDelete;
     872              :                 Pedestrians transformedPeds;
     873      1022278 :                 transformedPeds.reserve(pedestrians.size());
     874      7700390 :                 for (Pedestrians::iterator it_p = pedestrians.begin(); it_p != pedestrians.end(); ++it_p) {
     875      6678112 :                     PState* p = static_cast<PState*>(*it_p);
     876      6678112 :                     if (p->myWalkingAreaPath == path) {
     877      5716257 :                         transformedPeds.push_back(p);
     878      5716257 :                         if (path == debugPath) std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (untransformed), vecCoord="
     879            0 :                                                              << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
     880       961855 :                     } else if (p->myWalkingAreaPath->from == path->to && p->myWalkingAreaPath->to == path->from) {
     881        59386 :                         if (p->myWalkingAreaPath->dir != path->dir) {
     882              :                             // opposite direction is already in the correct coordinate system
     883        39563 :                             transformedPeds.push_back(p);
     884        39563 :                             if (path == debugPath) std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (untransformed), vecCoord="
     885            0 :                                                                  << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
     886              :                         } else {
     887              :                             // x position must be reversed
     888        19823 :                             PState* tp = new PState(*p);
     889        19823 :                             tp->reverse(path->length, usableWidth);
     890        19823 :                             toDelete.push_back(tp);
     891        19823 :                             transformedPeds.push_back(tp);
     892        19823 :                             if (path == debugPath) std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (semi-transformed), vecCoord="
     893            0 :                                                                  << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
     894              :                         }
     895              :                     } else {
     896       902469 :                         const Position relPos = path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1));
     897       902469 :                         const double newY = relPos.y() + lateral_offset;
     898       901910 :                         if (relPos != Position::INVALID && newY >= minY && newY <= maxY) {
     899       243396 :                             PState* tp = new PState(*p);
     900       243396 :                             tp->reset(relPos.x(), newY);
     901       243396 :                             toDelete.push_back(tp);
     902       243396 :                             transformedPeds.push_back(tp);
     903       243396 :                             if (path == debugPath) {
     904            0 :                                 std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << relPos.x() << " relY=" << newY << " (transformed), vecCoord=" << relPos << "\n";
     905              :                             }
     906              :                         } else {
     907       659073 :                             if (path == debugPath) {
     908            0 :                                 std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << relPos.x() << " relY=" << newY << " (invalid), vecCoord=" << relPos << "\n";
     909              :                             }
     910              :                         }
     911              :                     }
     912              :                 }
     913              :                 auto itFoe = myWalkingAreaFoes.find(&lane->getEdge());
     914      1022278 :                 if (itFoe != myWalkingAreaFoes.end()) {
     915              :                     // add vehicle foes on paths which cross this walkingarea
     916              :                     // translate the vehicle into a number of dummy-pedestrians
     917              :                     // that occupy the same space
     918      2239038 :                     for (const MSLane* foeLane : itFoe->second) {
     919       161518 :                         for (auto itVeh = foeLane->anyVehiclesBegin(); itVeh != foeLane->anyVehiclesEnd(); ++itVeh) {
     920       161518 :                             const MSVehicle* veh = *itVeh;
     921       161518 :                             const double vehWidth = veh->getVehicleType().getWidth();
     922       161518 :                             Boundary relCorners;
     923       161518 :                             Position relFront = path->shape.transformToVectorCoordinates(veh->getPosition(), true);
     924       161518 :                             Position relBack = path->shape.transformToVectorCoordinates(veh->getBackPosition(), true);
     925              :                             if (relFront == Position::INVALID) {
     926            0 :                                 WRITE_WARNINGF("Could not vehicle '%' front position % onto walkingarea '%' path=%, time=%.",
     927              :                                                veh->getID(), veh->getPosition(), lane->getID(), path->shape, time2string(SIMSTEP));
     928              :                             }
     929              :                             if (relBack == Position::INVALID) {
     930            0 :                                 WRITE_WARNINGF("Could not vehicle '%' back position % onto walkingarea '%' path=%, time=%.",
     931              :                                                veh->getID(), veh->getBackPosition(), lane->getID(), path->shape, time2string(SIMSTEP));
     932              :                             }
     933       161518 :                             PositionVector relCenter;
     934       161518 :                             relCenter.push_back(relFront);
     935       161518 :                             relCenter.push_back(relBack);
     936       161518 :                             relCenter.move2side(vehWidth / 2);
     937       161518 :                             relCorners.add(relCenter[0]);
     938       161518 :                             relCorners.add(relCenter[1]);
     939       161518 :                             relCenter.move2side(-vehWidth);
     940       161518 :                             relCorners.add(relCenter[0]);
     941       161518 :                             relCorners.add(relCenter[1]);
     942              :                             // persons should require less gap than the vehicles to prevent getting stuck
     943              :                             // when a vehicles moves towards them
     944       161518 :                             relCorners.growWidth(SAFETY_GAP / 2);
     945       161518 :                             const double xWidth = relCorners.getWidth();
     946       161518 :                             const double vehYmin = MAX2(minY - lateral_offset, relCorners.ymin());
     947       161518 :                             const double vehYmax = MIN2(maxY - lateral_offset, relCorners.ymax());
     948       161518 :                             const double xCenter = relCorners.getCenter().x();
     949              :                             Position yMinPos(xCenter, vehYmin);
     950              :                             Position yMaxPos(xCenter, vehYmax);
     951       161518 :                             const bool addFront = addVehicleFoe(veh, lane, yMinPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
     952       161518 :                             const bool addBack = addVehicleFoe(veh, lane, yMaxPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
     953       161518 :                             if (path == debugPath) {
     954              :                                 std::cout << "  veh=" << veh->getID()
     955            0 :                                           << " corners=" << relCorners
     956              :                                           << " xWidth=" << xWidth
     957            0 :                                           << " ymin=" << relCorners.ymin()
     958            0 :                                           << " ymax=" << relCorners.ymax()
     959              :                                           << " vehYmin=" << vehYmin
     960              :                                           << " vehYmax=" << vehYmax
     961            0 :                                           << "\n";
     962              :                             }
     963       161518 :                             if (addFront && addBack) {
     964              :                                 // add in-between positions
     965       161518 :                                 const double yDist = vehYmax - vehYmin;
     966       375616 :                                 for (double dist = stripeWidth; dist < yDist; dist += stripeWidth) {
     967       214098 :                                     const double relDist = dist / yDist;
     968       214098 :                                     Position between = (yMinPos * relDist) + (yMaxPos * (1 - relDist));
     969       214098 :                                     if (path == debugPath) {
     970            0 :                                         std::cout << "  vehBetween=" << veh->getID() << " pos=" << between << "\n";
     971              :                                     }
     972       214098 :                                     addVehicleFoe(veh, lane, between, dir * xWidth, stripeWidth, lateral_offset, minY, maxY, toDelete, transformedPeds);
     973              :                                 }
     974              :                             }
     975       161518 :                         }
     976              :                     }
     977              :                 }
     978      1022278 :                 moveInDirectionOnLane(transformedPeds, lane, currentTime, changedLane, dir, path == debugPath);
     979      1022278 :                 arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
     980              :                 // clean up
     981      1724439 :                 for (Pedestrians::iterator it_p = toDelete.begin(); it_p != toDelete.end(); ++it_p) {
     982       702161 :                     delete *it_p;
     983              :                 }
     984      1022278 :             }
     985              :         } else {
     986      6865091 :             moveInDirectionOnLane(pedestrians, lane, currentTime, changedLane, dir, false);
     987      6865091 :             arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
     988              :         }
     989              :     }
     990     17795454 : }
     991              : 
     992              : 
     993              : bool
     994       537134 : MSPModel_Striping::addVehicleFoe(const MSVehicle* veh, const MSLane* walkingarea, const Position& relPos, double xWidth, double yWidth, double lateral_offset,
     995              :                                  double minY, double maxY, Pedestrians& toDelete, Pedestrians& transformedPeds) {
     996              :     if (relPos != Position::INVALID) {
     997       537134 :         const double newY = relPos.y() + lateral_offset;
     998       537134 :         if (newY >= minY && newY <= maxY) {
     999       438942 :             PState* tp = new PStateVehicle(veh, walkingarea, relPos.x(), newY, xWidth, yWidth);
    1000              :             //std::cout << SIMTIME << " addVehicleFoe=" << veh->getID() << " rx=" << relPos.x() << " ry=" << newY << " s=" << tp->stripe() << " o=" << tp->otherStripe() << "\n";
    1001       438942 :             toDelete.push_back(tp);
    1002       438942 :             transformedPeds.push_back(tp);
    1003              :         }
    1004       537134 :         return true;
    1005              :     } else {
    1006              :         return false;
    1007              :     }
    1008              : }
    1009              : 
    1010              : void
    1011      7887369 : MSPModel_Striping::arriveAndAdvance(Pedestrians& pedestrians, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
    1012              :     // advance to the next lane / arrive at destination
    1013      7887369 :     sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
    1014              :     // can't use iterators because we do concurrent modification
    1015    103961047 :     for (int i = 0; i < (int)pedestrians.size(); i++) {
    1016     96073682 :         PState* const p = static_cast<PState*>(pedestrians[i]);
    1017     96073682 :         if (p->isRemoteControlled()) {
    1018        20245 :             continue;
    1019              :         }
    1020     96053437 :         if (p->getDirection() == dir && p->distToLaneEnd() < 0) {
    1021              :             // moveToNextLane may trigger re-insertion (for consecutive
    1022              :             // walks) so erase must be called first
    1023              :             pedestrians.erase(pedestrians.begin() + i);
    1024       873531 :             i--;
    1025       873531 :             p->moveToNextLane(currentTime);
    1026       873527 :             if (p->getLane() != nullptr) {
    1027       679543 :                 changedLane.insert(p->getPerson());
    1028       679543 :                 myActiveLanes[p->getLane()].push_back(p);
    1029              :             } else {
    1030              :                 // end walking stage and destroy PState
    1031       193984 :                 p->getStage()->moveToNextEdge(p->getPerson(), currentTime, dir);
    1032       193984 :                 myNumActivePedestrians--;
    1033              :             }
    1034              :         }
    1035              :     }
    1036      7887365 : }
    1037              : 
    1038              : 
    1039              : void
    1040      7887369 : MSPModel_Striping::moveInDirectionOnLane(Pedestrians& pedestrians, const MSLane* lane, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir, bool debug) {
    1041      7887369 :     const int stripes = numStripes(lane);
    1042              :     //std::cout << " laneWidth=" << lane->getWidth() << " stripeWidth=" << stripeWidth << " stripes=" << stripes << "\n";
    1043     15774738 :     Obstacles obs(stripes, Obstacle(dir)); // continuously updated
    1044              :     NextLanesObstacles nextLanesObs; // continuously updated
    1045      7887369 :     sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
    1046              : 
    1047     15774738 :     Obstacles crossingVehs(stripes, Obstacle(dir));
    1048              :     bool hasCrossingVehObs = false;
    1049      7887369 :     if (lane->getEdge().isCrossing()) {
    1050              :         // assume that vehicles will brake when already on the crossing
    1051       587200 :         hasCrossingVehObs = addCrossingVehs(lane, stripes, 0, dir, crossingVehs, true);
    1052              :     }
    1053              : 
    1054    103739644 :     for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
    1055     95852275 :         PState& p = *static_cast<PState*>(pedestrians[ii]);
    1056              :         UNUSED_PARAMETER(debug);
    1057              :         //if (debug) {
    1058              :         //    std::cout << SIMTIME << " CHECKING d=" << dir << " p=" << p.getID() << " relX=" << p.myRelX << " xmin=" << p.getMinX() << " xmax=" << p.getMaxX() << " pdir=" << p.getDirection() << "\n";
    1059              :         //}
    1060     95852275 :         Obstacles currentObs = obs;
    1061     95852275 :         if (p.getDirection() != dir || changedLane.count(p.getPerson()) != 0 || p.getRemotePosition() != Position::INVALID) {
    1062     45543838 :             if (!p.isWaitingToEnter() && !p.isJammed()) {
    1063              :                 //if DEBUGCOND(p) {
    1064              :                 //    std::cout << "   obs=" << p.getPerson()->getID() << "  y=" << p.getPosLat() << "  stripe=" << p.stripe() << " oStripe=" << p.otherStripe() << "\n";
    1065              :                 //}
    1066     26595322 :                 Obstacle o(p);
    1067     26595322 :                 if (p.getDirection() != dir && p.getSpeed(*p.getStage()) == 0.) {
    1068              :                     // ensure recognition of oncoming
    1069      5117621 :                     o.speed = (p.getDirection() == FORWARD ? 0.1 : -0.1);
    1070              :                 }
    1071     26595322 :                 if (o.closer(obs[p.stripe()], dir)) {
    1072     26591109 :                     obs[p.stripe()] = o;
    1073              :                 }
    1074     26595322 :                 if (o.closer(obs[p.otherStripe()], dir)) {
    1075     26590943 :                     obs[p.otherStripe()] = o;
    1076              :                 }
    1077              :             }
    1078              :             continue;
    1079     45543838 :         }
    1080     50308437 :         if DEBUGCOND(p) {
    1081            0 :             std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  currentObs=";
    1082            0 :             gDebugFlag1 = true;
    1083            0 :             DEBUG_PRINT(currentObs);
    1084              :         }
    1085     50308437 :         const MSLane* nextLane = p.myNLI.lane;
    1086     50308437 :         const MSLink* link = p.myNLI.link;
    1087     50308437 :         const double dist = p.distToLaneEnd();
    1088     50308437 :         const double speed = p.getStage()->getMaxSpeed(p.getPerson());
    1089     50308437 :         if (nextLane != nullptr && dist <= LOOKAHEAD_ONCOMING_DIST) {
    1090     13056254 :             const double currentLength = (p.myWalkingAreaPath == nullptr ? lane->getLength() : p.myWalkingAreaPath->length);
    1091     13056254 :             const Obstacles& nextObs = getNextLaneObstacles(
    1092              :                                            nextLanesObs, lane, nextLane, stripes,
    1093              :                                            p.myNLI.dir, currentLength, dir);
    1094              : 
    1095     13056254 :             if DEBUGCOND(p) {
    1096            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  nextObs=";
    1097            0 :                 DEBUG_PRINT(nextObs);
    1098              :             }
    1099     13056254 :             p.mergeObstacles(currentObs, nextObs);
    1100              :         }
    1101     50308437 :         if DEBUGCOND(p) {
    1102            0 :             std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithNext=";
    1103            0 :             DEBUG_PRINT(currentObs);
    1104              :         }
    1105     50308437 :         p.mergeObstacles(currentObs, getNeighboringObstacles(pedestrians, ii, stripes));
    1106     50308437 :         if DEBUGCOND(p) {
    1107            0 :             std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithNeigh=";
    1108            0 :             DEBUG_PRINT(currentObs);
    1109              :         }
    1110              :         // time gap to pass the intersection ahead of a vehicle.
    1111     50308437 :         const double passingClearanceTime = p.getPerson()->getFloatParam("pedestrian.timegap-crossing");
    1112     50308437 :         const double passingLength = p.getLength() + passingClearanceTime * speed;
    1113              :         // check link state
    1114     50308437 :         if DEBUGCOND(p) {
    1115            0 :             gDebugFlag1 = true; // get debug output from MSLink
    1116            0 :             std::cout << "   link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
    1117            0 :                       << " dist=" << dist << " d2=" << dist - p.getMinGap() << " la=" << LOOKAHEAD_SAMEDIR* speed << "\n";
    1118              :         }
    1119              :         if (link != nullptr
    1120              :                 // only check close before junction, @todo we should take deceleration into account here
    1121     38722268 :                 && dist - p.getMinGap() < LOOKAHEAD_SAMEDIR * speed
    1122              :                 // persons move before vehicles so we subtract DELTA_TO because they cannot rely on vehicles having passed the intersection in the current time step
    1123     60131039 :                 && !link->opened(currentTime - DELTA_T, speed, speed, passingLength, p.getImpatience(currentTime), speed, 0, 0, nullptr, p.ignoreRed(link), p.getPerson())) {
    1124              :             // prevent movement passed a closed link
    1125       656169 :             Obstacles closedLink(stripes, Obstacle(p.getEdgePos(0) + dir * (dist - NUMERICAL_EPS), 0, OBSTACLE_LINKCLOSED, "closedLink_" + link->getViaLaneOrLane()->getID(), 0));
    1126       656169 :             p.mergeObstacles(currentObs, closedLink);
    1127       656169 :             if DEBUGCOND(p) {
    1128            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithTLS=";
    1129            0 :                 DEBUG_PRINT(currentObs);
    1130              :             }
    1131              :             // consider rerouting over another crossing
    1132       656169 :             if (p.myWalkingAreaPath != nullptr) {
    1133              :                 // @todo actually another path would be needed starting at the current position
    1134       506289 :                 const MSLane* oldNext = p.myNLI.lane;
    1135       506289 :                 p.myNLI = getNextLane(p, p.getLane(), p.myWalkingAreaPath->from);
    1136       506289 :                 if (p.myNLI.lane != oldNext) {
    1137          161 :                     unregisterCrossingApproach(p, oldNext);
    1138              :                 }
    1139              :             }
    1140       656169 :         }
    1141     50308437 :         if DEBUGCOND(p) {
    1142            0 :             gDebugFlag1 = false;
    1143              :         }
    1144     50308437 :         if (&lane->getEdge() == p.getStage()->getDestination() && p.getStage()->getDestinationStop() != nullptr) {
    1145              :             Obstacles arrival;
    1146      1321577 :             if (p.getStage()->getDestinationStop()->getWaitingCapacity() > p.getStage()->getDestinationStop()->getNumWaitingPersons()) {
    1147      2425108 :                 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() + dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival", 0));
    1148              :             } else {
    1149       218046 :                 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() - dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival_blocked", 0));
    1150              :             }
    1151      1321577 :             p.mergeObstacles(currentObs, arrival);
    1152      1321577 :         }
    1153              : 
    1154     50308437 :         if (lane->getVehicleNumberWithPartials() > 0) {
    1155              :             // react to vehicles on the same lane
    1156              :             // @todo: improve efficiency by using the same iterator for all pedestrians on this lane
    1157       268517 :             Obstacles vehObs = getVehicleObstacles(lane, dir, &p);
    1158       268517 :             p.mergeObstacles(currentObs, vehObs);
    1159       268517 :             if DEBUGCOND(p) {
    1160            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithVehs=";
    1161            0 :                 DEBUG_PRINT(currentObs);
    1162              :             }
    1163       268517 :         }
    1164     50308437 :         if (hasCrossingVehObs) {
    1165        14539 :             p.mergeObstacles(currentObs, crossingVehs);
    1166        14539 :             if DEBUGCOND(p) {
    1167            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithVehs2=";
    1168            0 :                 DEBUG_PRINT(currentObs);
    1169              :             }
    1170              :         }
    1171              : 
    1172              :         // walk, taking into account all obstacles
    1173     50308437 :         p.walk(currentObs, currentTime);
    1174     50308437 :         gDebugFlag1 = false;
    1175     50308437 :         if (!p.isWaitingToEnter() && !p.isJammed()) {
    1176     30389597 :             Obstacle o(p);
    1177     30389597 :             if (o.closer(obs[p.stripe()], dir)) {
    1178     30388037 :                 obs[p.stripe()] = o;
    1179              :             }
    1180     30389597 :             if (o.closer(obs[p.otherStripe()], dir)) {
    1181     30388029 :                 obs[p.otherStripe()] = o;
    1182              :             }
    1183     30389597 :             if (MSGlobals::gCheck4Accidents && p.myWalkingAreaPath == nullptr && !p.isJammed()) {
    1184   1452790238 :                 for (int coll = 0; coll < ii; ++coll) {
    1185   1427075554 :                     PState& c = *static_cast<PState*>(pedestrians[coll]);
    1186   1427075554 :                     if (!c.isWaitingToEnter() && c.myWalkingAreaPath == nullptr && !c.isJammed()) {
    1187    771862029 :                         if (c.stripe() == p.stripe() || p.stripe() == c.otherStripe() || p.otherStripe() == c.stripe() || p.otherStripe() == c.otherStripe()) {
    1188    316996257 :                             Obstacle cObs(c);
    1189              :                             // we check only for real collisions, no min gap violations
    1190    316996257 :                             if (p.distanceTo(cObs, false) == DIST_OVERLAP) {
    1191       598100 :                                 WRITE_WARNING("Collision of person '" + p.getPerson()->getID() + "' and person '" + c.getPerson()->getID()
    1192              :                                               + "', lane='" + lane->getID() + "', time=" + time2string(currentTime) + ".");
    1193              :                             }
    1194              :                         }
    1195              :                     }
    1196              :                 }
    1197              :             }
    1198              :         }
    1199              :         //std::cout << SIMTIME << p.getPerson()->getID() << " lane=" << lane->getID() << " x=" << p.myRelX << "\n";
    1200     95852275 :     }
    1201     15774738 : }
    1202              : 
    1203              : 
    1204              : void
    1205       537031 : MSPModel_Striping::registerCrossingApproach(const PState& ped, const MSLane* crossing, const MSLane* beforeWA) {
    1206              :     // person has entered the walkingarea
    1207       537031 :     SUMOTime arrivalTime = SIMSTEP;
    1208              :     assert(ped.getLane()->isWalkingArea());
    1209       537031 :     const WalkingAreaPath* wa = getWalkingAreaPath(&ped.getLane()->getEdge(), beforeWA, crossing);
    1210       537031 :     const double speed = ped.getStage()->getMaxSpeed(ped.getPerson()) * (1 - dawdling / 2);
    1211       537031 :     arrivalTime += TIME2STEPS(wa->length / speed);
    1212       537031 :     SUMOTime leavingTime = arrivalTime + TIME2STEPS(crossing->getLength() / speed);
    1213       537031 :     crossing->getIncomingLanes()[0].viaLink->setApproachingPerson(ped.getPerson(), arrivalTime, leavingTime);
    1214       537031 :     if DEBUGCOND(ped) {
    1215            0 :         std::cout << SIMTIME << " register " << ped.getPerson()->getID() << " at crossing " << crossing->getID() << "\n";
    1216              :     }
    1217       537031 : }
    1218              : 
    1219              : 
    1220              : bool
    1221       877522 : MSPModel_Striping::addCrossingVehs(const MSLane* crossing, int stripes, double lateral_offset, int dir, Obstacles& obs, bool prio) {
    1222              :     bool hasCrossingVehObs = false;
    1223       877522 :     const MSLink* crossingExitLink = crossing->getLinkCont().front();
    1224       877522 :     gDebugFlag1 = DEBUGCOND2(crossing);
    1225       877522 :     const MSLink::LinkLeaders linkLeaders = crossingExitLink->getLeaderInfo(nullptr, crossing->getLength());
    1226       877522 :     gDebugFlag1 = false;
    1227       877522 :     if (linkLeaders.size() > 0) {
    1228       175556 :         for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
    1229              :             // the vehicle to enter the junction first has priority
    1230        89358 :             const MSVehicle* veh = (*it).vehAndGap.first;
    1231        89358 :             if (veh != nullptr) {
    1232        89358 :                 Obstacle vo((*it).distToCrossing, 0, OBSTACLE_VEHICLE, veh->getID(), veh->getVehicleType().getWidth() + 2 * minGapToVehicle, veh);
    1233              :                 // block entry to the crossing in walking direction but allow leaving it
    1234        89358 :                 Obstacle voBlock = vo;
    1235        89358 :                 if (dir == FORWARD) {
    1236        51745 :                     voBlock.xBack = NUMERICAL_EPS;
    1237              :                 } else {
    1238        37613 :                     voBlock.xFwd = crossing->getLength() - NUMERICAL_EPS;
    1239              :                 }
    1240              :                 // when approaching a priority crossings, vehicles must be able
    1241              :                 // to brake, otherwise the person must be able to cross in time
    1242        89358 :                 const double distToCrossBeforeVeh = (dir == FORWARD ? vo.xFwd : crossing->getLength() - vo.xBack);
    1243              :                 const double bGap = (prio
    1244        91021 :                                      ? veh->getCarFollowModel().brakeGap(veh->getSpeed(), veh->getCarFollowModel().getMaxDecel(), 0)
    1245         1663 :                                      : veh->getSpeed() * distToCrossBeforeVeh); // walking 1m/s
    1246              :                 double vehYmin;
    1247              :                 double vehYmax;
    1248              :                 // relY increases from left to right (the other way around from vehicles)
    1249        89358 :                 if ((*it).fromLeft()) {
    1250        70015 :                     vehYmin = -(*it).vehAndGap.second + lateral_offset; // vehicle back
    1251        70015 :                     vehYmax = vehYmin + veh->getVehicleType().getLength() + bGap + minGapToVehicle;
    1252        70015 :                     vehYmin -= minGapToVehicle;
    1253              :                 } else {
    1254        19343 :                     vehYmax = crossing->getWidth() + (*it).vehAndGap.second - lateral_offset; // vehicle back
    1255        19343 :                     vehYmin = vehYmax - veh->getVehicleType().getLength() - bGap - minGapToVehicle;
    1256        19343 :                     vehYmax += minGapToVehicle;
    1257              : 
    1258              :                 }
    1259       323621 :                 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax), stripes); ++s) {
    1260       142256 :                     if ((dir == FORWARD && obs[s].xBack > vo.xBack)
    1261       234510 :                             || (dir == BACKWARD && obs[s].xFwd < vo.xFwd)) {
    1262       233675 :                         if (!prio && veh->getSpeed() > SUMO_const_haltingSpeed) {
    1263              :                             // do not enter the crossing
    1264         9308 :                             obs[s] = voBlock;
    1265              :                         } else {
    1266       224367 :                             obs[s] = vo;
    1267              :                         }
    1268              :                         hasCrossingVehObs = true;
    1269              :                     }
    1270              :                 }
    1271        89358 :                 if (DEBUGCOND2(crossing)) {
    1272            0 :                     std::cout << SIMTIME
    1273              :                               << " crossingVeh=" << veh->getID()
    1274              :                               << " lane=" << crossing->getID()
    1275              :                               << " prio=" << prio
    1276              :                               << " latOffset=" << lateral_offset
    1277              :                               << " dir=" << dir
    1278            0 :                               << " stripes=" << stripes
    1279            0 :                               << " dist=" << (*it).distToCrossing
    1280            0 :                               << " gap=" << (*it).vehAndGap.second
    1281              :                               << " brakeGap=" << bGap
    1282              :                               << " fromLeft=" << (*it).fromLeft()
    1283              :                               << " distToCrossBefore=" << distToCrossBeforeVeh
    1284              :                               << " ymin=" << vehYmin
    1285              :                               << " ymax=" << vehYmax
    1286              :                               << " smin=" << PState::stripe(vehYmin)
    1287            0 :                               << " smax=" << PState::stripe(vehYmax)
    1288            0 :                               << "\n";
    1289            0 :                     DEBUG_PRINT(obs);
    1290              :                 }
    1291              :             }
    1292              :         }
    1293        86198 :         if (hasCrossingVehObs) {
    1294              :             // check whether the crossing is fully blocked
    1295        51548 :             const int reserved = getReserved((int)obs.size(), RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS);
    1296              :             bool allBlocked = true;
    1297              : 
    1298       285043 :             for (int i = 0; i < (int)obs.size(); i++) {
    1299       253760 :                 const Obstacle& o = obs[i];
    1300       253760 :                 if (o.type != OBSTACLE_VEHICLE && (
    1301        36528 :                             (dir == FORWARD && i >= reserved) ||
    1302        24198 :                             (dir == BACKWARD && i < (int)obs.size() - reserved))) {
    1303              :                     allBlocked = false;
    1304              :                     break;
    1305              :                 }
    1306              :             }
    1307        51548 :             if (allBlocked) {
    1308        31283 :                 if (DEBUGCOND2(crossing)) {
    1309            0 :                     std::cout << SIMTIME << " crossing=" << crossing->getID() << " allBlocked\n";
    1310              :                 }
    1311       220240 :                 for (Obstacle& o : obs) {
    1312       188957 :                     if (dir == FORWARD) {
    1313       112214 :                         o.xBack = NUMERICAL_EPS;
    1314              :                     } else {
    1315        76743 :                         o.xFwd = crossing->getLength() - NUMERICAL_EPS;
    1316              :                     }
    1317              :                 }
    1318              :             }
    1319              :         }
    1320              :     }
    1321       877522 :     return hasCrossingVehObs;
    1322       877522 : }
    1323              : 
    1324              : 
    1325              : MSPModel_Striping::Obstacles
    1326       286973 : MSPModel_Striping::getVehicleObstacles(const MSLane* lane, int dir, PState* ped) {
    1327       286973 :     const int stripes = numStripes(lane);
    1328       573946 :     Obstacles vehObs(stripes, Obstacle(dir));
    1329              :     int current = -1;
    1330              :     double minX = 0.;
    1331              :     double maxX = 0.;
    1332              :     double pRelY = -1.;
    1333              :     double pWidth = 0.;
    1334              :     std::string pID;
    1335       286973 :     bool debug = DEBUGCOND2(lane);
    1336       286973 :     if (ped != nullptr) {
    1337       268517 :         current = ped->stripe();
    1338       268517 :         minX = ped->getMinX();
    1339       268517 :         maxX = ped->getMaxX();
    1340              :         pRelY = ped->getPosLat();
    1341       268517 :         pWidth = ped->getPerson()->getVehicleType().getWidth();
    1342              :         pID = ped->getPerson()->getID();
    1343       268517 :         debug = DEBUGCOND(*ped);
    1344        18456 :     } else if (dir == BACKWARD) {
    1345              :         // checking vehicles on the next lane. Use entry point as reference
    1346              :         minX = lane->getLength();
    1347              :         maxX = lane->getLength();
    1348              :     }
    1349       286973 :     MSLane::AnyVehicleIterator begin = (dir == FORWARD ? lane->anyVehiclesUpstreamBegin() : lane->anyVehiclesBegin());
    1350              :     MSLane::AnyVehicleIterator end = (dir == FORWARD ? lane->anyVehiclesUpstreamEnd() : lane->anyVehiclesEnd());
    1351       740130 :     for (MSLane::AnyVehicleIterator it = begin; it != end; ++it) {
    1352       453157 :         const MSVehicle* veh = *it;
    1353       453157 :         const bool bidi = veh->getLane() == lane->getBidiLane();
    1354       453157 :         const double vehBack = veh->getBackPositionOnLane(lane);
    1355       453157 :         double vehFront = vehBack + veh->getVehicleType().getLength();
    1356              :         // ensure that vehicles are not blocked
    1357       453157 :         const double vehNextSpeed = veh->getWaitingTime() > DELTA_T ? 0 : MAX2(veh->getSpeed(), 1.0);
    1358       453157 :         const double clearance = SAFETY_GAP + vehNextSpeed * LOOKAHEAD_SAMEDIR;
    1359              :         // boundaries for range checking
    1360              :         double vehXMax;
    1361              :         double vehXMin;
    1362              :         double vehXMaxCheck;
    1363              :         double vehXMinCheck;
    1364       453157 :         if (bidi) {
    1365         1571 :             vehFront = vehBack - veh->getVehicleType().getLength();
    1366         1571 :             vehXMax = vehBack + SAFETY_GAP;
    1367         1571 :             vehXMin = vehFront - clearance;
    1368         1571 :             if (dir == FORWARD) {
    1369         1571 :                 vehXMaxCheck = vehBack + NUMERICAL_EPS;
    1370         1571 :                 vehXMinCheck = vehFront - LOOKAROUND_VEHICLES;
    1371              :             } else  {
    1372            0 :                 vehXMaxCheck = vehBack + LOOKAHEAD_SAMEDIR;
    1373              :                 vehXMinCheck = vehFront - clearance;
    1374              :             }
    1375              :         } else {
    1376       451586 :             vehXMax = vehFront + clearance;
    1377       451586 :             vehXMin = vehBack - SAFETY_GAP;
    1378       451586 :             if (dir == FORWARD) {
    1379              :                 vehXMaxCheck = vehFront + clearance;
    1380       328952 :                 vehXMinCheck = vehBack - LOOKAHEAD_SAMEDIR;
    1381              :             } else  {
    1382       122634 :                 vehXMaxCheck = vehFront + LOOKAROUND_VEHICLES;
    1383       122634 :                 vehXMinCheck = vehBack - NUMERICAL_EPS;
    1384              :             }
    1385              :         }
    1386       453157 :         if (debug) {
    1387            0 :             std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " check obstacle on lane=" << lane->getID()
    1388              :                       << "\n"
    1389              :                       << " vehXMin=" << vehXMin
    1390              :                       << " vehXMax=" << vehXMax
    1391              :                       << " vehXMinC=" << vehXMinCheck
    1392              :                       << " vehXMaxC=" << vehXMaxCheck
    1393              :                       << " minX=" << minX
    1394              :                       << " maxX=" << maxX
    1395              :                       << " bidi=" << bidi
    1396              :                       << " vFront=" << vehFront
    1397              :                       << " vBack=" << vehBack
    1398            0 :                       << "\n";
    1399              :         }
    1400       453157 :         if (vehXMaxCheck > minX && vehXMinCheck && vehXMinCheck <= maxX) {
    1401       351711 :             Obstacle vo(vehBack, veh->getSpeed() * (bidi ? -1 : 1), OBSTACLE_VEHICLE, veh->getID(), 0, veh);
    1402              :             // moving vehicles block space along their path
    1403       176189 :             vo.xFwd = vehXMax;
    1404       176189 :             vo.xBack = vehXMin;
    1405              :             // relY increases from left to right (the other way around from vehicles)
    1406              :             // XXX lateral offset for partial vehicles
    1407       176189 :             const double posLat = veh->getLateralPositionOnLane() * (bidi ? -1 : 1);
    1408       176189 :             const double vehYmax = 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - stripeWidth) - posLat;
    1409       176189 :             const double vehYmin = vehYmax - veh->getVehicleType().getWidth();
    1410       752624 :             for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax) + 1, stripes); ++s) {
    1411       576435 :                 Obstacle prior = vehObs[s];
    1412              :                 vehObs[s] = vo;
    1413       576435 :                 if (s == current && vehFront + SAFETY_GAP < minX) {
    1414              :                     // ignore if already overlapping while vehicle is still behind
    1415        16402 :                     if (pRelY - pWidth < vehYmax &&
    1416        16153 :                             pRelY + pWidth > vehYmin && dir == FORWARD) {
    1417         9996 :                         if (debug) {
    1418            0 :                             std::cout << "   ignoring vehicle '" << veh->getID() << " on stripe " << s << " vehFrontSG=" << vehFront + SAFETY_GAP << " minX=" << minX << "\n";
    1419              :                         }
    1420              :                         if (dir == FORWARD) {
    1421              :                             vehObs[s] = prior;
    1422              :                         } else {
    1423              :                             vehObs[s].xFwd = MIN2(vo.xFwd, vehFront + SAFETY_GAP);
    1424              :                         }
    1425              :                     }
    1426              :                 }
    1427              :             }
    1428       176189 :             if (debug) {
    1429            0 :                 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " obstacle on lane=" << lane->getID()
    1430              :                           << "\n"
    1431              :                           << "     ymin=" << vehYmin
    1432              :                           << " ymax=" << vehYmax
    1433              :                           << " smin=" << PState::stripe(vehYmin)
    1434            0 :                           << " smax=" << PState::stripe(vehYmax)
    1435            0 :                           << " relY=" << pRelY
    1436              :                           << " current=" << current
    1437            0 :                           << " vo.xFwd=" << vo.xFwd
    1438            0 :                           << " vo.xBack=" << vo.xBack
    1439              :                           << " vFront=" << vehFront
    1440              :                           << " vBack=" << vehBack
    1441            0 :                           << "\n";
    1442              :             }
    1443              :         }
    1444              :     }
    1445       286973 :     return vehObs;
    1446            0 : }
    1447              : 
    1448              : 
    1449              : // ===========================================================================
    1450              : // MSPModel_Striping::Obstacle method definitions
    1451              : // ===========================================================================
    1452     66370148 : MSPModel_Striping::Obstacle::Obstacle(int dir, double dist) :
    1453     66370148 :     xFwd(dir * dist),  // by default, far away when seen in dir
    1454     66370148 :     xBack(dir * dist),  // by default, far away when seen in dir
    1455     66370148 :     speed(0),
    1456     66370148 :     type(OBSTACLE_NONE),
    1457     66370148 :     description("") {
    1458     66370148 : }
    1459              : 
    1460              : 
    1461    472890085 : MSPModel_Striping::Obstacle::Obstacle(const PState& ped) :
    1462    472890085 :     xFwd(ped.getMaxX()),
    1463    472890085 :     xBack(ped.getMinX()),
    1464    472890085 :     speed(ped.getDirection() * ped.getSpeed(*ped.getStage())),
    1465    472890085 :     type(ped.getOType()),
    1466    472890085 :     description(ped.getID()) {
    1467              :     assert(!ped.isWaitingToEnter());
    1468    472890085 :     if (type == OBSTACLE_VEHICLE) {
    1469       464765 :         vehicle = static_cast<const PStateVehicle&>(ped).getVehicle();
    1470              :     }
    1471    472890085 : }
    1472              : 
    1473              : 
    1474              : bool
    1475    113969838 : MSPModel_Striping::Obstacle::closer(const Obstacle& o, int dir) {
    1476    113969838 :     if (dir == FORWARD) {
    1477     61296314 :         return xBack <= o.xBack;
    1478              :     } else {
    1479     52673524 :         return xFwd >= o.xFwd;
    1480              :     }
    1481              : }
    1482              : 
    1483              : 
    1484              : // ===========================================================================
    1485              : // MSPModel_Striping::PState method definitions
    1486              : // ===========================================================================
    1487       215143 : MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, const MSLane* lane):
    1488              :     MSPModel_InteractingState(person, stage, lane),
    1489       215143 :     myWalkingAreaPath(nullptr) {
    1490              :     const MSEdge* currentEdge = &lane->getEdge();
    1491              :     const ConstMSEdgeVector& route = myStage->getRoute();
    1492              :     assert(!route.empty());
    1493       215143 :     myDir = FORWARD;
    1494       215143 :     if (route.size() == 1) {
    1495              :         // only a single edge, move towards end pos
    1496        13175 :         myDir = (myEdgePos <= myStage->getArrivalPos()) ? FORWARD : BACKWARD;
    1497       201968 :     } else if (route.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
    1498              :         // start on an intersection
    1499            8 :         if (route.front()->isWalkingArea()) {
    1500            8 :             myWalkingAreaPath = getArbitraryPath(route.front());
    1501              :         }
    1502              :     } else {
    1503       201960 :         int passedFwd = 0;
    1504       201960 :         int passedBwd = 0;
    1505       201960 :         const bool mayStartForward = canTraverse(FORWARD, route, passedFwd) != UNDEFINED_DIRECTION;
    1506       201960 :         const bool mayStartBackward = canTraverse(BACKWARD, route, passedBwd) != UNDEFINED_DIRECTION;
    1507       201960 :         if DEBUGCOND(*this) {
    1508            0 :             std::cout << "  initialize dir for " << myPerson->getID() << " forward=" << mayStartForward << " backward=" << mayStartBackward << "\n";
    1509              :         }
    1510       201960 :         if (mayStartForward && mayStartBackward) {
    1511              :             // figure out the best direction via routing
    1512              :             ConstMSEdgeVector crossingRoute;
    1513         2462 :             MSNet::getInstance()->getPedestrianRouter(0).compute(currentEdge, route.back(), myEdgePos, myStage->getArrivalPos(), myStage->getMaxSpeed(person), 0, nullptr, crossingRoute, true);
    1514         2462 :             if (crossingRoute.size() > 1) {
    1515              :                 // route found
    1516         2454 :                 const MSEdge* nextEdge = crossingRoute[1];
    1517         2454 :                 if (nextEdge->getFromJunction() == currentEdge->getFromJunction() || nextEdge->getToJunction() == currentEdge->getFromJunction()) {
    1518         2079 :                     myDir = BACKWARD;
    1519              :                 }
    1520              :             }
    1521         2462 :             if DEBUGCOND(*this) {
    1522            0 :                 std::cout << " crossingRoute=" << toString(crossingRoute) << "\n";
    1523              :             }
    1524       201960 :         } else if (!mayStartForward && !mayStartBackward) {
    1525           61 :             int lastDisconnect = passedFwd >= passedBwd ? passedFwd : passedBwd;
    1526              :             std::string dLoc;
    1527           61 :             if (route.size() > 2) {
    1528           20 :                 dLoc = TLF(" between edge '%' and edge '%'", route[lastDisconnect - 1]->getID(), route[lastDisconnect]->getID());
    1529              :             }
    1530          366 :             WRITE_WARNINGF(TL("Person '%' walking from edge '%' to edge '%' has a disconnect%, time=%."),
    1531              :                            myPerson->getID(), route.front()->getID(), route.back()->getID(), dLoc, SIMTIME);
    1532           66 :             myDir =  passedFwd >= passedBwd ? FORWARD : BACKWARD;
    1533              :         } else {
    1534       370983 :             myDir = !mayStartBackward ? FORWARD : BACKWARD;
    1535              :         }
    1536              :     }
    1537       215143 :     if (myPosLat == UNSPECIFIED_POS_LAT || myLegacyPosLat) {
    1538       214983 :         if (myPosLat == UNSPECIFIED_POS_LAT) {
    1539       214797 :             myPosLat = 0;
    1540              :         }
    1541       214983 :         if (lane->getVehicleNumberWithPartials() > 0 && myPosLat == 0) {
    1542              :             // better start next to the road if nothing was specified
    1543         2139 :             myPosLat -= stripeWidth;
    1544              :         }
    1545       214983 :         if (myDir == FORWARD || lane->getPermissions() != SVC_PEDESTRIAN) {
    1546              :             // start at the right side of the sidewalk on shared roads
    1547       180710 :             myPosLat = stripeWidth * (numStripes(lane) - 1) - myPosLat;
    1548              :         }
    1549          160 :     } else if (myPosLat == RANDOM_POS_LAT) {
    1550           20 :         myPosLat = RandHelper::rand() * stripeWidth * (numStripes(lane) - 1);
    1551              :     } else {
    1552              :         // vehicle to striping coordinate system
    1553          140 :         myPosLat = posLatConversion(myPosLat, lane->getWidth());
    1554              :     }
    1555       215143 :     if DEBUGCOND(*this) {
    1556            0 :         std::cout << "  added new pedestrian " << myPerson->getID() << " on " << lane->getID() << " myEdgePos=" << myEdgePos << " myPosLat=" << myPosLat << " dir=" << myDir << " route=" << toString(myStage->getRoute()) << "\n";
    1557              :     }
    1558              : 
    1559       215143 :     myNLI = getNextLane(*this, lane, nullptr);
    1560       215139 : }
    1561              : 
    1562              : 
    1563           14 : MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, std::istringstream* in) :
    1564              :     MSPModel_InteractingState(person, stage, nullptr),
    1565           14 :     myWalkingAreaPath(nullptr) {
    1566           14 :     if (in != nullptr) {
    1567              :         std::string laneID;
    1568              :         std::string wapLaneFrom;
    1569              :         std::string wapLaneTo;
    1570              :         std::string nextLaneID;
    1571              :         std::string nextLinkFrom;
    1572              :         std::string nextLinkTo;
    1573              :         int nextDir;
    1574              : 
    1575           14 :         (*in) >> laneID
    1576           14 :               >> myEdgePos >> myPosLat >> myDir >> mySpeed >> mySpeedLat >> myWaitingToEnter >> myWaitingTime
    1577           14 :               >> wapLaneFrom >> wapLaneTo
    1578           14 :               >> myAmJammed
    1579              :               >> nextLaneID
    1580              :               >> nextLinkFrom
    1581           14 :               >> nextLinkTo
    1582           14 :               >> nextDir;
    1583              : 
    1584              : 
    1585           14 :         myLane = MSLane::dictionary(laneID);
    1586           14 :         if (myLane == nullptr) {
    1587            0 :             throw ProcessError("Unknown lane '" + laneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1588              :         }
    1589              : 
    1590              :         MSLane* nextLane = nullptr;
    1591           14 :         if (nextLaneID != "null") {
    1592           13 :             nextLane = MSLane::dictionary(nextLaneID);
    1593           13 :             if (nextLane == nullptr) {
    1594            0 :                 throw ProcessError("Unknown next lane '" + nextLaneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1595              :             }
    1596              :         }
    1597              :         const MSLink* link = nullptr;
    1598           14 :         if (nextLinkFrom != "null") {
    1599            2 :             MSLane* from = MSLane::dictionary(nextLinkFrom);
    1600            2 :             MSLane* to = MSLane::dictionary(nextLinkTo);
    1601            2 :             if (from == nullptr) {
    1602            0 :                 throw ProcessError("Unknown link origin lane '" + nextLinkFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1603              :             }
    1604            2 :             if (to == nullptr) {
    1605            0 :                 throw ProcessError("Unknown link destination lane '" + nextLinkTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1606              :             }
    1607            2 :             link = from->getLinkTo(to);
    1608              :         }
    1609           14 :         myNLI =  NextLaneInfo(nextLane, link, nextDir);
    1610              : 
    1611           14 :         if (wapLaneFrom != "null") {
    1612            1 :             MSLane* from = MSLane::dictionary(wapLaneFrom);
    1613            1 :             MSLane* to = MSLane::dictionary(wapLaneTo);
    1614            1 :             if (from == nullptr) {
    1615            0 :                 throw ProcessError("Unknown walkingAreaPath origin lane '" + wapLaneFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1616              :             }
    1617            1 :             if (to == nullptr) {
    1618            0 :                 throw ProcessError("Unknown walkingAreaPath destination lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1619              :             }
    1620            1 :             const auto pathIt = myWalkingAreaPaths.find(std::make_pair(from, to));
    1621            1 :             if (pathIt != myWalkingAreaPaths.end()) {
    1622            1 :                 myWalkingAreaPath = &pathIt->second;
    1623              :             } else {
    1624            0 :                 throw ProcessError("Unknown walkingAreaPath from lane '" + wapLaneFrom + "' to lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1625              :             }
    1626              :         }
    1627              :     }
    1628           14 : }
    1629              : 
    1630              : 
    1631       438942 : MSPModel_Striping::PState::PState() :
    1632       438942 :     MSPModel_InteractingState(nullptr, nullptr, nullptr) {}
    1633              : 
    1634              : 
    1635              : void
    1636            9 : MSPModel_Striping::PState::saveState(std::ostringstream& out) {
    1637            9 :     std::string wapLaneFrom = "null";
    1638            9 :     std::string wapLaneTo = "null";
    1639            9 :     if (myWalkingAreaPath != nullptr) {
    1640            1 :         wapLaneFrom = myWalkingAreaPath->from->getID();
    1641            1 :         wapLaneTo = myWalkingAreaPath->to->getID();
    1642              :     }
    1643            9 :     std::string nextLaneID = "null";
    1644            9 :     std::string nextLinkFrom = "null";
    1645            9 :     std::string nextLinkTo = "null";
    1646            9 :     if (myNLI.lane != nullptr) {
    1647              :         nextLaneID = myNLI.lane->getID();
    1648              :     }
    1649            9 :     if (myNLI.link != nullptr) {
    1650              :         nextLinkFrom = myNLI.link->getLaneBefore()->getID();
    1651            2 :         nextLinkTo = myNLI.link->getViaLaneOrLane()->getID();
    1652              :     }
    1653            9 :     out << " " << myLane->getID()
    1654           18 :         << " " << myEdgePos
    1655            9 :         << " " << myPosLat
    1656              :         << " " << myDir
    1657           18 :         << " " << mySpeed
    1658            9 :         << " " << mySpeedLat
    1659            9 :         << " " << myWaitingToEnter
    1660            9 :         << " " << myWaitingTime
    1661              :         << " " << wapLaneFrom
    1662              :         << " " << wapLaneTo
    1663            9 :         << " " << myAmJammed
    1664              :         << " " << nextLaneID
    1665              :         << " " << nextLinkFrom
    1666              :         << " " << nextLinkTo
    1667            9 :         << " " << myNLI.dir;
    1668            9 : }
    1669              : 
    1670              : double
    1671   1562274772 : MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
    1672              :     // @todo speed should have an influence here because faster persons need more space
    1673   1562274772 :     if (myDir == FORWARD) {
    1674   1400369022 :         return myEdgePos - getLength();
    1675              :     }
    1676    161905750 :     return myEdgePos - (includeMinGap ? getMinGap() : 0.);
    1677              : }
    1678              : 
    1679              : 
    1680              : double
    1681   1562274772 : MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
    1682              :     // @todo speed should have an influence here because faster persons need more space
    1683   1562274772 :     if (myDir == FORWARD) {
    1684   1400369022 :         return myEdgePos + (includeMinGap ? getMinGap() : 0.);
    1685              :     }
    1686    161905750 :     return myEdgePos + getLength();
    1687              : }
    1688              : 
    1689              : 
    1690              : double
    1691   1612583209 : MSPModel_Striping::PState::getLength() const {
    1692   1612583209 :     return myPerson->getVehicleType().getLength();
    1693              : }
    1694              : 
    1695              : 
    1696              : double
    1697   1012708360 : MSPModel_Striping::PState::getMinGap() const {
    1698   1012708360 :     return myPerson->getVehicleType().getMinGap();
    1699              : }
    1700              : 
    1701              : 
    1702              : int
    1703   4954261896 : MSPModel_Striping::PState::stripe(double relY) {
    1704   4954261896 :     return (int)floor(relY / stripeWidth + 0.5);
    1705              : }
    1706              : 
    1707              : 
    1708              : int
    1709   2125507779 : MSPModel_Striping::PState::otherStripe(double relY) const {
    1710   2125507779 :     const int s = stripe(relY);
    1711   2125507779 :     const double offset = relY - s * stripeWidth;
    1712   2125507779 :     const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
    1713              :     int result;
    1714   2125507779 :     if (offset > threshold) {
    1715       478532 :         result = s + 1;
    1716   2125029247 :     } else if (offset < -threshold) {
    1717       397150 :         result = s - 1;
    1718              :     } else {
    1719              :         result = s;
    1720              :     }
    1721              :     //std::cout.setf(std::ios::fixed , std::ios::floatfield);
    1722              :     //std::cout << std::setprecision(5);
    1723              :     //if DEBUGCOND(*this) std::cout << "  otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
    1724   2125507779 :     return result;
    1725              : }
    1726              : 
    1727              : int
    1728   2803792164 : MSPModel_Striping::PState::stripe() const {
    1729   2803792164 :     return MIN2(MAX2(0, stripe(myPosLat)), numStripes(myLane) - 1);
    1730              : }
    1731              : 
    1732              : 
    1733              : int
    1734   2111557772 : MSPModel_Striping::PState::otherStripe() const {
    1735   2111557772 :     return MIN2(MAX2(0, otherStripe(myPosLat)), numStripes(myLane) - 1);
    1736              : }
    1737              : 
    1738              : 
    1739              : double
    1740    102708183 : MSPModel_Striping::PState::distToLaneEnd() const {
    1741    102708183 :     if (myStage->getNextRouteEdge() == nullptr) {
    1742     21762721 :         return myDir * (myStage->getArrivalPos() - myEdgePos) - POSITION_EPS - (
    1743      1370352 :                    (myWaitingTime > DELTA_T && (myStage->getDestinationStop() == nullptr ||
    1744              :                                                 myStage->getDestinationStop()->getWaitingCapacity() > myStage->getDestinationStop()->getNumWaitingPersons()))
    1745     23133073 :                    ? getMinGap() : 0);
    1746              :     } else {
    1747     80945462 :         const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
    1748     80945462 :         return myDir == FORWARD ? length - myEdgePos : myEdgePos;
    1749              :     }
    1750              : }
    1751              : 
    1752              : 
    1753              : bool
    1754       873531 : MSPModel_Striping::PState::moveToNextLane(SUMOTime currentTime) {
    1755       873531 :     double dist = distToLaneEnd();
    1756       873531 :     if (DEBUGCOND(*this)) {
    1757            0 :         std::cout << SIMTIME << " ped=" << myPerson->getID() << " myEdgePos=" << myEdgePos << " dist=" << dist << "\n";
    1758              :     }
    1759       873531 :     if (dist <= 0) {
    1760              :         //if (ped.getPerson()->getID() == DEBUG1) {
    1761              :         //    std::cout << SIMTIME << " addToLane x=" << ped.myEdgePos << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
    1762              :         //}
    1763              :         //std::cout << " changing to " << newLane->getID() << " myPosLat=" << ped.myPosLat << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
    1764              :         //std::cout << " newY=" << ped.myPosLat << " myDir=" << ped.getDirection() << " newDir=" << newDir;
    1765       873531 :         const int oldDir = myDir;
    1766       873531 :         const MSLane* oldLane = myLane;
    1767       873531 :         myLane = myNLI.lane;
    1768       873531 :         myDir = myNLI.dir;
    1769       873531 :         const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
    1770       873531 :         if DEBUGCOND(*this) {
    1771            0 :             std::cout << SIMTIME
    1772            0 :                       << " ped=" << myPerson->getID()
    1773              :                       << " moveToNextLane old=" << oldLane->getID()
    1774            0 :                       << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
    1775              :                       << " oldDir=" << oldDir
    1776            0 :                       << " newDir=" << myDir
    1777            0 :                       << " myEdgePos=" << myEdgePos
    1778              :                       << " dist=" << dist
    1779            0 :                       << "\n";
    1780              :         }
    1781       873531 :         if (myLane == nullptr) {
    1782       193984 :             myEdgePos = myStage->getArrivalPos();
    1783              :         }
    1784              :         // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
    1785       873531 :         if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
    1786       193984 :             myLane = nullptr;
    1787              :         } else {
    1788       679547 :             const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, oldDir, normalLane ? nullptr : &myLane->getEdge());
    1789              :             UNUSED_PARAMETER(arrived);
    1790              :             assert(!arrived);
    1791              :             assert(myDir != UNDEFINED_DIRECTION);
    1792       679547 :             myNLI = getNextLane(*this, myLane, oldLane);
    1793              :             // reminders must be called after updated myNLI (to ensure that getNextEdgePtr returns the correct edge)
    1794       679547 :             myStage->activateEntryReminders(myPerson);
    1795              :             assert(myNLI.lane != oldLane); // do not turn around
    1796       679547 :             if DEBUGCOND(*this) {
    1797            0 :                 std::cout << "    nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
    1798              :             }
    1799       679547 :             if (myLane->getEdge().isWalkingArea()) {
    1800       306629 :                 if (myNLI.dir != UNDEFINED_DIRECTION) {
    1801       306592 :                     myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
    1802              :                     assert(myWalkingAreaPath->shape.size() >= 2);
    1803       306592 :                     if DEBUGCOND(*this) {
    1804            0 :                         std::cout << "  mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
    1805              :                     }
    1806           37 :                 } else if (myNLI.link != nullptr) {
    1807              :                     // using direct connection (instead of using walkingarea)
    1808           17 :                     myLane = myNLI.lane;
    1809              :                     assert(!myLane->getEdge().isWalkingArea());
    1810           17 :                     myStage->moveToNextEdge(myPerson, currentTime, myDir, &myLane->getEdge());
    1811           17 :                     myWalkingAreaPath = nullptr;
    1812           17 :                     myNLI = getNextLane(*this, myLane, oldLane);
    1813              :                 } else {
    1814              :                     // disconnected route. move to the next edge
    1815           40 :                     if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
    1816              :                         // try to determine direction from topology, otherwise maintain current direction
    1817           16 :                         const MSEdge* currRouteEdge = *myStage->getRouteStep();
    1818           16 :                         const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
    1819              :                         if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
    1820           16 :                                 || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
    1821            4 :                             myDir = BACKWARD;
    1822              :                         } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
    1823           12 :                                    || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
    1824           12 :                             myDir = FORWARD;
    1825              :                         }
    1826           16 :                         myStage->moveToNextEdge(myPerson, currentTime, oldDir, nullptr);
    1827           16 :                         myLane = myNLI.lane;
    1828              :                         assert(myLane != 0);
    1829              :                         assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
    1830           16 :                         myNLI = getNextLane(*this, myLane, oldLane);
    1831           16 :                         myWalkingAreaPath = nullptr;
    1832              :                     } else {
    1833           12 :                         throw ProcessError(TLF("Disconnected walk for person '%'.", myPerson->getID()));
    1834              :                     }
    1835              :                 }
    1836              :             } else {
    1837       372918 :                 myWalkingAreaPath = nullptr;
    1838              :             }
    1839              :             // adapt x to fit onto the new lane
    1840              :             // (make sure we do not move past the end of the new lane since that
    1841              :             // lane was not checked for obstacles)
    1842       679543 :             const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
    1843       679543 :             if (-dist > newLength) {
    1844              :                 assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
    1845              :                 // should not happen because the end of myLane should have been an obstacle as well
    1846              :                 // (only when the route is broken)
    1847            1 :                 dist = -newLength;
    1848              :             }
    1849       679543 :             if (myDir == BACKWARD) {
    1850       133721 :                 myEdgePos = newLength + dist;
    1851              :             } else {
    1852       545822 :                 myEdgePos = -dist;
    1853              :             }
    1854       679543 :             if DEBUGCOND(*this) {
    1855            0 :                 std::cout << SIMTIME << " update myEdgePos ped=" << myPerson->getID()
    1856              :                           << " newLength=" << newLength
    1857              :                           << " dist=" << dist
    1858            0 :                           << " myEdgePos=" << myEdgePos
    1859            0 :                           << "\n";
    1860              :             }
    1861              :             // adjust to change in direction
    1862       679543 :             if (myDir != oldDir) {
    1863        30970 :                 myPosLat = (numStripes(oldLane) - 1) * stripeWidth - myPosLat;
    1864              :             }
    1865              :             // adjust to differences in sidewalk width
    1866      1346946 :             const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
    1867       679543 :             myPosLat += offset * stripeWidth;
    1868       679543 :             if DEBUGCOND(*this) {
    1869            0 :                 std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
    1870            0 :                           << " newLane=" << Named::getIDSecure(myLane)
    1871            0 :                           << " newY=" << myPosLat
    1872            0 :                           << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
    1873            0 :                           << " od=" << oldDir << " nd=" << myDir
    1874            0 :                           << " offset=" << offset << "\n";
    1875              :             }
    1876              :         }
    1877       873527 :         myAngle = std::numeric_limits<double>::max(); // see #9014
    1878       873527 :         return true;
    1879              :     } else {
    1880              :         return false;
    1881              :     }
    1882              : }
    1883              : 
    1884              : 
    1885              : int
    1886     50359985 : MSPModel_Striping::getReserved(int stripes, double factor) {
    1887     50359985 :     return MIN2(
    1888     50359985 :                (int)floor(stripes * factor),
    1889     50359985 :                (int)floor(RESERVE_FOR_ONCOMING_MAX / stripeWidth));
    1890              : }
    1891              : 
    1892              : void
    1893     50308437 : MSPModel_Striping::PState::walk(const Obstacles& obs, SUMOTime currentTime) {
    1894     50308437 :     const int stripes = (int)obs.size();
    1895     50308437 :     const int sMax =  stripes - 1;
    1896              :     assert(stripes == numStripes(myLane));
    1897              :     // account stage-specific max speed but also for normal lane speed limit
    1898              :     // (speed limits on crossings and walkingareas ignored due to #11527)
    1899     50308437 :     const double vMax = (myStage->getConfiguredSpeed() >= 0
    1900     50308437 :                          ? myStage->getConfiguredSpeed()
    1901     56670158 :                          : (myLane->isNormal() || myLane->isInternal()
    1902     50454908 :                             ? myLane->getVehicleMaxSpeed(myPerson)
    1903      6215250 :                             : myStage->getMaxSpeed(myPerson)));
    1904              :     // ultimate goal is to choose the preferred stripe (chosen)
    1905     50308437 :     const int current = stripe();
    1906     50308437 :     const int other = otherStripe();
    1907              :     // compute distances
    1908     50308437 :     std::vector<double> distance(stripes);
    1909    223434298 :     for (int i = 0; i < stripes; ++i) {
    1910    173125861 :         distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
    1911              :     }
    1912              :     // compute utility for all stripes
    1913     50308437 :     std::vector<double> utility(stripes, 0);
    1914              :     // forbid stripes which are blocked and also all stripes behind them
    1915    223434298 :     for (int i = 0; i < stripes; ++i) {
    1916    173125861 :         if (distance[i] == DIST_OVERLAP) {
    1917     63066716 :             if (i == current && (!isWaitingToEnter() || stripe() != stripe(myPosLat))) {
    1918      3550090 :                 utility[i] += OBSTRUCTED_PENALTY;
    1919              :             }
    1920     63066716 :             if (i < current) {
    1921     91283660 :                 for (int j = 0; j <= i; ++j) {
    1922     56766155 :                     utility[j] += OBSTRUCTED_PENALTY;
    1923              :                 }
    1924              :             }
    1925     63066716 :             if (i > current) {
    1926     42059417 :                 for (int j = i; j < stripes; ++j) {
    1927     24712412 :                     utility[j] += OBSTRUCTED_PENALTY;
    1928              :                 }
    1929              :             }
    1930              :         }
    1931              :     }
    1932              :     // forbid a portion of the leftmost stripes (in walking direction).
    1933              :     // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
    1934              :     // may still deadlock in heavy pedestrian traffic
    1935     50308437 :     const bool onJunction = myLane->getEdge().isWalkingArea() || myLane->getEdge().isCrossing();
    1936     50308437 :     const int reserved = getReserved(stripes, (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
    1937     50308437 :     if (myDir == FORWARD) {
    1938     51851767 :         for (int i = 0; i < reserved; ++i) {
    1939     13013805 :             utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
    1940              :         }
    1941              :     } else {
    1942      6471837 :         for (int i = sMax; i > sMax - reserved; --i) {
    1943      2599923 :             utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
    1944              :         }
    1945              :     }
    1946              :     // adapt utility based on obstacles
    1947    223434298 :     for (int i = 0; i < stripes; ++i) {
    1948    173125861 :         if (obs[i].speed * myDir < 0) {
    1949              :             // penalize evasion to the left unless the obstacle is a vehicle
    1950      4333087 :             if ((myDir == FORWARD || obs[i].type == OBSTACLE_VEHICLE) && i > 0) {
    1951       819118 :                 utility[i - 1] -= 0.5;
    1952      3513969 :             } else if (myDir == BACKWARD && i < sMax) {
    1953       608217 :                 utility[i + 1] -= 0.5;
    1954              :             }
    1955              :         }
    1956              :         // compute expected distance achievable by staying on this stripe for a time horizon
    1957    173125861 :         const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
    1958    173125861 :         const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
    1959    173125861 :         const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
    1960    173125861 :         if (expectedDist >= 0) {
    1961    170002673 :             utility[i] += expectedDist;
    1962              :         } else {
    1963              :             // let only the distance count
    1964      3123188 :             utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
    1965              :         }
    1966              :     }
    1967              :     // discourage use of the leftmost stripe (in walking direction) if there are oncoming
    1968     50308437 :     if (myDir == FORWARD && obs[0].speed < 0) {
    1969      1439366 :         utility[0] += ONCOMING_CONFLICT_PENALTY;
    1970     48869071 :     } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
    1971      1470185 :         utility[sMax] += ONCOMING_CONFLICT_PENALTY;
    1972              :     }
    1973              :     // penalize lateral movement (if the current stripe permits walking)
    1974     50308437 :     if (distance[current] > 0 && myWaitingTime == 0) {
    1975    120092744 :         for (int i = 0; i < stripes; ++i) {
    1976     94205408 :             utility[i] += abs(i - current) * LATERAL_PENALTY;
    1977              :         }
    1978              :     }
    1979              :     // walk on the right side on shared space
    1980     50308437 :     if (myLane->getPermissions() != SVC_PEDESTRIAN && myDir == BACKWARD) {
    1981      2233302 :         for (int i = 0; i < stripes; ++i) {
    1982      1861373 :             if (i <= current) {
    1983      1790872 :                 utility[i] += (sMax - i + 1) * LATERAL_PENALTY;
    1984              :             }
    1985              :         }
    1986              :     }
    1987              : 
    1988              :     // select best stripe
    1989              :     int chosen = current;
    1990    223434298 :     for (int i = 0; i < stripes; ++i) {
    1991    173125861 :         if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
    1992              :             chosen = i;
    1993              :         }
    1994              :     }
    1995              :     // compute speed components along both axes
    1996     50308437 :     const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
    1997     50308437 :     double xDist = MIN3(distance[current], distance[other], distance[next]);
    1998     50308437 :     if (next != chosen) {
    1999              :         // ensure that we do not collide with an obstacle in the stripe beyond
    2000              :         // next as this might become the 'other' stripe in the next step
    2001       454195 :         const int nextOther = chosen < current ? current - 2 : current + 2;
    2002       454195 :         xDist = MIN2(xDist, distance[nextOther]);
    2003              :     }
    2004              :     // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
    2005              :     const double preferredGap = NUMERICAL_EPS;
    2006     50308437 :     double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
    2007     50308437 :     if (xSpeed < NUMERICAL_EPS) {
    2008              :         xSpeed = 0.;
    2009              :     }
    2010     50308437 :     if (DEBUGCOND(*this)) {
    2011            0 :         std::cout << " xSpeedPotential=" << xSpeed << "\n";
    2012              :     }
    2013              :     // avoid tiny steps
    2014              :     // XXX pressure from behind?
    2015     50308437 :     if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
    2016              :             // unless walking towards a short lane
    2017     19633427 :             !(
    2018     19908903 :                 (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
    2019     19633446 :                 || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
    2020     19633427 :                 || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
    2021              :        ) {
    2022              :         xSpeed = 0;
    2023              :     }
    2024     30675012 :     if (xSpeed == 0) {
    2025     23058877 :         if (DEBUGCOND(*this)) {
    2026            0 :             std::cout << " sharedWA=" << (myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())
    2027            0 :                       << " vehObs=" << Named::getIDSecure(obs[current].vehicle)
    2028            0 :                       << " vehWait=" << STEPS2TIME(obs[current].vehicle ? obs[current].vehicle->getWaitingTime() : 0)
    2029            0 :                       << "\n";
    2030              :         }
    2031     23058877 :         if (myWaitingTime > ((myLane->getEdge().isCrossing()
    2032              :                               // treat shared walkingarea like a crossing to avoid deadlocking vehicles
    2033     23051179 :                               || (myLane->getEdge().isWalkingArea() && obs[current].vehicle != nullptr && obs[current].vehicle->getWaitingTime() > jamTimeCrossing
    2034     46110366 :                                   && myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())) ? jamTimeCrossing : jamTime)
    2035     23009216 :                 || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
    2036     46039509 :                 || myAmJammed) {
    2037              :             // squeeze slowly through the crowd ignoring others
    2038      3986929 :             if (!myAmJammed) {
    2039        63626 :                 MSNet::getInstance()->getPersonControl().registerJammed();
    2040       254504 :                 WRITE_WARNINGF(TL("Person '%' is jammed on edge '%', time=%."),
    2041              :                                myPerson->getID(), myStage->getEdge()->getID(), time2string(SIMSTEP));
    2042        63626 :                 myAmJammed = true;
    2043              :             }
    2044      3986929 :             xSpeed = vMax * jamFactor;
    2045              :         }
    2046     27249560 :     } else if (myAmJammed && stripe(myPosLat) >= 0 && stripe(myPosLat) <= sMax && xDist >= MIN_STARTUP_DIST)  {
    2047        58273 :         myAmJammed = false;
    2048              :     }
    2049              :     // dawdling
    2050     50308437 :     const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
    2051     50308437 :     xSpeed -= dawdle;
    2052              : 
    2053              :     // XXX ensure that diagonal speed <= vMax
    2054              :     // avoid deadlocks on narrow sidewalks
    2055              :     //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
    2056              :     //    if DEBUGCOND(*this) std::cout << "  stepping aside to resolve oncoming deadlock\n";
    2057              :     //    xSpeed = POSITION_EPS; // reset myWaitingTime
    2058              :     //     if (myDir == FORWARD && chosen < sMax) {
    2059              :     //         chosen += 1;
    2060              :     //     } else if (myDir == BACKWARD && chosen > 0) {
    2061              :     //         chosen -= 1;
    2062              :     //     }
    2063              :     //}
    2064     50308437 :     const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
    2065              :     double ySpeed = 0;
    2066              :     double yDist = 0;
    2067     50308437 :     if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
    2068              :         // don't move laterally if the stripes are blocked
    2069     46791199 :         yDist = (chosen * stripeWidth) - myPosLat;
    2070     46791199 :         if (fabs(yDist) > NUMERICAL_EPS) {
    2071      2546620 :             ySpeed = (yDist > 0 ?
    2072      1179169 :                       MIN2(maxYSpeed, DIST2SPEED(yDist)) :
    2073      1367451 :                       MAX2(-maxYSpeed, DIST2SPEED(yDist)));
    2074              :         }
    2075      3517238 :     } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
    2076              :                // still on the road
    2077        10012 :                && stripe() == stripe(myPosLat)
    2078              :                // only when the vehicle is moving on the same lane
    2079      3522684 :                && !(myLane->getEdge().isCrossing() || myLane->getEdge().isWalkingArea())) {
    2080              :         // step aside to let the vehicle pass
    2081         3167 :         int stepAsideDir = myDir;
    2082         3167 :         if (myLane->getEdge().getLanes().size() > 1 || current > sMax / 2) {
    2083              :             // always step to the right on multi-lane edges or when closer to
    2084              :             // the right side
    2085              :             stepAsideDir = FORWARD;
    2086              :         }
    2087         3167 :         myAmJammed = true; // ignore pedestrian-pedestrian collisions
    2088         3167 :         ySpeed = stepAsideDir * vMax;
    2089              :     }
    2090              : 
    2091              :     // DEBUG
    2092     50308437 :     if DEBUGCOND(*this) {
    2093            0 :         std::cout << SIMTIME
    2094            0 :                   << " ped=" << myPerson->getID()
    2095            0 :                   << " edge=" << myStage->getEdge()->getID()
    2096            0 :                   << " x=" << myEdgePos
    2097            0 :                   << " y=" << myPosLat
    2098              :                   << " d=" << myDir
    2099            0 :                   << " pvx=" << mySpeed
    2100              :                   << " cur=" << current
    2101            0 :                   << " cho=" << chosen
    2102            0 :                   << " oth=" << other
    2103            0 :                   << " nxt=" << next
    2104            0 :                   << " vx=" << xSpeed
    2105              :                   << " dawdle=" << dawdle
    2106              :                   << " vy=" << ySpeed
    2107              :                   << " xd=" << xDist
    2108              :                   << " yd=" << yDist
    2109              :                   << " vMax=" << vMax
    2110            0 :                   << " wTime=" << myStage->getWaitingTime(currentTime)
    2111            0 :                   << " jammed=" << myAmJammed
    2112            0 :                   << "\n";
    2113            0 :         if (DEBUGCOND(*this)) {
    2114            0 :             for (int i = 0; i < stripes; ++i) {
    2115            0 :                 const Obstacle& o = obs[i];
    2116            0 :                 std::cout << " util=" << utility[i] << " dist=" << distance[i] << " o=" << o.description;
    2117            0 :                 if (o.description != "") {
    2118            0 :                     std::cout << " xF=" << o.xFwd << " xB=" << o.xBack << " v=" << o.speed;
    2119              :                 }
    2120            0 :                 if (i == current) {
    2121            0 :                     std::cout << " current";
    2122              :                 }
    2123            0 :                 if (i == other && i != current) {
    2124            0 :                     std::cout << " other";
    2125              :                 }
    2126            0 :                 if (i == chosen) {
    2127            0 :                     std::cout << " chosen";
    2128              :                 }
    2129            0 :                 if (i == next) {
    2130            0 :                     std::cout << " next";
    2131              :                 }
    2132            0 :                 std::cout << "\n";
    2133              :             }
    2134              :         }
    2135              :     }
    2136     50308437 :     myEdgePos += SPEED2DIST(xSpeed * myDir);
    2137     50308437 :     myPosLat += SPEED2DIST(ySpeed);
    2138     50308437 :     mySpeedLat = ySpeed;
    2139     50308437 :     mySpeed = xSpeed;
    2140     50308437 :     if (xSpeed >= SUMO_const_haltingSpeed) {
    2141     28853161 :         myWaitingToEnter = false;
    2142     28853161 :         myWaitingTime = 0;
    2143              :     } else {
    2144     21455276 :         myWaitingTime += DELTA_T;
    2145              :     }
    2146     50308437 :     myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
    2147     50308437 : }
    2148              : 
    2149              : 
    2150              : double
    2151      9822602 : MSPModel_Striping::PState::getImpatience(SUMOTime now) const {
    2152      9822602 :     return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
    2153      9822602 :                          + STEPS2TIME(myStage->getWaitingTime(now)) / MAX_WAIT_TOLERANCE));
    2154              : }
    2155              : 
    2156              : 
    2157              : Position
    2158     10082881 : MSPModel_Striping::PState::getPosition(const MSStageMoving& stage, SUMOTime) const {
    2159              :     if (myRemoteXYPos != Position::INVALID) {
    2160          363 :         return myRemoteXYPos;
    2161              :     }
    2162     10082518 :     if (myLane == nullptr) {
    2163              :         // pedestrian has already finished
    2164          156 :         return Position::INVALID;
    2165              :     }
    2166     10082362 :     const double lateral_offset = -getLatOffset();  // the minus is hunting me in my dreams but seems to be here for historical reasons
    2167     10082362 :     if (myWalkingAreaPath == nullptr) {
    2168      1466069 :         return stage.getLanePosition(myLane, myEdgePos, lateral_offset);
    2169              :     } else {
    2170              :         //if DEBUGCOND(*this) {
    2171              :         //    std::cout << SIMTIME
    2172              :         //        << " getPosition (walkingArea)"
    2173              :         //        << " p=" << myPerson->getID()
    2174              :         //        << " x=" << myEdgePos
    2175              :         //        << " y=" << myPosLat
    2176              :         //        << " latOffset=" << lateral_offset
    2177              :         //        << " shape=" << myWalkingAreaPath->shape
    2178              :         //        << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset)
    2179              :         //        << "\n";
    2180              :         //}
    2181      8616293 :         if (myWalkingAreaPath->angleOverride == INVALID_DOUBLE) {
    2182      8533557 :             return myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset);
    2183              :         } else {
    2184        82736 :             const double rotationOffset = myDir == FORWARD ? 0 : DEG2RAD(180);
    2185        82736 :             return myWalkingAreaPath->shape.sidePositionAtAngle(myEdgePos, lateral_offset, myWalkingAreaPath->angleOverride + rotationOffset);
    2186              :         }
    2187              :     }
    2188              : }
    2189              : 
    2190              : 
    2191              : double
    2192      3116151 : MSPModel_Striping::PState::getAngle(const MSStageMoving&, SUMOTime) const {
    2193      3116151 :     if (myAngle != std::numeric_limits<double>::max()) {
    2194              :         return myAngle;
    2195              :     }
    2196      1222972 :     if (myLane == nullptr) {
    2197              :         // pedestrian has already finished
    2198              :         return 0;
    2199              :     }
    2200      1222814 :     if (myWalkingAreaPath != nullptr && myWalkingAreaPath->angleOverride != INVALID_DOUBLE) {
    2201              :         return myWalkingAreaPath->angleOverride;
    2202              :     }
    2203      1205812 :     const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
    2204      1205812 :     double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myEdgePos) : myEdgePos;
    2205      1205812 :     double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
    2206      1205812 :     if (myDir == MSPModel::BACKWARD) {
    2207       397240 :         angle += atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
    2208              :     } else { // myDir == MSPModel::FORWARD
    2209      1035408 :         angle -= atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
    2210              :     }
    2211      1205812 :     if (angle > M_PI) {
    2212       279729 :         angle -= 2 * M_PI;
    2213              :     }
    2214      1205812 :     myAngle = angle;
    2215      1205812 :     return angle;
    2216              : }
    2217              : 
    2218              : 
    2219              : const MSEdge*
    2220       166312 : MSPModel_Striping::PState::getNextEdge(const MSStageMoving&) const {
    2221       166312 :     return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
    2222              : }
    2223              : 
    2224              : 
    2225              : const MSLane*
    2226         1489 : MSPModel_Striping::PState::getNextCrossing() const {
    2227         1489 :     return myNLI.lane != nullptr && myNLI.lane->isCrossing() ? myNLI.lane : nullptr;
    2228              : }
    2229              : 
    2230              : 
    2231              : void
    2232        19823 : MSPModel_Striping::PState::reverse(const double pathLength, const double usableWidth) {
    2233        19823 :     myEdgePos = pathLength - myEdgePos;
    2234        19823 :     myPosLat = usableWidth - myPosLat;
    2235        19823 :     myDir = -myWalkingAreaPath->dir;
    2236        19823 :     mySpeedLat = -mySpeedLat;
    2237        19823 : }
    2238              : 
    2239              : 
    2240              : void
    2241       243396 : MSPModel_Striping::PState::reset(const double edgePos, const double latPos) {
    2242       243396 :     myEdgePos = edgePos;
    2243       243396 :     myPosLat = latPos;
    2244       243396 :     myDir = UNDEFINED_DIRECTION;  // only an obstacle, speed may be orthogonal to dir
    2245       243396 :     mySpeed = 0.;
    2246       243396 :     mySpeedLat = 0.;
    2247       243396 : }
    2248              : 
    2249              : 
    2250              : void
    2251           17 : MSPModel_Striping::PState::moveTo(MSPerson* p, MSLane* lane, double lanePos, double lanePosLat, SUMOTime t) {
    2252              :     ConstMSEdgeVector newEdges; // keep route
    2253              :     int routeOffset = 0;
    2254              :     bool laneOnRoute = false;
    2255           17 :     const MSJunction* laneOnJunction = lane->isNormal() ? nullptr : lane->getEdge().getToJunction();
    2256           17 :     for (const MSEdge* edge : myStage->getRoute()) {
    2257              :         if (edge == &lane->getEdge()
    2258           12 :                 || edge->getToJunction() == laneOnJunction
    2259           17 :                 || edge->getFromJunction() == laneOnJunction) {
    2260              :             laneOnRoute = true;
    2261              :             break;
    2262              :         }
    2263            0 :         routeOffset++;
    2264              :     }
    2265           17 :     if (!laneOnRoute) {
    2266            0 :         throw ProcessError("Lane '" + lane->getID() + "' is not on the route of person '" + getID() + "'.");
    2267              :     }
    2268           17 :     Position pos = lane->geometryPositionAtOffset(lanePos, lanePosLat);
    2269           17 :     if (lane->getEdge().isWalkingArea() && (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane)) {
    2270              :         // entered new walkingarea. Determine path to guess position
    2271            8 :         const MSEdge* prevEdge = myStage->getRoute()[routeOffset];
    2272            8 :         const MSEdge* nextEdge = routeOffset + 1 < (int)myStage->getRoute().size() ? myStage->getRoute()[routeOffset + 1] : nullptr;
    2273            8 :         const WalkingAreaPath* guessed = guessPath(&lane->getEdge(), prevEdge, nextEdge);
    2274            8 :         const double maxPos = guessed->shape.length() - NUMERICAL_EPS;
    2275            8 :         if (lanePos > maxPos + POSITION_EPS || lanePos < -POSITION_EPS) {
    2276            0 :             throw ProcessError("Lane position " + toString(lanePos) + " cannot be mapped onto walkingarea '" + lane->getID()
    2277            0 :                                + "' (fromLane='" + guessed->from->getID()
    2278            0 :                                + "' toLane='" + guessed->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
    2279              :         }
    2280              :         // give some slack
    2281            8 :         lanePos = MIN2(maxPos, MAX2(NUMERICAL_EPS, lanePos));
    2282            8 :         pos = guessed->shape.positionAtOffset(lanePos, lanePosLat);
    2283              :     }
    2284           17 :     const double angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
    2285           17 :     moveToXY(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, newEdges, t);
    2286           17 : }
    2287              : 
    2288              : 
    2289              : void
    2290        10293 : MSPModel_Striping::PState::moveToXY(MSPerson* p, Position pos, MSLane* lane, double lanePos,
    2291              :                                     double lanePosLat, double angle, int routeOffset,
    2292              :                                     const ConstMSEdgeVector& edges, SUMOTime t) {
    2293        10293 :     MSPModel_Striping* pm = dynamic_cast<MSPModel_Striping*>(MSNet::getInstance()->getPersonControl().getMovementModel());
    2294              :     assert(p == myPerson);
    2295              :     assert(pm != nullptr);
    2296        10293 :     const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
    2297              :     // person already walking in this step. undo this to obtain the previous position
    2298        10293 :     const double oldX = myEdgePos - SPEED2DIST(mySpeed * myDir);
    2299              :     const double tmp = myEdgePos;
    2300        10293 :     myEdgePos = oldX;
    2301        10293 :     Position oldPos = getPosition(*myStage, t);
    2302        10293 :     myEdgePos = tmp;
    2303              :     //if (oldPos == Position::INVALID) {
    2304              :     //    oldPos = pos
    2305              :     //}
    2306        10293 :     myAngle = GeomHelper::fromNaviDegree(angle);
    2307              : #ifdef DEBUG_MOVETOXY
    2308              :     std::cout << SIMTIME << " ped=" << p->getID()
    2309              :               << " moveToXY"
    2310              :               << " pos=" << pos
    2311              :               << " lane=" << lane->getID()
    2312              :               << " lanePos=" << lanePos
    2313              :               << " lanePosLat=" << lanePosLat
    2314              :               << " angle=" << angle
    2315              :               << " routeOffset=" << routeOffset
    2316              :               << " edges=" << toString(edges)
    2317              :               << " oldLane=" << Named::getIDSecure(myLane)
    2318              :               << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
    2319              : #endif
    2320              : 
    2321        10293 :     if (lane != myLane && myLane != nullptr) {
    2322          281 :         pm->remove(this);
    2323              :         pm->registerActive();
    2324              :     }
    2325        10293 :     if (lane != nullptr &&
    2326        10293 :             fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
    2327        10288 :         myRemoteXYPos = Position::INVALID;
    2328        10288 :         const MSEdge* old = myStage->getEdge();
    2329        10288 :         const MSLane* oldLane = myLane;
    2330        10288 :         if (lane != myLane) {
    2331              :             // implicitly adds new active lane if necessary
    2332          281 :             pm->myActiveLanes[lane].push_back(this);
    2333              :         }
    2334        10288 :         if (edges.empty()) {
    2335              :             // map within route
    2336        10219 :             myStage->setRouteIndex(myPerson, routeOffset);
    2337              :         } else {
    2338           69 :             myStage->replaceRoute(myPerson, edges, routeOffset);
    2339              :         }
    2340        10288 :         if (!lane->getEdge().isNormal()) {
    2341          525 :             myStage->moveToNextEdge(myPerson, t, myDir, &lane->getEdge());
    2342              :         }
    2343              : 
    2344        10288 :         myLane = lane;
    2345        10288 :         const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
    2346        10288 :         if (lane->getEdge().isWalkingArea()) {
    2347          288 :             if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
    2348              :                 // entered new walkingarea. Determine path
    2349           51 :                 myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
    2350              : #ifdef DEBUG_MOVETOXY
    2351              :                 std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
    2352              :                           << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
    2353              : #endif
    2354              :             }
    2355              :             // lanePos and lanePosLat are matched onto the circumference of the
    2356              :             // walkingarea. Use pos instead
    2357          288 :             const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
    2358              :             if (relPos == Position::INVALID) {
    2359          168 :                 WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID()
    2360              :                               + "' (fromLane='" + myWalkingAreaPath->from->getID()
    2361              :                               + "' toLane='" + myWalkingAreaPath->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
    2362           42 :                 myRemoteXYPos = pos;
    2363              :             } else {
    2364          246 :                 myEdgePos = relPos.x();
    2365          246 :                 myPosLat = lateral_offset + relPos.y();
    2366              :             }
    2367              :         } else {
    2368        10000 :             myWalkingAreaPath = nullptr;
    2369        10000 :             myEdgePos = lanePos;
    2370        10000 :             myPosLat = lateral_offset - lanePosLat;
    2371              :         }
    2372              :         // guess direction
    2373        10288 :         const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
    2374        10288 :         if (myStage->getNextRouteEdge() != nullptr) {
    2375         5496 :             if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
    2376          396 :                     myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
    2377         4810 :                 myDir = FORWARD;
    2378              :             } else {
    2379          290 :                 myDir = BACKWARD;
    2380              :             }
    2381              :         } else {
    2382              :             // guess from angle
    2383         5188 :             if (angleDiff <= 90) {
    2384              :                 // keep direction
    2385         5168 :                 if (myDir == UNDEFINED_DIRECTION) {
    2386            0 :                     myDir = FORWARD;
    2387              :                 }
    2388              :             } else {
    2389              :                 // change direction
    2390           20 :                 myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
    2391              :             }
    2392              :         }
    2393              :         // update next lane info (after guessing direction)
    2394        10288 :         if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
    2395          239 :             const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge(), p->getVClass());
    2396              :             // assume that we will eventually move back onto the sidewalk if
    2397              :             // there is one
    2398          239 :             myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
    2399          239 :             myStage->activateEntryReminders(myPerson);
    2400              : #ifdef DEBUG_MOVETOXY
    2401              :             std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
    2402              : #endif
    2403              :         }
    2404              : #ifdef DEBUG_MOVETOXY
    2405              :         std::cout << " newRelPos=" << Position(myEdgePos, myPosLat) << " edge=" << myPerson->getEdge()->getID() << " newPos=" << myPerson->getPosition()
    2406              :                   << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
    2407              : #endif
    2408        10288 :         if (oldLane == myLane) {
    2409        10007 :             mySpeed = DIST2SPEED(fabs(oldX - myEdgePos));
    2410              :         } else {
    2411              :             //std::cout << SIMTIME << " oldX=" << oldX << " oldSpeed=" << mySpeed << " oldPos=" << oldPos << " pos=" << pos << " dist=" << oldPos.distanceTo2D(pos) << " oldLane=" << Named::getIDSecure(oldLane) << " lane=" << lane->getID() << "\n";
    2412          281 :             mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
    2413              :         }
    2414              :     } else {
    2415              :         // map outside the network
    2416            5 :         myRemoteXYPos = pos;
    2417            5 :         mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
    2418              :     }
    2419              : 
    2420        10293 : }
    2421              : 
    2422              : 
    2423              : double
    2424       665105 : MSPModel_Striping::PState::getPathLength() const {
    2425       665105 :     if (myWalkingAreaPath != nullptr) {
    2426       609026 :         return myWalkingAreaPath->length;
    2427              :     } else {
    2428              :         return 0;
    2429              :     }
    2430              : }
    2431              : 
    2432              : double
    2433   1089580935 : MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
    2434              :     // check for overlap
    2435   1089580935 :     const double maxX = getMaxX(includeMinGap);
    2436   1089580935 :     const double minX = getMinX(includeMinGap);
    2437              :     //if (DEBUGCOND(*this)) {
    2438              :     //    std::cout << std::setprecision(2) <<   "   distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
    2439              :     //}
    2440   1089580935 :     if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
    2441              :         // avoid blocking by itself on looped route
    2442    262824986 :         return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
    2443              :     }
    2444    826755949 :     if (myDir == FORWARD) {
    2445    721466642 :         return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
    2446              :     } else {
    2447    105289307 :         return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
    2448              :     }
    2449              : }
    2450              : 
    2451              : 
    2452              : void
    2453     65625493 : MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2) {
    2454    295633415 :     for (int i = 0; i < (int)into.size(); ++i) {
    2455    230007922 :         if (gDebugFlag1) {
    2456            0 :             std::cout << "     i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
    2457            0 :                       << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
    2458            0 :                       << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
    2459              :         }
    2460    230007922 :         const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
    2461    230007922 :         const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
    2462    230007922 :         if (dO < dI) {
    2463              :             into[i] = obs2[i];
    2464              :         } else if (dO == dI
    2465     56090091 :                    && into[i].type != OBSTACLE_PED
    2466     32658414 :                    && into[i].type != OBSTACLE_VEHICLE
    2467    227029445 :                    && (obs2[i].type == OBSTACLE_PED ||
    2468              :                        obs2[i].type == OBSTACLE_VEHICLE)) {
    2469              :             into[i] = obs2[i];
    2470              :         }
    2471              :     }
    2472     65625493 : }
    2473              : 
    2474              : void
    2475        18456 : MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
    2476       144910 :     for (int i = 0; i < (int)into.size(); ++i) {
    2477       126454 :         int i2 = i + offset;
    2478       126454 :         if (i2 >= 0 && i2 < (int)obs2.size()) {
    2479       125420 :             if (dir == FORWARD) {
    2480        90692 :                 if (obs2[i2].xBack < into[i].xBack) {
    2481              :                     into[i] = obs2[i2];
    2482              :                 }
    2483              :             } else {
    2484        34728 :                 if (obs2[i2].xFwd > into[i].xFwd) {
    2485              :                     into[i] = obs2[i2];
    2486              :                 }
    2487              :             }
    2488              :         }
    2489              :     }
    2490        18456 : }
    2491              : 
    2492              : 
    2493              : bool
    2494      9822602 : MSPModel_Striping::PState::ignoreRed(const MSLink* link) const {
    2495      9822602 :     if (link->haveRed()) {
    2496       611158 :         const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
    2497       611158 :         if (ignoreRedTime >= 0) {
    2498           40 :             const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
    2499           40 :             if (DEBUGCOND(*this)) {
    2500            0 :                 std::cout << SIMTIME << "  ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
    2501              :             }
    2502           40 :             return ignoreRedTime > redDuration;
    2503              :         } else {
    2504              :             return false;
    2505              :         }
    2506              :     } else {
    2507              :         return false;
    2508              :     }
    2509              : }
    2510              : 
    2511              : double
    2512   2124621386 : MSPModel_Striping::PState::getWidth() const {
    2513   2124621386 :     return myPerson->getVehicleType().getWidth();
    2514              : }
    2515              : 
    2516              : 
    2517              : bool
    2518     96073682 : MSPModel_Striping::PState::isRemoteControlled() const {
    2519     96073682 :     return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
    2520              : }
    2521              : 
    2522              : // ===========================================================================
    2523              : // MSPModel_Striping::PStateVehicle method definitions
    2524              : // ===========================================================================
    2525              : 
    2526       438942 : MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY, double xWidth, double yWidth):
    2527       438942 :     myVehicle(veh), myXWidth(xWidth), myYWidth(yWidth) {
    2528       438942 :     myLane = walkingarea; // to ensure correct limits when calling otherStripe()
    2529              :     // relX is the center but we want it to be the max value if the movement direction is forward
    2530              :     // and the min value otherwise (indicated by xWidth sign)
    2531       438942 :     myEdgePos = relX + xWidth / 2;
    2532       438942 :     myPosLat = relY;
    2533       438942 : }
    2534              : 
    2535              : const std::string&
    2536      1751875 : MSPModel_Striping::PStateVehicle::getID() const {
    2537      1751875 :     return myVehicle->getID();
    2538              : }
    2539              : 
    2540              : double
    2541       886393 : MSPModel_Striping::PStateVehicle::getWidth() const {
    2542       886393 :     return myYWidth;
    2543              : }
    2544              : 
    2545              : double
    2546       464765 : MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
    2547       464765 :     return myXWidth > 0 ? myEdgePos - myXWidth : myEdgePos;
    2548              : }
    2549              : 
    2550              : double
    2551       464765 : MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
    2552       464765 :     return myXWidth > 0 ? myEdgePos : myEdgePos - myXWidth;
    2553              : }
    2554              : 
    2555              : // ===========================================================================
    2556              : // MSPModel_Striping::MovePedestrians method definitions
    2557              : // ===========================================================================
    2558              : 
    2559              : SUMOTime
    2560      8897731 : MSPModel_Striping::MovePedestrians::execute(SUMOTime currentTime) {
    2561              :     std::set<MSPerson*> changedLane;
    2562      8897731 :     myModel->moveInDirection(currentTime, changedLane, FORWARD);
    2563      8897727 :     myModel->moveInDirection(currentTime, changedLane, BACKWARD);
    2564              :     // DEBUG
    2565              : #ifdef LOG_ALL
    2566              :     for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
    2567              :         const MSLane* lane = it_lane->first;
    2568              :         Pedestrians pedestrians = it_lane->second;
    2569              :         if (pedestrians.size() == 0) {
    2570              :             continue;
    2571              :         }
    2572              :         sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
    2573              :         std::cout << SIMTIME << " lane=" << lane->getID();
    2574              :         for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
    2575              :             const PState& p = *pedestrians[ii];
    2576              :             std::cout << " (" << p.getPerson()->getID() << " " << p.myEdgePos << "," << p.myPosLat << " " << p.getDirection() << ")";
    2577              :         }
    2578              :         std::cout << "\n";
    2579              :     }
    2580              : #endif
    2581      8897727 :     return DELTA_T;
    2582              : }
        

Generated by: LCOV version 2.0-1