LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSPModel_Striping.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 86.4 % 1334 1152
Test Date: 2026-03-26 16:31:35 Functions: 98.6 % 69 68

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2014-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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              : bool MSPModel_Striping::USE_NET_SPEEDS(false);
     108              : const double MSPModel_Striping::MAX_WAIT_TOLERANCE(120.); // seconds
     109              : const double MSPModel_Striping::LATERAL_SPEED_FACTOR(0.4);
     110              : const double MSPModel_Striping::MIN_STARTUP_DIST(0.4); // meters
     111              : 
     112              : 
     113              : // ===========================================================================
     114              : // MSPModel_Striping method definitions
     115              : // ===========================================================================
     116              : 
     117         6049 : MSPModel_Striping::MSPModel_Striping(const OptionsCont& oc, MSNet* net) {
     118         6049 :     myWalkingAreaDetail = oc.getInt("pedestrian.striping.walkingarea-detail");
     119         6049 :     initWalkingAreaPaths(net);
     120              :     // configurable parameters
     121         6049 :     stripeWidth = oc.getFloat("pedestrian.striping.stripe-width");
     122         6049 :     MSVehicleType* defaultPedType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
     123         6049 :     if (defaultPedType != nullptr && defaultPedType->getWidth() > stripeWidth) {
     124           12 :         WRITE_WARNINGF(TL("Pedestrian vType '%' width % is larger than pedestrian.striping.stripe-width and this may cause collisions with vehicles."),
     125              :                        DEFAULT_PEDTYPE_ID, defaultPedType->getWidth());
     126              :     }
     127              : 
     128         6049 :     dawdling = oc.getFloat("pedestrian.striping.dawdling");
     129         6049 :     minGapToVehicle = oc.getFloat("pedestrian.striping.mingap-to-vehicle");
     130         6049 :     RESERVE_FOR_ONCOMING_FACTOR = oc.getFloat("pedestrian.striping.reserve-oncoming");
     131         6049 :     RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS = oc.getFloat("pedestrian.striping.reserve-oncoming.junctions");
     132         6049 :     RESERVE_FOR_ONCOMING_MAX = oc.getFloat("pedestrian.striping.reserve-oncoming.max");
     133              :     // beginning with 1.20.0, sensible default speeds were set for crossings and walkingareas
     134         6049 :     USE_NET_SPEEDS = net->getNetworkVersion() >= MMVersion(1, 20);
     135              : 
     136         6049 :     jamTime = string2time(oc.getString("pedestrian.striping.jamtime"));
     137         6049 :     if (jamTime <= 0) {
     138            4 :         jamTime = SUMOTime_MAX;
     139              :     }
     140         6049 :     jamTimeCrossing = string2time(oc.getString("pedestrian.striping.jamtime.crossing"));
     141         6049 :     if (jamTimeCrossing <= 0) {
     142            0 :         jamTimeCrossing = SUMOTime_MAX;
     143              :     }
     144         6049 :     jamTimeNarrow = string2time(oc.getString("pedestrian.striping.jamtime.narrow"));
     145         6049 :     if (jamTimeNarrow <= 0) {
     146            0 :         jamTimeNarrow = SUMOTime_MAX;
     147              :     }
     148         6049 :     jamFactor = oc.getFloat("pedestrian.striping.jamfactor");
     149         6049 :     myLegacyPosLat = oc.getBool("pedestrian.striping.legacy-departposlat");
     150         6049 : }
     151              : 
     152              : 
     153        12070 : MSPModel_Striping::~MSPModel_Striping() {
     154              :     myWalkingAreaPaths.clear(); // need to recompute when lane pointers change
     155              :     myWalkingAreaFoes.clear();
     156              :     myMinNextLengths.clear();
     157        12070 : }
     158              : 
     159              : 
     160              : MSTransportableStateAdapter*
     161       243952 : MSPModel_Striping::add(MSTransportable* transportable, MSStageMoving* stage, SUMOTime) {
     162       243952 :     if (!transportable->isPerson()) {
     163              :         // containers are not supported (TODO add a warning here?)
     164              :         return nullptr;
     165              :     }
     166              :     MSPerson* person = static_cast<MSPerson*>(transportable);
     167       243952 :     MSNet* net = MSNet::getInstance();
     168       243952 :     if (!myAmActive) {
     169         4239 :         net->getBeginOfTimestepEvents()->addEvent(new MovePedestrians(this), net->getCurrentTimeStep() + DELTA_T);
     170         4239 :         myAmActive = true;
     171              :     }
     172              :     assert(person->getCurrentStageType() == MSStageType::WALKING);
     173       243952 :     const MSLane* lane = stage->checkDepartLane(person->getEdge(), person->getVClass(), stage->getDepartLane(), person->getID());
     174       243952 :     if (lane == nullptr) {
     175            8 :         const char* error = TL("Person '%' could not find sidewalk on edge '%', time=%.");
     176           16 :         if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
     177           24 :             WRITE_WARNINGF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep()));
     178            8 :             return nullptr;
     179              :         } else {
     180            0 :             throw ProcessError(TLF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep())));
     181              :         }
     182              :     }
     183       243944 :     PState* ped = new PState(person, stage, lane);
     184       243940 :     myActiveLanes[lane].push_back(ped);
     185       243940 :     myNumActivePedestrians++;
     186       243940 :     return ped;
     187              : }
     188              : 
     189              : 
     190              : MSTransportableStateAdapter*
     191           12 : MSPModel_Striping::loadState(MSTransportable* transportable, MSStageMoving* stage, std::istringstream& in) {
     192              :     MSPerson* person = static_cast<MSPerson*>(transportable);
     193           12 :     MSNet* net = MSNet::getInstance();
     194           12 :     if (!myAmActive) {
     195           10 :         net->getBeginOfTimestepEvents()->addEvent(new MovePedestrians(this), SIMSTEP);
     196           10 :         myAmActive = true;
     197              :     }
     198           12 :     PState* ped = new PState(person, stage, &in);
     199           12 :     myActiveLanes[ped->getLane()].push_back(ped);
     200           12 :     myNumActivePedestrians++;
     201           12 :     return ped;
     202              : }
     203              : 
     204              : 
     205              : int
     206   8401079381 : MSPModel_Striping::numStripes(const MSLane* lane) {
     207   8401079381 :     return MAX2(1, (int)floor(lane->getWidth() / stripeWidth));
     208              : }
     209              : 
     210              : 
     211              : int
     212       848949 : MSPModel_Striping::connectedDirection(const MSLane* from, const MSLane* to) {
     213       848949 :     if (from == nullptr || to == nullptr) {
     214            0 :         return UNDEFINED_DIRECTION;
     215       848949 :     } else if (from->getLinkTo(to) != nullptr) {
     216       601668 :         return FORWARD;
     217       247281 :     } else if (to->getLinkTo(from) != nullptr) {
     218       247281 :         return BACKWARD;
     219              :     } else {
     220            0 :         return UNDEFINED_DIRECTION;
     221              :     }
     222              : }
     223              : 
     224              : 
     225              : void
     226         6049 : MSPModel_Striping::initWalkingAreaPaths(const MSNet*) {
     227         6049 :     if (myWalkingAreaPaths.size() > 0) {
     228              :         return;
     229              :     }
     230              :     // collect vehicle lanes that cross walkingareas
     231       419116 :     for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
     232       413067 :         const MSEdge* edge = *i;
     233       413067 :         if (!edge->isWalkingArea() && !edge->isCrossing()) {
     234       764109 :             for (MSLane* lane : edge->getLanes()) {
     235       935661 :                 for (MSLink* link : lane->getLinkCont()) {
     236       516261 :                     if (link->getWalkingAreaFoe() != nullptr) {
     237              :                         // link is an exit link
     238         2936 :                         myWalkingAreaFoes[&link->getWalkingAreaFoe()->getEdge()].push_back(link->getLaneBefore());
     239              :                         //std::cout << " wa=" << link->getWalkingAreaFoe()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
     240              :                     }
     241       516261 :                     if (link->getWalkingAreaFoeExit() != nullptr) {
     242              :                         // link is an exit link
     243         3020 :                         myWalkingAreaFoes[&link->getWalkingAreaFoeExit()->getEdge()].push_back(link->getLaneBefore());
     244              :                         //std::cout << " wa=" << link->getWalkingAreaFoeExit()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
     245              :                     }
     246              :                 }
     247              :             }
     248              :         }
     249              :     }
     250              : 
     251              :     // build walkingareaPaths
     252       419116 :     for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
     253       413067 :         insertWalkArePaths(*i, myWalkingAreaPaths);
     254              :     }
     255              : }
     256              : 
     257              : 
     258              : void
     259       413067 : MSPModel_Striping::insertWalkArePaths(const MSEdge* edge, WalkingAreaPaths& into) {
     260       413067 :     if (edge->isWalkingArea()) {
     261        59949 :         const MSLane* walkingArea = getSidewalk<MSEdge, MSLane>(edge);
     262        59949 :         myMinNextLengths[walkingArea] = walkingArea->getLength();
     263              :         // build all possible paths across this walkingArea
     264              :         // gather all incident lanes
     265              :         std::vector<const MSLane*> lanes;
     266       133389 :         for (const MSEdge* in : edge->getPredecessors()) {
     267        73440 :             if (!in->isTazConnector()) {
     268        69094 :                 lanes.push_back(getSidewalk<MSEdge, MSLane>(in));
     269        69094 :                 if (lanes.back() == nullptr) {
     270            0 :                     throw ProcessError("Invalid connection from edge '" + in->getID() + "' to walkingarea edge '" + edge->getID() + "'");
     271              :                 }
     272              :             }
     273              :         }
     274       133575 :         for (const MSEdge* out : edge->getSuccessors()) {
     275        73626 :             if (!out->isTazConnector()) {
     276        69280 :                 lanes.push_back(getSidewalk<MSEdge, MSLane>(out));
     277        69280 :                 if (lanes.back() == nullptr) {
     278            0 :                     throw ProcessError("Invalid connection from walkingarea edge '" + edge->getID() + "' to edge '" + out->getID() + "'");
     279              :                 }
     280              :             }
     281              :         }
     282              :         // build all combinations
     283       198323 :         for (int j = 0; j < (int)lanes.size(); ++j) {
     284       484304 :             for (int k = 0; k < (int)lanes.size(); ++k) {
     285       345930 :                 if (j != k) {
     286              :                     // build the walkingArea
     287       207556 :                     const MSLane* const from = lanes[j];
     288       207556 :                     const MSLane* const to = lanes[k];
     289       207556 :                     const int fromDir = from->getLinkTo(walkingArea) != nullptr ? FORWARD : BACKWARD;
     290       207556 :                     const int toDir = walkingArea->getLinkTo(to) != nullptr ? FORWARD : BACKWARD;
     291       207556 :                     PositionVector shape;
     292       311590 :                     Position fromPos = from->getShape()[fromDir == FORWARD ? -1 : 0];
     293       311078 :                     Position toPos = to->getShape()[toDir == FORWARD ? 0 : -1];
     294       207556 :                     const double maxExtent = fromPos.distanceTo2D(toPos) / 4; // prevent sharp corners
     295       207556 :                     const double extrapolateBy = MIN2(maxExtent, walkingArea->getWidth() / 2);
     296              :                     // assemble shape
     297       207556 :                     shape.push_back(fromPos);
     298       207556 :                     if (extrapolateBy > POSITION_EPS) {
     299              :                         PositionVector fromShp = from->getShape();
     300       206546 :                         fromShp.extrapolate(extrapolateBy);
     301       413092 :                         shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
     302              :                         PositionVector nextShp = to->getShape();
     303       206546 :                         nextShp.extrapolate(extrapolateBy);
     304       413092 :                         shape.push_back_noDoublePos(toDir == FORWARD ? nextShp.front() : nextShp.back());
     305       206546 :                     }
     306       207556 :                     shape.push_back_noDoublePos(toPos);
     307       207556 :                     if (shape.size() < 2) {
     308              :                         PositionVector fromShp = from->getShape();
     309          558 :                         fromShp.extrapolate(1.5 * POSITION_EPS); // noDoublePos requires a difference of POSITION_EPS in at least one coordinate
     310         1116 :                         shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
     311              :                         assert(shape.size() == 2);
     312       207556 :                     } else if (myWalkingAreaDetail > 4) {
     313          448 :                         shape = shape.bezier(myWalkingAreaDetail);
     314              :                     }
     315              :                     double angleOverride = INVALID_DOUBLE;
     316       207556 :                     if (shape.size() >= 4 && shape.length() < walkingArea->getWidth()) {
     317        53848 :                         const double aStart = shape.angleAt2D(0);
     318        53848 :                         const double aEnd = shape.angleAt2D((int)shape.size() - 2);
     319        53848 :                         if (fabs(aStart - aEnd) < DEG2RAD(10)) {
     320         9031 :                             angleOverride = (aStart + aEnd) / 2;
     321              :                         }
     322              :                     }
     323       207556 :                     if (fromDir == BACKWARD) {
     324              :                         // will be walking backward on walkingArea
     325       208068 :                         shape = shape.reverse();
     326              :                     }
     327       207556 :                     WalkingAreaPath wap = WalkingAreaPath(from, walkingArea, to, shape, fromDir, angleOverride);
     328       207556 :                     into.insert(std::make_pair(std::make_pair(from, to), wap));
     329       240518 :                     myMinNextLengths[walkingArea] = MIN2(myMinNextLengths[walkingArea], wap.length);
     330       207556 :                 }
     331              :             }
     332              :         }
     333        59949 :     }
     334       413067 : }
     335              : 
     336              : 
     337              : const MSPModel_Striping::WalkingAreaPath*
     338            8 : MSPModel_Striping::getArbitraryPath(const MSEdge* walkingArea) {
     339              :     assert(walkingArea->isWalkingArea());
     340              :     std::vector<const MSLane*> lanes;
     341           24 :     for (const MSEdge* const pred : walkingArea->getPredecessors()) {
     342           16 :         lanes.push_back(getSidewalk<MSEdge, MSLane>(pred));
     343              :     }
     344           24 :     for (const MSEdge* const succ : walkingArea->getSuccessors()) {
     345           16 :         lanes.push_back(getSidewalk<MSEdge, MSLane>(succ));
     346              :     }
     347            8 :     if (lanes.size() < 1) {
     348            0 :         throw ProcessError(TLF("Invalid walkingarea '%' does not allow continuation.", walkingArea->getID()));
     349              :     }
     350            8 :     return &myWalkingAreaPaths.find(std::make_pair(lanes.front(), lanes.back()))->second;
     351            8 : }
     352              : 
     353              : const MSPModel_Striping::WalkingAreaPath*
     354           46 : MSPModel_Striping::guessPath(const MSEdge* walkingArea, const MSEdge* before, const MSEdge* after) {
     355              :     assert(walkingArea->isWalkingArea());
     356           46 :     const MSLane* swBefore = getSidewalk<MSEdge, MSLane>(before);
     357           46 :     const MSLane* swAfter = getSidewalk<MSEdge, MSLane>(after);
     358           46 :     const auto pathIt = myWalkingAreaPaths.find(std::make_pair(swBefore, swAfter));
     359           46 :     if (pathIt != myWalkingAreaPaths.end()) {
     360           19 :         return &pathIt->second;
     361              :     }
     362              :     const MSEdgeVector& preds = walkingArea->getPredecessors();
     363           27 :     const MSEdgeVector& succs = walkingArea->getSuccessors();
     364           27 :     bool useBefore = swBefore != nullptr && std::find(preds.begin(), preds.end(), before) != preds.end();
     365           27 :     bool useAfter = swAfter != nullptr && std::find(succs.begin(), succs.end(), after) != succs.end();
     366           27 :     if (useBefore) {
     367           21 :         if (useAfter) {
     368            0 :             return getWalkingAreaPath(walkingArea, swBefore, swAfter);
     369           21 :         } else if (succs.size() > 0) {
     370              :             // could also try to exploit direction
     371           21 :             return getWalkingAreaPath(walkingArea, swBefore, getSidewalk<MSEdge, MSLane>(succs.front()));
     372              :         }
     373            6 :     } else if (useAfter && preds.size() > 0) {
     374              :         // could also try to exploit direction
     375            6 :         return getWalkingAreaPath(walkingArea, getSidewalk<MSEdge, MSLane>(preds.front()), swAfter);
     376              :     }
     377            0 :     return getArbitraryPath(walkingArea);
     378              : }
     379              : 
     380              : 
     381              : const MSPModel_Striping::WalkingAreaPath*
     382       834216 : MSPModel_Striping::getWalkingAreaPath(const MSEdge* walkingArea, const MSLane* before, const MSLane* after) {
     383              :     assert(walkingArea->isWalkingArea());
     384       834216 :     const auto pathIt = myWalkingAreaPaths.find(std::make_pair(before, after));
     385       834216 :     if (pathIt != myWalkingAreaPaths.end()) {
     386       834182 :         return &pathIt->second;
     387              :     }
     388              :     // this can happen in case of moveToXY where before can point anywhere
     389              :     // or when a person starts directly on a walking area (before == nullptr)
     390           38 :     for (const MSEdge* const pred : walkingArea->getPredecessors()) {
     391           38 :         const auto pathIt2 = myWalkingAreaPaths.find(std::make_pair(getSidewalk<MSEdge, MSLane>(pred), after));
     392           38 :         if (pathIt2 != myWalkingAreaPaths.end()) {
     393           34 :             return &pathIt2->second;
     394              :         }
     395              :     }
     396            0 :     return getArbitraryPath(walkingArea);
     397              : }
     398              : 
     399              : 
     400              : 
     401              : MSPModel_Striping::NextLaneInfo
     402      1503143 : MSPModel_Striping::getNextLane(const PState& ped, const MSLane* currentLane, const MSLane* prevLane) {
     403              :     const MSEdge* currentEdge = &currentLane->getEdge();
     404      1503143 :     const MSJunction* junction = ped.getDirection() == FORWARD ? currentEdge->getToJunction() : currentEdge->getFromJunction();
     405      1503143 :     const MSEdge* nextRouteEdge = ped.getStage()->getNextRouteEdge();
     406      1503143 :     const MSLane* nextRouteLane = getSidewalk<MSEdge, MSLane>(nextRouteEdge, ped.getPerson()->getVClass());
     407              :     // result values
     408              :     const MSLane* nextLane = nextRouteLane;
     409      1503143 :     const MSLink* link = nullptr;
     410      1503143 :     int nextDir = UNDEFINED_DIRECTION;
     411              : 
     412              :     //if DEBUGCOND(ped) {
     413              :     //    std::cout << "  nextRouteLane=" << Named::getIDSecure(nextRouteLane) << " junction=" << junction->getID() << "\n";
     414              :     //}
     415      1503143 :     if (nextRouteLane == nullptr && nextRouteEdge != nullptr) {
     416           56 :         std::string error = "Person '" + ped.getPerson()->getID() + "' could not find sidewalk on edge '" + nextRouteEdge->getID() + "', time="
     417           56 :                             + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".";
     418           56 :         if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
     419           76 :             WRITE_WARNING(error);
     420           24 :             nextRouteLane = nextRouteEdge->getLanes().front();
     421              :         } else {
     422            4 :             throw ProcessError(error);
     423              :         }
     424              :     }
     425              : 
     426      1503139 :     if (nextRouteLane != nullptr) {
     427      1270859 :         if (currentEdge->isInternal()) {
     428              :             assert(junction == currentEdge->getFromJunction());
     429        23623 :             nextDir = junction == nextRouteEdge->getFromJunction() ? FORWARD : BACKWARD;
     430        23623 :             if (nextDir == FORWARD) {
     431        22653 :                 nextLane = currentLane->getLinkCont()[0]->getViaLaneOrLane();
     432              :             } else {
     433          970 :                 nextLane = currentLane->getLogicalPredecessorLane();
     434              :             }
     435        23623 :             if DEBUGCOND(ped) {
     436            0 :                 std::cout << "  internal\n";
     437              :             }
     438      1247236 :         } else if (currentEdge->isCrossing()) {
     439        33062 :             nextDir = ped.getDirection();
     440        33062 :             if (nextDir == FORWARD) {
     441        16767 :                 nextLane = currentLane->getLinkCont()[0]->getLane();
     442              :             } else {
     443        16295 :                 nextLane = currentLane->getLogicalPredecessorLane();
     444              :             }
     445        33062 :             if DEBUGCOND(ped) {
     446            0 :                 std::cout << "  crossing\n";
     447              :             }
     448        33062 :             if (currentLane->isPriorityCrossing()) {
     449        31037 :                 unregisterCrossingApproach(ped, currentLane);
     450              :             }
     451      1214174 :         } else if (currentEdge->isWalkingArea())  {
     452              :             ConstMSEdgeVector crossingRoute;
     453              :             // departPos can be 0 because the direction of the walkingArea does not matter
     454              :             // for the arrivalPos, we need to make sure that the route does not deviate across other junctions
     455       848986 :             const int nextRouteEdgeDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
     456       848986 :             const double arrivalPos = (nextRouteEdge == ped.getStage()->getRoute().back()
     457       848986 :                                        ? ped.getStage()->getArrivalPos()
     458       204822 :                                        : (nextRouteEdgeDir == FORWARD ? 0 : nextRouteEdge->getLength()));
     459              :             SUMOAbstractRouter<MSEdge, SUMOVehicle>::Prohibitions prohibited;
     460       848986 :             if (prevLane != nullptr) {
     461       848938 :                 prohibited[&prevLane->getEdge()].end = std::numeric_limits<double>::max();
     462              :             }
     463      1697972 :             MSNet::getInstance()->getPedestrianRouter(0, prohibited).compute(currentEdge, nextRouteEdge, 0, arrivalPos,
     464       848986 :                     ped.getStage()->getMaxSpeed(ped.getPerson()),
     465       848986 :                     0, junction, ped.getPerson()->getVTypeParameter(), crossingRoute, true);
     466       848986 :             if DEBUGCOND(ped) {
     467              :                 std::cout
     468              :                         << "   nre=" << nextRouteEdge->getID()
     469              :                         << "   nreDir=" << nextRouteEdgeDir
     470            0 :                         << "   aPos=" << arrivalPos
     471            0 :                         << " crossingRoute=" << toString(crossingRoute)
     472            0 :                         << "\n";
     473              :             }
     474       848986 :             if (crossingRoute.size() > 1) {
     475       848949 :                 const MSEdge* nextEdge = crossingRoute[1];
     476       848949 :                 nextLane = getSidewalk<MSEdge, MSLane>(crossingRoute[1], ped.getPerson()->getVClass());
     477              :                 assert((nextEdge->getFromJunction() == junction || nextEdge->getToJunction() == junction));
     478              :                 assert(nextLane != prevLane);
     479       848949 :                 nextDir = connectedDirection(currentLane, nextLane);
     480       848949 :                 if DEBUGCOND(ped) {
     481            0 :                     std::cout << " nextDir=" << nextDir << "\n";
     482              :                 }
     483              :                 assert(nextDir != UNDEFINED_DIRECTION);
     484       848949 :                 if (nextDir == FORWARD) {
     485       601668 :                     link = currentLane->getLinkTo(nextLane);
     486              :                 } else {
     487       247281 :                     link = nextLane->getLinkTo(currentLane);
     488       247281 :                     if (nextEdge->isCrossing() && link->getTLLogic() == nullptr) {
     489       195074 :                         const MSLane* oppositeWalkingArea = nextLane->getLogicalPredecessorLane();
     490       195074 :                         link = oppositeWalkingArea->getLinkTo(nextLane);
     491              :                     }
     492              :                 }
     493              :                 assert(link != nullptr);
     494       848949 :                 if (nextLane->isPriorityCrossing()) {
     495       487479 :                     registerCrossingApproach(ped, nextLane, prevLane);
     496              :                 }
     497              :             } else {
     498           37 :                 if DEBUGCOND(ped) {
     499            0 :                     std::cout << SIMTIME
     500            0 :                               << " no route from '" << (currentEdge == nullptr ? "NULL" : currentEdge->getID())
     501            0 :                               << "' to '" << (nextRouteEdge == nullptr ? "NULL" : nextRouteEdge->getID())
     502            0 :                               << "\n";
     503              :                 }
     504              :                 // check if a direct connection exists (moving onto the walkingarea was the wrong choice)
     505           37 :                 if (ped.getDirection() == FORWARD) {
     506           24 :                     link = prevLane->getLinkTo(nextRouteLane);
     507              :                 } else {
     508           13 :                     link = nextRouteLane->getLinkTo(prevLane);
     509              :                 }
     510           37 :                 if (link != nullptr) {
     511              :                     // leave direction as UNDEFINED_DIRECTION to signal that currentLane must be changed
     512              :                     nextLane = link->getViaLaneOrLane();
     513              :                 } else {
     514           80 :                     WRITE_WARNING("Person '" + ped.getPerson()->getID() + "' could not find route across junction '" + junction->getID()
     515              :                                   + "' from walkingArea '" + currentEdge->getID()
     516              :                                   + "' to edge '" + nextRouteEdge->getID() + "', time=" +
     517              :                                   time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     518              :                     // error indicated by nextDir == UNDEFINED_DIRECTION
     519              :                     nextLane = nextRouteLane;
     520              :                 }
     521              :             }
     522      1214174 :         } else if (currentEdge == nextRouteEdge) {
     523              :             // strange loop in this route. No need to use walkingArea
     524            8 :             nextDir = -ped.getDirection();
     525              :         } else {
     526              :             // normal edge. by default use next / previous walking area
     527       365180 :             nextDir = ped.getDirection();
     528       365180 :             nextLane = getNextWalkingArea(currentLane, ped.getDirection(), link);
     529       365180 :             if (nextLane != nullptr) {
     530              :                 // walking area found
     531       326431 :                 if DEBUGCOND(ped) {
     532            0 :                     std::cout << "  next walkingArea " << (nextDir == FORWARD ? "forward" : "backward") << "\n";
     533              :                 }
     534              :             } else {
     535              :                 // walk forward by default
     536        38749 :                 if (junction == nextRouteEdge->getToJunction()) {
     537         3938 :                     nextDir = BACKWARD;
     538        34811 :                 } else if (junction == nextRouteEdge->getFromJunction()) {
     539              :                     nextDir = FORWARD;
     540              :                 } else {
     541              :                     // topological disconnect, find a direction that makes sense
     542              :                     // for the future part of the route
     543          212 :                     ConstMSEdgeVector futureRoute = ped.getStage()->getRoute();
     544          212 :                     futureRoute.erase(futureRoute.begin(), futureRoute.begin() + ped.getStage()->getRoutePosition() + 1);
     545          212 :                     int passedFwd = 0;
     546          212 :                     int passedBwd = 0;
     547          212 :                     canTraverse(FORWARD, futureRoute, passedFwd);
     548          212 :                     canTraverse(BACKWARD, futureRoute, passedBwd);
     549          212 :                     nextDir = (passedFwd >= passedBwd) ? FORWARD : BACKWARD;
     550          212 :                     if DEBUGCOND(ped) {
     551            0 :                         std::cout << " nextEdge=" << nextRouteEdge->getID() << " passedFwd=" << passedFwd << " passedBwd=" << passedBwd << " futureRoute=" << toString(futureRoute) << " nextDir=" << nextDir << "\n";
     552              :                     }
     553          212 :                 }
     554              :                 // try to use a direct link as fallback
     555              :                 // direct links only exist if built explicitly. They are used to model tl-controlled links if there are no crossings
     556        38749 :                 if (ped.getDirection() == FORWARD) {
     557        34291 :                     link = currentLane->getLinkTo(nextRouteLane);
     558        34291 :                     if (link != nullptr) {
     559        32624 :                         if DEBUGCOND(ped) {
     560            0 :                             std::cout << "  direct forward\n";
     561              :                         }
     562        32624 :                         nextLane = currentLane->getInternalFollowingLane(nextRouteLane);
     563              :                     }
     564              :                 } else {
     565         4458 :                     link = nextRouteLane->getLinkTo(currentLane);
     566         4458 :                     if (link != nullptr) {
     567         3178 :                         if DEBUGCOND(ped) {
     568            0 :                             std::cout << "  direct backward\n";
     569              :                         }
     570         3178 :                         nextLane = nextRouteLane->getInternalFollowingLane(currentLane);
     571         3178 :                         if (nextLane != nullptr) {
     572              :                             // advance to the end of consecutive internal lanes
     573         5307 :                             while (nextLane->getLinkCont()[0]->getViaLaneOrLane()->isInternal()) {
     574            5 :                                 nextLane = nextLane->getLinkCont()[0]->getViaLaneOrLane();
     575              :                             }
     576              :                         }
     577              :                     }
     578              :                 }
     579              :             }
     580       364653 :             if (nextLane == nullptr) {
     581              :                 // no internal lane found
     582              :                 nextLane = nextRouteLane;
     583         8783 :                 if DEBUGCOND(ped) {
     584            0 :                     std::cout << SIMTIME << " no next lane found for " << currentLane->getID() << " dir=" << ped.getDirection() << "\n";
     585              :                 }
     586         8783 :                 if (usingInternalLanesStatic() && currentLane->getLinkCont().size() > 0) {
     587            0 :                     WRITE_WARNING("Person '" + ped.getPerson()->getID() + "' could not find route across junction '" + junction->getID()
     588              :                                   + "' from edge '" + currentEdge->getID()
     589              :                                   + "' to edge '" + nextRouteEdge->getID() + "', time=" +
     590              :                                   time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     591              :                 }
     592       356397 :             } else if (nextLane->getLength() <= POSITION_EPS) {
     593              :                 // internal lane too short
     594              :                 // most often this is due to a zero-size junction. However, if
     595              :                 // the person needs to pass a crossing we cannot skip ahead
     596        10955 :                 if ((nextLane->getCanonicalSuccessorLane() == nullptr
     597        10947 :                         || !nextLane->getCanonicalSuccessorLane()->isCrossing())
     598        32845 :                         && (nextLane->getLogicalPredecessorLane() == nullptr ||
     599        10943 :                             !nextLane->getLogicalPredecessorLane()->isCrossing())) {
     600              :                     //WRITE_WARNING("Person '" + ped.getID()
     601              :                     //        + "' skips short lane '" + nextLane->getID()
     602              :                     //        + "' length=" + toString(nextLane->getLength())
     603              :                     //        + " time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     604              :                     nextLane = nextRouteLane;
     605        10955 :                     nextDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
     606              :                 }
     607              :             }
     608              :         }
     609              :     }
     610      1503139 :     if DEBUGCOND(ped) {
     611            0 :         std::cout << SIMTIME
     612              :                   << " p=" << ped.getPerson()->getID()
     613              :                   << " l=" << currentLane->getID()
     614            0 :                   << " nl=" << (nextLane == nullptr ? "NULL" : nextLane->getID())
     615            0 :                   << " nrl=" << (nextRouteLane == nullptr ? "NULL" : nextRouteLane->getID())
     616              :                   << " d=" << nextDir
     617            0 :                   << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
     618            0 :                   << " pedDir=" << ped.getDirection()
     619            0 :                   << "\n";
     620              :     }
     621              :     assert(nextLane != 0 || nextRouteLane == 0);
     622      1503139 :     return NextLaneInfo(nextLane, link, nextDir);
     623              : }
     624              : 
     625              : 
     626              : const MSLane*
     627       365180 : MSPModel_Striping::getNextWalkingArea(const MSLane* currentLane, const int dir, const MSLink*& link) {
     628       365180 :     if (dir == FORWARD) {
     629       365000 :         for (const MSLink* const l : currentLane->getLinkCont()) {
     630       330709 :             if (l->getLane()->isWalkingArea()) {
     631       270059 :                 link = l;
     632              :                 return l->getLane();
     633              :             }
     634              :         }
     635              :     } else {
     636              :         const std::vector<MSLane::IncomingLaneInfo>& laneInfos = currentLane->getIncomingLanes();
     637        67440 :         for (std::vector<MSLane::IncomingLaneInfo>::const_iterator it = laneInfos.begin(); it != laneInfos.end(); ++it) {
     638        62982 :             if ((*it).lane->isWalkingArea()) {
     639        56372 :                 link = (*it).viaLink;
     640        56372 :                 return (*it).lane;
     641              :             }
     642              :         }
     643              :     }
     644              :     return nullptr;
     645              : }
     646              : 
     647              : 
     648              : MSPModel_Striping::Obstacles
     649     71217353 : MSPModel_Striping::getNeighboringObstacles(const Pedestrians& pedestrians, int egoIndex, int stripes) {
     650     71217353 :     const PState& ego = *static_cast<PState*>(pedestrians[egoIndex]);
     651     71217353 :     const int egoStripe = ego.stripe();
     652     71217353 :     Obstacles obs(stripes, Obstacle(ego.getDirection()));
     653     71217353 :     std::vector<bool> haveBlocker(stripes, false);
     654  10810868769 :     for (int index = egoIndex + 1; index < (int)pedestrians.size(); index++) {
     655  10796447115 :         const PState& p = *static_cast<PState*>(pedestrians[index]);
     656  10796447115 :         if DEBUGCOND(ego) {
     657            0 :             std::cout << SIMTIME << " ped=" << ego.getID() << " cur=" << egoStripe << " checking neighbor " << p.getID()
     658            0 :                       << " nCur=" << p.stripe() << " nOth=" << p.otherStripe();
     659              :         }
     660  10796447115 :         if (!p.isWaitingToEnter() && !p.isJammed()) {
     661    147981734 :             const Obstacle o(p);
     662    147981734 :             if DEBUGCOND(ego) {
     663            0 :                 std::cout << " dist=" << ego.distanceTo(o) << std::endl;
     664              :             }
     665    147981734 :             if (ego.distanceTo(o) == DIST_BEHIND) {
     666              :                 break;
     667              :             }
     668     91186035 :             if (ego.distanceTo(o) == DIST_OVERLAP) {
     669     91186035 :                 if (p.stripe() != egoStripe || p.getDirection() != ego.getDirection()) {
     670     67629532 :                     obs[p.stripe()] = o;
     671     67629532 :                     haveBlocker[p.stripe()] = true;
     672              :                 } else {
     673              :                     //std::cout << SIMTIME << "   ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe=" << egoStripe << "\n";
     674              :                 }
     675     91186035 :                 if (p.otherStripe() != egoStripe || p.getDirection() != ego.getDirection()) {
     676     67629532 :                     obs[p.otherStripe()] = o;
     677     67629532 :                     haveBlocker[p.otherStripe()] = true;
     678              :                 } else {
     679              :                     //std::cout << SIMTIME << "   ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe2=" << egoStripe << "\n";
     680              :                 }
     681              :             } else {
     682            0 :                 if (!haveBlocker[p.stripe()]) {
     683            0 :                     obs[p.stripe()] = o;
     684              :                 }
     685            0 :                 if (!haveBlocker[p.otherStripe()]) {
     686            0 :                     obs[p.otherStripe()] = o;
     687              :                 }
     688              :             }
     689              :         }
     690              :     }
     691     71217353 :     if DEBUGCOND(ego) {
     692            0 :         std::cout << SIMTIME << " ped=" << ego.getPerson()->getID() << "  neighObs=";
     693            0 :         DEBUG_PRINT(obs);
     694              :     }
     695     71217353 :     return obs;
     696            0 : }
     697              : 
     698              : 
     699              : int
     700      3106786 : MSPModel_Striping::getStripeOffset(int origStripes, int destStripes, bool addRemainder) {
     701      3106786 :     int offset = (destStripes - origStripes) / 2;
     702      3106786 :     if (addRemainder) {
     703        13285 :         offset += (destStripes - origStripes) % 2;
     704              :     }
     705      3106786 :     return offset;
     706              : }
     707              : 
     708              : 
     709              : const MSPModel_Striping::Obstacles&
     710     18427413 : MSPModel_Striping::getNextLaneObstacles(NextLanesObstacles& nextLanesObs, const
     711              :                                         MSLane* lane, const MSLane* nextLane, int stripes, int nextDir,
     712              :                                         double currentLength, int currentDir) {
     713              :     if (nextLanesObs.count(nextLane) == 0) {
     714      2350092 :         const double nextLength = nextLane->isWalkingArea() ? myMinNextLengths[nextLane] : nextLane->getLength();
     715              :         // figure out the which pedestrians are ahead on the next lane
     716      2350092 :         const int nextStripes = numStripes(nextLane);
     717              :         // do not move past the end of the next lane in a single step
     718      4700184 :         Obstacles obs(stripes, Obstacle(nextDir == FORWARD ? nextLength : 0, 0, OBSTACLE_NEXTEND, "nextEnd", 0));
     719              : 
     720      2350092 :         const int offset = getStripeOffset(nextStripes, stripes, currentDir != nextDir && nextStripes > stripes);
     721              :         //std::cout << SIMTIME << " getNextLaneObstacles"
     722              :         //    << " nextLane=" << nextLane->getID()
     723              :         //    << " nextLength=" << nextLength
     724              :         //    << " nextDir=" << nextDir
     725              :         //    << " currentLength=" << currentLength
     726              :         //    << " currentDir=" << currentDir
     727              :         //    << " stripes=" << stripes
     728              :         //    << " nextStripes=" << nextStripes
     729              :         //    << " offset=" << offset
     730              :         //    << "\n";
     731      2350092 :         if (nextStripes < stripes) {
     732              :             // some stripes do not continue
     733      2040977 :             for (int ii = 0; ii < stripes; ++ii) {
     734      1761556 :                 if (ii < offset || ii >= nextStripes + offset) {
     735      2417202 :                     obs[ii] = Obstacle(nextDir == FORWARD ? 0 : nextLength, 0, OBSTACLE_END, "stripeEnd", 0);
     736              :                 }
     737              :             }
     738              :         }
     739      2350092 :         Pedestrians& pedestrians = getPedestrians(nextLane);
     740      2350092 :         if (nextLane->isWalkingArea()) {
     741      1210294 :             transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
     742              :             // complex transformation into the coordinate system of the current lane
     743              :             // (pedestrians on next lane may walk at arbitrary angles relative to the current lane)
     744      1210294 :             double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
     745      1210294 :             if ((stripes - nextStripes) % 2 != 0) {
     746       457496 :                 lateral_offset += 0.5 * stripeWidth;
     747              :             }
     748              :             nextDir = currentDir;
     749              :             // transform pedestrians into the current coordinate system
     750      9067543 :             for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
     751      7857249 :                 const PState& p = *static_cast<PState*>(pedestrians[ii]);
     752      7857249 :                 if (p.isWaitingToEnter() || p.isJammed()) {
     753      2675040 :                     continue;
     754              :                 }
     755      5182209 :                 Position pPos = p.getPosition(*p.getStage(), -1);
     756      5182209 :                 Position relPos = lane->getShape().transformToVectorCoordinates(pPos, true);
     757              :                 if (relPos == Position::INVALID) {
     758            0 :                     WRITE_WARNINGF("Could not map position % onto lane '%'", pPos, lane->getID());
     759              :                 }
     760      5182209 :                 const double newY = relPos.y() + lateral_offset;
     761              :                 //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";
     762      5182209 :                 if ((currentDir == FORWARD && relPos.x() >= lane->getLength()) || (currentDir == BACKWARD && relPos.x() < 0)) {
     763      5180771 :                     addCloserObstacle(obs, relPos.x(), p.stripe(newY), stripes, p.getPerson()->getID(), p.getPerson()->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
     764      5180771 :                     addCloserObstacle(obs, relPos.x(), p.otherStripe(newY), stripes, p.getPerson()->getID(), p.getPerson()->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
     765              :                 }
     766              :             }
     767              :         } else {
     768              :             // simple transformation into the coordinate system of the current lane
     769              :             // (only need to worry about currentDir and nextDir)
     770              :             // XXX consider waitingToEnter on nextLane
     771      1139798 :             sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(nextDir));
     772     35689609 :             for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
     773     34549811 :                 const PState& p = *static_cast<PState*>(pedestrians[ii]);
     774     34549811 :                 if (p.isWaitingToEnter() || p.isJammed()) {
     775     22998490 :                     continue;
     776              :                 }
     777              :                 double newY = p.getPosLat();
     778     11551321 :                 Obstacle pObs(p);
     779     11551321 :                 if (nextDir != currentDir) {
     780       290481 :                     newY = (nextStripes - 1) * stripeWidth - newY;
     781       290481 :                     pObs.speed *= -1;
     782              :                 }
     783     11551321 :                 newY += offset * stripeWidth;
     784     11551321 :                 const int stripe = p.stripe(newY);
     785     11551321 :                 if (stripe >= 0 && stripe < stripes) {
     786     11551318 :                     obs[stripe] = pObs;
     787              :                 }
     788     11551321 :                 const int otherStripe = p.otherStripe(newY);
     789     11551321 :                 if (otherStripe >= 0 && otherStripe < stripes) {
     790     11551318 :                     obs[otherStripe] = pObs;
     791              :                 }
     792              :             }
     793      1139798 :             if (nextLane->isCrossing()) {
     794              :                 // add vehicle obstacles
     795       329243 :                 const MSLink* crossingEntryLink = nextLane->getIncomingLanes().front().viaLink;
     796       329243 :                 const bool prio = crossingEntryLink->havePriority() || crossingEntryLink->getTLLogic() != nullptr;
     797       329243 :                 addCrossingVehs(nextLane, stripes, offset, nextDir, obs, prio, currentDir != nextDir);
     798              :             }
     799      1139798 :             if (nextLane->getVehicleNumberWithPartials() > 0) {
     800        18627 :                 Obstacles vehObs = getVehicleObstacles(nextLane, nextDir);
     801        18627 :                 PState::mergeObstacles(obs, vehObs, nextDir, offset);
     802        18627 :             }
     803      1139798 :             transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
     804              :         }
     805      2350092 :         nextLanesObs[nextLane] = obs;
     806      2350092 :     }
     807     18427413 :     return nextLanesObs[nextLane];
     808              : }
     809              : 
     810              : void
     811      2350092 : MSPModel_Striping::transformToCurrentLanePositions(Obstacles& obs, int currentDir, int nextDir, double currentLength, double nextLength) {
     812     13310532 :     for (Obstacle& o : obs) {
     813     10960440 :         if (currentDir == FORWARD) {
     814      7271206 :             if (nextDir == FORWARD) {
     815      6926321 :                 o.xFwd += currentLength;
     816      6926321 :                 o.xBack += currentLength;
     817              :             } else {
     818       344885 :                 const double tmp = o.xFwd;
     819       344885 :                 o.xFwd = currentLength + nextLength - o.xBack;
     820       344885 :                 o.xBack = currentLength + nextLength - tmp;
     821              :             }
     822              :         } else {
     823      3689234 :             if (nextDir == FORWARD) {
     824       850909 :                 const double tmp = o.xFwd;
     825       850909 :                 o.xFwd = -o.xBack;
     826       850909 :                 o.xBack = -tmp;
     827              :             } else {
     828      2838325 :                 o.xFwd -= nextLength;
     829      2838325 :                 o.xBack -= nextLength;
     830              :             }
     831              :         }
     832              :     }
     833      2350092 : }
     834              : 
     835              : 
     836              : void
     837     10361542 : MSPModel_Striping::addCloserObstacle(Obstacles& obs, double x, int stripe, int numStripes, const std::string& id, double width, int dir, ObstacleType type) {
     838     10361542 :     if (stripe >= 0 && stripe < numStripes) {
     839      2402041 :         if ((dir == FORWARD && x - width / 2. < obs[stripe].xBack) || (dir == BACKWARD && x + width / 2. > obs[stripe].xFwd)) {
     840      2100946 :             obs[stripe] = Obstacle(x, 0, type, id, width);
     841              :         }
     842              :     }
     843     10361542 : }
     844              : 
     845              : void
     846      6253784 : MSPModel_Striping::moveInDirection(SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
     847     50288503 :     for (ActiveLanes::iterator it_lane = myActiveLanes.begin(); it_lane != myActiveLanes.end(); ++it_lane) {
     848     44034723 :         const MSLane* lane = it_lane->first;
     849     44034723 :         Pedestrians& pedestrians = it_lane->second;
     850     44034723 :         if (pedestrians.size() == 0) {
     851     34761260 :             continue;
     852              :         }
     853              :         //std::cout << SIMTIME << ">>> lane=" << lane->getID() << " numPeds=" << pedestrians.size() << "\n";
     854      9273463 :         if (lane->isWalkingArea()) {
     855      2093024 :             const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
     856      2093024 :             const double minY = stripeWidth * - 0.5 + NUMERICAL_EPS;
     857      2093024 :             const double maxY = stripeWidth * (numStripes(lane) - 0.5) - NUMERICAL_EPS;
     858              :             const WalkingAreaPath* debugPath = nullptr;
     859              :             // need to handle each walkingAreaPath separately and transform
     860              :             // coordinates beforehand
     861              :             std::set<const WalkingAreaPath*, walkingarea_path_sorter> paths;
     862     19172065 :             for (Pedestrians::iterator it = pedestrians.begin(); it != pedestrians.end(); ++it) {
     863     17079041 :                 const PState* p = static_cast<PState*>(*it);
     864              :                 assert(p->myWalkingAreaPath != 0);
     865     17079041 :                 if (p->getDirection() == dir) {
     866      8555013 :                     paths.insert(p->myWalkingAreaPath);
     867      8555013 :                     if DEBUGCOND(*p) {
     868            0 :                         debugPath = p->myWalkingAreaPath;
     869            0 :                         std::cout << SIMTIME << " debugging WalkingAreaPath from=" << debugPath->from->getID() << " to=" << debugPath->to->getID() << " minY=" << minY << " maxY=" << maxY << " latOffset=" << lateral_offset << "\n";
     870              :                     }
     871              :                 }
     872              :             }
     873      2093024 :             const double usableWidth = (numStripes(lane) - 1) * stripeWidth;
     874      3220061 :             for (std::set<const WalkingAreaPath*, walkingarea_path_sorter>::iterator it = paths.begin(); it != paths.end(); ++it) {
     875      1127037 :                 const WalkingAreaPath* path = *it;
     876              :                 Pedestrians toDelete;
     877              :                 Pedestrians transformedPeds;
     878      1127037 :                 transformedPeds.reserve(pedestrians.size());
     879     10643481 :                 for (Pedestrians::iterator it_p = pedestrians.begin(); it_p != pedestrians.end(); ++it_p) {
     880      9516444 :                     PState* p = static_cast<PState*>(*it_p);
     881      9516444 :                     if (p->myWalkingAreaPath == path) {
     882      8555013 :                         transformedPeds.push_back(p);
     883      8555013 :                         if (path == debugPath) std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (untransformed), vecCoord="
     884            0 :                                                              << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
     885       961431 :                     } else if (p->myWalkingAreaPath->from == path->to && p->myWalkingAreaPath->to == path->from) {
     886        43228 :                         if (p->myWalkingAreaPath->dir != path->dir) {
     887              :                             // opposite direction is already in the correct coordinate system
     888        39780 :                             transformedPeds.push_back(p);
     889        39780 :                             if (path == debugPath) std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (untransformed), vecCoord="
     890            0 :                                                                  << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
     891              :                         } else {
     892              :                             // x position must be reversed
     893         3448 :                             PState* tp = new PState(*p);
     894         3448 :                             tp->reverse(path->length, usableWidth);
     895         3448 :                             toDelete.push_back(tp);
     896         3448 :                             transformedPeds.push_back(tp);
     897         3448 :                             if (path == debugPath) std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << p->getEdgePos(0) << " relY=" << p->getPosLat() << " (semi-transformed), vecCoord="
     898            0 :                                                                  << path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1)) << "\n";
     899              :                         }
     900              :                     } else {
     901       918203 :                         const Position relPos = path->shape.transformToVectorCoordinates(p->getPosition(*p->getStage(), -1));
     902       918203 :                         const double newY = relPos.y() + lateral_offset;
     903       917096 :                         if (relPos != Position::INVALID && newY >= minY && newY <= maxY) {
     904       256851 :                             PState* tp = new PState(*p);
     905       256851 :                             tp->reset(relPos.x(), newY);
     906       256851 :                             toDelete.push_back(tp);
     907       256851 :                             transformedPeds.push_back(tp);
     908       256851 :                             if (path == debugPath) {
     909            0 :                                 std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << relPos.x() << " relY=" << newY << " (transformed), vecCoord=" << relPos << "\n";
     910              :                             }
     911              :                         } else {
     912       661352 :                             if (path == debugPath) {
     913            0 :                                 std::cout << "  ped=" << p->getPerson()->getID() << "  relX=" << relPos.x() << " relY=" << newY << " (invalid), vecCoord=" << relPos << "\n";
     914              :                             }
     915              :                         }
     916              :                     }
     917              :                 }
     918              :                 auto itFoe = myWalkingAreaFoes.find(&lane->getEdge());
     919      1127037 :                 if (itFoe != myWalkingAreaFoes.end()) {
     920              :                     // add vehicle foes on paths which cross this walkingarea
     921              :                     // translate the vehicle into a number of dummy-pedestrians
     922              :                     // that occupy the same space
     923      2265351 :                     for (const MSLane* foeLane : itFoe->second) {
     924       184908 :                         for (auto itVeh = foeLane->anyVehiclesBegin(); itVeh != foeLane->anyVehiclesEnd(); ++itVeh) {
     925       184908 :                             const MSVehicle* veh = *itVeh;
     926       184908 :                             const double vehWidth = veh->getVehicleType().getWidth();
     927       184908 :                             Boundary relCorners;
     928       184908 :                             Position relFront = path->shape.transformToVectorCoordinates(veh->getPosition(), true);
     929       184908 :                             Position relBack = path->shape.transformToVectorCoordinates(veh->getBackPosition(), true);
     930              :                             if (relFront == Position::INVALID) {
     931            0 :                                 WRITE_WARNINGF("Could not vehicle '%' front position % onto walkingarea '%' path=%, time=%.",
     932              :                                                veh->getID(), veh->getPosition(), lane->getID(), path->shape, time2string(SIMSTEP));
     933              :                             }
     934              :                             if (relBack == Position::INVALID) {
     935            0 :                                 WRITE_WARNINGF("Could not vehicle '%' back position % onto walkingarea '%' path=%, time=%.",
     936              :                                                veh->getID(), veh->getBackPosition(), lane->getID(), path->shape, time2string(SIMSTEP));
     937              :                             }
     938       184908 :                             PositionVector relCenter;
     939       184908 :                             relCenter.push_back(relFront);
     940       184908 :                             relCenter.push_back(relBack);
     941       184908 :                             relCenter.move2side(vehWidth / 2);
     942       184908 :                             relCorners.add(relCenter[0]);
     943       184908 :                             relCorners.add(relCenter[1]);
     944       184908 :                             relCenter.move2side(-vehWidth);
     945       184908 :                             relCorners.add(relCenter[0]);
     946       184908 :                             relCorners.add(relCenter[1]);
     947              :                             // persons should require less gap than the vehicles to prevent getting stuck
     948              :                             // when a vehicles moves towards them
     949       184908 :                             relCorners.growWidth(SAFETY_GAP / 2);
     950       184908 :                             const double xWidth = relCorners.getWidth();
     951       184908 :                             const double vehYmin = MAX2(minY - lateral_offset, relCorners.ymin());
     952       184908 :                             const double vehYmax = MIN2(maxY - lateral_offset, relCorners.ymax());
     953       184908 :                             const double xCenter = relCorners.getCenter().x();
     954              :                             Position yMinPos(xCenter, vehYmin);
     955              :                             Position yMaxPos(xCenter, vehYmax);
     956       184908 :                             const bool addFront = addVehicleFoe(veh, lane, yMinPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
     957       184908 :                             const bool addBack = addVehicleFoe(veh, lane, yMaxPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
     958       184908 :                             if (path == debugPath) {
     959              :                                 std::cout << "  veh=" << veh->getID()
     960            0 :                                           << " corners=" << relCorners
     961              :                                           << " xWidth=" << xWidth
     962            0 :                                           << " ymin=" << relCorners.ymin()
     963            0 :                                           << " ymax=" << relCorners.ymax()
     964              :                                           << " vehYmin=" << vehYmin
     965              :                                           << " vehYmax=" << vehYmax
     966            0 :                                           << "\n";
     967              :                             }
     968       184908 :                             if (addFront && addBack) {
     969              :                                 // add in-between positions
     970       184908 :                                 const double yDist = vehYmax - vehYmin;
     971       421806 :                                 for (double dist = stripeWidth; dist < yDist; dist += stripeWidth) {
     972       236898 :                                     const double relDist = dist / yDist;
     973       236898 :                                     Position between = (yMinPos * relDist) + (yMaxPos * (1 - relDist));
     974       236898 :                                     if (path == debugPath) {
     975            0 :                                         std::cout << "  vehBetween=" << veh->getID() << " pos=" << between << "\n";
     976              :                                     }
     977       236898 :                                     addVehicleFoe(veh, lane, between, dir * xWidth, stripeWidth, lateral_offset, minY, maxY, toDelete, transformedPeds);
     978              :                                 }
     979              :                             }
     980       184908 :                         }
     981              :                     }
     982              :                 }
     983      1127037 :                 moveInDirectionOnLane(transformedPeds, lane, currentTime, changedLane, dir, path == debugPath);
     984      1127037 :                 arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
     985              :                 // clean up
     986      1892255 :                 for (Pedestrians::iterator it_p = toDelete.begin(); it_p != toDelete.end(); ++it_p) {
     987       765218 :                     delete *it_p;
     988              :                 }
     989      1127037 :             }
     990              :         } else {
     991      7180439 :             moveInDirectionOnLane(pedestrians, lane, currentTime, changedLane, dir, false);
     992      7180439 :             arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
     993              :         }
     994              :     }
     995      6253780 : }
     996              : 
     997              : 
     998              : bool
     999       606714 : MSPModel_Striping::addVehicleFoe(const MSVehicle* veh, const MSLane* walkingarea, const Position& relPos, double xWidth, double yWidth, double lateral_offset,
    1000              :                                  double minY, double maxY, Pedestrians& toDelete, Pedestrians& transformedPeds) {
    1001              :     if (relPos != Position::INVALID) {
    1002       606714 :         const double newY = relPos.y() + lateral_offset;
    1003       606714 :         if (newY >= minY && newY <= maxY) {
    1004       504919 :             PState* tp = new PStateVehicle(veh, walkingarea, relPos.x(), newY, xWidth, yWidth);
    1005              :             //std::cout << SIMTIME << " addVehicleFoe=" << veh->getID() << " rx=" << relPos.x() << " ry=" << newY << " s=" << tp->stripe() << " o=" << tp->otherStripe() << "\n";
    1006       504919 :             toDelete.push_back(tp);
    1007       504919 :             transformedPeds.push_back(tp);
    1008              :         }
    1009       606714 :         return true;
    1010              :     } else {
    1011              :         return false;
    1012              :     }
    1013              : }
    1014              : 
    1015              : void
    1016      8307476 : MSPModel_Striping::arriveAndAdvance(Pedestrians& pedestrians, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
    1017              :     // advance to the next lane / arrive at destination
    1018      8307476 :     sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
    1019              :     // can't use iterators because we do concurrent modification
    1020    143372131 :     for (int i = 0; i < (int)pedestrians.size(); i++) {
    1021    135064659 :         PState* const p = static_cast<PState*>(pedestrians[i]);
    1022    135064659 :         if (p->isRemoteControlled()) {
    1023        26806 :             continue;
    1024              :         }
    1025    135037853 :         if (p->getDirection() == dir && p->distToLaneEnd() < 0) {
    1026              :             // moveToNextLane may trigger re-insertion (for consecutive
    1027              :             // walks) so erase must be called first
    1028              :             pedestrians.erase(pedestrians.begin() + i);
    1029       987586 :             i--;
    1030       987586 :             p->moveToNextLane(currentTime);
    1031       987582 :             if (p->getLane() != nullptr) {
    1032       756694 :                 changedLane.insert(p->getPerson());
    1033       756694 :                 myActiveLanes[p->getLane()].push_back(p);
    1034              :             } else {
    1035              :                 // end walking stage and destroy PState
    1036       230888 :                 p->getStage()->moveToNextEdge(p->getPerson(), currentTime, dir);
    1037       230888 :                 myNumActivePedestrians--;
    1038              :             }
    1039              :         }
    1040              :     }
    1041      8307472 : }
    1042              : 
    1043              : 
    1044              : void
    1045      8307476 : MSPModel_Striping::moveInDirectionOnLane(Pedestrians& pedestrians, const MSLane* lane, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir, bool debug) {
    1046      8307476 :     const int stripes = numStripes(lane);
    1047              :     //std::cout << " laneWidth=" << lane->getWidth() << " stripeWidth=" << stripeWidth << " stripes=" << stripes << "\n";
    1048     16614952 :     Obstacles obs(stripes, Obstacle(dir)); // continuously updated
    1049              :     NextLanesObstacles nextLanesObs; // continuously updated
    1050      8307476 :     sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
    1051              : 
    1052      8307476 :     Obstacles crossingVehs(stripes, Obstacle(dir));
    1053              :     bool hasCrossingVehObs = false;
    1054      8307476 :     if (lane->isCrossing()) {
    1055              :         // assume that vehicles will brake when already on the crossing
    1056       611288 :         hasCrossingVehObs = addCrossingVehs(lane, stripes, 0, dir, crossingVehs, true, false);
    1057              :     }
    1058              : 
    1059    143214407 :     for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
    1060    134906931 :         PState& p = *static_cast<PState*>(pedestrians[ii]);
    1061              :         UNUSED_PARAMETER(debug);
    1062              :         //if (debug) {
    1063              :         //    std::cout << SIMTIME << " CHECKING d=" << dir << " p=" << p.getID() << " relX=" << p.myRelX << " xmin=" << p.getMinX() << " xmax=" << p.getMaxX() << " pdir=" << p.getDirection() << "\n";
    1064              :         //}
    1065    134906931 :         Obstacles currentObs = obs;
    1066    134906931 :         if (p.getDirection() != dir || changedLane.count(p.getPerson()) != 0 || p.getRemotePosition() != Position::INVALID) {
    1067     63689578 :             if (!p.isWaitingToEnter() && !p.isJammed()) {
    1068              :                 //if DEBUGCOND(p) {
    1069              :                 //    std::cout << "   obs=" << p.getPerson()->getID() << "  y=" << p.getPosLat() << "  stripe=" << p.stripe() << " oStripe=" << p.otherStripe() << "\n";
    1070              :                 //}
    1071     31173399 :                 Obstacle o(p);
    1072     31173399 :                 if (p.getDirection() != dir && p.getSpeed() == 0.) {
    1073              :                     // ensure recognition of oncoming
    1074      8550125 :                     o.speed = (p.getDirection() == FORWARD ? 0.1 : -0.1);
    1075              :                 }
    1076     31173399 :                 if (o.closer(obs[p.stripe()], dir)) {
    1077     31169094 :                     obs[p.stripe()] = o;
    1078              :                 }
    1079     31173399 :                 if (o.closer(obs[p.otherStripe()], dir)) {
    1080     31168972 :                     obs[p.otherStripe()] = o;
    1081              :                 }
    1082              :             }
    1083              :             continue;
    1084     63689578 :         }
    1085     71217353 :         if DEBUGCOND(p) {
    1086            0 :             std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  currentObs=";
    1087            0 :             gDebugFlag1 = true;
    1088            0 :             DEBUG_PRINT(currentObs);
    1089              :         }
    1090     71217353 :         const MSLane* nextLane = p.myNLI.lane;
    1091     71217353 :         const MSLink* link = p.myNLI.link;
    1092     71217353 :         const double dist = p.distToLaneEnd();
    1093              :         const double speed(p.getStage()->getConfiguredSpeed() >= 0
    1094     71217353 :                            ? p.getStage()->getConfiguredSpeed()
    1095     59019208 :                            : ((nextLane != nullptr && (USE_NET_SPEEDS || nextLane->isNormal() || nextLane->isInternal()))
    1096    128828443 :                               ? nextLane->getVehicleMaxSpeed(p.getPerson())
    1097     13496137 :                               : p.getStage()->getMaxSpeed(p.getPerson())));
    1098              : 
    1099              : 
    1100     71217353 :         if (nextLane != nullptr && dist <= LOOKAHEAD_ONCOMING_DIST) {
    1101     18427413 :             const double currentLength = (p.myWalkingAreaPath == nullptr ? lane->getLength() : p.myWalkingAreaPath->length);
    1102     18427413 :             const Obstacles& nextObs = getNextLaneObstacles(
    1103              :                                            nextLanesObs, lane, nextLane, stripes,
    1104              :                                            p.myNLI.dir, currentLength, dir);
    1105              : 
    1106     18427413 :             if DEBUGCOND(p) {
    1107            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  nextObs=";
    1108            0 :                 DEBUG_PRINT(nextObs);
    1109              :             }
    1110     18427413 :             p.mergeObstacles(currentObs, nextObs);
    1111              :         }
    1112     71217353 :         if DEBUGCOND(p) {
    1113            0 :             std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithNext=";
    1114            0 :             DEBUG_PRINT(currentObs);
    1115              :         }
    1116     71217353 :         p.mergeObstacles(currentObs, getNeighboringObstacles(pedestrians, ii, stripes));
    1117     71217353 :         if DEBUGCOND(p) {
    1118            0 :             std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithNeigh=";
    1119            0 :             DEBUG_PRINT(currentObs);
    1120              :         }
    1121              :         // time gap to pass the intersection ahead of a vehicle.
    1122     71217353 :         const double passingLength = p.getLength() + p.getPerson()->getTimegapCrossing() * speed;
    1123              :         // check link state
    1124     71217353 :         if DEBUGCOND(p) {
    1125            0 :             gDebugFlag1 = true; // get debug output from MSLink
    1126            0 :             std::cout << "   link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
    1127            0 :                       << " dist=" << dist << " d2=" << dist - p.getMinGap() << " la=" << LOOKAHEAD_SAMEDIR* speed << "\n";
    1128              :         }
    1129              :         if (link != nullptr
    1130              :                 // only check close before junction, @todo we should take deceleration into account here
    1131     58105127 :                 && dist - p.getMinGap() < LOOKAHEAD_SAMEDIR * speed
    1132              :                 // persons move before vehicles so we subtract DELTA_TO because they cannot rely on vehicles having passed the intersection in the current time step
    1133     83577217 :                 && (!link->opened(currentTime - DELTA_T, speed, speed, passingLength, p.getImpatience(), speed, 0, 0, nullptr, p.ignoreRed(link), p.getPerson())
    1134     11700923 :                     || p.stopForYellow(link))) {
    1135              :             // prevent movement passed a closed link
    1136       659859 :             Obstacles closedLink(stripes, Obstacle(p.getEdgePos(0) + dir * (dist - NUMERICAL_EPS), 0, OBSTACLE_LINKCLOSED, "closedLink_" + link->getViaLaneOrLane()->getID(), 0));
    1137       659859 :             p.mergeObstacles(currentObs, closedLink);
    1138       659859 :             if DEBUGCOND(p) {
    1139            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithTLS=";
    1140            0 :                 DEBUG_PRINT(currentObs);
    1141              :             }
    1142              :             // consider rerouting over another crossing
    1143       659859 :             if (p.myWalkingAreaPath != nullptr) {
    1144              :                 // @todo actually another path would be needed starting at the current position
    1145       502191 :                 const MSLane* oldNext = p.myNLI.lane;
    1146       502191 :                 p.myNLI = getNextLane(p, p.getLane(), p.myWalkingAreaPath->from);
    1147       502191 :                 if (p.myNLI.lane != oldNext && oldNext->isPriorityCrossing()) {
    1148          153 :                     unregisterCrossingApproach(p, oldNext);
    1149              :                 }
    1150              :             }
    1151       659859 :         }
    1152     71217353 :         if DEBUGCOND(p) {
    1153            0 :             gDebugFlag1 = false;
    1154              :         }
    1155     71217353 :         if (&lane->getEdge() == p.getStage()->getDestination() && p.getStage()->getDestinationStop() != nullptr) {
    1156              :             Obstacles arrival;
    1157      1385631 :             if (p.getStage()->getDestinationStop()->getWaitingCapacity() > p.getStage()->getDestinationStop()->getNumWaitingPersons() ||
    1158              :                     (!p.getStage()->getDestinationStop()->checkPersonCapacity())) {
    1159      2567384 :                 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() + dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival", 0));
    1160              :             } else {
    1161       203878 :                 arrival = Obstacles(stripes, Obstacle(p.getStage()->getArrivalPos() - dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival_blocked", 0));
    1162              :             }
    1163      1385631 :             p.mergeObstacles(currentObs, arrival);
    1164      1385631 :         }
    1165              : 
    1166     71217353 :         if (lane->getVehicleNumberWithPartials() > 0) {
    1167              :             // react to vehicles on the same lane
    1168              :             // @todo: improve efficiency by using the same iterator for all pedestrians on this lane
    1169       275497 :             Obstacles vehObs = getVehicleObstacles(lane, dir, &p);
    1170       275497 :             p.mergeObstacles(currentObs, vehObs);
    1171       275497 :             if DEBUGCOND(p) {
    1172            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithVehs=";
    1173            0 :                 DEBUG_PRINT(currentObs);
    1174              :             }
    1175       275497 :         }
    1176     71217353 :         if (hasCrossingVehObs) {
    1177        24786 :             p.mergeObstacles(currentObs, crossingVehs);
    1178        24786 :             if DEBUGCOND(p) {
    1179            0 :                 std::cout << SIMTIME << " ped=" << p.getPerson()->getID() << "  obsWithVehs2=";
    1180            0 :                 DEBUG_PRINT(currentObs);
    1181              :             }
    1182              :         }
    1183              : 
    1184              :         // walk, taking into account all obstacles
    1185     71217353 :         p.walk(currentObs);
    1186     71217353 :         gDebugFlag1 = false;
    1187     71217353 :         if (!p.isWaitingToEnter() && !p.isJammed()) {
    1188     36052969 :             Obstacle o(p);
    1189     36052969 :             if (o.closer(obs[p.stripe()], dir)) {
    1190     36051414 :                 obs[p.stripe()] = o;
    1191              :             }
    1192     36052969 :             if (o.closer(obs[p.otherStripe()], dir)) {
    1193     36051409 :                 obs[p.otherStripe()] = o;
    1194              :             }
    1195     36052969 :             if (MSGlobals::gCheck4Accidents && p.myWalkingAreaPath == nullptr && !p.isJammed()) {
    1196   2946736950 :                 for (int coll = 0; coll < ii; ++coll) {
    1197   2916513102 :                     PState& c = *static_cast<PState*>(pedestrians[coll]);
    1198   2916513102 :                     if (!c.isWaitingToEnter() && c.myWalkingAreaPath == nullptr && !c.isJammed()) {
    1199   1298237055 :                         if (c.stripe() == p.stripe() || p.stripe() == c.otherStripe() || p.otherStripe() == c.stripe() || p.otherStripe() == c.otherStripe()) {
    1200    491718229 :                             Obstacle cObs(c);
    1201              :                             // we check only for real collisions, no min gap violations
    1202    491718229 :                             if (p.distanceTo(cObs, false) == DIST_OVERLAP) {
    1203      1165892 :                                 WRITE_WARNING("Collision of person '" + p.getPerson()->getID() + "' and person '" + c.getPerson()->getID()
    1204              :                                               + "', lane='" + lane->getID() + "', time=" + time2string(currentTime) + ".");
    1205              :                             }
    1206              :                         }
    1207              :                     }
    1208              :                 }
    1209              :             }
    1210              :         }
    1211              :         //std::cout << SIMTIME << p.getPerson()->getID() << " lane=" << lane->getID() << " x=" << p.myRelX << "\n";
    1212    134906931 :     }
    1213     16614952 : }
    1214              : 
    1215              : 
    1216              : void
    1217       487479 : MSPModel_Striping::registerCrossingApproach(const PState& ped, const MSLane* crossing, const MSLane* beforeWA) {
    1218              :     // person has entered the walkingarea
    1219       487479 :     SUMOTime arrivalTime = SIMSTEP;
    1220              :     assert(ped.getLane()->isWalkingArea());
    1221       487479 :     const WalkingAreaPath* wa = getWalkingAreaPath(&ped.getLane()->getEdge(), beforeWA, crossing);
    1222       487479 :     const double speed = ped.getStage()->getMaxSpeed(ped.getPerson()) * (1 - dawdling / 2);
    1223       487479 :     arrivalTime += TIME2STEPS(wa->length / speed);
    1224       487479 :     SUMOTime leavingTime = arrivalTime + TIME2STEPS(crossing->getLength() / speed);
    1225       487479 :     crossing->getIncomingLanes()[0].viaLink->setApproachingPerson(ped.getPerson(), arrivalTime, leavingTime);
    1226       487479 :     if DEBUGCOND(ped) {
    1227            0 :         std::cout << SIMTIME << " register " << ped.getPerson()->getID() << " at crossing " << crossing->getID() << "\n";
    1228              :     }
    1229       487479 : }
    1230              : 
    1231              : 
    1232              : bool
    1233       940531 : MSPModel_Striping::addCrossingVehs(const MSLane* crossing, int stripes, double lateral_offset, int dir, Obstacles& obs, bool prio, bool flipY) {
    1234              :     bool hasCrossingVehObs = false;
    1235       940531 :     const MSLink* crossingExitLink = crossing->getLinkCont().front();
    1236       940531 :     gDebugFlag1 = DEBUGCOND2(crossing);
    1237       940531 :     const MSLink::LinkLeaders linkLeaders = crossingExitLink->getLeaderInfo(nullptr, crossing->getLength());
    1238       940531 :     gDebugFlag1 = false;
    1239       940531 :     if (linkLeaders.size() > 0) {
    1240       215106 :         for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
    1241              :             // the vehicle to enter the junction first has priority
    1242       109620 :             const MSVehicle* veh = (*it).vehAndGap.first;
    1243       109620 :             if (veh != nullptr) {
    1244       109620 :                 Obstacle vo((*it).distToCrossing, 0, OBSTACLE_VEHICLE, veh->getID(), veh->getVehicleType().getWidth() + 2 * minGapToVehicle, veh);
    1245              :                 // block entry to the crossing in walking direction but allow leaving it
    1246       109620 :                 Obstacle voBlock = vo;
    1247       109620 :                 if (dir == FORWARD) {
    1248        61444 :                     voBlock.xBack = NUMERICAL_EPS;
    1249              :                 } else {
    1250        48176 :                     voBlock.xFwd = crossing->getLength() - NUMERICAL_EPS;
    1251              :                 }
    1252              :                 // when approaching a priority crossings, vehicles must be able
    1253              :                 // to brake, otherwise the person must be able to cross in time
    1254       109620 :                 const double distToCrossBeforeVeh = (dir == FORWARD ? vo.xFwd : crossing->getLength() - vo.xBack);
    1255              :                 const double bGap = (prio
    1256       111237 :                                      ? veh->getCarFollowModel().brakeGap(veh->getSpeed(), veh->getCarFollowModel().getMaxDecel(), 0)
    1257         1617 :                                      : veh->getSpeed() * distToCrossBeforeVeh); // walking 1m/s
    1258              :                 double vehYmin;
    1259              :                 double vehYmax;
    1260              :                 // relY increases from left to right (the other way around from vehicles)
    1261       109620 :                 if ((*it).fromLeft()) {
    1262        71212 :                     vehYmin = -(*it).vehAndGap.second + lateral_offset; // vehicle back
    1263        71212 :                     vehYmax = vehYmin + veh->getVehicleType().getLength() + bGap + minGapToVehicle;
    1264        71212 :                     vehYmin -= minGapToVehicle;
    1265              :                 } else {
    1266        38408 :                     vehYmax = crossing->getWidth() + (*it).vehAndGap.second - lateral_offset; // vehicle back
    1267        38408 :                     vehYmin = vehYmax - veh->getVehicleType().getLength() - bGap - minGapToVehicle;
    1268        38408 :                     vehYmax += minGapToVehicle;
    1269              : 
    1270              :                 }
    1271       438752 :                 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax), stripes); ++s) {
    1272       185493 :                     if ((dir == FORWARD && obs[s].xBack > vo.xBack)
    1273       329411 :                             || (dir == BACKWARD && obs[s].xFwd < vo.xFwd)) {
    1274       327767 :                         if (!prio && veh->getSpeed() > SUMO_const_haltingSpeed) {
    1275              :                             // do not enter the crossing
    1276         9162 :                             obs[s] = voBlock;
    1277              :                         } else {
    1278       318605 :                             obs[s] = vo;
    1279              :                         }
    1280              :                         hasCrossingVehObs = true;
    1281              :                     }
    1282              :                 }
    1283       109620 :                 if (flipY) {
    1284        24244 :                     Obstacles tmp = obs;
    1285       174170 :                     for (int i = 0; i < (int)obs.size(); i++) {
    1286       149926 :                         obs[i] = tmp[obs.size() - 1 - i];
    1287              :                     }
    1288        24244 :                 }
    1289       109620 :                 if (DEBUGCOND2(crossing)) {
    1290            0 :                     std::cout << SIMTIME
    1291              :                               << " crossingVeh=" << veh->getID()
    1292              :                               << " lane=" << crossing->getID()
    1293              :                               << " prio=" << prio
    1294              :                               << " latOffset=" << lateral_offset
    1295              :                               << " dir=" << dir
    1296            0 :                               << " flipY=" << flipY
    1297              :                               << " stripes=" << stripes
    1298            0 :                               << " dist=" << (*it).distToCrossing
    1299            0 :                               << " gap=" << (*it).vehAndGap.second
    1300              :                               << " brakeGap=" << bGap
    1301              :                               << " fromLeft=" << (*it).fromLeft()
    1302              :                               << " distToCrossBefore=" << distToCrossBeforeVeh
    1303              :                               << " ymin=" << vehYmin
    1304              :                               << " ymax=" << vehYmax
    1305              :                               << " smin=" << PState::stripe(vehYmin)
    1306            0 :                               << " smax=" << PState::stripe(vehYmax)
    1307            0 :                               << "\n";
    1308            0 :                     DEBUG_PRINT(obs);
    1309              :                 }
    1310              :             }
    1311              :         }
    1312       105486 :         if (hasCrossingVehObs) {
    1313              :             // check whether the crossing is fully blocked
    1314        70976 :             const int reserved = getReserved((int)obs.size(), RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS);
    1315              :             bool allBlocked = true;
    1316              : 
    1317       391664 :             for (int i = 0; i < (int)obs.size(); i++) {
    1318       347803 :                 const Obstacle& o = obs[i];
    1319       347803 :                 if (o.type != OBSTACLE_VEHICLE && (
    1320        54695 :                             (dir == FORWARD && i >= reserved) ||
    1321        39196 :                             (dir == BACKWARD && i < (int)obs.size() - reserved))) {
    1322              :                     allBlocked = false;
    1323              :                     break;
    1324              :                 }
    1325              :             }
    1326        70976 :             if (allBlocked) {
    1327        43861 :                 if (DEBUGCOND2(crossing)) {
    1328            0 :                     std::cout << SIMTIME << " crossing=" << crossing->getID() << " allBlocked\n";
    1329              :                 }
    1330       311724 :                 for (Obstacle& o : obs) {
    1331       267863 :                     if (dir == FORWARD) {
    1332       149057 :                         o.xBack = NUMERICAL_EPS;
    1333              :                     } else {
    1334       118806 :                         o.xFwd = crossing->getLength() - NUMERICAL_EPS;
    1335              :                     }
    1336              :                 }
    1337              :             }
    1338              :         }
    1339              :     }
    1340       940531 :     return hasCrossingVehObs;
    1341       940531 : }
    1342              : 
    1343              : 
    1344              : MSPModel_Striping::Obstacles
    1345       294124 : MSPModel_Striping::getVehicleObstacles(const MSLane* lane, int dir, PState* ped) {
    1346       294124 :     const int stripes = numStripes(lane);
    1347       588248 :     Obstacles vehObs(stripes, Obstacle(dir));
    1348              :     int current = -1;
    1349              :     double minX = 0.;
    1350              :     double maxX = 0.;
    1351              :     double pRelY = -1.;
    1352              :     double pWidth = 0.;
    1353              :     std::string pID;
    1354       294124 :     bool debug = DEBUGCOND2(lane);
    1355       294124 :     if (ped != nullptr) {
    1356       275497 :         current = ped->stripe();
    1357       275497 :         minX = ped->getMinX();
    1358       275497 :         maxX = ped->getMaxX();
    1359              :         pRelY = ped->getPosLat();
    1360       275497 :         pWidth = ped->getPerson()->getVehicleType().getWidth();
    1361              :         pID = ped->getPerson()->getID();
    1362       275497 :         debug = DEBUGCOND(*ped);
    1363        18627 :     } else if (dir == BACKWARD) {
    1364              :         // checking vehicles on the next lane. Use entry point as reference
    1365              :         minX = lane->getLength();
    1366              :         maxX = lane->getLength();
    1367              :     }
    1368       294124 :     MSLane::AnyVehicleIterator begin = (dir == FORWARD ? lane->anyVehiclesUpstreamBegin() : lane->anyVehiclesBegin());
    1369              :     MSLane::AnyVehicleIterator end = (dir == FORWARD ? lane->anyVehiclesUpstreamEnd() : lane->anyVehiclesEnd());
    1370       780078 :     for (MSLane::AnyVehicleIterator it = begin; it != end; ++it) {
    1371       485954 :         const MSVehicle* veh = *it;
    1372       485954 :         const bool bidi = veh->getLane() == lane->getBidiLane();
    1373       485954 :         const double vehBack = veh->getBackPositionOnLane(lane);
    1374       485954 :         double vehFront = vehBack + veh->getVehicleType().getLength();
    1375              :         // ensure that vehicles are not blocked
    1376       485954 :         const double vehNextSpeed = veh->getWaitingTime() > DELTA_T ? 0 : MAX2(veh->getSpeed(), 1.0);
    1377       485954 :         const double clearance = SAFETY_GAP + vehNextSpeed * LOOKAHEAD_SAMEDIR;
    1378              :         // boundaries for range checking
    1379              :         double vehXMax;
    1380              :         double vehXMin;
    1381              :         double vehXMaxCheck;
    1382              :         double vehXMinCheck;
    1383       485954 :         if (bidi) {
    1384         1617 :             vehFront = vehBack - veh->getVehicleType().getLength();
    1385         1617 :             vehXMax = vehBack + SAFETY_GAP;
    1386         1617 :             vehXMin = vehFront - clearance;
    1387         1617 :             if (dir == FORWARD) {
    1388         1617 :                 vehXMaxCheck = vehBack + NUMERICAL_EPS;
    1389         1617 :                 vehXMinCheck = vehFront - LOOKAROUND_VEHICLES;
    1390              :             } else  {
    1391            0 :                 vehXMaxCheck = vehBack + LOOKAHEAD_SAMEDIR;
    1392              :                 vehXMinCheck = vehFront - clearance;
    1393              :             }
    1394              :         } else {
    1395       484337 :             vehXMax = vehFront + clearance;
    1396       484337 :             vehXMin = vehBack - SAFETY_GAP;
    1397       484337 :             if (dir == FORWARD) {
    1398              :                 vehXMaxCheck = vehFront + clearance;
    1399       362157 :                 vehXMinCheck = vehBack - LOOKAHEAD_SAMEDIR;
    1400              :             } else  {
    1401       122180 :                 vehXMaxCheck = vehFront + LOOKAROUND_VEHICLES;
    1402       122180 :                 vehXMinCheck = vehBack - NUMERICAL_EPS;
    1403              :             }
    1404              :         }
    1405       485954 :         if (debug) {
    1406            0 :             std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " check obstacle on lane=" << lane->getID()
    1407              :                       << "\n"
    1408              :                       << " vehXMin=" << vehXMin
    1409              :                       << " vehXMax=" << vehXMax
    1410              :                       << " vehXMinC=" << vehXMinCheck
    1411              :                       << " vehXMaxC=" << vehXMaxCheck
    1412              :                       << " minX=" << minX
    1413              :                       << " maxX=" << maxX
    1414              :                       << " bidi=" << bidi
    1415              :                       << " vFront=" << vehFront
    1416              :                       << " vBack=" << vehBack
    1417            0 :                       << "\n";
    1418              :         }
    1419       485954 :         if (vehXMaxCheck > minX && vehXMinCheck && vehXMinCheck <= maxX) {
    1420       369698 :             Obstacle vo(vehBack, veh->getSpeed() * (bidi ? -1 : 1), OBSTACLE_VEHICLE, veh->getID(), 0, veh);
    1421              :             // moving vehicles block space along their path
    1422       185203 :             vo.xFwd = vehXMax;
    1423       185203 :             vo.xBack = vehXMin;
    1424              :             // relY increases from left to right (the other way around from vehicles)
    1425              :             // XXX lateral offset for partial vehicles
    1426       185203 :             const double posLat = veh->getLateralPositionOnLane() * (bidi ? -1 : 1);
    1427       185203 :             const double vehYmax = 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - stripeWidth) - posLat;
    1428       185203 :             const double vehYmin = vehYmax - veh->getVehicleType().getWidth();
    1429       803455 :             for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax) + 1, stripes); ++s) {
    1430       618252 :                 Obstacle prior = vehObs[s];
    1431              :                 vehObs[s] = vo;
    1432       618252 :                 if (s == current && vehFront + SAFETY_GAP < minX) {
    1433              :                     // ignore if already overlapping while vehicle is still behind
    1434        16044 :                     if (pRelY - pWidth < vehYmax &&
    1435        15743 :                             pRelY + pWidth > vehYmin && dir == FORWARD) {
    1436         9878 :                         if (debug) {
    1437            0 :                             std::cout << "   ignoring vehicle '" << veh->getID() << " on stripe " << s << " vehFrontSG=" << vehFront + SAFETY_GAP << " minX=" << minX << "\n";
    1438              :                         }
    1439              :                         if (dir == FORWARD) {
    1440              :                             vehObs[s] = prior;
    1441              :                         } else {
    1442              :                             vehObs[s].xFwd = MIN2(vo.xFwd, vehFront + SAFETY_GAP);
    1443              :                         }
    1444              :                     }
    1445              :                 }
    1446              :             }
    1447       185203 :             if (debug) {
    1448            0 :                 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " obstacle on lane=" << lane->getID()
    1449              :                           << "\n"
    1450              :                           << "     ymin=" << vehYmin
    1451              :                           << " ymax=" << vehYmax
    1452              :                           << " smin=" << PState::stripe(vehYmin)
    1453            0 :                           << " smax=" << PState::stripe(vehYmax)
    1454            0 :                           << " relY=" << pRelY
    1455              :                           << " current=" << current
    1456            0 :                           << " vo.xFwd=" << vo.xFwd
    1457            0 :                           << " vo.xBack=" << vo.xBack
    1458              :                           << " vFront=" << vehFront
    1459              :                           << " vBack=" << vehBack
    1460            0 :                           << "\n";
    1461              :             }
    1462              :         }
    1463              :     }
    1464       294124 :     return vehObs;
    1465            0 : }
    1466              : 
    1467              : 
    1468              : // ===========================================================================
    1469              : // MSPModel_Striping::Obstacle method definitions
    1470              : // ===========================================================================
    1471     88126429 : MSPModel_Striping::Obstacle::Obstacle(int dir, double dist) :
    1472     88126429 :     xFwd(dir * dist),  // by default, far away when seen in dir
    1473     88126429 :     xBack(dir * dist),  // by default, far away when seen in dir
    1474     88126429 :     speed(0),
    1475     88126429 :     type(OBSTACLE_NONE),
    1476     88126429 :     description("") {
    1477     88126429 : }
    1478              : 
    1479              : 
    1480    718477652 : MSPModel_Striping::Obstacle::Obstacle(const PState& ped) :
    1481    718477652 :     xFwd(ped.getMaxX()),
    1482    718477652 :     xBack(ped.getMinX()),
    1483    718477652 :     speed(ped.getDirection() * ped.getSpeed()),
    1484    718477652 :     type(ped.getOType()),
    1485    718477652 :     description(ped.getID()) {
    1486              :     assert(!ped.isWaitingToEnter());
    1487    718477652 :     if (type == OBSTACLE_VEHICLE) {
    1488       539718 :         vehicle = static_cast<const PStateVehicle&>(ped).getVehicle();
    1489              :     }
    1490    718477652 : }
    1491              : 
    1492              : 
    1493              : bool
    1494    134452736 : MSPModel_Striping::Obstacle::closer(const Obstacle& o, int dir) {
    1495    134452736 :     if (dir == FORWARD) {
    1496     72594190 :         return xBack <= o.xBack;
    1497              :     } else {
    1498     61858546 :         return xFwd >= o.xFwd;
    1499              :     }
    1500              : }
    1501              : 
    1502              : 
    1503              : // ===========================================================================
    1504              : // MSPModel_Striping::PState method definitions
    1505              : // ===========================================================================
    1506       243944 : MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, const MSLane* lane):
    1507              :     MSPModel_InteractingState(person, stage, lane),
    1508       243944 :     myWalkingAreaPath(nullptr) {
    1509              :     const MSEdge* currentEdge = &lane->getEdge();
    1510              :     const ConstMSEdgeVector& route = myStage->getRoute();
    1511              :     assert(!route.empty());
    1512       243944 :     myDir = FORWARD;
    1513       243944 :     if (route.size() == 1) {
    1514              :         // only a single edge, move towards end pos
    1515        13483 :         myDir = (myEdgePos <= myStage->getArrivalPos()) ? FORWARD : BACKWARD;
    1516       230461 :     } else if (route.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
    1517              :         // start on an intersection
    1518            8 :         if (route.front()->isWalkingArea()) {
    1519            8 :             myWalkingAreaPath = getArbitraryPath(route.front());
    1520              :         }
    1521              :     } else {
    1522       230453 :         int passedFwd = 0;
    1523       230453 :         int passedBwd = 0;
    1524       230453 :         const bool mayStartForward = canTraverse(FORWARD, route, passedFwd) != UNDEFINED_DIRECTION;
    1525       230453 :         const bool mayStartBackward = canTraverse(BACKWARD, route, passedBwd) != UNDEFINED_DIRECTION;
    1526       230453 :         if DEBUGCOND(*this) {
    1527            0 :             std::cout << "  initialize dir for " << myPerson->getID() << " forward=" << mayStartForward << " backward=" << mayStartBackward << "\n";
    1528              :         }
    1529       230453 :         if (mayStartForward && mayStartBackward) {
    1530              :             // figure out the best direction via routing
    1531              :             ConstMSEdgeVector crossingRoute;
    1532         7434 :             MSNet::getInstance()->getPedestrianRouter(0).compute(currentEdge, route.back(), myEdgePos, myStage->getArrivalPos(),
    1533         2478 :                     myStage->getMaxSpeed(person), 0, nullptr, person->getVTypeParameter(), crossingRoute, true);
    1534         2478 :             if (crossingRoute.size() > 1) {
    1535              :                 // route found
    1536         2470 :                 const MSEdge* nextEdge = crossingRoute[1];
    1537         2470 :                 if (nextEdge->getFromJunction() == currentEdge->getFromJunction() || nextEdge->getToJunction() == currentEdge->getFromJunction()) {
    1538         1883 :                     myDir = BACKWARD;
    1539              :                 }
    1540              :             }
    1541         2478 :             if DEBUGCOND(*this) {
    1542            0 :                 std::cout << " crossingRoute=" << toString(crossingRoute) << "\n";
    1543              :             }
    1544       230453 :         } else if (!mayStartForward && !mayStartBackward) {
    1545          157 :             int lastDisconnect = passedFwd >= passedBwd ? passedFwd : passedBwd;
    1546              :             std::string dLoc;
    1547          157 :             if (route.size() > 2) {
    1548          260 :                 dLoc = TLF(" between edge '%' and edge '%'", route[lastDisconnect - 1]->getID(), route[lastDisconnect]->getID());
    1549              :             }
    1550          942 :             WRITE_WARNINGF(TL("Person '%' walking from edge '%' to edge '%' has a disconnect%, time=%."),
    1551              :                            myPerson->getID(), route.front()->getID(), route.back()->getID(), dLoc, SIMTIME);
    1552          162 :             myDir =  passedFwd >= passedBwd ? FORWARD : BACKWARD;
    1553              :         } else {
    1554       426055 :             myDir = !mayStartBackward ? FORWARD : BACKWARD;
    1555              :         }
    1556              :     }
    1557       243944 :     if (myPosLat == UNSPECIFIED_POS_LAT || myLegacyPosLat) {
    1558       243660 :         if (myPosLat == UNSPECIFIED_POS_LAT) {
    1559       243474 :             myPosLat = 0;
    1560              :         }
    1561       243660 :         if (lane->getVehicleNumberWithPartials() > 0 && myPosLat == 0) {
    1562              :             // better start next to the road if nothing was specified
    1563         2158 :             myPosLat -= stripeWidth;
    1564              :         }
    1565       243660 :         if (myDir == FORWARD || lane->getPermissions() != SVC_PEDESTRIAN) {
    1566              :             // start at the right side of the sidewalk on shared roads
    1567       207919 :             myPosLat = stripeWidth * (numStripes(lane) - 1) - myPosLat;
    1568              :         }
    1569          284 :     } else if (myPosLat == RANDOM_POS_LAT) {
    1570           20 :         myPosLat = RandHelper::rand() * stripeWidth * (numStripes(lane) - 1);
    1571              :     } else {
    1572              :         // vehicle to striping coordinate system
    1573          264 :         myPosLat = posLatConversion(myPosLat, lane->getWidth());
    1574              :     }
    1575       243944 :     if DEBUGCOND(*this) {
    1576            0 :         std::cout << "  added new pedestrian " << myPerson->getID() << " on " << lane->getID() << " myEdgePos=" << myEdgePos << " myPosLat=" << myPosLat << " dir=" << myDir << " route=" << toString(myStage->getRoute()) << "\n";
    1577              :     }
    1578              : 
    1579       243944 :     myNLI = getNextLane(*this, lane, nullptr);
    1580       243940 : }
    1581              : 
    1582              : 
    1583           12 : MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, std::istringstream* in) :
    1584              :     MSPModel_InteractingState(person, stage, nullptr),
    1585           12 :     myWalkingAreaPath(nullptr) {
    1586           12 :     if (in != nullptr) {
    1587              :         std::string laneID;
    1588              :         std::string wapLaneFrom;
    1589              :         std::string wapLaneTo;
    1590              :         std::string nextLaneID;
    1591              :         std::string nextLinkFrom;
    1592              :         std::string nextLinkTo;
    1593              :         int nextDir;
    1594              : 
    1595           12 :         (*in) >> laneID
    1596           12 :               >> myEdgePos >> myPosLat >> myDir >> mySpeed >> mySpeedLat >> myWaitingToEnter >> myWaitingTime
    1597           12 :               >> wapLaneFrom >> wapLaneTo
    1598           12 :               >> myAmJammed
    1599              :               >> nextLaneID
    1600              :               >> nextLinkFrom
    1601           12 :               >> nextLinkTo
    1602           12 :               >> nextDir;
    1603              : 
    1604              : 
    1605           12 :         myLane = MSLane::dictionary(laneID);
    1606           12 :         if (myLane == nullptr) {
    1607            0 :             throw ProcessError("Unknown lane '" + laneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1608              :         }
    1609              : 
    1610              :         MSLane* nextLane = nullptr;
    1611           12 :         if (nextLaneID != "null") {
    1612           11 :             nextLane = MSLane::dictionary(nextLaneID);
    1613           11 :             if (nextLane == nullptr) {
    1614            0 :                 throw ProcessError("Unknown next lane '" + nextLaneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1615              :             }
    1616              :         }
    1617              :         const MSLink* link = nullptr;
    1618           12 :         if (nextLinkFrom != "null") {
    1619            2 :             MSLane* from = MSLane::dictionary(nextLinkFrom);
    1620            2 :             MSLane* to = MSLane::dictionary(nextLinkTo);
    1621            2 :             if (from == nullptr) {
    1622            0 :                 throw ProcessError("Unknown link origin lane '" + nextLinkFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1623              :             }
    1624            2 :             if (to == nullptr) {
    1625            0 :                 throw ProcessError("Unknown link destination lane '" + nextLinkTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1626              :             }
    1627            2 :             link = from->getLinkTo(to);
    1628              :         }
    1629           12 :         myNLI =  NextLaneInfo(nextLane, link, nextDir);
    1630              : 
    1631           12 :         if (wapLaneFrom != "null") {
    1632            1 :             MSLane* from = MSLane::dictionary(wapLaneFrom);
    1633            1 :             MSLane* to = MSLane::dictionary(wapLaneTo);
    1634            1 :             if (from == nullptr) {
    1635            0 :                 throw ProcessError("Unknown walkingAreaPath origin lane '" + wapLaneFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1636              :             }
    1637            1 :             if (to == nullptr) {
    1638            0 :                 throw ProcessError("Unknown walkingAreaPath destination lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1639              :             }
    1640            1 :             const auto pathIt = myWalkingAreaPaths.find(std::make_pair(from, to));
    1641            1 :             if (pathIt != myWalkingAreaPaths.end()) {
    1642            1 :                 myWalkingAreaPath = &pathIt->second;
    1643              :             } else {
    1644            0 :                 throw ProcessError("Unknown walkingAreaPath from lane '" + wapLaneFrom + "' to lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1645              :             }
    1646              :         }
    1647              :     }
    1648           12 : }
    1649              : 
    1650              : 
    1651       504919 : MSPModel_Striping::PState::PState() :
    1652       504919 :     MSPModel_InteractingState(nullptr, nullptr, nullptr) {}
    1653              : 
    1654              : 
    1655              : void
    1656            8 : MSPModel_Striping::PState::saveState(std::ostringstream& out) {
    1657            8 :     std::string wapLaneFrom = "null";
    1658            8 :     std::string wapLaneTo = "null";
    1659            8 :     if (myWalkingAreaPath != nullptr) {
    1660            1 :         wapLaneFrom = myWalkingAreaPath->from->getID();
    1661            1 :         wapLaneTo = myWalkingAreaPath->to->getID();
    1662              :     }
    1663            8 :     std::string nextLaneID = "null";
    1664            8 :     std::string nextLinkFrom = "null";
    1665            8 :     std::string nextLinkTo = "null";
    1666            8 :     if (myNLI.lane != nullptr) {
    1667              :         nextLaneID = myNLI.lane->getID();
    1668              :     }
    1669            8 :     if (myNLI.link != nullptr) {
    1670              :         nextLinkFrom = myNLI.link->getLaneBefore()->getID();
    1671            2 :         nextLinkTo = myNLI.link->getViaLaneOrLane()->getID();
    1672              :     }
    1673            8 :     out << " " << myLane->getID()
    1674           16 :         << " " << myEdgePos
    1675            8 :         << " " << myPosLat
    1676              :         << " " << myDir
    1677           16 :         << " " << mySpeed
    1678            8 :         << " " << mySpeedLat
    1679            8 :         << " " << myWaitingToEnter
    1680            8 :         << " " << myWaitingTime
    1681              :         << " " << wapLaneFrom
    1682              :         << " " << wapLaneTo
    1683            8 :         << " " << myAmJammed
    1684              :         << " " << nextLaneID
    1685              :         << " " << nextLinkFrom
    1686              :         << " " << nextLinkTo
    1687            8 :         << " " << myNLI.dir;
    1688            8 : }
    1689              : 
    1690              : double
    1691   2307396243 : MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
    1692              :     // @todo speed should have an influence here because faster persons need more space
    1693   2307396243 :     if (myDir == FORWARD) {
    1694   2138322650 :         return myEdgePos - getLength();
    1695              :     }
    1696    169073593 :     return myEdgePos - (includeMinGap ? getMinGap() : 0.);
    1697              : }
    1698              : 
    1699              : 
    1700              : double
    1701   2307396243 : MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
    1702              :     // @todo speed should have an influence here because faster persons need more space
    1703   2307396243 :     if (myDir == FORWARD) {
    1704   2138322650 :         return myEdgePos + (includeMinGap ? getMinGap() : 0.);
    1705              :     }
    1706    169073593 :     return myEdgePos + getLength();
    1707              : }
    1708              : 
    1709              : 
    1710              : double
    1711   2378613596 : MSPModel_Striping::PState::getLength() const {
    1712   2378613596 :     return myPerson->getVehicleType().getLength();
    1713              : }
    1714              : 
    1715              : 
    1716              : double
    1717   1561520668 : MSPModel_Striping::PState::getMinGap() const {
    1718   1561520668 :     return myPerson->getVehicleType().getMinGap();
    1719              : }
    1720              : 
    1721              : 
    1722              : int
    1723   8436474051 : MSPModel_Striping::PState::stripe(double relY) {
    1724   8436474051 :     return (int)floor(relY / stripeWidth + 0.5);
    1725              : }
    1726              : 
    1727              : 
    1728              : int
    1729   3675074598 : MSPModel_Striping::PState::otherStripe(double relY) const {
    1730   3675074598 :     const int s = stripe(relY);
    1731   3675074598 :     const double offset = relY - s * stripeWidth;
    1732   3675074598 :     const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
    1733              :     int result;
    1734   3675074598 :     if (offset > threshold) {
    1735       504344 :         result = s + 1;
    1736   3674570254 :     } else if (offset < -threshold) {
    1737       426835 :         result = s - 1;
    1738              :     } else {
    1739              :         result = s;
    1740              :     }
    1741              :     //std::cout.setf(std::ios::fixed , std::ios::floatfield);
    1742              :     //std::cout << std::setprecision(5);
    1743              :     //if DEBUGCOND(*this) std::cout << "  otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
    1744   3675074598 :     return result;
    1745              : }
    1746              : 
    1747              : int
    1748   4725779966 : MSPModel_Striping::PState::stripe() const {
    1749   4725779966 :     return MIN2(MAX2(0, stripe(myPosLat)), numStripes(myLane) - 1);
    1750              : }
    1751              : 
    1752              : 
    1753              : int
    1754   3658342506 : MSPModel_Striping::PState::otherStripe() const {
    1755   3658342506 :     return MIN2(MAX2(0, otherStripe(myPosLat)), numStripes(myLane) - 1);
    1756              : }
    1757              : 
    1758              : 
    1759              : double
    1760    144670361 : MSPModel_Striping::PState::distToLaneEnd() const {
    1761    144670361 :     if (myStage->getNextRouteEdge() == nullptr) {
    1762     24817972 :         return myDir * (myStage->getArrivalPos() - myEdgePos) - POSITION_EPS - (
    1763      2226789 :                    (myWaitingTime > DELTA_T && (myStage->getDestinationStop() == nullptr ||
    1764              :                                                 myStage->getDestinationStop()->getWaitingCapacity() > myStage->getDestinationStop()->getNumWaitingPersons()))
    1765     27044761 :                    ? getMinGap() : 0);
    1766              :     } else {
    1767    119852389 :         const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
    1768    119852389 :         return myDir == FORWARD ? length - myEdgePos : myEdgePos;
    1769              :     }
    1770              : }
    1771              : 
    1772              : 
    1773              : bool
    1774       987586 : MSPModel_Striping::PState::moveToNextLane(SUMOTime currentTime) {
    1775       987586 :     double dist = distToLaneEnd();
    1776       987586 :     if (DEBUGCOND(*this)) {
    1777            0 :         std::cout << SIMTIME << " ped=" << myPerson->getID() << " myEdgePos=" << myEdgePos << " dist=" << dist << "\n";
    1778              :     }
    1779       987586 :     if (dist <= 0) {
    1780              :         //if (ped.getPerson()->getID() == DEBUG1) {
    1781              :         //    std::cout << SIMTIME << " addToLane x=" << ped.myEdgePos << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
    1782              :         //}
    1783              :         //std::cout << " changing to " << newLane->getID() << " myPosLat=" << ped.myPosLat << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
    1784              :         //std::cout << " newY=" << ped.myPosLat << " myDir=" << ped.getDirection() << " newDir=" << newDir;
    1785       987586 :         const int oldDir = myDir;
    1786       987586 :         const MSLane* oldLane = myLane;
    1787       987586 :         myLane = myNLI.lane;
    1788       987586 :         myDir = myNLI.dir;
    1789       987586 :         const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
    1790       987586 :         if DEBUGCOND(*this) {
    1791            0 :             std::cout << SIMTIME
    1792            0 :                       << " ped=" << myPerson->getID()
    1793              :                       << " moveToNextLane old=" << oldLane->getID()
    1794            0 :                       << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
    1795              :                       << " oldDir=" << oldDir
    1796            0 :                       << " newDir=" << myDir
    1797            0 :                       << " myEdgePos=" << myEdgePos
    1798              :                       << " dist=" << dist
    1799            0 :                       << "\n";
    1800              :         }
    1801       987586 :         if (myLane == nullptr) {
    1802       230888 :             myEdgePos = myStage->getArrivalPos();
    1803              :         }
    1804              :         // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
    1805       987586 :         if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
    1806       230888 :             myLane = nullptr;
    1807              :         } else {
    1808       756698 :             const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, oldDir, normalLane ? nullptr : &myLane->getEdge());
    1809              :             UNUSED_PARAMETER(arrived);
    1810              :             assert(!arrived);
    1811              :             assert(myDir != UNDEFINED_DIRECTION);
    1812       756698 :             myNLI = getNextLane(*this, myLane, oldLane);
    1813              :             // reminders must be called after updated myNLI (to ensure that getNextEdgePtr returns the correct edge)
    1814       756698 :             myStage->activateEntryReminders(myPerson);
    1815              :             assert(myNLI.lane != oldLane); // do not turn around
    1816       756698 :             if DEBUGCOND(*this) {
    1817            0 :                 std::cout << "    nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
    1818              :             }
    1819       756698 :             if (myLane->isWalkingArea()) {
    1820       346747 :                 if (myNLI.dir != UNDEFINED_DIRECTION) {
    1821       346710 :                     myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
    1822              :                     assert(myWalkingAreaPath->shape.size() >= 2);
    1823       346710 :                     if DEBUGCOND(*this) {
    1824            0 :                         std::cout << "  mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
    1825              :                     }
    1826           37 :                 } else if (myNLI.link != nullptr) {
    1827              :                     // using direct connection (instead of using walkingarea)
    1828           17 :                     myLane = myNLI.lane;
    1829              :                     assert(!myLane->isWalkingArea());
    1830           17 :                     myStage->moveToNextEdge(myPerson, currentTime, myDir, &myLane->getEdge());
    1831           17 :                     myWalkingAreaPath = nullptr;
    1832           17 :                     myNLI = getNextLane(*this, myLane, oldLane);
    1833              :                 } else {
    1834              :                     // disconnected route. move to the next edge
    1835           40 :                     if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
    1836              :                         // try to determine direction from topology, otherwise maintain current direction
    1837           16 :                         const MSEdge* currRouteEdge = *myStage->getRouteStep();
    1838           16 :                         const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
    1839              :                         if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
    1840           16 :                                 || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
    1841            4 :                             myDir = BACKWARD;
    1842              :                         } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
    1843           12 :                                    || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
    1844           12 :                             myDir = FORWARD;
    1845              :                         }
    1846           16 :                         myStage->moveToNextEdge(myPerson, currentTime, oldDir, nullptr);
    1847           16 :                         myLane = myNLI.lane;
    1848              :                         assert(myLane != 0);
    1849              :                         assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
    1850           16 :                         myNLI = getNextLane(*this, myLane, oldLane);
    1851           16 :                         myWalkingAreaPath = nullptr;
    1852              :                     } else {
    1853           12 :                         throw ProcessError(TLF("Disconnected walk for person '%'.", myPerson->getID()));
    1854              :                     }
    1855              :                 }
    1856              :             } else {
    1857       409951 :                 myWalkingAreaPath = nullptr;
    1858              :             }
    1859              :             // adapt x to fit onto the new lane
    1860              :             // (make sure we do not move past the end of the new lane since that
    1861              :             // lane was not checked for obstacles)
    1862       756694 :             const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
    1863       756694 :             if (-dist > newLength) {
    1864              :                 assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
    1865              :                 // should not happen because the end of myLane should have been an obstacle as well
    1866              :                 // (only when the route is broken)
    1867            1 :                 dist = -newLength;
    1868              :             }
    1869       756694 :             if (myDir == BACKWARD) {
    1870       145698 :                 myEdgePos = newLength + dist;
    1871              :             } else {
    1872       610996 :                 myEdgePos = -dist;
    1873              :             }
    1874       756694 :             if DEBUGCOND(*this) {
    1875            0 :                 std::cout << SIMTIME << " update myEdgePos ped=" << myPerson->getID()
    1876              :                           << " newLength=" << newLength
    1877              :                           << " dist=" << dist
    1878            0 :                           << " myEdgePos=" << myEdgePos
    1879            0 :                           << "\n";
    1880              :             }
    1881              :             // adjust to change in direction
    1882       756694 :             if (myDir != oldDir) {
    1883        32614 :                 myPosLat = (numStripes(oldLane) - 1) * stripeWidth - myPosLat;
    1884              :             }
    1885              :             // adjust to differences in sidewalk width
    1886      1500231 :             const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
    1887       756694 :             myPosLat += offset * stripeWidth;
    1888       756694 :             if DEBUGCOND(*this) {
    1889            0 :                 std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
    1890            0 :                           << " newLane=" << Named::getIDSecure(myLane)
    1891            0 :                           << " newY=" << myPosLat
    1892            0 :                           << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
    1893            0 :                           << " od=" << oldDir << " nd=" << myDir
    1894            0 :                           << " offset=" << offset << "\n";
    1895              :             }
    1896              :         }
    1897       987582 :         myAngle = std::numeric_limits<double>::max(); // see #9014
    1898       987582 :         return true;
    1899              :     } else {
    1900              :         return false;
    1901              :     }
    1902              : }
    1903              : 
    1904              : 
    1905              : int
    1906     71288329 : MSPModel_Striping::getReserved(int stripes, double factor) {
    1907     71288329 :     return MIN2(
    1908     71288329 :                (int)floor(stripes * factor),
    1909     71288329 :                (int)floor(RESERVE_FOR_ONCOMING_MAX / stripeWidth));
    1910              : }
    1911              : 
    1912              : void
    1913     71217353 : MSPModel_Striping::PState::walk(const Obstacles& obs) {
    1914     71217353 :     const int stripes = (int)obs.size();
    1915     71217353 :     const int sMax =  stripes - 1;
    1916              :     assert(stripes == numStripes(myLane));
    1917              :     // account stage-specific max speed but also for normal lane speed limit
    1918              :     // (speed limits on crossings and walkingareas ignored due to #11527)
    1919     71217353 :     const double vMax = (myStage->getConfiguredSpeed() >= 0
    1920     71217353 :                          ? myStage->getConfiguredSpeed()
    1921      9168727 :                          : (USE_NET_SPEEDS || myLane->isNormal() || myLane->isInternal()
    1922     79607255 :                             ? myLane->getVehicleMaxSpeed(myPerson)
    1923       723762 :                             : myStage->getMaxSpeed(myPerson)));
    1924              :     // ultimate goal is to choose the preferred stripe (chosen)
    1925     71217353 :     const int current = stripe();
    1926     71217353 :     const int other = otherStripe();
    1927              :     // compute distances
    1928     71217353 :     std::vector<double> distance(stripes);
    1929    308206643 :     for (int i = 0; i < stripes; ++i) {
    1930    236989290 :         distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
    1931              :     }
    1932              :     // compute utility for all stripes
    1933     71217353 :     std::vector<double> utility(stripes, 0);
    1934              :     // forbid stripes which are blocked and also all stripes behind them
    1935    308206643 :     for (int i = 0; i < stripes; ++i) {
    1936    236989290 :         if (distance[i] == DIST_OVERLAP) {
    1937    109080270 :             if (i == current && (!isWaitingToEnter() || stripe() != stripe(myPosLat))) {
    1938      8108386 :                 utility[i] += OBSTRUCTED_PENALTY;
    1939              :             }
    1940    109080270 :             if (i < current) {
    1941    149877353 :                 for (int j = 0; j <= i; ++j) {
    1942     91111640 :                     utility[j] += OBSTRUCTED_PENALTY;
    1943              :                 }
    1944              :             }
    1945    109080270 :             if (i > current) {
    1946     70113033 :                 for (int j = i; j < stripes; ++j) {
    1947     40402528 :                     utility[j] += OBSTRUCTED_PENALTY;
    1948              :                 }
    1949              :             }
    1950              :         }
    1951              :     }
    1952              :     // forbid a portion of the leftmost stripes (in walking direction).
    1953              :     // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
    1954              :     // may still deadlock in heavy pedestrian traffic
    1955     71217353 :     const bool onJunction = myLane->isWalkingArea() || myLane->isCrossing();
    1956     71217353 :     const int reserved = getReserved(stripes, (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
    1957     71217353 :     if (myDir == FORWARD) {
    1958     75191250 :         for (int i = 0; i < reserved; ++i) {
    1959     17855789 :             utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
    1960              :         }
    1961              :     } else {
    1962      6900728 :         for (int i = sMax; i > sMax - reserved; --i) {
    1963      2828413 :             utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
    1964              :         }
    1965              :     }
    1966              :     // adapt utility based on obstacles
    1967    308206643 :     for (int i = 0; i < stripes; ++i) {
    1968    236989290 :         if (obs[i].speed * myDir < 0) {
    1969              :             // penalize evasion to the left unless the obstacle is a vehicle
    1970      4450170 :             if ((myDir == FORWARD || obs[i].type == OBSTACLE_VEHICLE) && i > 0) {
    1971       857252 :                 utility[i - 1] -= 0.5;
    1972      3592918 :             } else if (myDir == BACKWARD && i < sMax) {
    1973       589458 :                 utility[i + 1] -= 0.5;
    1974              :             }
    1975              :         }
    1976              :         // compute expected distance achievable by staying on this stripe for a time horizon
    1977    236989290 :         const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
    1978    236989290 :         const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
    1979    236989290 :         const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
    1980    236989290 :         if (expectedDist >= 0) {
    1981    233872636 :             utility[i] += expectedDist;
    1982              :         } else {
    1983              :             // let only the distance count
    1984      3116654 :             utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
    1985              :         }
    1986              :     }
    1987              :     // discourage use of the leftmost stripe (in walking direction) if there are oncoming
    1988     71217353 :     if (myDir == FORWARD && obs[0].speed < 0) {
    1989      1500925 :         utility[0] += ONCOMING_CONFLICT_PENALTY;
    1990     69716428 :     } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
    1991      1505939 :         utility[sMax] += ONCOMING_CONFLICT_PENALTY;
    1992              :     }
    1993              :     // penalize lateral movement (if the current stripe permits walking)
    1994     71217353 :     if (distance[current] > 0 && myWaitingTime == 0) {
    1995    131120260 :         for (int i = 0; i < stripes; ++i) {
    1996    102678625 :             utility[i] += abs(i - current) * LATERAL_PENALTY;
    1997              :         }
    1998              :     }
    1999              :     // walk on the right side on shared space
    2000     71217353 :     if (myLane->getPermissions() != SVC_PEDESTRIAN && myDir == BACKWARD) {
    2001      2369136 :         for (int i = 0; i < stripes; ++i) {
    2002      1974458 :             if (i <= current) {
    2003      1881274 :                 utility[i] += (sMax - i + 1) * LATERAL_PENALTY;
    2004              :             }
    2005              :         }
    2006              :     }
    2007              : 
    2008              :     // select best stripe
    2009              :     int chosen = current;
    2010    308206643 :     for (int i = 0; i < stripes; ++i) {
    2011    236989290 :         if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
    2012              :             chosen = i;
    2013              :         }
    2014              :     }
    2015              :     // compute speed components along both axes
    2016     71217353 :     const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
    2017     71217353 :     double xDist = MIN3(distance[current], distance[other], distance[next]);
    2018     71217353 :     if (next != chosen) {
    2019              :         // ensure that we do not collide with an obstacle in the stripe beyond
    2020              :         // next as this might become the 'other' stripe in the next step
    2021       487578 :         const int nextOther = chosen < current ? current - 2 : current + 2;
    2022       487578 :         xDist = MIN2(xDist, distance[nextOther]);
    2023              :     }
    2024              :     // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
    2025              :     const double preferredGap = NUMERICAL_EPS;
    2026     71217353 :     double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
    2027     71217353 :     if (xSpeed < NUMERICAL_EPS) {
    2028              :         xSpeed = 0.;
    2029              :     }
    2030     71217353 :     if (DEBUGCOND(*this)) {
    2031            0 :         std::cout << " xSpeedPotential=" << xSpeed << "\n";
    2032              :     }
    2033              :     // avoid tiny steps
    2034              :     // XXX pressure from behind?
    2035     71217353 :     if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
    2036              :             // unless walking towards a short lane
    2037     33018797 :             !(
    2038     33302734 :                 (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
    2039     33018813 :                 || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
    2040     33018797 :                 || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
    2041              :        ) {
    2042              :         xSpeed = 0;
    2043              :     }
    2044     38198558 :     if (xSpeed == 0) {
    2045     40897713 :         if (DEBUGCOND(*this)) {
    2046            0 :             std::cout << " sharedWA=" << (myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())
    2047            0 :                       << " vehObs=" << Named::getIDSecure(obs[current].vehicle)
    2048            0 :                       << " vehWait=" << STEPS2TIME(obs[current].vehicle ? obs[current].vehicle->getWaitingTime() : 0)
    2049            0 :                       << "\n";
    2050              :         }
    2051     40897713 :         if (myWaitingTime > ((myLane->isCrossing()
    2052              :                               // treat shared walkingarea like a crossing to avoid deadlocking vehicles
    2053     40893812 :                               || (myLane->isWalkingArea() && obs[current].vehicle != nullptr && obs[current].vehicle->getWaitingTime() > jamTimeCrossing
    2054     81791808 :                                   && myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())) ? jamTimeCrossing : jamTime)
    2055     40810580 :                 || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
    2056     81679708 :                 || myAmJammed) {
    2057              :             // squeeze slowly through the crowd ignoring others
    2058      9377874 :             if (!myAmJammed) {
    2059        97971 :                 MSNet::getInstance()->getPersonControl().registerJammed();
    2060       391884 :                 WRITE_WARNINGF(TL("Person '%' is jammed on edge '%', time=%."),
    2061              :                                myPerson->getID(), myStage->getEdge()->getID(), time2string(SIMSTEP));
    2062        97971 :                 myAmJammed = true;
    2063              :             }
    2064      9377874 :             xSpeed = vMax * jamFactor;
    2065              :         }
    2066     30319640 :     } else if (myAmJammed && stripe(myPosLat) >= 0 && stripe(myPosLat) <= sMax && xDist >= MIN_STARTUP_DIST)  {
    2067        88916 :         myAmJammed = false;
    2068              :     }
    2069              :     // dawdling
    2070     71217353 :     const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
    2071     71217353 :     xSpeed -= dawdle;
    2072              : 
    2073              :     // XXX ensure that diagonal speed <= vMax
    2074              :     // avoid deadlocks on narrow sidewalks
    2075              :     //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
    2076              :     //    if DEBUGCOND(*this) std::cout << "  stepping aside to resolve oncoming deadlock\n";
    2077              :     //    xSpeed = POSITION_EPS; // reset myWaitingTime
    2078              :     //     if (myDir == FORWARD && chosen < sMax) {
    2079              :     //         chosen += 1;
    2080              :     //     } else if (myDir == BACKWARD && chosen > 0) {
    2081              :     //         chosen -= 1;
    2082              :     //     }
    2083              :     //}
    2084     71217353 :     const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
    2085              :     double ySpeed = 0;
    2086              :     double yDist = 0;
    2087     71217353 :     if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
    2088              :         // don't move laterally if the stripes are blocked
    2089     63158468 :         yDist = (chosen * stripeWidth) - myPosLat;
    2090     63158468 :         if (fabs(yDist) > NUMERICAL_EPS) {
    2091      2754971 :             ySpeed = (yDist > 0 ?
    2092      1264572 :                       MIN2(maxYSpeed, DIST2SPEED(yDist)) :
    2093      1490399 :                       MAX2(-maxYSpeed, DIST2SPEED(yDist)));
    2094              :         }
    2095      8058885 :     } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
    2096              :                // still on the road
    2097         9741 :                && stripe() == stripe(myPosLat)
    2098              :                // only when the vehicle is moving on the same lane
    2099      8064245 :                && !(myLane->isCrossing() || myLane->isWalkingArea())) {
    2100              :         // step aside to let the vehicle pass
    2101         3124 :         int stepAsideDir = myDir;
    2102         3124 :         if (myLane->getEdge().getLanes().size() > 1 || current > sMax / 2) {
    2103              :             // always step to the right on multi-lane edges or when closer to
    2104              :             // the right side
    2105              :             stepAsideDir = FORWARD;
    2106              :         }
    2107         3124 :         myAmJammed = true; // ignore pedestrian-pedestrian collisions
    2108         3124 :         ySpeed = stepAsideDir * vMax;
    2109              :     }
    2110              : 
    2111              :     // DEBUG
    2112     71217353 :     if DEBUGCOND(*this) {
    2113            0 :         std::cout << SIMTIME
    2114            0 :                   << " ped=" << myPerson->getID()
    2115            0 :                   << " edge=" << myStage->getEdge()->getID()
    2116            0 :                   << " x=" << myEdgePos
    2117            0 :                   << " y=" << myPosLat
    2118              :                   << " d=" << myDir
    2119            0 :                   << " pvx=" << mySpeed
    2120              :                   << " cur=" << current
    2121            0 :                   << " cho=" << chosen
    2122            0 :                   << " oth=" << other
    2123            0 :                   << " nxt=" << next
    2124            0 :                   << " vx=" << xSpeed
    2125              :                   << " dawdle=" << dawdle
    2126              :                   << " vy=" << ySpeed
    2127              :                   << " xd=" << xDist
    2128              :                   << " yd=" << yDist
    2129              :                   << " vMax=" << vMax
    2130            0 :                   << " wTime=" << myStage->getWaitingTime()
    2131            0 :                   << " jammed=" << myAmJammed
    2132            0 :                   << "\n";
    2133            0 :         if (DEBUGCOND(*this)) {
    2134            0 :             for (int i = 0; i < stripes; ++i) {
    2135            0 :                 const Obstacle& o = obs[i];
    2136            0 :                 std::cout << " util=" << utility[i] << " dist=" << distance[i] << " o=" << o.description;
    2137            0 :                 if (o.description != "") {
    2138            0 :                     std::cout << " xF=" << o.xFwd << " xB=" << o.xBack << " v=" << o.speed;
    2139              :                 }
    2140            0 :                 if (i == current) {
    2141            0 :                     std::cout << " current";
    2142              :                 }
    2143            0 :                 if (i == other && i != current) {
    2144            0 :                     std::cout << " other";
    2145              :                 }
    2146            0 :                 if (i == chosen) {
    2147            0 :                     std::cout << " chosen";
    2148              :                 }
    2149            0 :                 if (i == next) {
    2150            0 :                     std::cout << " next";
    2151              :                 }
    2152            0 :                 std::cout << "\n";
    2153              :             }
    2154              :         }
    2155              :     }
    2156     71217353 :     myEdgePos += SPEED2DIST(xSpeed * myDir);
    2157     71217353 :     myPosLat += SPEED2DIST(ySpeed);
    2158     71217353 :     mySpeedLat = ySpeed;
    2159     71217353 :     mySpeed = xSpeed;
    2160     71217353 :     if (xSpeed >= SUMO_const_haltingSpeed) {
    2161     35326534 :         myWaitingToEnter = false;
    2162     35326534 :         myWaitingTime = 0;
    2163              :     } else {
    2164     35890819 :         myWaitingTime += DELTA_T;
    2165     35890819 :         myTotalWaitingTime += DELTA_T;
    2166              :     }
    2167     71217353 :     myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
    2168     71217353 : }
    2169              : 
    2170              : 
    2171              : double
    2172     12359864 : MSPModel_Striping::PState::getImpatience() const {
    2173     12359864 :     return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
    2174     12359864 :                          + STEPS2TIME(myStage->getWaitingTime()) / MAX_WAIT_TOLERANCE));
    2175              : }
    2176              : 
    2177              : 
    2178              : Position
    2179     10970950 : MSPModel_Striping::PState::getPosition(const MSStageMoving& stage, SUMOTime) const {
    2180              :     if (myRemoteXYPos != Position::INVALID) {
    2181         6384 :         return myRemoteXYPos;
    2182              :     }
    2183     10964566 :     if (myLane == nullptr) {
    2184              :         // pedestrian has already finished
    2185          203 :         return Position::INVALID;
    2186              :     }
    2187     10964363 :     const double lateral_offset = -getLatOffset();  // the minus is hunting me in my dreams but seems to be here for historical reasons
    2188     10964363 :     if (myWalkingAreaPath == nullptr) {
    2189      1116428 :         return stage.getLanePosition(myLane, myEdgePos, lateral_offset);
    2190              :     } else {
    2191              :         //if DEBUGCOND(*this) {
    2192              :         //    std::cout << SIMTIME
    2193              :         //        << " getPosition (walkingArea)"
    2194              :         //        << " p=" << myPerson->getID()
    2195              :         //        << " x=" << myEdgePos
    2196              :         //        << " y=" << myPosLat
    2197              :         //        << " latOffset=" << lateral_offset
    2198              :         //        << " shape=" << myWalkingAreaPath->shape
    2199              :         //        << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset)
    2200              :         //        << "\n";
    2201              :         //}
    2202      9847935 :         if (myWalkingAreaPath->angleOverride == INVALID_DOUBLE) {
    2203      9658682 :             return myWalkingAreaPath->shape.positionAtOffset(myEdgePos, lateral_offset);
    2204              :         } else {
    2205       189253 :             const double rotationOffset = myDir == FORWARD ? 0 : DEG2RAD(180);
    2206       189253 :             return myWalkingAreaPath->shape.sidePositionAtAngle(myEdgePos, lateral_offset, myWalkingAreaPath->angleOverride + rotationOffset);
    2207              :         }
    2208              :     }
    2209              : }
    2210              : 
    2211              : 
    2212              : double
    2213      2863631 : MSPModel_Striping::PState::getAngle(const MSStageMoving&, SUMOTime) const {
    2214      2863631 :     if (myAngle != std::numeric_limits<double>::max()) {
    2215              :         return myAngle;
    2216              :     }
    2217       928876 :     if (myLane == nullptr) {
    2218              :         // pedestrian has already finished
    2219              :         return 0;
    2220              :     }
    2221       928671 :     if (myWalkingAreaPath != nullptr && myWalkingAreaPath->angleOverride != INVALID_DOUBLE) {
    2222              :         return myWalkingAreaPath->angleOverride;
    2223              :     }
    2224       877892 :     const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
    2225       877892 :     double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myEdgePos) : myEdgePos;
    2226       877892 :     double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
    2227       877892 :     if (myDir == MSPModel::BACKWARD) {
    2228       272482 :         angle += atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
    2229              :     } else { // myDir == MSPModel::FORWARD
    2230       770922 :         angle -= atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
    2231              :     }
    2232       877892 :     if (angle > M_PI) {
    2233       187723 :         angle -= 2 * M_PI;
    2234              :     }
    2235       877892 :     myAngle = angle;
    2236       877892 :     return angle;
    2237              : }
    2238              : 
    2239              : 
    2240              : const MSEdge*
    2241       166742 : MSPModel_Striping::PState::getNextEdge(const MSStageMoving&) const {
    2242       166742 :     return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
    2243              : }
    2244              : 
    2245              : 
    2246              : const MSLane*
    2247         1643 : MSPModel_Striping::PState::getNextCrossing() const {
    2248         1643 :     return myNLI.lane != nullptr && myNLI.lane->isCrossing() ? myNLI.lane : nullptr;
    2249              : }
    2250              : 
    2251              : 
    2252              : void
    2253         3448 : MSPModel_Striping::PState::reverse(const double pathLength, const double usableWidth) {
    2254         3448 :     myEdgePos = pathLength - myEdgePos;
    2255         3448 :     myPosLat = usableWidth - myPosLat;
    2256         3448 :     myDir = -myWalkingAreaPath->dir;
    2257         3448 :     mySpeedLat = -mySpeedLat;
    2258         3448 : }
    2259              : 
    2260              : 
    2261              : void
    2262       256851 : MSPModel_Striping::PState::reset(const double edgePos, const double latPos) {
    2263       256851 :     myEdgePos = edgePos;
    2264       256851 :     myPosLat = latPos;
    2265       256851 :     myDir = UNDEFINED_DIRECTION;  // only an obstacle, speed may be orthogonal to dir
    2266       256851 :     mySpeed = 0.;
    2267       256851 :     mySpeedLat = 0.;
    2268       256851 : }
    2269              : 
    2270              : 
    2271              : void
    2272           12 : MSPModel_Striping::PState::moveTo(MSPerson* p, MSLane* lane, double lanePos, double lanePosLat, SUMOTime t) {
    2273              :     ConstMSEdgeVector newEdges; // keep route
    2274              :     int routeOffset = 0;
    2275              :     bool laneOnRoute = false;
    2276           12 :     const MSJunction* laneOnJunction = lane->isNormal() ? nullptr : lane->getEdge().getToJunction();
    2277           12 :     for (const MSEdge* edge : myStage->getRoute()) {
    2278              :         if (edge == &lane->getEdge()
    2279            9 :                 || edge->getToJunction() == laneOnJunction
    2280           12 :                 || edge->getFromJunction() == laneOnJunction) {
    2281              :             laneOnRoute = true;
    2282              :             break;
    2283              :         }
    2284            0 :         routeOffset++;
    2285              :     }
    2286           12 :     if (!laneOnRoute) {
    2287            0 :         throw ProcessError("Lane '" + lane->getID() + "' is not on the route of person '" + getID() + "'.");
    2288              :     }
    2289           12 :     Position pos = lane->geometryPositionAtOffset(lanePos, lanePosLat);
    2290           12 :     if (lane->isWalkingArea() && (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane)) {
    2291              :         // entered new walkingarea. Determine path to guess position
    2292            6 :         const MSEdge* prevEdge = myStage->getRoute()[routeOffset];
    2293            6 :         const MSEdge* nextEdge = routeOffset + 1 < (int)myStage->getRoute().size() ? myStage->getRoute()[routeOffset + 1] : nullptr;
    2294            6 :         const WalkingAreaPath* guessed = guessPath(&lane->getEdge(), prevEdge, nextEdge);
    2295            6 :         const double maxPos = guessed->shape.length() - NUMERICAL_EPS;
    2296            6 :         if (lanePos > maxPos + POSITION_EPS || lanePos < -POSITION_EPS) {
    2297            0 :             throw ProcessError("Lane position " + toString(lanePos) + " cannot be mapped onto walkingarea '" + lane->getID()
    2298            0 :                                + "' (fromLane='" + guessed->from->getID()
    2299            0 :                                + "' toLane='" + guessed->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
    2300              :         }
    2301              :         // give some slack
    2302            6 :         lanePos = MIN2(maxPos, MAX2(NUMERICAL_EPS, lanePos));
    2303            6 :         pos = guessed->shape.positionAtOffset(lanePos, lanePosLat);
    2304              :     }
    2305           12 :     const double angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
    2306           12 :     moveToXY(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, newEdges, t);
    2307           12 : }
    2308              : 
    2309              : 
    2310              : void
    2311        13518 : MSPModel_Striping::PState::moveToXY(MSPerson* p, Position pos, MSLane* lane, double lanePos,
    2312              :                                     double lanePosLat, double angle, int routeOffset,
    2313              :                                     const ConstMSEdgeVector& edges, SUMOTime t) {
    2314        13518 :     MSPModel_Striping* pm = dynamic_cast<MSPModel_Striping*>(MSNet::getInstance()->getPersonControl().getMovementModel());
    2315              :     assert(p == myPerson);
    2316              :     assert(pm != nullptr);
    2317        13518 :     const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
    2318              :     // person already walking in this step. undo this to obtain the previous position
    2319        13518 :     const double oldX = myEdgePos - SPEED2DIST(mySpeed * myDir);
    2320              :     const double tmp = myEdgePos;
    2321        13518 :     myEdgePos = oldX;
    2322        13518 :     Position oldPos = getPosition(*myStage, t);
    2323        13518 :     myEdgePos = tmp;
    2324              :     //if (oldPos == Position::INVALID) {
    2325              :     //    oldPos = pos
    2326              :     //}
    2327        13518 :     myAngle = GeomHelper::fromNaviDegree(angle);
    2328              : #ifdef DEBUG_MOVETOXY
    2329              :     std::cout << SIMTIME << " ped=" << p->getID()
    2330              :               << " moveToXY"
    2331              :               << " pos=" << pos
    2332              :               << " lane=" << lane->getID()
    2333              :               << " lanePos=" << lanePos
    2334              :               << " lanePosLat=" << lanePosLat
    2335              :               << " angle=" << angle
    2336              :               << " routeOffset=" << routeOffset
    2337              :               << " edges=" << toString(edges)
    2338              :               << " oldLane=" << Named::getIDSecure(myLane)
    2339              :               << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
    2340              : #endif
    2341              : 
    2342        13518 :     if (lane != myLane && myLane != nullptr && lane != nullptr) {
    2343          317 :         pm->remove(this);
    2344              :         pm->registerActive();
    2345              :     }
    2346        13518 :     if (lane != nullptr &&
    2347        10386 :             fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
    2348        10382 :         myRemoteXYPos = Position::INVALID;
    2349        10382 :         const MSEdge* old = myStage->getEdge();
    2350        10382 :         const MSLane* oldLane = myLane;
    2351        10382 :         if (lane != myLane) {
    2352              :             // implicitly adds new active lane if necessary
    2353          317 :             pm->myActiveLanes[lane].push_back(this);
    2354              :         }
    2355        10382 :         if (edges.empty()) {
    2356              :             // map within route
    2357        10342 :             myStage->setRouteIndex(myPerson, routeOffset);
    2358              :         } else {
    2359           40 :             myStage->replaceRoute(myPerson, edges, routeOffset);
    2360              :         }
    2361        10382 :         if (!lane->getEdge().isNormal()) {
    2362          389 :             myStage->moveToNextEdge(myPerson, t, myDir, &lane->getEdge());
    2363              :         }
    2364              : 
    2365        10382 :         myLane = lane;
    2366        10382 :         const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
    2367        10382 :         if (lane->isWalkingArea()) {
    2368          190 :             if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
    2369              :                 // entered new walkingarea. Determine path
    2370           40 :                 myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
    2371              : #ifdef DEBUG_MOVETOXY
    2372              :                 std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
    2373              :                           << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
    2374              : #endif
    2375              :             }
    2376              :             // lanePos and lanePosLat are matched onto the circumference of the
    2377              :             // walkingarea. Use pos instead
    2378          190 :             const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
    2379              :             if (relPos == Position::INVALID) {
    2380            0 :                 WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID()
    2381              :                               + "' (fromLane='" + myWalkingAreaPath->from->getID()
    2382              :                               + "' toLane='" + myWalkingAreaPath->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
    2383            0 :                 myRemoteXYPos = pos;
    2384              :             } else {
    2385          190 :                 myEdgePos = relPos.x();
    2386          190 :                 myPosLat = lateral_offset + relPos.y();
    2387              :             }
    2388              :         } else {
    2389        10192 :             myWalkingAreaPath = nullptr;
    2390        10192 :             myEdgePos = lanePos;
    2391        10192 :             myPosLat = lateral_offset - lanePosLat;
    2392        10192 :             lane->requireCollisionCheck();
    2393              :         }
    2394              :         // guess direction
    2395        10382 :         const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
    2396        10382 :         if (myStage->getNextRouteEdge() != nullptr) {
    2397         6194 :             if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
    2398          880 :                     myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
    2399         4534 :                 myDir = FORWARD;
    2400              :             } else {
    2401          780 :                 myDir = BACKWARD;
    2402              :             }
    2403              :         } else {
    2404              :             // guess from angle
    2405         5068 :             if (angleDiff <= 90) {
    2406              :                 // keep direction
    2407         5008 :                 if (myDir == UNDEFINED_DIRECTION) {
    2408            0 :                     myDir = FORWARD;
    2409              :                 }
    2410              :             } else {
    2411              :                 // change direction
    2412           60 :                 myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
    2413              :             }
    2414              :         }
    2415              :         // update next lane info (after guessing direction)
    2416        10382 :         if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
    2417          277 :             const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge(), p->getVClass());
    2418              :             // assume that we will eventually move back onto the sidewalk if
    2419              :             // there is one
    2420          277 :             myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
    2421          277 :             myStage->activateEntryReminders(myPerson);
    2422              : #ifdef DEBUG_MOVETOXY
    2423              :             std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
    2424              : #endif
    2425              :         }
    2426              : #ifdef DEBUG_MOVETOXY
    2427              :         std::cout << " newRelPos=" << Position(myEdgePos, myPosLat) << " edge=" << myPerson->getEdge()->getID()
    2428              :                   << " newPos=" << myPerson->getPosition()
    2429              :                   << " latOffset=" << getLatOffset()
    2430              :                   << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
    2431              : #endif
    2432        10382 :         if (oldLane == myLane) {
    2433        10065 :             mySpeed = DIST2SPEED(fabs(oldX - myEdgePos));
    2434              :         } else {
    2435              :             //std::cout << SIMTIME << " oldX=" << oldX << " oldSpeed=" << mySpeed << " oldPos=" << oldPos << " pos=" << pos << " dist=" << oldPos.distanceTo2D(pos) << " oldLane=" << Named::getIDSecure(oldLane) << " lane=" << lane->getID() << "\n";
    2436          317 :             mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
    2437              :         }
    2438              :     } else {
    2439              :         // map outside the network
    2440         3136 :         myRemoteXYPos = pos;
    2441         3136 :         mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
    2442              :     }
    2443              : 
    2444        13518 : }
    2445              : 
    2446              : 
    2447              : double
    2448       746398 : MSPModel_Striping::PState::getPathLength() const {
    2449       746398 :     if (myWalkingAreaPath != nullptr) {
    2450       689650 :         return myWalkingAreaPath->length;
    2451              :     } else {
    2452              :         return 0;
    2453              :     }
    2454              : }
    2455              : 
    2456              : double
    2457   1589182812 : MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
    2458              :     // check for overlap
    2459   1589182812 :     const double maxX = getMaxX(includeMinGap);
    2460   1589182812 :     const double minX = getMinX(includeMinGap);
    2461              :     //if (DEBUGCOND(*this)) {
    2462              :     //    std::cout << std::setprecision(2) <<   "   distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
    2463              :     //}
    2464   1589182812 :     if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
    2465              :         // avoid blocking by itself on looped route
    2466    465758645 :         return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
    2467              :     }
    2468   1123424167 :     if (myDir == FORWARD) {
    2469   1012495885 :         return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
    2470              :     } else {
    2471    110928282 :         return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
    2472              :     }
    2473              : }
    2474              : 
    2475              : 
    2476              : void
    2477     91990539 : MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2) {
    2478    402644301 :     for (int i = 0; i < (int)into.size(); ++i) {
    2479    310653762 :         if (gDebugFlag1) {
    2480            0 :             std::cout << "     i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
    2481            0 :                       << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
    2482            0 :                       << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
    2483              :         }
    2484    310653762 :         const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
    2485    310653762 :         const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
    2486    310653762 :         if (dO < dI) {
    2487              :             into[i] = obs2[i];
    2488              :         } else if (dO == dI
    2489     77136870 :                    && into[i].type != OBSTACLE_PED
    2490     33826420 :                    && into[i].type != OBSTACLE_VEHICLE
    2491    298207568 :                    && (obs2[i].type == OBSTACLE_PED ||
    2492              :                        obs2[i].type == OBSTACLE_VEHICLE)) {
    2493              :             into[i] = obs2[i];
    2494              :         }
    2495              :     }
    2496     91990539 : }
    2497              : 
    2498              : void
    2499        18627 : MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
    2500       146352 :     for (int i = 0; i < (int)into.size(); ++i) {
    2501       127725 :         int i2 = i + offset;
    2502       127725 :         if (i2 >= 0 && i2 < (int)obs2.size()) {
    2503       126421 :             if (dir == FORWARD) {
    2504        90408 :                 if (obs2[i2].xBack < into[i].xBack) {
    2505              :                     into[i] = obs2[i2];
    2506              :                 }
    2507              :             } else {
    2508        36013 :                 if (obs2[i2].xFwd > into[i].xFwd) {
    2509              :                     into[i] = obs2[i2];
    2510              :                 }
    2511              :             }
    2512              :         }
    2513              :     }
    2514        18627 : }
    2515              : 
    2516              : 
    2517              : bool
    2518     12359864 : MSPModel_Striping::PState::ignoreRed(const MSLink* link) const {
    2519     12359864 :     if (link->haveRed()) {
    2520       613953 :         const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
    2521       613953 :         if (ignoreRedTime >= 0) {
    2522           40 :             const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
    2523           40 :             if (DEBUGCOND(*this)) {
    2524            0 :                 std::cout << SIMTIME << "  ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
    2525              :             }
    2526           40 :             return ignoreRedTime > redDuration;
    2527              :         } else {
    2528              :             return false;
    2529              :         }
    2530              :     } else {
    2531              :         return false;
    2532              :     }
    2533              : }
    2534              : 
    2535              : 
    2536              : bool
    2537     11700923 : MSPModel_Striping::PState::stopForYellow(const MSLink* link) const {
    2538              :     // main use case is at rail_crossing
    2539     11700923 :     if (link->haveYellow()) {
    2540          918 :         const double ignoreYellowTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_YELLOW_TIME, -1);
    2541          918 :         if (ignoreYellowTime >= 0) {
    2542            0 :             const double yellowDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
    2543            0 :             if (DEBUGCOND(*this)) {
    2544            0 :                 std::cout << SIMTIME << "  ignoreYellowTime=" << ignoreYellowTime << " yellowDuration=" << yellowDuration << "\n";
    2545              :             }
    2546            0 :             return ignoreYellowTime < yellowDuration;
    2547              :         } else {
    2548              :             return true;
    2549              :         }
    2550              :     } else {
    2551              :         return false;
    2552              :     }
    2553              : }
    2554              : 
    2555              : double
    2556   3674055644 : MSPModel_Striping::PState::getWidth() const {
    2557   3674055644 :     return myPerson->getVehicleType().getWidth();
    2558              : }
    2559              : 
    2560              : 
    2561              : bool
    2562    135064659 : MSPModel_Striping::PState::isRemoteControlled() const {
    2563    135064659 :     return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
    2564              : }
    2565              : 
    2566              : // ===========================================================================
    2567              : // MSPModel_Striping::PStateVehicle method definitions
    2568              : // ===========================================================================
    2569              : 
    2570       504919 : MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY, double xWidth, double yWidth):
    2571       504919 :     myVehicle(veh), myXWidth(xWidth), myYWidth(yWidth) {
    2572       504919 :     myLane = walkingarea; // to ensure correct limits when calling otherStripe()
    2573              :     // relX is the center but we want it to be the max value if the movement direction is forward
    2574              :     // and the min value otherwise (indicated by xWidth sign)
    2575       504919 :     myEdgePos = relX + xWidth / 2;
    2576       504919 :     myPosLat = relY;
    2577       504919 : }
    2578              : 
    2579              : const std::string&
    2580      1970776 : MSPModel_Striping::PStateVehicle::getID() const {
    2581      1970776 :     return myVehicle->getID();
    2582              : }
    2583              : 
    2584              : double
    2585      1018954 : MSPModel_Striping::PStateVehicle::getWidth() const {
    2586      1018954 :     return myYWidth;
    2587              : }
    2588              : 
    2589              : double
    2590       539718 : MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
    2591       539718 :     return myXWidth > 0 ? myEdgePos - myXWidth : myEdgePos;
    2592              : }
    2593              : 
    2594              : double
    2595       539718 : MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
    2596       539718 :     return myXWidth > 0 ? myEdgePos : myEdgePos - myXWidth;
    2597              : }
    2598              : 
    2599              : // ===========================================================================
    2600              : // MSPModel_Striping::MovePedestrians method definitions
    2601              : // ===========================================================================
    2602              : 
    2603              : SUMOTime
    2604      3126894 : MSPModel_Striping::MovePedestrians::execute(SUMOTime currentTime) {
    2605              :     std::set<MSPerson*> changedLane;
    2606      3126894 :     myModel->moveInDirection(currentTime, changedLane, FORWARD);
    2607      3126890 :     myModel->moveInDirection(currentTime, changedLane, BACKWARD);
    2608              :     // DEBUG
    2609              : #ifdef LOG_ALL
    2610              :     for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
    2611              :         const MSLane* lane = it_lane->first;
    2612              :         Pedestrians pedestrians = it_lane->second;
    2613              :         if (pedestrians.size() == 0) {
    2614              :             continue;
    2615              :         }
    2616              :         sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
    2617              :         std::cout << SIMTIME << " lane=" << lane->getID();
    2618              :         for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
    2619              :             const PState& p = *pedestrians[ii];
    2620              :             std::cout << " (" << p.getPerson()->getID() << " " << p.myEdgePos << "," << p.myPosLat << " " << p.getDirection() << ")";
    2621              :         }
    2622              :         std::cout << "\n";
    2623              :     }
    2624              : #endif
    2625      3126890 :     return DELTA_T;
    2626              : }
        

Generated by: LCOV version 2.0-1