LCOV - code coverage report
Current view: top level - src/microsim/transportables - MSPModel_Striping.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 1204 1392 86.5 %
Date: 2024-05-07 15:28:01 Functions: 78 79 98.7 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2014-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      14             : /// @file    MSPModel_Striping.cpp
      15             : /// @author  Jakob Erdmann
      16             : /// @author  Michael Behrisch
      17             : /// @date    Mon, 13 Jan 2014
      18             : ///
      19             : // The pedestrian following model (prototype)
      20             : /****************************************************************************/
      21             : #include <config.h>
      22             : 
      23             : #include <cmath>
      24             : #include <algorithm>
      25             : #include <utils/common/RandHelper.h>
      26             : #include <utils/geom/GeomHelper.h>
      27             : #include <utils/options/OptionsCont.h>
      28             : #include <utils/router/PedestrianRouter.h>
      29             : #include <microsim/MSNet.h>
      30             : #include <microsim/MSEdge.h>
      31             : #include <microsim/MSEventControl.h>
      32             : #include <microsim/MSLane.h>
      33             : #include <microsim/MSLink.h>
      34             : #include <microsim/MSJunction.h>
      35             : #include <microsim/MSStoppingPlace.h>
      36             : #include <microsim/MSVehicleControl.h>
      37             : #include <microsim/MSGlobals.h>
      38             : #include <microsim/transportables/MSStage.h>
      39             : #include <microsim/transportables/MSTransportableControl.h>
      40             : #include "MSPModel_Striping.h"
      41             : 
      42             : 
      43             : // ===========================================================================
      44             : // DEBUGGING HELPERS
      45             : // ===========================================================================
      46             : //
      47             : #define DEBUGID1 ""
      48             : #define DEBUGID2 ""
      49             : //#define DEBUGCOND(PED) (false)
      50             : //#define DEBUGCOND(PED) ((PED).myPerson->getID() == DEBUGID1 || (PED).myPerson->getID() == DEBUGID2)
      51             : #define DEBUGCOND(PED) ((PED).myPerson->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             : MSPModel_Striping::Pedestrians MSPModel_Striping::noPedestrians;
      84             : 
      85             : // model parameters (static to simplify access from class PState
      86             : double MSPModel_Striping::stripeWidth;
      87             : double MSPModel_Striping::dawdling;
      88             : double MSPModel_Striping::minGapToVehicle;
      89             : int MSPModel_Striping::myWalkingAreaDetail;
      90             : SUMOTime MSPModel_Striping::jamTime;
      91             : SUMOTime MSPModel_Striping::jamTimeCrossing;
      92             : SUMOTime MSPModel_Striping::jamTimeNarrow;
      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::LOOKAROUND_VEHICLES(60.0); // meters
      97             : const double MSPModel_Striping::LATERAL_PENALTY(-1.); // meters
      98             : const double MSPModel_Striping::OBSTRUCTED_PENALTY(-300000.); // meters
      99             : const double MSPModel_Striping::INAPPROPRIATE_PENALTY(-20000.); // meters
     100             : const double MSPModel_Striping::ONCOMING_CONFLICT_PENALTY(-1000.); // meters
     101             : const double MSPModel_Striping::OBSTRUCTION_THRESHOLD(MSPModel_Striping::OBSTRUCTED_PENALTY * 0.5); // despite obstruction, additional utility may have been added
     102             : const double MSPModel_Striping::SQUEEZE(0.7);
     103             : double MSPModel_Striping::RESERVE_FOR_ONCOMING_FACTOR;
     104             : double MSPModel_Striping::RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS;
     105             : double MSPModel_Striping::RESERVE_FOR_ONCOMING_MAX;
     106             : const double MSPModel_Striping::MAX_WAIT_TOLERANCE(120.); // seconds
     107             : const double MSPModel_Striping::LATERAL_SPEED_FACTOR(0.4);
     108             : const double MSPModel_Striping::MIN_STARTUP_DIST(0.4); // meters
     109             : 
     110             : 
     111             : // ===========================================================================
     112             : // MSPModel_Striping method definitions
     113             : // ===========================================================================
     114             : 
     115        3246 : MSPModel_Striping::MSPModel_Striping(const OptionsCont& oc, MSNet* net) :
     116        3246 :     myNumActivePedestrians(0),
     117        3246 :     myAmActive(false) {
     118        3246 :     myWalkingAreaDetail = oc.getInt("pedestrian.striping.walkingarea-detail");
     119        3246 :     initWalkingAreaPaths(net);
     120             :     // configurable parameters
     121        3246 :     stripeWidth = oc.getFloat("pedestrian.striping.stripe-width");
     122        3246 :     MSVehicleType* defaultPedType = MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true);
     123        3246 :     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        3246 :     dawdling = oc.getFloat("pedestrian.striping.dawdling");
     129        3246 :     minGapToVehicle = oc.getFloat("pedestrian.striping.mingap-to-vehicle");
     130        3246 :     RESERVE_FOR_ONCOMING_FACTOR = oc.getFloat("pedestrian.striping.reserve-oncoming");
     131        3246 :     RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS = oc.getFloat("pedestrian.striping.reserve-oncoming.junctions");
     132        3246 :     RESERVE_FOR_ONCOMING_MAX = oc.getFloat("pedestrian.striping.reserve-oncoming.max");
     133             : 
     134        3246 :     jamTime = string2time(oc.getString("pedestrian.striping.jamtime"));
     135        3246 :     if (jamTime <= 0) {
     136           4 :         jamTime = SUMOTime_MAX;
     137             :     }
     138        3246 :     jamTimeCrossing = string2time(oc.getString("pedestrian.striping.jamtime.crossing"));
     139        3246 :     if (jamTimeCrossing <= 0) {
     140           0 :         jamTimeCrossing = SUMOTime_MAX;
     141             :     }
     142        3246 :     jamTimeNarrow = string2time(oc.getString("pedestrian.striping.jamtime.narrow"));
     143        3246 :     if (jamTimeNarrow <= 0) {
     144           0 :         jamTimeNarrow = SUMOTime_MAX;
     145             :     }
     146        3246 :     myLegacyPosLat = oc.getBool("pedestrian.striping.legacy-departposlat");
     147        3246 : }
     148             : 
     149             : 
     150        6476 : MSPModel_Striping::~MSPModel_Striping() {
     151        3238 :     clearState();
     152             :     myWalkingAreaPaths.clear(); // need to recompute when lane pointers change
     153             :     myWalkingAreaFoes.clear();
     154             :     myMinNextLengths.clear();
     155        6476 : }
     156             : 
     157             : void
     158        6506 : MSPModel_Striping::clearState() {
     159             :     myActiveLanes.clear();
     160        6506 :     myNumActivePedestrians = 0;
     161        6506 :     myAmActive = false;
     162        6506 : }
     163             : 
     164             : MSTransportableStateAdapter*
     165      269559 : MSPModel_Striping::add(MSTransportable* transportable, MSStageMoving* stage, SUMOTime) {
     166      269559 :     if (!transportable->isPerson()) {
     167             :         // containers are not supported (TODO add a warning here?)
     168             :         return nullptr;
     169             :     }
     170             :     MSPerson* person = static_cast<MSPerson*>(transportable);
     171      269559 :     MSNet* net = MSNet::getInstance();
     172      269559 :     if (!myAmActive) {
     173        2158 :         net->getBeginOfTimestepEvents()->addEvent(new MovePedestrians(this), net->getCurrentTimeStep() + DELTA_T);
     174        2158 :         myAmActive = true;
     175             :     }
     176             :     assert(person->getCurrentStageType() == MSStageType::WALKING);
     177      269559 :     const MSLane* lane = stage->checkDepartLane(person->getEdge(), person->getVClass(), stage->getDepartLane(), person->getID());
     178      269559 :     if (lane == nullptr) {
     179           8 :         const char* error = TL("Person '%' could not find sidewalk on edge '%', time=%.");
     180          16 :         if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
     181          24 :             WRITE_WARNINGF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep()));
     182           8 :             return nullptr;
     183             :         } else {
     184           0 :             throw ProcessError(TLF(error, person->getID(), person->getEdge()->getID(), time2string(net->getCurrentTimeStep())));
     185             :         }
     186             :     }
     187      269551 :     PState* ped = new PState(person, stage, lane);
     188      269547 :     myActiveLanes[lane].push_back(ped);
     189      269547 :     myNumActivePedestrians++;
     190      269547 :     return ped;
     191             : }
     192             : 
     193             : 
     194             : MSTransportableStateAdapter*
     195          20 : MSPModel_Striping::loadState(MSTransportable* transportable, MSStageMoving* stage, std::istringstream& in) {
     196             :     MSPerson* person = static_cast<MSPerson*>(transportable);
     197          20 :     MSNet* net = MSNet::getInstance();
     198          20 :     if (!myAmActive) {
     199          16 :         net->getBeginOfTimestepEvents()->addEvent(new MovePedestrians(this), SIMSTEP);
     200          16 :         myAmActive = true;
     201             :     }
     202          20 :     PState* ped = new PState(person, stage, &in);
     203          20 :     myActiveLanes[ped->getLane()].push_back(ped);
     204          20 :     myNumActivePedestrians++;
     205          20 :     return ped;
     206             : }
     207             : 
     208             : 
     209             : void
     210        2276 : MSPModel_Striping::remove(MSTransportableStateAdapter* state) {
     211        2276 :     const MSLane* lane = dynamic_cast<PState*>(state)->myLane;
     212        2276 :     Pedestrians& pedestrians = myActiveLanes[lane];
     213       52788 :     for (Pedestrians::iterator it = pedestrians.begin(); it != pedestrians.end(); ++it) {
     214       52788 :         if (*it == state) {
     215             :             pedestrians.erase(it);
     216        2276 :             myNumActivePedestrians--;
     217             :             return;
     218             :         }
     219             :     }
     220             : }
     221             : 
     222             : 
     223             : bool
     224     3155613 : MSPModel_Striping::blockedAtDist(const SUMOTrafficObject* ego, const MSLane* lane, double vehSide, double vehWidth,
     225             :                                  double oncomingGap, std::vector<const MSPerson*>* collectBlockers) {
     226     3155613 :     const Pedestrians& pedestrians = getPedestrians(lane);
     227     3162815 :     for (Pedestrians::const_iterator it_ped = pedestrians.begin(); it_ped != pedestrians.end(); ++it_ped) {
     228       33147 :         const PState& ped = **it_ped;
     229       33147 :         const double leaderFrontDist = (ped.myDir == FORWARD ? vehSide - ped.myRelX : ped.myRelX - vehSide);
     230       33147 :         const double leaderBackDist = leaderFrontDist + ped.getLength();
     231       33147 :         if DEBUGCOND(ped) {
     232           0 :             std::cout << SIMTIME << " lane=" << lane->getID() << " dir=" << ped.myDir << " pX=" << ped.myRelX << " pL=" << ped.getLength()
     233             :                       << " vehSide=" << vehSide
     234             :                       << " vehWidth=" << vehWidth
     235             :                       << " lBD=" << leaderBackDist
     236             :                       << " lFD=" << leaderFrontDist
     237           0 :                       << "\n";
     238             :         }
     239       33147 :         if (leaderBackDist >= -vehWidth
     240       27898 :                 && (leaderFrontDist < 0
     241             :                     // give right of way to (close) approaching pedestrians unless they are standing
     242       22218 :                     || (leaderFrontDist <= oncomingGap && ped.myWaitingTime < TIME2STEPS(2.0)))) {
     243       25975 :             if (MSLink::ignoreFoe(ego, ped.myPerson)) {
     244          30 :                 continue;
     245             :             }
     246             :             // found one pedestrian that is not completely past the crossing point
     247             :             //std::cout << SIMTIME << " blocking pedestrian foeLane=" << lane->getID() << " ped=" << ped.myPerson->getID() << " dir=" << ped.myDir << " pX=" << ped.myRelX << " pL=" << ped.getLength() << " fDTC=" << distToCrossing << " lBD=" << leaderBackDist << "\n";
     248       25945 :             if (collectBlockers == nullptr) {
     249             :                 return true;
     250             :             } else {
     251           0 :                 collectBlockers->push_back(ped.myPerson);
     252             :             }
     253             :         }
     254             :     }
     255     3129668 :     if (collectBlockers == nullptr) {
     256             :         return false;
     257             :     } else {
     258           0 :         return collectBlockers->size() > 0;
     259             :     }
     260             : }
     261             : 
     262             : 
     263             : bool
     264     3606600 : MSPModel_Striping::hasPedestrians(const MSLane* lane) {
     265     3606600 :     return getPedestrians(lane).size() > 0;
     266             : }
     267             : 
     268             : 
     269             : bool
     270       94657 : MSPModel_Striping::usingInternalLanes() {
     271       94657 :     return usingInternalLanesStatic();
     272             : }
     273             : 
     274             : bool
     275      269121 : MSPModel_Striping::usingInternalLanesStatic() {
     276      269121 :     return MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks() && MSNet::getInstance()->hasPedestrianNetwork();
     277             : }
     278             : 
     279             : PersonDist
     280      722676 : MSPModel_Striping::nextBlocking(const MSLane* lane, double minPos, double minRight, double maxLeft, double stopTime, bool bidi) {
     281             :     PersonDist result((const MSPerson*)nullptr, std::numeric_limits<double>::max());
     282      722676 :     const Pedestrians& pedestrians = getPedestrians(lane);
     283     3952937 :     for (Pedestrians::const_iterator it_ped = pedestrians.begin(); it_ped != pedestrians.end(); ++it_ped) {
     284     3230261 :         const PState& ped = **it_ped;
     285             :         // account for distance covered by oncoming pedestrians
     286     3230261 :         double relX2 = ped.myRelX - (ped.myDir == FORWARD ? 0 : stopTime * ped.myPerson->getMaxSpeed());
     287     3230261 :         double dist = ((relX2 - minPos) * (bidi ? -1 : 1)
     288     3230261 :                        - (ped.myDir == FORWARD ? ped.myPerson->getVehicleType().getLength() : 0));
     289     3230261 :         const bool aheadOfVehicle = bidi ? ped.myRelX < minPos : ped.myRelX > minPos;
     290     3230261 :         if (aheadOfVehicle && dist < result.second) {
     291     1378793 :             const double center = lane->getWidth() - (ped.myRelY + stripeWidth * 0.5);
     292     1378793 :             const double halfWidth = 0.5 * ped.myPerson->getVehicleType().getWidth();
     293     1378793 :             const bool overlap = (center + halfWidth > minRight && center - halfWidth < maxLeft);
     294     1378793 :             if DEBUGCOND(ped) {
     295           0 :                 std::cout << "  nextBlocking lane=" << lane->getID() << " bidi=" << bidi
     296             :                           << " minPos=" << minPos << " minRight=" << minRight << " maxLeft=" << maxLeft
     297             :                           << " stopTime=" << stopTime
     298           0 :                           << " pedY=" << ped.myRelY
     299           0 :                           << " pedX=" << ped.myRelX
     300             :                           << " relX2=" << relX2
     301             :                           << " center=" << center
     302             :                           << " pedLeft=" << center + halfWidth
     303           0 :                           << " pedRight=" << center - halfWidth
     304           0 :                           << " overlap=" << overlap
     305           0 :                           << "\n";
     306             :             }
     307     1378793 :             if (overlap) {
     308      125656 :                 result.first = ped.myPerson;
     309             :                 result.second = dist;
     310             :             }
     311             :         }
     312             :     }
     313      722676 :     return result;
     314             : }
     315             : 
     316             : 
     317             : MSPModel_Striping::Pedestrians&
     318     8606986 : MSPModel_Striping::getPedestrians(const MSLane* lane) {
     319             :     ActiveLanes::iterator it = myActiveLanes.find(lane);
     320     8606986 :     if (it != myActiveLanes.end()) {
     321             :         //std::cout << " found lane=" << lane->getID() << " n=" << it->second.size() << "\n";
     322     3310259 :         return (it->second);
     323             :     } else {
     324             :         return noPedestrians;
     325             :     }
     326             : }
     327             : 
     328             : 
     329             : int
     330  3283778522 : MSPModel_Striping::numStripes(const MSLane* lane) {
     331  3283778522 :     return MAX2(1, (int)floor(lane->getWidth() / stripeWidth));
     332             : }
     333             : 
     334             : int
     335      404614 : MSPModel_Striping::connectedDirection(const MSLane* from, const MSLane* to) {
     336      404614 :     if (from == nullptr || to == nullptr) {
     337           0 :         return UNDEFINED_DIRECTION;
     338      404614 :     } else if (from->getLinkTo(to) != nullptr) {
     339      301426 :         return FORWARD;
     340      103188 :     } else if (to->getLinkTo(from) != nullptr) {
     341      103188 :         return BACKWARD;
     342             :     } else {
     343           0 :         return UNDEFINED_DIRECTION;
     344             :     }
     345             : }
     346             : 
     347             : 
     348             : void
     349        3246 : MSPModel_Striping::initWalkingAreaPaths(const MSNet*) {
     350        3246 :     if (myWalkingAreaPaths.size() > 0) {
     351             :         return;
     352             :     }
     353             :     // collect vehicle lanes that cross walkingareas
     354      279199 :     for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
     355      275953 :         const MSEdge* edge = *i;
     356      275953 :         if (!edge->isWalkingArea() && !edge->isCrossing()) {
     357      528000 :             for (MSLane* lane : edge->getLanes()) {
     358      655653 :                 for (MSLink* link : lane->getLinkCont()) {
     359      368254 :                     if (link->getWalkingAreaFoe() != nullptr) {
     360             :                         // link is an exit link
     361        4652 :                         myWalkingAreaFoes[&link->getWalkingAreaFoe()->getEdge()].push_back(link->getLaneBefore());
     362             :                         //std::cout << " wa=" << link->getWalkingAreaFoe()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
     363             :                     }
     364      368254 :                     if (link->getWalkingAreaFoeExit() != nullptr) {
     365             :                         // link is an exit link
     366        4728 :                         myWalkingAreaFoes[&link->getWalkingAreaFoeExit()->getEdge()].push_back(link->getLaneBefore());
     367             :                         //std::cout << " wa=" << link->getWalkingAreaFoeExit()->getEdge().getID() << " foe=" << link->getLaneBefore()->getID() << "\n";
     368             :                     }
     369             :                 }
     370             :             }
     371             :         }
     372             :     }
     373             : 
     374             :     // build walkingareaPaths
     375      279199 :     for (MSEdgeVector::const_iterator i = MSEdge::getAllEdges().begin(); i != MSEdge::getAllEdges().end(); ++i) {
     376      275953 :         insertWalkArePaths(*i, myWalkingAreaPaths);
     377             :     }
     378             : }
     379             : 
     380             : 
     381             : void
     382      275953 : MSPModel_Striping::insertWalkArePaths(const MSEdge* edge, WalkingAreaPaths& into) {
     383      275953 :     if (edge->isWalkingArea()) {
     384       29854 :         const MSLane* walkingArea = getSidewalk<MSEdge, MSLane>(edge);
     385       29854 :         myMinNextLengths[walkingArea] = walkingArea->getLength();
     386             :         // build all possible paths across this walkingArea
     387             :         // gather all incident lanes
     388             :         std::vector<const MSLane*> lanes;
     389       67204 :         for (const MSEdge* in : edge->getPredecessors()) {
     390       37350 :             if (!in->isTazConnector()) {
     391       36858 :                 lanes.push_back(getSidewalk<MSEdge, MSLane>(in));
     392       36858 :                 if (lanes.back() == nullptr) {
     393           0 :                     throw ProcessError("Invalid connection from edge '" + in->getID() + "' to walkingarea edge '" + edge->getID() + "'");
     394             :                 }
     395             :             }
     396             :         }
     397       67435 :         for (const MSEdge* out : edge->getSuccessors()) {
     398       37581 :             if (!out->isTazConnector()) {
     399       37089 :                 lanes.push_back(getSidewalk<MSEdge, MSLane>(out));
     400       37089 :                 if (lanes.back() == nullptr) {
     401           0 :                     throw ProcessError("Invalid connection from walkingarea edge '" + edge->getID() + "' to edge '" + out->getID() + "'");
     402             :                 }
     403             :             }
     404             :         }
     405             :         // build all combinations
     406      103801 :         for (int j = 0; j < (int)lanes.size(); ++j) {
     407      281824 :             for (int k = 0; k < (int)lanes.size(); ++k) {
     408      207877 :                 if (j != k) {
     409             :                     // build the walkingArea
     410      133930 :                     const MSLane* const from = lanes[j];
     411      133930 :                     const MSLane* const to = lanes[k];
     412      133930 :                     const int fromDir = from->getLinkTo(walkingArea) != nullptr ? FORWARD : BACKWARD;
     413      133930 :                     const int toDir = walkingArea->getLinkTo(to) != nullptr ? FORWARD : BACKWARD;
     414      133930 :                     PositionVector shape;
     415      201256 :                     Position fromPos = from->getShape()[fromDir == FORWARD ? -1 : 0];
     416      200534 :                     Position toPos = to->getShape()[toDir == FORWARD ? 0 : -1];
     417      133930 :                     const double maxExtent = fromPos.distanceTo2D(toPos) / 4; // prevent sharp corners
     418      133930 :                     const double extrapolateBy = MIN2(maxExtent, walkingArea->getWidth() / 2);
     419             :                     // assemble shape
     420      133930 :                     shape.push_back(fromPos);
     421      133930 :                     if (extrapolateBy > POSITION_EPS) {
     422             :                         PositionVector fromShp = from->getShape();
     423      132538 :                         fromShp.extrapolate(extrapolateBy);
     424      265076 :                         shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
     425             :                         PositionVector nextShp = to->getShape();
     426      132538 :                         nextShp.extrapolate(extrapolateBy);
     427      265076 :                         shape.push_back_noDoublePos(toDir == FORWARD ? nextShp.front() : nextShp.back());
     428      132538 :                     }
     429      133930 :                     shape.push_back_noDoublePos(toPos);
     430      133930 :                     if (shape.size() < 2) {
     431             :                         PositionVector fromShp = from->getShape();
     432         622 :                         fromShp.extrapolate(1.5 * POSITION_EPS); // noDoublePos requires a difference of POSITION_EPS in at least one coordinate
     433        1244 :                         shape.push_back_noDoublePos(fromDir == FORWARD ? fromShp.back() : fromShp.front());
     434             :                         assert(shape.size() == 2);
     435      133930 :                     } else if (myWalkingAreaDetail > 4) {
     436         448 :                         shape = shape.bezier(myWalkingAreaDetail);
     437             :                     }
     438             :                     double angleOverride = INVALID_DOUBLE;
     439      133930 :                     if (shape.size() >= 4 && shape.length() < walkingArea->getWidth()) {
     440       27770 :                         const double aStart = shape.angleAt2D(0);
     441       27770 :                         const double aEnd = shape.angleAt2D((int)shape.size() - 2);
     442       27770 :                         if (fabs(aStart - aEnd) < DEG2RAD(10)) {
     443        3632 :                             angleOverride = (aStart + aEnd) / 2;
     444             :                         }
     445             :                     }
     446      133930 :                     if (fromDir == BACKWARD) {
     447             :                         // will be walking backward on walkingArea
     448      134652 :                         shape = shape.reverse();
     449             :                     }
     450      133930 :                     WalkingAreaPath wap = WalkingAreaPath(from, walkingArea, to, shape, fromDir, angleOverride);
     451           0 :                     into.insert(std::make_pair(std::make_pair(from, to), wap));
     452      267860 :                     myMinNextLengths[walkingArea] = MIN2(myMinNextLengths[walkingArea], wap.length);
     453      133930 :                 }
     454             :             }
     455             :         }
     456             :     }
     457      275953 : }
     458             : 
     459             : 
     460             : const MSPModel_Striping::WalkingAreaPath*
     461          10 : MSPModel_Striping::getArbitraryPath(const MSEdge* walkingArea) {
     462             :     assert(walkingArea->isWalkingArea());
     463             :     std::vector<const MSLane*> lanes;
     464          30 :     for (const MSEdge* const pred : walkingArea->getPredecessors()) {
     465          20 :         lanes.push_back(getSidewalk<MSEdge, MSLane>(pred));
     466             :     }
     467          30 :     for (const MSEdge* const succ : walkingArea->getSuccessors()) {
     468          20 :         lanes.push_back(getSidewalk<MSEdge, MSLane>(succ));
     469             :     }
     470          10 :     if (lanes.size() < 1) {
     471           0 :         throw ProcessError(TLF("Invalid walkingarea '%' does not allow continuation.", walkingArea->getID()));
     472             :     }
     473          10 :     return &myWalkingAreaPaths.find(std::make_pair(lanes.front(), lanes.back()))->second;
     474             : }
     475             : 
     476             : const MSPModel_Striping::WalkingAreaPath*
     477          72 : MSPModel_Striping::guessPath(const MSEdge* walkingArea, const MSEdge* before, const MSEdge* after) {
     478             :     assert(walkingArea->isWalkingArea());
     479          72 :     const MSLane* swBefore = getSidewalk<MSEdge, MSLane>(before);
     480          72 :     const MSLane* swAfter = getSidewalk<MSEdge, MSLane>(after);
     481          72 :     const auto pathIt = myWalkingAreaPaths.find(std::make_pair(swBefore, swAfter));
     482          72 :     if (pathIt != myWalkingAreaPaths.end()) {
     483          29 :         return &pathIt->second;
     484             :     }
     485             :     const MSEdgeVector& preds = walkingArea->getPredecessors();
     486          43 :     const MSEdgeVector& succs = walkingArea->getSuccessors();
     487          43 :     bool useBefore = swBefore != nullptr && std::find(preds.begin(), preds.end(), before) != preds.end();
     488          43 :     bool useAfter = swAfter != nullptr && std::find(succs.begin(), succs.end(), after) != succs.end();
     489          43 :     if (useBefore) {
     490          33 :         if (useAfter) {
     491           0 :             return getWalkingAreaPath(walkingArea, swBefore, swAfter);
     492          33 :         } else if (succs.size() > 0) {
     493             :             // could also try to exploit direction
     494          33 :             return getWalkingAreaPath(walkingArea, swBefore, getSidewalk<MSEdge, MSLane>(succs.front()));
     495             :         }
     496          10 :     } else if (useAfter && preds.size() > 0) {
     497             :         // could also try to exploit direction
     498          10 :         return getWalkingAreaPath(walkingArea, getSidewalk<MSEdge, MSLane>(preds.front()), swAfter);
     499             :     }
     500           0 :     return getArbitraryPath(walkingArea);
     501             : }
     502             : 
     503             : 
     504             : const MSPModel_Striping::WalkingAreaPath*
     505      103744 : MSPModel_Striping::getWalkingAreaPath(const MSEdge* walkingArea, const MSLane* before, const MSLane* after) {
     506             :     assert(walkingArea->isWalkingArea());
     507      103744 :     const auto pathIt = myWalkingAreaPaths.find(std::make_pair(before, after));
     508      103744 :     if (pathIt != myWalkingAreaPaths.end()) {
     509      103738 :         return &pathIt->second;
     510             :     } else {
     511             :         // this can happen in case of moveToXY where before can point anywhere
     512             :         const MSEdgeVector& preds = walkingArea->getPredecessors();
     513           6 :         if (preds.size() > 0) {
     514           6 :             const MSEdge* const pred = walkingArea->getPredecessors().front();
     515           6 :             const auto pathIt2 = myWalkingAreaPaths.find(std::make_pair(getSidewalk<MSEdge, MSLane>(pred), after));
     516             :             assert(pathIt2 != myWalkingAreaPaths.end());
     517           6 :             return &pathIt2->second;
     518             :         } else {
     519           0 :             return getArbitraryPath(walkingArea);
     520             :         }
     521             :     }
     522             : }
     523             : 
     524             : 
     525             : 
     526             : MSPModel_Striping::NextLaneInfo
     527     1253409 : MSPModel_Striping::getNextLane(const PState& ped, const MSLane* currentLane, const MSLane* prevLane) {
     528             :     const MSEdge* currentEdge = &currentLane->getEdge();
     529     1253409 :     const MSJunction* junction = ped.myDir == FORWARD ? currentEdge->getToJunction() : currentEdge->getFromJunction();
     530     1253409 :     const MSEdge* nextRouteEdge = ped.myStage->getNextRouteEdge();
     531     1253409 :     const MSLane* nextRouteLane = getSidewalk<MSEdge, MSLane>(nextRouteEdge, ped.myPerson->getVClass());
     532             :     // result values
     533             :     const MSLane* nextLane = nextRouteLane;
     534     1253409 :     const MSLink* link = nullptr;
     535     1253409 :     int nextDir = UNDEFINED_DIRECTION;
     536             : 
     537             :     //if DEBUGCOND(ped) {
     538             :     //    std::cout << "  nextRouteLane=" << Named::getIDSecure(nextRouteLane) << " junction=" << junction->getID() << "\n";
     539             :     //}
     540     1253409 :     if (nextRouteLane == nullptr && nextRouteEdge != nullptr) {
     541          56 :         std::string error = "Person '" + ped.myPerson->getID() + "' could not find sidewalk on edge '" + nextRouteEdge->getID() + "', time="
     542          84 :                             + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".";
     543          56 :         if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
     544          76 :             WRITE_WARNING(error);
     545          24 :             nextRouteLane = nextRouteEdge->getLanes().front();
     546             :         } else {
     547           8 :             throw ProcessError(error);
     548             :         }
     549             :     }
     550             : 
     551     1253405 :     if (nextRouteLane != nullptr) {
     552      986324 :         if (currentEdge->isInternal()) {
     553             :             assert(junction == currentEdge->getFromJunction());
     554      145618 :             nextDir = junction == nextRouteEdge->getFromJunction() ? FORWARD : BACKWARD;
     555      145618 :             if (nextDir == FORWARD) {
     556       84518 :                 nextLane = currentLane->getLinkCont()[0]->getViaLaneOrLane();
     557             :             } else {
     558       61100 :                 nextLane = currentLane->getLogicalPredecessorLane();
     559             :             }
     560      145618 :             if DEBUGCOND(ped) {
     561           0 :                 std::cout << "  internal\n";
     562             :             }
     563      840706 :         } else if (currentEdge->isCrossing()) {
     564       12211 :             nextDir = ped.myDir;
     565       12211 :             if (ped.myDir == FORWARD) {
     566        6588 :                 nextLane = currentLane->getLinkCont()[0]->getLane();
     567             :             } else {
     568        5623 :                 nextLane = currentLane->getLogicalPredecessorLane();
     569             :             }
     570       12211 :             if DEBUGCOND(ped) {
     571           0 :                 std::cout << "  crossing\n";
     572             :             }
     573      828495 :         } else if (currentEdge->isWalkingArea())  {
     574             :             ConstMSEdgeVector crossingRoute;
     575             :             // departPos can be 0 because the direction of the walkingArea does not matter
     576             :             // for the arrivalPos, we need to make sure that the route does not deviate across other junctions
     577      404651 :             const int nextRouteEdgeDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
     578      404651 :             const double arrivalPos = (nextRouteEdge == ped.myStage->getRoute().back()
     579      404651 :                                        ? ped.myStage->getArrivalPos()
     580       13043 :                                        : (nextRouteEdgeDir == FORWARD ? 0 : nextRouteEdge->getLength()));
     581             :             MSEdgeVector prohibited;
     582      404651 :             if (prevLane != nullptr) {
     583      404579 :                 prohibited.push_back(&prevLane->getEdge());
     584             :             }
     585      404651 :             MSNet::getInstance()->getPedestrianRouter(0, prohibited).compute(currentEdge, nextRouteEdge, 0, arrivalPos, ped.myStage->getMaxSpeed(ped.myPerson), 0, junction, crossingRoute, true);
     586      404651 :             if DEBUGCOND(ped) {
     587             :                 std::cout
     588             :                         << "   nre=" << nextRouteEdge->getID()
     589             :                         << "   nreDir=" << nextRouteEdgeDir
     590           0 :                         << "   aPos=" << arrivalPos
     591           0 :                         << " crossingRoute=" << toString(crossingRoute)
     592           0 :                         << "\n";
     593             :             }
     594      404651 :             if (crossingRoute.size() > 1) {
     595      404614 :                 const MSEdge* nextEdge = crossingRoute[1];
     596      404614 :                 nextLane = getSidewalk<MSEdge, MSLane>(crossingRoute[1], ped.myPerson->getVClass());
     597             :                 assert((nextEdge->getFromJunction() == junction || nextEdge->getToJunction() == junction));
     598             :                 assert(nextLane != prevLane);
     599      404614 :                 nextDir = connectedDirection(currentLane, nextLane);
     600      404614 :                 if DEBUGCOND(ped) {
     601           0 :                     std::cout << " nextDir=" << nextDir << "\n";
     602             :                 }
     603             :                 assert(nextDir != UNDEFINED_DIRECTION);
     604      404614 :                 if (nextDir == FORWARD) {
     605      301426 :                     link = currentLane->getLinkTo(nextLane);
     606             :                 } else {
     607      103188 :                     link = nextLane->getLinkTo(currentLane);
     608      103188 :                     if (nextEdge->isCrossing() && link->getTLLogic() == nullptr) {
     609       88554 :                         const MSLane* oppositeWalkingArea = nextLane->getLogicalPredecessorLane();
     610       88554 :                         link = oppositeWalkingArea->getLinkTo(nextLane);
     611             :                     }
     612             :                 }
     613             :                 assert(link != nullptr);
     614             :             } else {
     615          37 :                 if DEBUGCOND(ped) {
     616           0 :                     std::cout << SIMTIME
     617           0 :                               << " no route from '" << (currentEdge == nullptr ? "NULL" : currentEdge->getID())
     618           0 :                               << "' to '" << (nextRouteEdge == nullptr ? "NULL" : nextRouteEdge->getID())
     619           0 :                               << "\n";
     620             :                 }
     621             :                 // check if a direct connection exists (moving onto the walkingarea was the wrong choice)
     622          37 :                 if (ped.myDir == FORWARD) {
     623          24 :                     link = prevLane->getLinkTo(nextRouteLane);
     624             :                 } else {
     625          13 :                     link = nextRouteLane->getLinkTo(prevLane);
     626             :                 }
     627          37 :                 if (link != nullptr) {
     628             :                     // leave direction as UNDEFINED_DIRECTION to signal that currentLane must be changed
     629             :                     nextLane = link->getViaLaneOrLane();
     630             :                 } else {
     631          40 :                     WRITE_WARNING("Person '" + ped.myPerson->getID() + "' could not find route across junction '" + junction->getID()
     632             :                                   + "' from walkingArea '" + currentEdge->getID()
     633             :                                   + "' to edge '" + nextRouteEdge->getID() + "', time=" +
     634             :                                   time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     635             :                     // error indicated by nextDir == UNDEFINED_DIRECTION
     636             :                     nextLane = nextRouteLane;
     637             :                 }
     638             :             }
     639      423844 :         } else if (currentEdge == nextRouteEdge) {
     640             :             // strange loop in this route. No need to use walkingArea
     641           8 :             nextDir = -ped.myDir;
     642             :         } else {
     643             :             // normal edge. by default use next / previous walking area
     644      423836 :             nextDir = ped.myDir;
     645      423836 :             nextLane = getNextWalkingArea(currentLane, ped.myDir, link);
     646      423836 :             if (nextLane != nullptr) {
     647             :                 // walking area found
     648       97064 :                 if DEBUGCOND(ped) {
     649           0 :                     std::cout << "  next walkingArea " << (nextDir == FORWARD ? "forward" : "backward") << "\n";
     650             :                 }
     651             :             } else {
     652             :                 // walk forward by default
     653      326772 :                 if (junction == nextRouteEdge->getToJunction()) {
     654      145743 :                     nextDir = BACKWARD;
     655      181029 :                 } else if (junction == nextRouteEdge->getFromJunction()) {
     656             :                     nextDir = FORWARD;
     657             :                 } else {
     658             :                     // topological disconnect, find a direction that makes sense
     659             :                     // for the future part of the route
     660         776 :                     ConstMSEdgeVector futureRoute = ped.myStage->getRoute();
     661         776 :                     futureRoute.erase(futureRoute.begin(), futureRoute.begin() + ped.myStage->getRoutePosition() + 1);
     662         776 :                     int passedFwd = 0;
     663         776 :                     int passedBwd = 0;
     664         776 :                     canTraverse(FORWARD, futureRoute, passedFwd);
     665         776 :                     canTraverse(BACKWARD, futureRoute, passedBwd);
     666         776 :                     nextDir = (passedFwd >= passedBwd) ? FORWARD : BACKWARD;
     667         776 :                     if DEBUGCOND(ped) {
     668           0 :                         std::cout << " nextEdge=" << nextRouteEdge->getID() << " passedFwd=" << passedFwd << " passedBwd=" << passedBwd << " futureRoute=" << toString(futureRoute) << " nextDir=" << nextDir << "\n";
     669             :                     }
     670             :                 }
     671             :                 // try to use a direct link as fallback
     672             :                 // direct links only exist if built explicitly. They are used to model tl-controlled links if there are no crossings
     673      326772 :                 if (ped.myDir == FORWARD) {
     674      101753 :                     link = currentLane->getLinkTo(nextRouteLane);
     675      101753 :                     if (link != nullptr) {
     676       94426 :                         if DEBUGCOND(ped) {
     677           0 :                             std::cout << "  direct forward\n";
     678             :                         }
     679       94426 :                         nextLane = currentLane->getInternalFollowingLane(nextRouteLane);
     680             :                     }
     681             :                 } else {
     682      225019 :                     link = nextRouteLane->getLinkTo(currentLane);
     683      225019 :                     if (link != nullptr) {
     684       63397 :                         if DEBUGCOND(ped) {
     685           0 :                             std::cout << "  direct backward\n";
     686             :                         }
     687       63397 :                         nextLane = nextRouteLane->getInternalFollowingLane(currentLane);
     688       63397 :                         if (nextLane != nullptr) {
     689             :                             // advance to the end of consecutive internal lanes
     690      125805 :                             while (nextLane->getLinkCont()[0]->getViaLaneOrLane()->isInternal()) {
     691           5 :                                 nextLane = nextLane->getLinkCont()[0]->getViaLaneOrLane();
     692             :                             }
     693             :                         }
     694             :                     }
     695             :                 }
     696             :             }
     697      423836 :             if (nextLane == nullptr) {
     698             :                 // no internal lane found
     699             :                 nextLane = nextRouteLane;
     700      174464 :                 if DEBUGCOND(ped) {
     701           0 :                     std::cout << SIMTIME << " no next lane found for " << currentLane->getID() << " dir=" << ped.myDir << "\n";
     702             :                 }
     703      174464 :                 if (usingInternalLanesStatic() && currentLane->getLinkCont().size() > 0) {
     704           0 :                     WRITE_WARNING("Person '" + ped.myPerson->getID() + "' could not find route across junction '" + junction->getID()
     705             :                                   + "' from edge '" + currentEdge->getID()
     706             :                                   + "' to edge '" + nextRouteEdge->getID() + "', time=" +
     707             :                                   time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     708             :                 }
     709      249372 :             } else if (nextLane->getLength() <= POSITION_EPS) {
     710             :                 // internal lane too short
     711             :                 // most often this is due to a zero-size junction. However, if
     712             :                 // the person needs to pass a crossing we cannot skip ahead
     713       11369 :                 if ((nextLane->getCanonicalSuccessorLane() == nullptr
     714       11361 :                         || !nextLane->getCanonicalSuccessorLane()->getEdge().isCrossing())
     715       34087 :                         && (nextLane->getLogicalPredecessorLane() == nullptr ||
     716       11357 :                             !nextLane->getLogicalPredecessorLane()->getEdge().isCrossing())) {
     717             :                     //WRITE_WARNING("Person '" + ped.getID()
     718             :                     //        + "' skips short lane '" + nextLane->getID()
     719             :                     //        + "' length=" + toString(nextLane->getLength())
     720             :                     //        + " time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
     721             :                     nextLane = nextRouteLane;
     722       11369 :                     nextDir = nextRouteEdge->getFromJunction() == junction ? FORWARD : BACKWARD;
     723             :                 }
     724             :             }
     725             :         }
     726             :     }
     727     1253405 :     if DEBUGCOND(ped) {
     728           0 :         std::cout << SIMTIME
     729           0 :                   << " p=" << ped.myPerson->getID()
     730             :                   << " l=" << currentLane->getID()
     731           0 :                   << " nl=" << (nextLane == nullptr ? "NULL" : nextLane->getID())
     732           0 :                   << " nrl=" << (nextRouteLane == nullptr ? "NULL" : nextRouteLane->getID())
     733             :                   << " d=" << nextDir
     734           0 :                   << " link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
     735           0 :                   << " pedDir=" << ped.myDir
     736           0 :                   << "\n";
     737             :     }
     738             :     assert(nextLane != 0 || nextRouteLane == 0);
     739     1253405 :     return NextLaneInfo(nextLane, link, nextDir);
     740             : }
     741             : 
     742             : 
     743             : const MSLane*
     744      423836 : MSPModel_Striping::getNextWalkingArea(const MSLane* currentLane, const int dir, const MSLink*& link) {
     745      423836 :     if (dir == FORWARD) {
     746      313979 :         for (const MSLink* const l : currentLane->getLinkCont()) {
     747      212226 :             if (l->getLane()->getEdge().isWalkingArea()) {
     748       83426 :                 link = l;
     749             :                 return l->getLane();
     750             :             }
     751             :         }
     752             :     } else {
     753             :         const std::vector<MSLane::IncomingLaneInfo>& laneInfos = currentLane->getIncomingLanes();
     754      389493 :         for (std::vector<MSLane::IncomingLaneInfo>::const_iterator it = laneInfos.begin(); it != laneInfos.end(); ++it) {
     755      164474 :             if ((*it).lane->getEdge().isWalkingArea()) {
     756       13638 :                 link = (*it).viaLink;
     757             :                 return (*it).lane;
     758             :             }
     759             :         }
     760             :     }
     761             :     return nullptr;
     762             : }
     763             : 
     764             : 
     765             : MSPModel_Striping::Obstacles
     766    49720913 : MSPModel_Striping::getNeighboringObstacles(const Pedestrians& pedestrians, int egoIndex, int stripes) {
     767    49720913 :     const PState& ego = *pedestrians[egoIndex];
     768    49720913 :     const int egoStripe = ego.stripe();
     769    49720913 :     Obstacles obs(stripes, Obstacle(ego.myDir));
     770    49720913 :     std::vector<bool> haveBlocker(stripes, false);
     771  8688806049 :     for (int index = egoIndex + 1; index < (int)pedestrians.size(); index++) {
     772  8675247753 :         const PState& p = *pedestrians[index];
     773  8675247753 :         if DEBUGCOND(ego) {
     774           0 :             std::cout << SIMTIME << " ped=" << ego.getID() << " cur=" << egoStripe << " checking neighbor " << p.getID()
     775           0 :                       << " nCur=" << p.stripe() << " nOth=" << p.otherStripe();
     776             :         }
     777  8675247753 :         if (!p.myWaitingToEnter && !p.myAmJammed) {
     778    58243719 :             const Obstacle o(p);
     779    58243719 :             if DEBUGCOND(ego) {
     780           0 :                 std::cout << " dist=" << ego.distanceTo(o) << std::endl;
     781             :             }
     782    58243719 :             if (ego.distanceTo(o) == DIST_BEHIND) {
     783             :                 break;
     784             :             }
     785    22081102 :             if (ego.distanceTo(o) == DIST_OVERLAP) {
     786    22081102 :                 if (p.stripe() != egoStripe || p.myDir != ego.myDir) {
     787    18157240 :                     obs[p.stripe()] = o;
     788    18157240 :                     haveBlocker[p.stripe()] = true;
     789             :                 } else {
     790             :                     //std::cout << SIMTIME << "   ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe=" << egoStripe << "\n";
     791             :                 }
     792    22081102 :                 if (p.otherStripe() != egoStripe || p.myDir != ego.myDir) {
     793    18157240 :                     obs[p.otherStripe()] = o;
     794    18157240 :                     haveBlocker[p.otherStripe()] = true;
     795             :                 } else {
     796             :                     //std::cout << SIMTIME << "   ignoring overlap between " << ego.getID() << " and " << p.getID() << " on stripe2=" << egoStripe << "\n";
     797             :                 }
     798             :             } else {
     799           0 :                 if (!haveBlocker[p.stripe()]) {
     800           0 :                     obs[p.stripe()] = o;
     801             :                 }
     802           0 :                 if (!haveBlocker[p.otherStripe()]) {
     803           0 :                     obs[p.otherStripe()] = o;
     804             :                 }
     805             :             }
     806             :         }
     807             :     }
     808    49720913 :     if DEBUGCOND(ego) {
     809           0 :         std::cout << SIMTIME << " ped=" << ego.myPerson->getID() << "  neighObs=";
     810           0 :         DEBUG_PRINT(obs);
     811             :     }
     812    49720913 :     return obs;
     813           0 : }
     814             : 
     815             : 
     816             : int
     817     1804003 : MSPModel_Striping::getStripeOffset(int origStripes, int destStripes, bool addRemainder) {
     818     1804003 :     int offset = (destStripes - origStripes) / 2;
     819     1804003 :     if (addRemainder) {
     820        4905 :         offset += (destStripes - origStripes) % 2;
     821             :     }
     822     1804003 :     return offset;
     823             : }
     824             : 
     825             : 
     826             : const MSPModel_Striping::Obstacles&
     827    28850248 : MSPModel_Striping::getNextLaneObstacles(NextLanesObstacles& nextLanesObs, const
     828             :                                         MSLane* lane, const MSLane* nextLane, int stripes, int nextDir,
     829             :                                         double currentLength, int currentDir) {
     830             :     if (nextLanesObs.count(nextLane) == 0) {
     831     1122097 :         const double nextLength = nextLane->getEdge().isWalkingArea() ? myMinNextLengths[nextLane] : nextLane->getLength();
     832             :         // figure out the which pedestrians are ahead on the next lane
     833     1122097 :         const int nextStripes = numStripes(nextLane);
     834             :         // do not move past the end of the next lane in a single step
     835     3366291 :         Obstacles obs(stripes, Obstacle(nextDir == FORWARD ? nextLength : 0, 0, OBSTACLE_NEXTEND, "nextEnd", 0));
     836             : 
     837     1122097 :         const int offset = getStripeOffset(nextStripes, stripes, currentDir != nextDir && nextStripes > stripes);
     838             :         //std::cout << SIMTIME << " getNextLaneObstacles"
     839             :         //    << " nextLane=" << nextLane->getID()
     840             :         //    << " nextLength=" << nextLength
     841             :         //    << " nextDir=" << nextDir
     842             :         //    << " currentLength=" << currentLength
     843             :         //    << " currentDir=" << currentDir
     844             :         //    << " stripes=" << stripes
     845             :         //    << " nextStripes=" << nextStripes
     846             :         //    << " offset=" << offset
     847             :         //    << "\n";
     848     1122097 :         if (nextStripes < stripes) {
     849             :             // some stripes do not continue
     850     1406088 :             for (int ii = 0; ii < stripes; ++ii) {
     851     1211017 :                 if (ii < offset || ii >= nextStripes + offset) {
     852     1657590 :                     obs[ii] = Obstacle(nextDir == FORWARD ? 0 : nextLength, 0, OBSTACLE_END, "stripeEnd", 0);
     853             :                 }
     854             :             }
     855             :         }
     856     1122097 :         Pedestrians& pedestrians = getPedestrians(nextLane);
     857     1122097 :         if (nextLane->getEdge().isWalkingArea()) {
     858      290356 :             transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
     859             :             // complex transformation into the coordinate system of the current lane
     860             :             // (pedestrians on next lane may walk at arbitrary angles relative to the current lane)
     861      290356 :             double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
     862      290356 :             if ((stripes - nextStripes) % 2 != 0) {
     863      180231 :                 lateral_offset += 0.5 * stripeWidth;
     864             :             }
     865             :             nextDir = currentDir;
     866             :             // transform pedestrians into the current coordinate system
     867     1734159 :             for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
     868     1443803 :                 PState& p = *pedestrians[ii];
     869     1443803 :                 if (p.myWaitingToEnter || p.myAmJammed) {
     870        3062 :                     continue;
     871             :                 }
     872     1440741 :                 Position relPos =  lane->getShape().transformToVectorCoordinates(p.getPosition(*p.myStage, -1), true);
     873     1440741 :                 const double newY = relPos.y() + lateral_offset;
     874             :                 //if (p.myPerson->getID() == "ped200") std::cout << "    ped=" << p.myPerson->getID() << "  relX=" << relPos.x() << " relY=" << newY << " latOff=" << lateral_offset << " s=" << p.stripe(newY) << " os=" << p.otherStripe(newY) << "\n";
     875     1440741 :                 if ((currentDir == FORWARD && relPos.x() >= lane->getLength()) || (currentDir == BACKWARD && relPos.x() < 0)) {
     876     1436961 :                     addCloserObstacle(obs, relPos.x(), p.stripe(newY), stripes, p.myPerson->getID(), p.myPerson->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
     877     1436961 :                     addCloserObstacle(obs, relPos.x(), p.otherStripe(newY), stripes, p.myPerson->getID(), p.myPerson->getVehicleType().getWidth(), currentDir, OBSTACLE_PED);
     878             :                 }
     879             :             }
     880             :         } else {
     881             :             // simple transformation into the coordinate system of the current lane
     882             :             // (only need to worry about currentDir and nextDir)
     883             :             // XXX consider waitingToEnter on nextLane
     884      831741 :             sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(nextDir));
     885    26471530 :             for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
     886    25639789 :                 const PState& p = *pedestrians[ii];
     887    25639789 :                 if (p.myWaitingToEnter || p.myAmJammed) {
     888    14273502 :                     continue;
     889             :                 }
     890    11366287 :                 double newY = p.myRelY;
     891    11366287 :                 Obstacle pObs(p);
     892    11366287 :                 if (nextDir != currentDir) {
     893     2408228 :                     newY = (nextStripes - 1) * stripeWidth - newY;
     894     2408228 :                     pObs.speed *= -1;
     895             :                 }
     896    11366287 :                 newY += offset * stripeWidth;
     897    11366287 :                 const int stripe = p.stripe(newY);
     898    11366287 :                 if (stripe >= 0 && stripe < stripes) {
     899    11366284 :                     obs[stripe] = pObs;
     900             :                 }
     901    11366287 :                 const int otherStripe = p.otherStripe(newY);
     902    11366287 :                 if (otherStripe >= 0 && otherStripe < stripes) {
     903    11366284 :                     obs[otherStripe] = pObs;
     904             :                 }
     905             :             }
     906      831741 :             if (nextLane->getEdge().isCrossing()) {
     907             :                 // add vehicle obstacles
     908       79766 :                 const MSLink* crossingEntryLink = nextLane->getIncomingLanes().front().viaLink;
     909       79766 :                 const bool prio = crossingEntryLink->havePriority() || crossingEntryLink->getTLLogic() != nullptr;
     910       79766 :                 addCrossingVehs(nextLane, stripes, offset, nextDir, obs, prio);
     911             :             }
     912      831741 :             if (nextLane->getVehicleNumberWithPartials() > 0) {
     913       19193 :                 Obstacles vehObs = getVehicleObstacles(nextLane, nextDir);
     914       19193 :                 PState::mergeObstacles(obs, vehObs, nextDir, offset);
     915       19193 :             }
     916      831741 :             transformToCurrentLanePositions(obs, currentDir, nextDir, currentLength, nextLength);
     917             :         }
     918     1122097 :         nextLanesObs[nextLane] = obs;
     919     1122097 :     }
     920    28850248 :     return nextLanesObs[nextLane];
     921             : }
     922             : 
     923             : void
     924     1122097 : MSPModel_Striping::transformToCurrentLanePositions(Obstacles& obs, int currentDir, int nextDir, double currentLength, double nextLength) {
     925     6504567 :     for (int ii = 0; ii < (int)obs.size(); ++ii) {
     926     5382470 :         Obstacle& o = obs[ii];
     927     5382470 :         if (currentDir == FORWARD) {
     928     3518521 :             if (nextDir == FORWARD) {
     929     3356320 :                 o.xFwd += currentLength;
     930     3356320 :                 o.xBack += currentLength;
     931             :             } else {
     932      162201 :                 const double tmp = o.xFwd;
     933      162201 :                 o.xFwd = currentLength + nextLength - o.xBack;
     934      162201 :                 o.xBack = currentLength + nextLength - tmp;
     935             :             }
     936             :         } else {
     937     1863949 :             if (nextDir == FORWARD) {
     938      487461 :                 const double tmp = o.xFwd;
     939      487461 :                 o.xFwd = -o.xBack;
     940      487461 :                 o.xBack = -tmp;
     941             :             } else {
     942     1376488 :                 o.xFwd -= nextLength;
     943     1376488 :                 o.xBack -= nextLength;
     944             :             }
     945             :         }
     946             :     }
     947     1122097 : }
     948             : 
     949             : 
     950             : void
     951     2873922 : MSPModel_Striping::addCloserObstacle(Obstacles& obs, double x, int stripe, int numStripes, const std::string& id, double width, int dir, ObstacleType type) {
     952     2873922 :     if (stripe >= 0 && stripe < numStripes) {
     953     1068467 :         if ((dir == FORWARD && x - width / 2. < obs[stripe].xBack) || (dir == BACKWARD && x + width / 2. > obs[stripe].xFwd)) {
     954      723690 :             obs[stripe] = Obstacle(x, 0, type, id, width);
     955             :         }
     956             :     }
     957     2873922 : }
     958             : 
     959             : void
     960     3704788 : MSPModel_Striping::moveInDirection(SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
     961    48411843 :     for (ActiveLanes::iterator it_lane = myActiveLanes.begin(); it_lane != myActiveLanes.end(); ++it_lane) {
     962    44707059 :         const MSLane* lane = it_lane->first;
     963    44707059 :         Pedestrians& pedestrians = it_lane->second;
     964    44707059 :         if (pedestrians.size() == 0) {
     965    39631827 :             continue;
     966             :         }
     967             :         //std::cout << SIMTIME << ">>> lane=" << lane->getID() << " numPeds=" << pedestrians.size() << "\n";
     968     5075232 :         if (lane->getEdge().isWalkingArea()) {
     969      604922 :             const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
     970      604922 :             const double minY = stripeWidth * - 0.5 + NUMERICAL_EPS;
     971      604922 :             const double maxY = stripeWidth * (numStripes(lane) - 0.5) - NUMERICAL_EPS;
     972             :             const WalkingAreaPath* debugPath = nullptr;
     973             :             // need to handle each walkingAreaPath separately and transform
     974             :             // coordinates beforehand
     975             :             std::set<const WalkingAreaPath*, walkingarea_path_sorter> paths;
     976     3437887 :             for (Pedestrians::iterator it = pedestrians.begin(); it != pedestrians.end(); ++it) {
     977     2832965 :                 const PState* p = *it;
     978             :                 assert(p->myWalkingAreaPath != 0);
     979     2832965 :                 if (p->myDir == dir) {
     980     1422451 :                     paths.insert(p->myWalkingAreaPath);
     981     1422451 :                     if DEBUGCOND(*p) {
     982           0 :                         debugPath = p->myWalkingAreaPath;
     983           0 :                         std::cout << SIMTIME << " debugging WalkingAreaPath from=" << debugPath->from->getID() << " to=" << debugPath->to->getID() << " minY=" << minY << " maxY=" << maxY << " latOffset=" << lateral_offset << "\n";
     984             :                     }
     985             :                 }
     986             :             }
     987      604922 :             const double usableWidth = (numStripes(lane) - 1) * stripeWidth;
     988      981329 :             for (std::set<const WalkingAreaPath*, walkingarea_path_sorter>::iterator it = paths.begin(); it != paths.end(); ++it) {
     989      376407 :                 const WalkingAreaPath* path = *it;
     990             :                 Pedestrians toDelete;
     991             :                 Pedestrians transformedPeds;
     992      376407 :                 transformedPeds.reserve(pedestrians.size());
     993     2754129 :                 for (Pedestrians::iterator it_p = pedestrians.begin(); it_p != pedestrians.end(); ++it_p) {
     994     2377722 :                     PState* p = *it_p;
     995     2377722 :                     if (p->myWalkingAreaPath == path) {
     996     1422451 :                         transformedPeds.push_back(p);
     997     1422451 :                         if (path == debugPath) std::cout << "  ped=" << p->myPerson->getID() << "  relX=" << p->myRelX << " relY=" << p->myRelY << " (untransformed), vecCoord="
     998           0 :                                                              << path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1)) << "\n";
     999      955271 :                     } else if (p->myWalkingAreaPath->from == path->to && p->myWalkingAreaPath->to == path->from) {
    1000       53933 :                         if (p->myWalkingAreaPath->dir != path->dir) {
    1001             :                             // opposite direction is already in the correct coordinate system
    1002       39899 :                             transformedPeds.push_back(p);
    1003       39899 :                             if (path == debugPath) std::cout << "  ped=" << p->myPerson->getID() << "  relX=" << p->myRelX << " relY=" << p->myRelY << " (untransformed), vecCoord="
    1004           0 :                                                                  << path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1)) << "\n";
    1005             :                         } else {
    1006             :                             // x position must be reversed
    1007       14034 :                             PState* tp = new PState(*p);
    1008       14034 :                             tp->myRelX = path->length - p->myRelX;
    1009       14034 :                             tp->myRelY = usableWidth - p->myRelY;
    1010       14034 :                             tp->myDir = !path->dir;
    1011       14034 :                             tp->mySpeed = -p->mySpeed;
    1012       14034 :                             tp->mySpeedLat = -p->mySpeedLat;
    1013       14034 :                             toDelete.push_back(tp);
    1014       14034 :                             transformedPeds.push_back(tp);
    1015       14034 :                             if (path == debugPath) std::cout << "  ped=" << p->myPerson->getID() << "  relX=" << p->myRelX << " relY=" << p->myRelY << " (semi-transformed), vecCoord="
    1016           0 :                                                                  << path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1)) << "\n";
    1017             :                         }
    1018             :                     } else {
    1019      901338 :                         const Position relPos = path->shape.transformToVectorCoordinates(p->getPosition(*p->myStage, -1));
    1020      901338 :                         const double newY = relPos.y() + lateral_offset;
    1021      900890 :                         if (relPos != Position::INVALID && newY >= minY && newY <= maxY) {
    1022      241988 :                             PState* tp = new PState(*p);
    1023      241988 :                             tp->myRelX = relPos.x();
    1024      241988 :                             tp->myRelY = newY;
    1025             :                             // only an obstacle, speed may be orthogonal to dir
    1026      241988 :                             tp->myDir = !dir;
    1027      241988 :                             tp->mySpeed = 0;
    1028      241988 :                             tp->mySpeedLat = 0;
    1029      241988 :                             toDelete.push_back(tp);
    1030      241988 :                             transformedPeds.push_back(tp);
    1031      241988 :                             if (path == debugPath) {
    1032           0 :                                 std::cout << "  ped=" << p->myPerson->getID() << "  relX=" << relPos.x() << " relY=" << newY << " (transformed), vecCoord=" << relPos << "\n";
    1033             :                             }
    1034             :                         } else {
    1035      659350 :                             if (path == debugPath) {
    1036           0 :                                 std::cout << "  ped=" << p->myPerson->getID() << "  relX=" << relPos.x() << " relY=" << newY << " (invalid), vecCoord=" << relPos << "\n";
    1037             :                             }
    1038             :                         }
    1039             :                     }
    1040             :                 }
    1041             :                 auto itFoe = myWalkingAreaFoes.find(&lane->getEdge());
    1042      376407 :                 if (itFoe != myWalkingAreaFoes.end()) {
    1043             :                     // add vehicle foes on paths which cross this walkingarea
    1044             :                     // translate the vehicle into a number of dummy-pedestrians
    1045             :                     // that occupy the same space
    1046     2296156 :                     for (const MSLane* foeLane : itFoe->second) {
    1047      171221 :                         for (auto itVeh = foeLane->anyVehiclesBegin(); itVeh != foeLane->anyVehiclesEnd(); ++itVeh) {
    1048      171221 :                             const MSVehicle* veh = *itVeh;
    1049      171221 :                             const double vehWidth = veh->getVehicleType().getWidth();
    1050      171221 :                             Boundary relCorners;
    1051      171221 :                             Position relFront = path->shape.transformToVectorCoordinates(veh->getPosition());
    1052      171221 :                             Position relBack = path->shape.transformToVectorCoordinates(veh->getBackPosition());
    1053      171221 :                             PositionVector relCenter;
    1054      171221 :                             relCenter.push_back(relFront);
    1055      171221 :                             relCenter.push_back(relBack);
    1056      171221 :                             relCenter.move2side(vehWidth / 2);
    1057      171221 :                             relCorners.add(relCenter[0]);
    1058      171221 :                             relCorners.add(relCenter[1]);
    1059      171221 :                             relCenter.move2side(-vehWidth);
    1060      171221 :                             relCorners.add(relCenter[0]);
    1061      171221 :                             relCorners.add(relCenter[1]);
    1062             :                             // persons should requier less gap than the vehicles to prevent getting stuck
    1063             :                             // when a vehicles moves towards them
    1064      171221 :                             relCorners.growWidth(SAFETY_GAP / 2);
    1065      171221 :                             const double xWidth = relCorners.getWidth();
    1066      171221 :                             const double vehYmin = MAX2(minY - lateral_offset, relCorners.ymin());
    1067      171221 :                             const double vehYmax = MIN2(maxY - lateral_offset, relCorners.ymax());
    1068      171221 :                             const double xCenter = relCorners.getCenter().x();
    1069             :                             Position yMinPos(xCenter, vehYmin);
    1070             :                             Position yMaxPos(xCenter, vehYmax);
    1071      171221 :                             const bool addFront = addVehicleFoe(veh, lane, yMinPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
    1072      171221 :                             const bool addBack = addVehicleFoe(veh, lane, yMaxPos, dir * xWidth, 0, lateral_offset, minY, maxY, toDelete, transformedPeds);
    1073      171221 :                             if (path == debugPath) {
    1074             :                                 std::cout << "  veh=" << veh->getID()
    1075           0 :                                           << " corners=" << relCorners
    1076             :                                           << " xWidth=" << xWidth
    1077           0 :                                           << " ymin=" << relCorners.ymin()
    1078           0 :                                           << " ymax=" << relCorners.ymax()
    1079             :                                           << " vehYmin=" << vehYmin
    1080             :                                           << " vehYmax=" << vehYmax
    1081           0 :                                           << "\n";
    1082             :                             }
    1083      171221 :                             if (addFront && addBack) {
    1084             :                                 // add in-between positions
    1085      171221 :                                 const double yDist = vehYmax - vehYmin;
    1086      479336 :                                 for (double dist = stripeWidth; dist < yDist; dist += stripeWidth) {
    1087      308115 :                                     const double relDist = dist / yDist;
    1088      308115 :                                     Position between = (yMinPos * relDist) + (yMaxPos * (1 - relDist));
    1089      308115 :                                     if (path == debugPath) {
    1090           0 :                                         std::cout << "  vehBetween=" << veh->getID() << " pos=" << between << "\n";
    1091             :                                     }
    1092      308115 :                                     addVehicleFoe(veh, lane, between, dir * xWidth, stripeWidth, lateral_offset, minY, maxY, toDelete, transformedPeds);
    1093             :                                 }
    1094             :                             }
    1095      171221 :                         }
    1096             :                     }
    1097             :                 }
    1098      376407 :                 moveInDirectionOnLane(transformedPeds, lane, currentTime, changedLane, dir, path == debugPath);
    1099      376407 :                 arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
    1100             :                 // clean up
    1101     1182626 :                 for (Pedestrians::iterator it_p = toDelete.begin(); it_p != toDelete.end(); ++it_p) {
    1102      806219 :                     delete *it_p;
    1103             :                 }
    1104             :             }
    1105             :         } else {
    1106     4470310 :             moveInDirectionOnLane(pedestrians, lane, currentTime, changedLane, dir, false);
    1107     4470310 :             arriveAndAdvance(pedestrians, currentTime, changedLane, dir);
    1108             :         }
    1109             :     }
    1110     3704784 : }
    1111             : 
    1112             : 
    1113             : bool
    1114      650557 : MSPModel_Striping::addVehicleFoe(const MSVehicle* veh, const MSLane* walkingarea, const Position& relPos, double xWidth, double yWidth, double lateral_offset,
    1115             :                                  double minY, double maxY, Pedestrians& toDelete, Pedestrians& transformedPeds) {
    1116             :     if (relPos != Position::INVALID) {
    1117      650557 :         const double newY = relPos.y() + lateral_offset;
    1118      650557 :         if (newY >= minY && newY <= maxY) {
    1119      550197 :             PState* tp = new PStateVehicle(veh, walkingarea, relPos.x(), newY, xWidth, yWidth);
    1120             :             //std::cout << SIMTIME << " addVehicleFoe=" << veh->getID() << " rx=" << relPos.x() << " ry=" << newY << " s=" << tp->stripe() << " o=" << tp->otherStripe() << "\n";
    1121      550197 :             toDelete.push_back(tp);
    1122      550197 :             transformedPeds.push_back(tp);
    1123             :         }
    1124      650557 :         return true;
    1125             :     } else {
    1126             :         return false;
    1127             :     }
    1128             : }
    1129             : 
    1130             : void
    1131     4846717 : MSPModel_Striping::arriveAndAdvance(Pedestrians& pedestrians, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir) {
    1132             :     // advance to the next lane / arrive at destination
    1133     4846717 :     sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
    1134             :     // can't use iterators because we do concurrent modification
    1135   103931039 :     for (int i = 0; i < (int)pedestrians.size(); i++) {
    1136    99084326 :         PState* const p = pedestrians[i];
    1137    99084326 :         if (p->isRemoteControlled()) {
    1138       32302 :             continue;
    1139             :         }
    1140    99052024 :         if (p->myDir == dir && p->distToLaneEnd() < 0) {
    1141             :             // moveToNextLane may trigger re-insertion (for consecutive
    1142             :             // walks) so erase must be called first
    1143             :             pedestrians.erase(pedestrians.begin() + i);
    1144      948585 :             i--;
    1145      948585 :             p->moveToNextLane(currentTime);
    1146      948581 :             if (p->myLane != nullptr) {
    1147      681906 :                 changedLane.insert(p->myPerson);
    1148      681906 :                 myActiveLanes[p->myLane].push_back(p);
    1149             :             } else {
    1150             :                 // end walking stage and destroy PState
    1151      266675 :                 p->myStage->moveToNextEdge(p->myPerson, currentTime, dir);
    1152      266675 :                 myNumActivePedestrians--;
    1153             :             }
    1154             :         }
    1155             :     }
    1156     4846713 : }
    1157             : 
    1158             : 
    1159             : void
    1160     4846717 : MSPModel_Striping::moveInDirectionOnLane(Pedestrians& pedestrians, const MSLane* lane, SUMOTime currentTime, std::set<MSPerson*>& changedLane, int dir, bool debug) {
    1161     4846717 :     const int stripes = numStripes(lane);
    1162             :     //std::cout << " laneWidth=" << lane->getWidth() << " stripeWidth=" << stripeWidth << " stripes=" << stripes << "\n";
    1163     9693434 :     Obstacles obs(stripes, Obstacle(dir)); // continously updated
    1164             :     NextLanesObstacles nextLanesObs; // continously updated
    1165     4846717 :     sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(dir));
    1166             : 
    1167     9693434 :     Obstacles crossingVehs(stripes, Obstacle(dir));
    1168             :     bool hasCrossingVehObs = false;
    1169     4846717 :     if (lane->getEdge().isCrossing()) {
    1170             :         // assume that vehicles will brake when already on the crossing
    1171       80574 :         hasCrossingVehObs = addCrossingVehs(lane, stripes, 0, dir, crossingVehs, true);
    1172             :     }
    1173             : 
    1174   103821614 :     for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
    1175    98974897 :         PState& p = *pedestrians[ii];
    1176             :         UNUSED_PARAMETER(debug);
    1177             :         //if (debug) {
    1178             :         //    std::cout << SIMTIME << " CHECKING d=" << dir << " p=" << p.getID() << " relX=" << p.myRelX << " xmin=" << p.getMinX() << " xmax=" << p.getMaxX() << " pdir=" << p.myDir << "\n";
    1179             :         //}
    1180    98974897 :         Obstacles currentObs = obs;
    1181    98974897 :         if (p.myDir != dir || changedLane.count(p.myPerson) != 0 || p.myRemoteXYPos != Position::INVALID) {
    1182    49253984 :             if (!p.myWaitingToEnter && !p.myAmJammed) {
    1183             :                 //if DEBUGCOND(p) {
    1184             :                 //    std::cout << "   obs=" << p.myPerson->getID() << "  y=" << p.myRelY << "  stripe=" << p.stripe() << " oStripe=" << p.otherStripe() << "\n";
    1185             :                 //}
    1186    24315658 :                 Obstacle o(p);
    1187    24315658 :                 if (p.myDir != dir && p.mySpeed == 0) {
    1188             :                     // ensure recognition of oncoming
    1189     4724158 :                     o.speed = (p.myDir == FORWARD ? 0.1 : -0.1);
    1190             :                 }
    1191    24315658 :                 if (o.closer(obs[p.stripe()], dir)) {
    1192    24303900 :                     obs[p.stripe()] = o;
    1193             :                 }
    1194    24315658 :                 if (o.closer(obs[p.otherStripe()], dir)) {
    1195    24304077 :                     obs[p.otherStripe()] = o;
    1196             :                 }
    1197             :             }
    1198             :             continue;
    1199    49253984 :         }
    1200    49720913 :         if DEBUGCOND(p) {
    1201           0 :             std::cout << SIMTIME << " ped=" << p.myPerson->getID() << "  currentObs=";
    1202           0 :             gDebugFlag1 = true;
    1203           0 :             DEBUG_PRINT(currentObs);
    1204             :         }
    1205    49720913 :         const MSLane* nextLane = p.myNLI.lane;
    1206    49720913 :         const MSLink* link = p.myNLI.link;
    1207    49720913 :         const double dist = p.distToLaneEnd();
    1208    49720913 :         const double speed = p.myStage->getMaxSpeed(p.myPerson);
    1209    49720913 :         if (nextLane != nullptr && dist <= LOOKAHEAD_ONCOMING) {
    1210    28850248 :             const double currentLength = (p.myWalkingAreaPath == nullptr ? lane->getLength() : p.myWalkingAreaPath->length);
    1211    28850248 :             const Obstacles& nextObs = getNextLaneObstacles(
    1212             :                                            nextLanesObs, lane, nextLane, stripes,
    1213             :                                            p.myNLI.dir, currentLength, dir);
    1214             : 
    1215    28850248 :             if DEBUGCOND(p) {
    1216           0 :                 std::cout << SIMTIME << " ped=" << p.myPerson->getID() << "  nextObs=";
    1217           0 :                 DEBUG_PRINT(nextObs);
    1218             :             }
    1219    28850248 :             p.mergeObstacles(currentObs, nextObs);
    1220             :         }
    1221    49720913 :         if DEBUGCOND(p) {
    1222           0 :             std::cout << SIMTIME << " ped=" << p.myPerson->getID() << "  obsWithNext=";
    1223           0 :             DEBUG_PRINT(currentObs);
    1224             :         }
    1225    49720913 :         p.mergeObstacles(currentObs, getNeighboringObstacles(pedestrians, ii, stripes));
    1226    49720913 :         if DEBUGCOND(p) {
    1227           0 :             std::cout << SIMTIME << " ped=" << p.myPerson->getID() << "  obsWithNeigh=";
    1228           0 :             DEBUG_PRINT(currentObs);
    1229             :         }
    1230             :         // time gap to pass the intersection ahead of a vehicle.
    1231             :         const double passingClearanceTime = 2;
    1232    49720913 :         const double passingLength = p.getLength() + passingClearanceTime * speed;
    1233             :         // check link state
    1234    49720913 :         if DEBUGCOND(p) {
    1235           0 :             gDebugFlag1 = true; // get debug output from MSLink
    1236           0 :             std::cout << "   link=" << (link == nullptr ? "NULL" : link->getViaLaneOrLane()->getID())
    1237           0 :                       << " dist=" << dist << " d2=" << dist - p.getMinGap() << " la=" << LOOKAHEAD_SAMEDIR* speed << "\n";
    1238             :         }
    1239             :         if (link != nullptr
    1240             :                 // only check close before junction, @todo we should take deceleration into account here
    1241    29820838 :                 && dist - p.getMinGap() < LOOKAHEAD_SAMEDIR * speed
    1242             :                 // persons move before vehicles so we subtract DELTA_TO because they cannot rely on vehicles having passed the intersection in the current time step
    1243    59399576 :                 && !link->opened(currentTime - DELTA_T, speed, speed, passingLength, p.getImpatience(currentTime), speed, 0, 0, nullptr, p.ignoreRed(link), p.myPerson)) {
    1244             :             // prevent movement passed a closed link
    1245      911038 :             Obstacles closedLink(stripes, Obstacle(p.myRelX + dir * (dist - NUMERICAL_EPS), 0, OBSTACLE_LINKCLOSED, "closedLink_" + link->getViaLaneOrLane()->getID(), 0));
    1246      455519 :             p.mergeObstacles(currentObs, closedLink);
    1247      455519 :             if DEBUGCOND(p) {
    1248           0 :                 std::cout << SIMTIME << " ped=" << p.myPerson->getID() << "  obsWithTLS=";
    1249           0 :                 DEBUG_PRINT(currentObs);
    1250             :             }
    1251             :             // consider rerouting over another crossing
    1252      455519 :             if (p.myWalkingAreaPath != nullptr) {
    1253             :                 // @todo actually another path would be needed starting at the current position
    1254      300841 :                 p.myNLI = getNextLane(p, p.myLane, p.myWalkingAreaPath->from);
    1255             :             }
    1256      455519 :         }
    1257    49720913 :         if DEBUGCOND(p) {
    1258           0 :             gDebugFlag1 = false;
    1259             :         }
    1260    49720913 :         if (&lane->getEdge() == p.myStage->getDestination() && p.myStage->getDestinationStop() != nullptr) {
    1261             :             Obstacles arrival;
    1262     1160663 :             if (p.myStage->getDestinationStop()->getWaitingCapacity() > p.myStage->getDestinationStop()->getNumWaitingPersons()) {
    1263     1012000 :                 arrival = Obstacles(stripes, Obstacle(p.myStage->getArrivalPos() + dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival", 0));
    1264             :             } else {
    1265      148663 :                 arrival = Obstacles(stripes, Obstacle(p.myStage->getArrivalPos() - dir * p.getMinGap(), 0, OBSTACLE_ARRIVALPOS, "arrival_blocked", 0));
    1266             :             }
    1267     1160663 :             p.mergeObstacles(currentObs, arrival);
    1268     1160663 :         }
    1269             : 
    1270    49720913 :         if (lane->getVehicleNumberWithPartials() > 0) {
    1271             :             // react to vehicles on the same lane
    1272             :             // @todo: improve efficiency by using the same iterator for all pedestrians on this lane
    1273      272764 :             Obstacles vehObs = getVehicleObstacles(lane, dir, &p);
    1274      272764 :             p.mergeObstacles(currentObs, vehObs);
    1275      272764 :             if DEBUGCOND(p) {
    1276           0 :                 std::cout << SIMTIME << " ped=" << p.myPerson->getID() << "  obsWithVehs=";
    1277           0 :                 DEBUG_PRINT(currentObs);
    1278             :             }
    1279      272764 :         }
    1280    49720913 :         if (hasCrossingVehObs) {
    1281        1489 :             p.mergeObstacles(currentObs, crossingVehs);
    1282        1489 :             if DEBUGCOND(p) {
    1283           0 :                 std::cout << SIMTIME << " ped=" << p.myPerson->getID() << "  obsWithVehs2=";
    1284           0 :                 DEBUG_PRINT(currentObs);
    1285             :             }
    1286             :         }
    1287             : 
    1288             :         // walk, taking into account all obstacles
    1289    49720913 :         p.walk(currentObs, currentTime);
    1290    49720913 :         gDebugFlag1 = false;
    1291    49720913 :         if (!p.myWaitingToEnter && !p.myAmJammed) {
    1292    24905101 :             Obstacle o(p);
    1293    24905101 :             if (o.closer(obs[p.stripe()], dir)) {
    1294    24903486 :                 obs[p.stripe()] = o;
    1295             :             }
    1296    24905101 :             if (o.closer(obs[p.otherStripe()], dir)) {
    1297    24903482 :                 obs[p.otherStripe()] = o;
    1298             :             }
    1299    24905101 :             if (MSGlobals::gCheck4Accidents && p.myWalkingAreaPath == nullptr && !p.myAmJammed) {
    1300   813781302 :                 for (int coll = 0; coll < ii; ++coll) {
    1301   790284400 :                     PState& c = *pedestrians[coll];
    1302   790284400 :                     if (!c.myWaitingToEnter && c.myWalkingAreaPath == nullptr && !c.myAmJammed) {
    1303   550469925 :                         if (c.stripe() == p.stripe() || p.stripe() == c.otherStripe() || p.otherStripe() == c.stripe() || p.otherStripe() == c.otherStripe()) {
    1304   266610815 :                             Obstacle cObs(c);
    1305             :                             // we check only for real collisions, no min gap violations
    1306   266610815 :                             if (p.distanceTo(cObs, false) == DIST_OVERLAP) {
    1307       52564 :                                 WRITE_WARNING("Collision of person '" + p.myPerson->getID() + "' and person '" + c.myPerson->getID()
    1308             :                                               + "', lane='" + lane->getID() + "', time=" + time2string(currentTime) + ".");
    1309             :                             }
    1310             :                         }
    1311             :                     }
    1312             :                 }
    1313             :             }
    1314             :         }
    1315             :         //std::cout << SIMTIME << p.myPerson->getID() << " lane=" << lane->getID() << " x=" << p.myRelX << "\n";
    1316    98974897 :     }
    1317     9693434 : }
    1318             : 
    1319             : bool
    1320      160340 : MSPModel_Striping::addCrossingVehs(const MSLane* crossing, int stripes, double lateral_offset, int dir, Obstacles& obs, bool prio) {
    1321             :     bool hasCrossingVehObs = false;
    1322      160340 :     const MSLink* crossingExitLink = crossing->getLinkCont().front();
    1323      160340 :     gDebugFlag1 = DEBUGCOND2(crossing);
    1324      160340 :     const MSLink::LinkLeaders linkLeaders = crossingExitLink->getLeaderInfo(nullptr, crossing->getLength());
    1325      160340 :     gDebugFlag1 = false;
    1326      160340 :     if (linkLeaders.size() > 0) {
    1327       21740 :         for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
    1328             :             // the vehicle to enter the junction first has priority
    1329       11119 :             const MSVehicle* veh = (*it).vehAndGap.first;
    1330       11119 :             if (veh != nullptr) {
    1331       11119 :                 Obstacle vo((*it).distToCrossing, 0, OBSTACLE_VEHICLE, veh->getID(), veh->getVehicleType().getWidth() + 2 * minGapToVehicle, veh);
    1332             :                 // block entry to the crossing in walking direction but allow leaving it
    1333       11119 :                 Obstacle voBlock = vo;
    1334       11119 :                 if (dir == FORWARD) {
    1335        5769 :                     voBlock.xBack = NUMERICAL_EPS;
    1336             :                 } else {
    1337        5350 :                     voBlock.xFwd = crossing->getLength() - NUMERICAL_EPS;
    1338             :                 }
    1339             :                 // when approaching a priority crossings, vehicles must be able
    1340             :                 // to brake, otherwise the person must be able to cross in time
    1341       11119 :                 const double distToCrossBeforeVeh = (dir == FORWARD ? vo.xFwd : crossing->getLength() - vo.xBack);
    1342             :                 const double bGap = (prio
    1343       12849 :                                      ? veh->getCarFollowModel().brakeGap(veh->getSpeed(), veh->getCarFollowModel().getMaxDecel(), 0)
    1344        1730 :                                      : veh->getSpeed() * distToCrossBeforeVeh); // walking 1m/s
    1345             :                 double vehYmin;
    1346             :                 double vehYmax;
    1347             :                 // relY increases from left to right (the other way around from vehicles)
    1348       11119 :                 if ((*it).fromLeft()) {
    1349        7128 :                     vehYmin = -(*it).vehAndGap.second + lateral_offset; // vehicle back
    1350        7128 :                     vehYmax = vehYmin + veh->getVehicleType().getLength() + bGap + minGapToVehicle;
    1351        7128 :                     vehYmin -= minGapToVehicle;
    1352             :                 } else {
    1353        3991 :                     vehYmax = crossing->getWidth() + (*it).vehAndGap.second - lateral_offset; // vehicle back
    1354        3991 :                     vehYmin = vehYmax - veh->getVehicleType().getLength() - bGap - minGapToVehicle;
    1355        3991 :                     vehYmax += minGapToVehicle;
    1356             : 
    1357             :                 }
    1358       41050 :                 for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax), stripes); ++s) {
    1359       14097 :                     if ((dir == FORWARD && obs[s].xBack > vo.xBack)
    1360       30203 :                             || (dir == BACKWARD && obs[s].xFwd < vo.xFwd)) {
    1361       29192 :                         if (!prio && veh->getSpeed() > SUMO_const_haltingSpeed) {
    1362             :                             // do not enter the crossing
    1363        9738 :                             obs[s] = voBlock;
    1364             :                         } else {
    1365       19454 :                             obs[s] = vo;
    1366             :                         }
    1367             :                         hasCrossingVehObs = true;
    1368             :                     }
    1369             :                 }
    1370       11119 :                 if (DEBUGCOND2(crossing)) {
    1371           0 :                     std::cout << SIMTIME
    1372             :                               << " crossingVeh=" << veh->getID()
    1373             :                               << " lane=" << crossing->getID()
    1374           0 :                               << " prio=" << prio
    1375             :                               << " latOffset=" << lateral_offset
    1376             :                               << " dir=" << dir
    1377           0 :                               << " stripes=" << stripes
    1378           0 :                               << " dist=" << (*it).distToCrossing
    1379           0 :                               << " gap=" << (*it).vehAndGap.second
    1380             :                               << " brakeGap=" << bGap
    1381           0 :                               << " fromLeft=" << (*it).fromLeft()
    1382             :                               << " distToCrossBefore=" << distToCrossBeforeVeh
    1383             :                               << " ymin=" << vehYmin
    1384             :                               << " ymax=" << vehYmax
    1385             :                               << " smin=" << PState::stripe(vehYmin)
    1386           0 :                               << " smax=" << PState::stripe(vehYmax)
    1387           0 :                               << "\n";
    1388           0 :                     DEBUG_PRINT(obs);
    1389             :                 }
    1390             :             }
    1391             :         }
    1392       10621 :         if (hasCrossingVehObs) {
    1393             :             // check whether the crossing is fully blocked
    1394        6046 :             const int reserved = getReserved((int)obs.size(), RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS);
    1395             :             bool allBlocked = true;
    1396             : 
    1397       32993 :             for (int i = 0; i < (int)obs.size(); i++) {
    1398       29680 :                 const Obstacle& o = obs[i];
    1399       29680 :                 if (o.type != OBSTACLE_VEHICLE && (
    1400        4206 :                             (dir == FORWARD && i >= reserved) ||
    1401        3001 :                             (dir == BACKWARD && i < (int)obs.size() - reserved))) {
    1402             :                     allBlocked = false;
    1403             :                     break;
    1404             :                 }
    1405             :             }
    1406        6046 :             if (allBlocked) {
    1407        3313 :                 if (DEBUGCOND2(crossing)) {
    1408           0 :                     std::cout << SIMTIME << " crossing=" << crossing->getID() << " allBlocked\n";
    1409             :                 }
    1410       24818 :                 for (Obstacle& o : obs) {
    1411       21505 :                     if (dir == FORWARD) {
    1412        9911 :                         o.xBack = NUMERICAL_EPS;
    1413             :                     } else {
    1414       11594 :                         o.xFwd = crossing->getLength() - NUMERICAL_EPS;
    1415             :                     }
    1416             :                 }
    1417             :             }
    1418             :         }
    1419             :     }
    1420      160340 :     return hasCrossingVehObs;
    1421             : }
    1422             : 
    1423             : 
    1424             : MSPModel_Striping::Obstacles
    1425      291957 : MSPModel_Striping::getVehicleObstacles(const MSLane* lane, int dir, PState* ped) {
    1426      291957 :     const int stripes = numStripes(lane);
    1427      583914 :     Obstacles vehObs(stripes, Obstacle(dir));
    1428             :     int current = -1;
    1429             :     double minX = 0.;
    1430             :     double maxX = 0.;
    1431             :     double pRelY = -1.;
    1432             :     double pWidth = 0.;
    1433             :     std::string pID;
    1434      291957 :     bool debug = DEBUGCOND2(lane);
    1435      291957 :     if (ped != nullptr) {
    1436      272764 :         current = ped->stripe();
    1437      272764 :         minX = ped->getMinX();
    1438      272764 :         maxX = ped->getMaxX();
    1439      272764 :         pRelY = ped->myRelY;
    1440      272764 :         pWidth = ped->myPerson->getVehicleType().getWidth();
    1441      272764 :         pID = ped->myPerson->getID();
    1442      272764 :         debug = DEBUGCOND(*ped);
    1443       19193 :     } else if (dir == BACKWARD) {
    1444             :         // checking vehicles on the next lane. Use entry point as reference
    1445             :         minX = lane->getLength();
    1446             :         maxX = lane->getLength();
    1447             :     }
    1448      291957 :     MSLane::AnyVehicleIterator begin = (dir == FORWARD ? lane->anyVehiclesUpstreamBegin() : lane->anyVehiclesBegin());
    1449             :     MSLane::AnyVehicleIterator end = (dir == FORWARD ? lane->anyVehiclesUpstreamEnd() : lane->anyVehiclesEnd());
    1450      760260 :     for (MSLane::AnyVehicleIterator it = begin; it != end; ++it) {
    1451      468303 :         const MSVehicle* veh = *it;
    1452      468303 :         const bool bidi = veh->getLane() == lane->getBidiLane();
    1453      468303 :         const double vehBack = veh->getBackPositionOnLane(lane);
    1454      468303 :         double vehFront = vehBack + veh->getVehicleType().getLength();
    1455             :         // ensure that vehicles are not blocked
    1456      468303 :         const double vehNextSpeed = MAX2(veh->getSpeed(), 1.0);
    1457      468303 :         const double clearance = SAFETY_GAP + vehNextSpeed * LOOKAHEAD_SAMEDIR;
    1458             :         // boundaries for range checking
    1459             :         double vehXMax;
    1460             :         double vehXMin;
    1461             :         double vehXMaxCheck;
    1462             :         double vehXMinCheck;
    1463      468303 :         if (bidi) {
    1464        1571 :             vehFront = vehBack - veh->getVehicleType().getLength();
    1465        1571 :             vehXMax = vehBack + SAFETY_GAP;
    1466        1571 :             vehXMin = vehFront - clearance;
    1467        1571 :             if (dir == FORWARD) {
    1468        1571 :                 vehXMaxCheck = vehBack + NUMERICAL_EPS;
    1469        1571 :                 vehXMinCheck = vehFront - LOOKAROUND_VEHICLES;
    1470             :             } else  {
    1471           0 :                 vehXMaxCheck = vehBack + LOOKAHEAD_SAMEDIR;
    1472             :                 vehXMinCheck = vehFront - clearance;
    1473             :             }
    1474             :         } else {
    1475      466732 :             vehXMax = vehFront + clearance;
    1476      466732 :             vehXMin = vehBack - SAFETY_GAP;
    1477      466732 :             if (dir == FORWARD) {
    1478             :                 vehXMaxCheck = vehFront + clearance;
    1479      343975 :                 vehXMinCheck = vehBack - LOOKAHEAD_SAMEDIR;
    1480             :             } else  {
    1481      122757 :                 vehXMaxCheck = vehFront + LOOKAROUND_VEHICLES;
    1482      122757 :                 vehXMinCheck = vehBack - NUMERICAL_EPS;
    1483             :             }
    1484             :         }
    1485      468303 :         if (debug) {
    1486           0 :             std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " check obstacle on lane=" << lane->getID()
    1487             :                       << "\n"
    1488             :                       << " vehXMin=" << vehXMin
    1489             :                       << " vehXMax=" << vehXMax
    1490             :                       << " vehXMinC=" << vehXMinCheck
    1491             :                       << " vehXMaxC=" << vehXMaxCheck
    1492             :                       << " minX=" << minX
    1493             :                       << " maxX=" << maxX
    1494           0 :                       << " bidi=" << bidi
    1495             :                       << " vFront=" << vehFront
    1496             :                       << " vBack=" << vehBack
    1497           0 :                       << "\n";
    1498             :         }
    1499      468303 :         if (vehXMaxCheck > minX && vehXMinCheck && vehXMinCheck <= maxX) {
    1500      358077 :             Obstacle vo(vehBack, veh->getSpeed() * (bidi ? -1 : 1), OBSTACLE_VEHICLE, veh->getID(), 0, veh);
    1501             :             // moving vehicles block space along their path
    1502      179372 :             vo.xFwd = vehXMax;
    1503      179372 :             vo.xBack = vehXMin;
    1504             :             // relY increases from left to right (the other way around from vehicles)
    1505             :             // XXX lateral offset for partial vehicles
    1506      179372 :             const double posLat = veh->getLateralPositionOnLane() * (bidi ? -1 : 1);
    1507      179372 :             const double vehYmax = 0.5 * (lane->getWidth() + veh->getVehicleType().getWidth() - stripeWidth) - posLat;
    1508      179372 :             const double vehYmin = vehYmax - veh->getVehicleType().getWidth();
    1509      765956 :             for (int s = MAX2(0, PState::stripe(vehYmin)); s < MIN2(PState::stripe(vehYmax) + 1, stripes); ++s) {
    1510      586584 :                 Obstacle prior = vehObs[s];
    1511             :                 vehObs[s] = vo;
    1512      586584 :                 if (s == current && vehFront + SAFETY_GAP < minX) {
    1513             :                     // ignore if aleady overlapping while vehicle is still behind
    1514       18009 :                     if (pRelY - pWidth < vehYmax &&
    1515       17888 :                             pRelY + pWidth > vehYmin && dir == FORWARD) {
    1516       11770 :                         if (debug) {
    1517           0 :                             std::cout << "   ignoring vehicle '" << veh->getID() << " on stripe " << s << " vehFrontSG=" << vehFront + SAFETY_GAP << " minX=" << minX << "\n";
    1518             :                         }
    1519             :                         if (dir == FORWARD) {
    1520             :                             vehObs[s] = prior;
    1521             :                         } else {
    1522             :                             vehObs[s].xFwd = MIN2(vo.xFwd, vehFront + SAFETY_GAP);
    1523             :                         }
    1524             :                     }
    1525             :                 }
    1526             :             }
    1527      179372 :             if (debug) {
    1528           0 :                 std::cout << SIMTIME << " ped=" << pID << " veh=" << veh->getID() << " obstacle on lane=" << lane->getID()
    1529             :                           << "\n"
    1530             :                           << "     ymin=" << vehYmin
    1531             :                           << " ymax=" << vehYmax
    1532             :                           << " smin=" << PState::stripe(vehYmin)
    1533           0 :                           << " smax=" << PState::stripe(vehYmax)
    1534           0 :                           << " relY=" << pRelY
    1535             :                           << " current=" << current
    1536           0 :                           << " vo.xFwd=" << vo.xFwd
    1537           0 :                           << " vo.xBack=" << vo.xBack
    1538             :                           << " vFront=" << vehFront
    1539             :                           << " vBack=" << vehBack
    1540           0 :                           << "\n";
    1541             :             }
    1542             :         }
    1543             :     }
    1544      291957 :     return vehObs;
    1545           0 : }
    1546             : 
    1547             : 
    1548             : // ===========================================================================
    1549             : // MSPModel_Striping::Obstacle method definitions
    1550             : // ===========================================================================
    1551    59706304 : MSPModel_Striping::Obstacle::Obstacle(int dir, double dist) :
    1552    59706304 :     xFwd(dir * dist),  // by default, far away when seen in dir
    1553    59706304 :     xBack(dir * dist),  // by default, far away when seen in dir
    1554    59706304 :     speed(0),
    1555    59706304 :     type(OBSTACLE_NONE),
    1556    59706304 :     description("") {
    1557    59706304 : }
    1558             : 
    1559             : 
    1560   385441580 : MSPModel_Striping::Obstacle::Obstacle(const PState& ped) :
    1561   385441580 :     xFwd(ped.getMaxX()),
    1562   385441580 :     xBack(ped.getMinX()),
    1563   385441580 :     speed(ped.myDir * ped.mySpeed),
    1564   385441580 :     type(ped.getOType()),
    1565   385441580 :     description(ped.getID()) {
    1566             :     assert(!ped.myWaitingToEnter);
    1567   385441580 :     if (type == OBSTACLE_VEHICLE) {
    1568      585143 :         vehicle = static_cast<const PStateVehicle&>(ped).getVehicle();
    1569             :     }
    1570   385441580 : }
    1571             : 
    1572             : 
    1573             : bool
    1574    98441518 : MSPModel_Striping::Obstacle::closer(const Obstacle& o, int dir) {
    1575    98441518 :     if (dir == FORWARD) {
    1576    51249788 :         return xBack <= o.xBack;
    1577             :     } else {
    1578    47191730 :         return xFwd >= o.xFwd;
    1579             :     }
    1580             : }
    1581             : 
    1582             : 
    1583             : // ===========================================================================
    1584             : // MSPModel_Striping::PState method definitions
    1585             : // ===========================================================================
    1586      269551 : MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, const MSLane* lane):
    1587      269551 :     myPerson(person),
    1588      269551 :     myStage(stage),
    1589      269551 :     myLane(lane),
    1590      269551 :     myRelX(stage->getDepartPos()),
    1591      269551 :     myRelY(stage->getDepartPosLat()),
    1592      269551 :     myDir(FORWARD),
    1593      269551 :     mySpeed(0),
    1594      269551 :     mySpeedLat(0),
    1595      269551 :     myWaitingToEnter(true),
    1596      269551 :     myWaitingTime(0),
    1597      269551 :     myWalkingAreaPath(nullptr),
    1598      269551 :     myAmJammed(false),
    1599      269551 :     myRemoteXYPos(Position::INVALID),
    1600      269551 :     myAngle(std::numeric_limits<double>::max()) {
    1601             :     const MSEdge* currentEdge = &lane->getEdge();
    1602             :     const ConstMSEdgeVector& route = myStage->getRoute();
    1603             :     assert(!route.empty());
    1604      269551 :     if (route.size() == 1) {
    1605             :         // only a single edge, move towards end pos
    1606       11649 :         myDir = (myRelX <= myStage->getArrivalPos()) ? FORWARD : BACKWARD;
    1607      257902 :     } else if (route.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
    1608             :         // start on an intersection
    1609             :         myDir = FORWARD;
    1610          10 :         if (route.front()->isWalkingArea()) {
    1611          10 :             myWalkingAreaPath = getArbitraryPath(route.front());
    1612             :         }
    1613             :     } else {
    1614      257892 :         int passedFwd = 0;
    1615      257892 :         int passedBwd = 0;
    1616      257892 :         const bool mayStartForward = canTraverse(FORWARD, route, passedFwd) != UNDEFINED_DIRECTION;
    1617      257892 :         const bool mayStartBackward = canTraverse(BACKWARD, route, passedBwd) != UNDEFINED_DIRECTION;
    1618      257892 :         if DEBUGCOND(*this) {
    1619           0 :             std::cout << "  initialize dir for " << myPerson->getID() << " forward=" << mayStartForward << " backward=" << mayStartBackward << "\n";
    1620             :         }
    1621      257892 :         if (mayStartForward && mayStartBackward) {
    1622             :             // figure out the best direction via routing
    1623             :             ConstMSEdgeVector crossingRoute;
    1624        6110 :             MSNet::getInstance()->getPedestrianRouter(0).compute(currentEdge, route.back(), myRelX, myStage->getArrivalPos(), myStage->getMaxSpeed(person), 0, nullptr, crossingRoute, true);
    1625        3055 :             if (crossingRoute.size() > 1) {
    1626             :                 // route found
    1627        3047 :                 const MSEdge* nextEdge = crossingRoute[1];
    1628        3047 :                 if (nextEdge->getFromJunction() == currentEdge->getFromJunction() || nextEdge->getToJunction() == currentEdge->getFromJunction()) {
    1629        2307 :                     myDir = BACKWARD;
    1630             :                 }
    1631             :             }
    1632        3055 :             if DEBUGCOND(*this) {
    1633           0 :                 std::cout << " crossingRoute=" << toString(crossingRoute) << "\n";
    1634             :             }
    1635      254837 :         } else if (!mayStartForward && !mayStartBackward) {
    1636         103 :             int lastDisconnect = passedFwd >= passedBwd ? passedFwd : passedBwd;
    1637         206 :             std::string dLoc = TLF(", time=%.", SIMTIME);
    1638         103 :             if (route.size() > 2) {
    1639         225 :                 dLoc = TLF("between edge '%' and edge '%', time=%.", route[lastDisconnect - 1]->getID(), route[lastDisconnect]->getID(), SIMTIME);
    1640             :             }
    1641         618 :             WRITE_WARNINGF(TL("Person '%' walking from edge '%' to edge '%' has a disconnect%"),
    1642             :                            myPerson->getID(), route.front()->getID(), route.back()->getID(), dLoc);
    1643         108 :             myDir =  passedFwd >= passedBwd ? FORWARD : BACKWARD;
    1644             :         } else {
    1645      421072 :             myDir = !mayStartBackward ? FORWARD : BACKWARD;
    1646             :         }
    1647             :     }
    1648      269551 :     if (myRelY == UNSPECIFIED_POS_LAT || myLegacyPosLat) {
    1649      268771 :         if (myRelY == UNSPECIFIED_POS_LAT) {
    1650      268601 :             myRelY = 0;
    1651             :         }
    1652      268771 :         if (lane->getVehicleNumberWithPartials() > 0 && myRelY == 0) {
    1653             :             // better start next to the road if nothing was specified
    1654        1949 :             myRelY -= stripeWidth;
    1655             :         }
    1656      268771 :         if (myDir == FORWARD || lane->getPermissions() != SVC_PEDESTRIAN) {
    1657             :             // start at the right side of the sidewalk on shared roads
    1658      252298 :             myRelY = stripeWidth * (numStripes(lane) - 1) - myRelY;
    1659             :         }
    1660         780 :     } else if (myRelY == RANDOM_POS_LAT) {
    1661          20 :         myRelY = RandHelper::rand() * stripeWidth * (numStripes(lane) - 1);
    1662             :     } else {
    1663             :         // convert vehicle-style posLat (0 is center, left is larger)
    1664             :         // into striping coordinates (0 is on the leftmost stripe, right is larger)
    1665         760 :         myRelY = lane->getWidth() / 2 - myRelY - stripeWidth / 2;
    1666             :     }
    1667      269551 :     if DEBUGCOND(*this) {
    1668           0 :         std::cout << "  added new pedestrian " << myPerson->getID() << " on " << lane->getID() << " myRelX=" << myRelX << " myRelY=" << myRelY << " dir=" << myDir << " route=" << toString(myStage->getRoute()) << "\n";
    1669             :     }
    1670             : 
    1671      269551 :     myNLI = getNextLane(*this, lane, nullptr);
    1672      269547 : }
    1673             : 
    1674             : 
    1675      550197 : MSPModel_Striping::PState::PState():
    1676      550197 :     myPerson(nullptr),
    1677      550197 :     myStage(nullptr),
    1678      550197 :     myLane(nullptr),
    1679      550197 :     myRelX(0),
    1680      550197 :     myRelY(0),
    1681      550197 :     myDir(UNDEFINED_DIRECTION),
    1682      550197 :     mySpeed(0),
    1683      550197 :     mySpeedLat(0),
    1684      550197 :     myWaitingToEnter(false),
    1685      550197 :     myWaitingTime(0),
    1686      550197 :     myWalkingAreaPath(nullptr),
    1687      550197 :     myAmJammed(false),
    1688      550197 :     myRemoteXYPos(Position::INVALID),
    1689      550197 :     myAngle(std::numeric_limits<double>::max()) {
    1690      550197 : }
    1691             : 
    1692             : 
    1693          20 : MSPModel_Striping::PState::PState(MSPerson* person, MSStageMoving* stage, std::istringstream* in):
    1694          20 :     myPerson(person),
    1695          20 :     myStage(stage),
    1696          20 :     myLane(nullptr),
    1697          20 :     myWalkingAreaPath(nullptr),
    1698          20 :     myRemoteXYPos(Position::INVALID),
    1699          20 :     myAngle(std::numeric_limits<double>::max()) {
    1700          20 :     if (in != nullptr) {
    1701             :         std::string laneID;
    1702             :         std::string wapLaneFrom;
    1703             :         std::string wapLaneTo;
    1704             :         std::string nextLaneID;
    1705             :         std::string nextLinkFrom;
    1706             :         std::string nextLinkTo;
    1707             :         int nextDir;
    1708             : 
    1709          20 :         (*in) >> laneID
    1710          20 :               >> myRelX >> myRelY >> myDir >> mySpeed >> mySpeedLat >> myWaitingToEnter >> myWaitingTime
    1711          20 :               >> wapLaneFrom >> wapLaneTo
    1712          20 :               >> myAmJammed
    1713             :               >> nextLaneID
    1714             :               >> nextLinkFrom
    1715          20 :               >> nextLinkTo
    1716          20 :               >> nextDir;
    1717             : 
    1718             : 
    1719          20 :         myLane = MSLane::dictionary(laneID);
    1720          20 :         if (myLane == nullptr) {
    1721           0 :             throw ProcessError("Unknown lane '" + laneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1722             :         }
    1723             : 
    1724             :         MSLane* nextLane = nullptr;
    1725          20 :         if (nextLaneID != "null") {
    1726          18 :             nextLane = MSLane::dictionary(nextLaneID);
    1727          18 :             if (nextLane == nullptr) {
    1728           0 :                 throw ProcessError("Unknown next lane '" + nextLaneID + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1729             :             }
    1730             :         }
    1731             :         const MSLink* link = nullptr;
    1732          20 :         if (nextLinkFrom != "null") {
    1733           4 :             MSLane* from = MSLane::dictionary(nextLinkFrom);
    1734           4 :             MSLane* to = MSLane::dictionary(nextLinkTo);
    1735           4 :             if (from == nullptr) {
    1736           0 :                 throw ProcessError("Unknown link origin lane '" + nextLinkFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1737             :             }
    1738           4 :             if (to == nullptr) {
    1739           0 :                 throw ProcessError("Unknown link destination lane '" + nextLinkTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1740             :             }
    1741           4 :             link = from->getLinkTo(to);
    1742             :         }
    1743          20 :         myNLI =  NextLaneInfo(nextLane, link, nextDir);
    1744             : 
    1745          20 :         if (wapLaneFrom != "null") {
    1746           2 :             MSLane* from = MSLane::dictionary(wapLaneFrom);
    1747           2 :             MSLane* to = MSLane::dictionary(wapLaneTo);
    1748           2 :             if (from == nullptr) {
    1749           0 :                 throw ProcessError("Unknown walkingAreaPath origin lane '" + wapLaneFrom + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1750             :             }
    1751           2 :             if (to == nullptr) {
    1752           0 :                 throw ProcessError("Unknown walkingAreaPath destination lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1753             :             }
    1754           2 :             const auto pathIt = myWalkingAreaPaths.find(std::make_pair(from, to));
    1755           2 :             if (pathIt != myWalkingAreaPaths.end()) {
    1756           2 :                 myWalkingAreaPath = &pathIt->second;
    1757             :             } else {
    1758           0 :                 throw ProcessError("Unknown walkingAreaPath from lane '" + wapLaneFrom + "' to lane '" + wapLaneTo + "' when loading walk for person '" + myPerson->getID() + "' from state.");
    1759             :             }
    1760             :         }
    1761             :     }
    1762          20 : }
    1763             : 
    1764             : void
    1765          14 : MSPModel_Striping::PState::saveState(std::ostringstream& out) {
    1766          14 :     std::string wapLaneFrom = "null";
    1767          14 :     std::string wapLaneTo = "null";
    1768          14 :     if (myWalkingAreaPath != nullptr) {
    1769           2 :         wapLaneFrom = myWalkingAreaPath->from->getID();
    1770           2 :         wapLaneTo = myWalkingAreaPath->to->getID();
    1771             :     }
    1772          14 :     std::string nextLaneID = "null";
    1773          14 :     std::string nextLinkFrom = "null";
    1774          14 :     std::string nextLinkTo = "null";
    1775          14 :     if (myNLI.lane != nullptr) {
    1776             :         nextLaneID = myNLI.lane->getID();
    1777             :     }
    1778          14 :     if (myNLI.link != nullptr) {
    1779             :         nextLinkFrom = myNLI.link->getLaneBefore()->getID();
    1780           4 :         nextLinkTo = myNLI.link->getViaLaneOrLane()->getID();
    1781             :     }
    1782          14 :     out << " " << myLane->getID()
    1783          28 :         << " " << myRelX
    1784          14 :         << " " << myRelY
    1785             :         << " " << myDir
    1786          28 :         << " " << mySpeed
    1787          14 :         << " " << mySpeedLat
    1788          14 :         << " " << myWaitingToEnter
    1789          14 :         << " " << myWaitingTime
    1790             :         << " " << wapLaneFrom
    1791             :         << " " << wapLaneTo
    1792          14 :         << " " << myAmJammed
    1793             :         << " " << nextLaneID
    1794             :         << " " << nextLinkFrom
    1795             :         << " " << nextLinkTo
    1796          14 :         << " " << myNLI.dir;
    1797          14 : }
    1798             : 
    1799             : double
    1800  1472016297 : MSPModel_Striping::PState::getMinX(const bool includeMinGap) const {
    1801             :     // @todo speed should have an influence here because faster persons need more space
    1802  1472016297 :     if (myDir == FORWARD) {
    1803   986353271 :         return myRelX - getLength();
    1804             :     }
    1805   485663026 :     return myRelX - (includeMinGap ? getMinGap() : 0.);
    1806             : }
    1807             : 
    1808             : 
    1809             : double
    1810  1472016297 : MSPModel_Striping::PState::getMaxX(const bool includeMinGap) const {
    1811             :     // @todo speed should have an influence here because faster persons need more space
    1812  1472016297 :     if (myDir == FORWARD) {
    1813   986353271 :         return myRelX + (includeMinGap ? getMinGap() : 0.);
    1814             :     }
    1815   485663026 :     return myRelX + getLength();
    1816             : }
    1817             : 
    1818             : 
    1819             : double
    1820  1521770357 : MSPModel_Striping::PState::getLength() const {
    1821  1521770357 :     return myPerson->getVehicleType().getLength();
    1822             : }
    1823             : 
    1824             : 
    1825             : double
    1826   923936095 : MSPModel_Striping::PState::getMinGap() const {
    1827   923936095 :     return myPerson->getVehicleType().getMinGap();
    1828             : }
    1829             : 
    1830             : 
    1831             : int
    1832  3309934933 : MSPModel_Striping::PState::stripe(double relY) {
    1833  3309934933 :     return (int)floor(relY / stripeWidth + 0.5);
    1834             : }
    1835             : 
    1836             : 
    1837             : int
    1838  1354946753 : MSPModel_Striping::PState::otherStripe(double relY) const {
    1839  1354946753 :     const int s = stripe(relY);
    1840  1354946753 :     const double offset = relY - s * stripeWidth;
    1841  1354946753 :     const double threshold = MAX2(NUMERICAL_EPS, stripeWidth - SQUEEZE * getWidth());
    1842             :     int result;
    1843  1354946753 :     if (offset > threshold) {
    1844      447188 :         result = s + 1;
    1845  1354499565 :     } else if (offset < -threshold) {
    1846      311964 :         result = s - 1;
    1847             :     } else {
    1848             :         result = s;
    1849             :     }
    1850             :     //std::cout.setf(std::ios::fixed , std::ios::floatfield);
    1851             :     //std::cout << std::setprecision(5);
    1852             :     //if DEBUGCOND(*this) std::cout << "  otherStripe " << myPerson->getID() << " offset=" << offset << " threshold=" << threshold << " rawResult=" << result << "\n";
    1853  1354946753 :     return result;
    1854             : }
    1855             : 
    1856             : int
    1857  1932239896 : MSPModel_Striping::PState::stripe() const {
    1858  1932239896 :     return MIN2(MAX2(0, stripe(myRelY)), numStripes(myLane) - 1);
    1859             : }
    1860             : 
    1861             : 
    1862             : int
    1863  1342143505 : MSPModel_Striping::PState::otherStripe() const {
    1864  1342143505 :     return MIN2(MAX2(0, otherStripe(myRelY)), numStripes(myLane) - 1);
    1865             : }
    1866             : 
    1867             : 
    1868             : double
    1869   101596609 : MSPModel_Striping::PState::distToLaneEnd() const {
    1870   101596609 :     if (myStage->getNextRouteEdge() == nullptr) {
    1871    16861592 :         return myDir * (myStage->getArrivalPos() - myRelX) - POSITION_EPS - (
    1872      573562 :                    (myWaitingTime > DELTA_T && (myStage->getDestinationStop() == nullptr ||
    1873             :                                                 myStage->getDestinationStop()->getWaitingCapacity() > myStage->getDestinationStop()->getNumWaitingPersons()))
    1874    17435154 :                    ? getMinGap() : 0);
    1875             :     } else {
    1876    84735017 :         const double length = myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length;
    1877    84735017 :         return myDir == FORWARD ? length - myRelX : myRelX;
    1878             :     }
    1879             : }
    1880             : 
    1881             : 
    1882             : bool
    1883      948585 : MSPModel_Striping::PState::moveToNextLane(SUMOTime currentTime) {
    1884      948585 :     double dist = distToLaneEnd();
    1885      948585 :     if (DEBUGCOND(*this)) {
    1886           0 :         std::cout << SIMTIME << " ped=" << myPerson->getID() << " myRelX=" << myRelX << " dist=" << dist << "\n";
    1887             :     }
    1888      948585 :     if (dist <= 0) {
    1889             :         //if (ped.myPerson->getID() == DEBUG1) {
    1890             :         //    std::cout << SIMTIME << " addToLane x=" << ped.myRelX << " newDir=" << newDir << " newLane=" << newLane->getID() << " walkingAreaShape=" << walkingAreaShape << "\n";
    1891             :         //}
    1892             :         //std::cout << " changing to " << newLane->getID() << " myRelY=" << ped.myRelY << " oldStripes=" << numStripes(myLane) << " newStripes=" << numStripes(newLane);
    1893             :         //std::cout << " newY=" << ped.myRelY << " myDir=" << ped.myDir << " newDir=" << newDir;
    1894      948585 :         const int oldDir = myDir;
    1895      948585 :         const MSLane* oldLane = myLane;
    1896      948585 :         myLane = myNLI.lane;
    1897      948585 :         myDir = myNLI.dir;
    1898      948585 :         const bool normalLane = (myLane == nullptr || myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL || &myLane->getEdge() == myStage->getNextRouteEdge());
    1899      948585 :         if DEBUGCOND(*this) {
    1900           0 :             std::cout << SIMTIME
    1901           0 :                       << " ped=" << myPerson->getID()
    1902             :                       << " moveToNextLane old=" << oldLane->getID()
    1903           0 :                       << " new=" << (myLane == nullptr ? "NULL" : myLane->getID())
    1904             :                       << " oldDir=" << oldDir
    1905           0 :                       << " newDir=" << myDir
    1906           0 :                       << " myRelX=" << myRelX
    1907             :                       << " dist=" << dist
    1908           0 :                       << "\n";
    1909             :         }
    1910      948585 :         if (myLane == nullptr) {
    1911      266675 :             myRelX = myStage->getArrivalPos();
    1912             :         }
    1913             :         // moveToNextEdge might destroy the person and thus mess up the heap. Better check first
    1914      948585 :         if (myStage->getRouteStep() == myStage->getRoute().end() - 1) {
    1915      266675 :             myLane = nullptr;
    1916             :         } else {
    1917      681910 :             const bool arrived = myStage->moveToNextEdge(myPerson, currentTime, oldDir, normalLane ? nullptr : &myLane->getEdge());
    1918             :             UNUSED_PARAMETER(arrived);
    1919             :             assert(!arrived);
    1920             :             assert(myDir != UNDEFINED_DIRECTION);
    1921      681910 :             myNLI = getNextLane(*this, myLane, oldLane);
    1922             :             // reminders must be called after updated myNLI (to ensure that getNextEdgePtr returns the correct edge)
    1923      681910 :             myStage->activateEntryReminders(myPerson);
    1924             :             assert(myNLI.lane != oldLane); // do not turn around
    1925      681910 :             if DEBUGCOND(*this) {
    1926           0 :                 std::cout << "    nextLane=" << (myNLI.lane == nullptr ? "NULL" : myNLI.lane->getID()) << "\n";
    1927             :             }
    1928      681910 :             if (myLane->getEdge().isWalkingArea()) {
    1929      103738 :                 if (myNLI.dir != UNDEFINED_DIRECTION) {
    1930      103701 :                     myWalkingAreaPath = getWalkingAreaPath(&myLane->getEdge(), oldLane, myNLI.lane);
    1931             :                     assert(myWalkingAreaPath->shape.size() >= 2);
    1932      103701 :                     if DEBUGCOND(*this) {
    1933           0 :                         std::cout << "  mWAPath shape=" << myWalkingAreaPath->shape << " length=" << myWalkingAreaPath->length << "\n";
    1934             :                     }
    1935          37 :                 } else if (myNLI.link != nullptr) {
    1936             :                     // using direct connection (instead of using walkingarea)
    1937          17 :                     myLane = myNLI.lane;
    1938             :                     assert(!myLane->getEdge().isWalkingArea());
    1939          17 :                     myStage->moveToNextEdge(myPerson, currentTime, myDir, &myLane->getEdge());
    1940          17 :                     myWalkingAreaPath = nullptr;
    1941          17 :                     myNLI = getNextLane(*this, myLane, oldLane);
    1942             :                 } else {
    1943             :                     // disconnnected route. move to the next edge
    1944          40 :                     if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
    1945             :                         // try to determine direction from topology, otherwise maintain current direction
    1946          16 :                         const MSEdge* currRouteEdge = *myStage->getRouteStep();
    1947          16 :                         const MSEdge* nextRouteEdge = myStage->getNextRouteEdge();
    1948             :                         if ((nextRouteEdge->getToJunction() == currRouteEdge->getFromJunction())
    1949          16 :                                 || nextRouteEdge->getToJunction() == currRouteEdge->getToJunction()) {
    1950           4 :                             myDir = BACKWARD;
    1951             :                         } else if ((nextRouteEdge->getFromJunction() == currRouteEdge->getFromJunction())
    1952          12 :                                    || nextRouteEdge->getFromJunction() == currRouteEdge->getToJunction()) {
    1953          12 :                             myDir = FORWARD;
    1954             :                         }
    1955          16 :                         myStage->moveToNextEdge(myPerson, currentTime, oldDir, nullptr);
    1956          16 :                         myLane = myNLI.lane;
    1957             :                         assert(myLane != 0);
    1958             :                         assert(myLane->getEdge().getFunction() == SumoXMLEdgeFunc::NORMAL);
    1959          16 :                         myNLI = getNextLane(*this, myLane, oldLane);
    1960          16 :                         myWalkingAreaPath = nullptr;
    1961             :                     } else {
    1962          16 :                         throw ProcessError(TLF("Disconnected walk for person '%'.", myPerson->getID()));
    1963             :                     }
    1964             :                 }
    1965             :             } else {
    1966      578172 :                 myWalkingAreaPath = nullptr;
    1967             :             }
    1968             :             // adapt x to fit onto the new lane
    1969             :             // (make sure we do not move past the end of the new lane since that
    1970             :             // lane was not checked for obstacles)
    1971      681906 :             const double newLength = (myWalkingAreaPath == nullptr ? myLane->getLength() : myWalkingAreaPath->length);
    1972      681906 :             if (-dist > newLength) {
    1973             :                 assert(OptionsCont::getOptions().getBool("ignore-route-errors"));
    1974             :                 // should not happen because the end of myLane should have been an obstacle as well
    1975             :                 // (only when the route is broken)
    1976           0 :                 dist = -newLength;
    1977             :             }
    1978      681906 :             if (myDir == BACKWARD) {
    1979      246068 :                 myRelX = newLength + dist;
    1980             :             } else {
    1981      435838 :                 myRelX = -dist;
    1982             :             }
    1983      681906 :             if DEBUGCOND(*this) {
    1984           0 :                 std::cout << SIMTIME << " update myRelX ped=" << myPerson->getID()
    1985             :                           << " newLength=" << newLength
    1986             :                           << " dist=" << dist
    1987           0 :                           << " myRelX=" << myRelX
    1988           0 :                           << "\n";
    1989             :             }
    1990             :             // adjust to change in direction
    1991      681906 :             if (myDir != oldDir) {
    1992      102792 :                 myRelY = (numStripes(oldLane) - 1) * stripeWidth - myRelY;
    1993             :             }
    1994             :             // adjust to differences in sidewalk width
    1995      779921 :             const int offset = getStripeOffset(numStripes(oldLane), numStripes(myLane), oldDir != myDir && numStripes(myLane) < numStripes(oldLane));
    1996      681906 :             myRelY += offset * stripeWidth;
    1997      681906 :             if DEBUGCOND(*this) {
    1998           0 :                 std::cout << SIMTIME << " transformY ped=" << myPerson->getID()
    1999           0 :                           << " newLane=" << Named::getIDSecure(myLane)
    2000           0 :                           << " newY=" << myRelY
    2001           0 :                           << " os=" << numStripes(oldLane) << " ns=" << numStripes(myLane)
    2002           0 :                           << " od=" << oldDir << " nd=" << myDir
    2003           0 :                           << " offset=" << offset << "\n";
    2004             :             }
    2005             :         }
    2006      948581 :         myAngle = std::numeric_limits<double>::max(); // see #9014
    2007      948581 :         return true;
    2008             :     } else {
    2009             :         return false;
    2010             :     }
    2011             : }
    2012             : 
    2013             : 
    2014             : int
    2015    49726959 : MSPModel_Striping::getReserved(int stripes, double factor) {
    2016    49726959 :     return MIN2(
    2017    49726959 :                (int)floor(stripes * factor),
    2018    49726959 :                (int)floor(RESERVE_FOR_ONCOMING_MAX / stripeWidth));
    2019             : }
    2020             : 
    2021             : void
    2022    49720913 : MSPModel_Striping::PState::walk(const Obstacles& obs, SUMOTime currentTime) {
    2023    49720913 :     const int stripes = (int)obs.size();
    2024    49720913 :     const int sMax =  stripes - 1;
    2025             :     assert(stripes == numStripes(myLane));
    2026             :     // account stage-specific max speed but also for normal lane speed limit
    2027             :     // (speed limits on crossings and walkingareas ignored due to #11527)
    2028    49720913 :     const double vMax = (myStage->getConfiguredSpeed() >= 0
    2029    49720913 :                          ? myStage->getConfiguredSpeed()
    2030    55490723 :                          : (myLane->isNormal() || myLane->isInternal()
    2031    53916894 :                             ? myLane->getVehicleMaxSpeed(myPerson)
    2032     1573829 :                             : myStage->getMaxSpeed(myPerson)));
    2033             :     // ultimate goal is to choose the prefered stripe (chosen)
    2034    49720913 :     const int current = stripe();
    2035    49720913 :     const int other = otherStripe();
    2036             :     // compute distances
    2037    49720913 :     std::vector<double> distance(stripes);
    2038   224334165 :     for (int i = 0; i < stripes; ++i) {
    2039   174613252 :         distance[i] = distanceTo(obs[i], obs[i].type == OBSTACLE_PED);
    2040             :     }
    2041             :     // compute utility for all stripes
    2042    49720913 :     std::vector<double> utility(stripes, 0);
    2043             :     // forbid stripes which are blocked and also all stripes behind them
    2044   224334165 :     for (int i = 0; i < stripes; ++i) {
    2045   174613252 :         if (distance[i] == DIST_OVERLAP) {
    2046    53567763 :             if (i == current && (!myWaitingToEnter || stripe() != stripe(myRelY))) {
    2047     3358814 :                 utility[i] += OBSTRUCTED_PENALTY;
    2048             :             }
    2049    53567763 :             if (i < current) {
    2050    61573846 :                 for (int j = 0; j <= i; ++j) {
    2051    39147085 :                     utility[j] += OBSTRUCTED_PENALTY;
    2052             :                 }
    2053             :             }
    2054    53567763 :             if (i > current) {
    2055    53666981 :                 for (int j = i; j < stripes; ++j) {
    2056    32753623 :                     utility[j] += OBSTRUCTED_PENALTY;
    2057             :                 }
    2058             :             }
    2059             :         }
    2060             :     }
    2061             :     // forbid a portion of the leftmost stripes (in walking direction).
    2062             :     // lanes with stripes less than 1 / RESERVE_FOR_ONCOMING_FACTOR
    2063             :     // may still deadlock in heavy pedestrian traffic
    2064    49720913 :     const bool onJunction = myLane->getEdge().isWalkingArea() || myLane->getEdge().isCrossing();
    2065    49720913 :     const int reserved = getReserved(stripes, (onJunction ? RESERVE_FOR_ONCOMING_FACTOR_JUNCTIONS : RESERVE_FOR_ONCOMING_FACTOR));
    2066    49720913 :     if (myDir == FORWARD) {
    2067    38613366 :         for (int i = 0; i < reserved; ++i) {
    2068     5443776 :             utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
    2069             :         }
    2070             :     } else {
    2071    14199220 :         for (int i = sMax; i > sMax - reserved; --i) {
    2072      713748 :             utility[i] += INAPPROPRIATE_PENALTY * (i == current ? 0.5 : 1);
    2073             :         }
    2074             :     }
    2075             :     // adapt utility based on obstacles
    2076   224334165 :     for (int i = 0; i < stripes; ++i) {
    2077   174613252 :         if (obs[i].speed * myDir < 0) {
    2078             :             // penalize evasion to the left unless the obstacle is a vehicle
    2079     4231137 :             if ((myDir == FORWARD || obs[i].type == OBSTACLE_VEHICLE) && i > 0) {
    2080      842648 :                 utility[i - 1] -= 0.5;
    2081     3388489 :             } else if (myDir == BACKWARD && i < sMax) {
    2082      587670 :                 utility[i + 1] -= 0.5;
    2083             :             }
    2084             :         }
    2085             :         // compute expected distance achievable by staying on this stripe for a time horizon
    2086   174613252 :         const double walkDist = MAX2(0., distance[i]); // disregard special distance flags
    2087   174613252 :         const double lookAhead = obs[i].speed * myDir >= 0 ? LOOKAHEAD_SAMEDIR : LOOKAHEAD_ONCOMING;
    2088   174613252 :         const double expectedDist = MIN2(vMax * LOOKAHEAD_SAMEDIR, walkDist + obs[i].speed * myDir * lookAhead);
    2089   174613252 :         if (expectedDist >= 0) {
    2090   171593485 :             utility[i] += expectedDist;
    2091             :         } else {
    2092             :             // let only the distance count
    2093     3019767 :             utility[i] += ONCOMING_CONFLICT_PENALTY + distance[i];
    2094             :         }
    2095             :     }
    2096             :     // discourage use of the leftmost stripe (in walking direction) if there are oncoming
    2097    49720913 :     if (myDir == FORWARD && obs[0].speed < 0) {
    2098     1386619 :         utility[0] += ONCOMING_CONFLICT_PENALTY;
    2099    48334294 :     } else if (myDir == BACKWARD && obs[sMax].speed > 0) {
    2100     1419331 :         utility[sMax] += ONCOMING_CONFLICT_PENALTY;
    2101             :     }
    2102             :     // penalize lateral movement (if the current stripe permits walking)
    2103    49720913 :     if (distance[current] > 0 && myWaitingTime == 0) {
    2104   106898128 :         for (int i = 0; i < stripes; ++i) {
    2105    84323459 :             utility[i] += abs(i - current) * LATERAL_PENALTY;
    2106             :         }
    2107             :     }
    2108             :     // walk on the right side on shared space
    2109    49720913 :     if (myLane->getPermissions() != SVC_PEDESTRIAN && myDir == BACKWARD) {
    2110    47361568 :         for (int i = 0; i < stripes; ++i) {
    2111    35739465 :             if (i <= current) {
    2112    30035129 :                 utility[i] += (sMax - i + 1) * LATERAL_PENALTY;
    2113             :             }
    2114             :         }
    2115             :     }
    2116             : 
    2117             :     // select best stripe
    2118             :     int chosen = current;
    2119   224334165 :     for (int i = 0; i < stripes; ++i) {
    2120   174613252 :         if (utility[i] > utility[chosen] && utility[i] >= INAPPROPRIATE_PENALTY * 0.5) {
    2121             :             chosen = i;
    2122             :         }
    2123             :     }
    2124             :     // compute speed components along both axes
    2125    49720913 :     const int next = (chosen == current ? current : (chosen < current ? current - 1 : current + 1));
    2126    49720913 :     double xDist = MIN3(distance[current], distance[other], distance[next]);
    2127    49720913 :     if (next != chosen) {
    2128             :         // ensure that we do not collide with an obstacle in the stripe beyond
    2129             :         // next as this might become the 'other' stripe in the next step
    2130     1208310 :         const int nextOther = chosen < current ? current - 2 : current + 2;
    2131     1208310 :         xDist = MIN2(xDist, distance[nextOther]);
    2132             :     }
    2133             :     // XXX preferred gap differs between approaching a standing obstacle or a moving obstacle
    2134             :     const double preferredGap = NUMERICAL_EPS;
    2135    49720913 :     double xSpeed = MIN2(vMax, MAX2(0., DIST2SPEED(xDist - preferredGap)));
    2136    49720913 :     if (xSpeed < NUMERICAL_EPS) {
    2137             :         xSpeed = 0.;
    2138             :     }
    2139    49720913 :     if (DEBUGCOND(*this)) {
    2140           0 :         std::cout << " xSpeedPotential=" << xSpeed << "\n";
    2141             :     }
    2142             :     // avoid tiny steps
    2143             :     // XXX pressure from behind?
    2144    49720913 :     if (mySpeed == 0 && xDist < MIN_STARTUP_DIST &&
    2145             :             // unless walking towards a short lane
    2146    22990822 :             !(
    2147    23177225 :                 (xDist == distance[current] && obs[current].type >= OBSTACLE_END)
    2148    22990830 :                 || (xDist == distance[other] && obs[other].type >= OBSTACLE_END)
    2149    22990822 :                 || (xDist == distance[next] && obs[next].type >= OBSTACLE_END))
    2150             :        ) {
    2151             :         xSpeed = 0;
    2152             :     }
    2153    49720913 :     if (xSpeed == 0) {
    2154    26262912 :         if (DEBUGCOND(*this)) {
    2155           0 :             std::cout << " sharedWA=" << (myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())
    2156           0 :                       << " vehObs=" << Named::getIDSecure(obs[current].vehicle)
    2157           0 :                       << " vehWait=" << STEPS2TIME(obs[current].vehicle ? obs[current].vehicle->getWaitingTime() : 0)
    2158           0 :                       << "\n";
    2159             :         }
    2160    26262912 :         if (myWaitingTime > ((myLane->getEdge().isCrossing()
    2161             :                               // treat shared walkingarea like a crossing to avoid deadlocking vehicles
    2162    26256791 :                               || (myLane->getEdge().isWalkingArea() && obs[current].vehicle != nullptr && obs[current].vehicle->getWaitingTime() > jamTimeCrossing
    2163    52520033 :                                   && myWalkingAreaFoes.find(&myLane->getEdge()) != myWalkingAreaFoes.end())) ? jamTimeCrossing : jamTime)
    2164    26199528 :                 || (sMax == 0 && obs[0].speed * myDir < 0 && myWaitingTime > jamTimeNarrow)
    2165    52447164 :                 || myAmJammed) {
    2166             :             // squeeze slowly through the crowd ignoring others
    2167     3841177 :             if (!myAmJammed) {
    2168       63115 :                 MSNet::getInstance()->getPersonControl().registerJammed();
    2169      252460 :                 WRITE_WARNINGF(TL("Person '%' is jammed on edge '%', time=%."),
    2170             :                                myPerson->getID(), myStage->getEdge()->getID(), time2string(SIMSTEP));
    2171       63115 :                 myAmJammed = true;
    2172             :             }
    2173     3841177 :             xSpeed = vMax / 4;
    2174             :         }
    2175    23458001 :     } else if (myAmJammed && stripe(myRelY) >= 0 && stripe(myRelY) <= sMax && xDist >= MIN_STARTUP_DIST)  {
    2176       64631 :         myAmJammed = false;
    2177             :     }
    2178             :     // dawdling
    2179    49720913 :     const double dawdle = MIN2(xSpeed, RandHelper::rand() * vMax * dawdling);
    2180    49720913 :     xSpeed -= dawdle;
    2181             : 
    2182             :     // XXX ensure that diagonal speed <= vMax
    2183             :     // avoid deadlocks on narrow sidewalks
    2184             :     //if (oncoming && xSpeed == 0 && myStage->getWaitingTime(currentTime) > TIME2STEPS(ONCOMIN_PATIENCE)) {
    2185             :     //    if DEBUGCOND(*this) std::cout << "  stepping asside to resolve oncoming deadlock\n";
    2186             :     //    xSpeed = POSITION_EPS; // reset myWaitingTime
    2187             :     //     if (myDir == FORWARD && chosen < sMax) {
    2188             :     //         chosen += 1;
    2189             :     //     } else if (myDir == BACKWARD && chosen > 0) {
    2190             :     //         chosen -= 1;
    2191             :     //     }
    2192             :     //}
    2193    49720913 :     const double maxYSpeed = MIN2(MAX2(vMax * LATERAL_SPEED_FACTOR, vMax - xSpeed), stripeWidth);
    2194             :     double ySpeed = 0;
    2195             :     double yDist = 0;
    2196    49720913 :     if (utility[next] > OBSTRUCTION_THRESHOLD && utility[chosen] > OBSTRUCTION_THRESHOLD) {
    2197             :         // don't move laterally if the stripes are blocked
    2198    46418767 :         yDist = (chosen * stripeWidth) - myRelY;
    2199    46418767 :         if (fabs(yDist) > NUMERICAL_EPS) {
    2200     6038209 :             ySpeed = (yDist > 0 ?
    2201     2966792 :                       MIN2(maxYSpeed, DIST2SPEED(yDist)) :
    2202     3071417 :                       MAX2(-maxYSpeed, DIST2SPEED(yDist)));
    2203             :         }
    2204     3302146 :     } else if (utility[next] <= OBSTRUCTION_THRESHOLD && obs[next].type == OBSTACLE_VEHICLE
    2205             :                // still on the road
    2206        9944 :                && stripe() == stripe(myRelY)
    2207             :                // only when the vehicle is moving on the same lane
    2208     3307803 :                && !(myLane->getEdge().isCrossing() || myLane->getEdge().isWalkingArea())) {
    2209             :         // step aside to let the vehicle pass
    2210        3435 :         int stepAsideDir = myDir;
    2211        3435 :         if (myLane->getEdge().getLanes().size() > 1 || current > sMax / 2) {
    2212             :             // always step to the right on multi-lane edges or when closer to
    2213             :             // the right side
    2214             :             stepAsideDir = FORWARD;
    2215             :         }
    2216        3435 :         myAmJammed = true; // ignore pedestrian-pedestrian collisions
    2217        3435 :         ySpeed = stepAsideDir * vMax;
    2218             :     }
    2219             : 
    2220             :     // DEBUG
    2221    49720913 :     if DEBUGCOND(*this) {
    2222           0 :         std::cout << SIMTIME
    2223           0 :                   << " ped=" << myPerson->getID()
    2224           0 :                   << " edge=" << myStage->getEdge()->getID()
    2225           0 :                   << " x=" << myRelX
    2226           0 :                   << " y=" << myRelY
    2227             :                   << " d=" << myDir
    2228           0 :                   << " pvx=" << mySpeed
    2229             :                   << " cur=" << current
    2230           0 :                   << " cho=" << chosen
    2231           0 :                   << " oth=" << other
    2232           0 :                   << " nxt=" << next
    2233           0 :                   << " vx=" << xSpeed
    2234             :                   << " dawdle=" << dawdle
    2235             :                   << " vy=" << ySpeed
    2236             :                   << " xd=" << xDist
    2237             :                   << " yd=" << yDist
    2238             :                   << " vMax=" << vMax
    2239           0 :                   << " wTime=" << myStage->getWaitingTime(currentTime)
    2240           0 :                   << " jammed=" << myAmJammed
    2241           0 :                   << "\n";
    2242           0 :         if (DEBUGCOND(*this)) {
    2243           0 :             for (int i = 0; i < stripes; ++i) {
    2244           0 :                 const Obstacle& o = obs[i];
    2245           0 :                 std::cout << " util=" << utility[i] << " dist=" << distance[i] << " o=" << o.description;
    2246           0 :                 if (o.description != "") {
    2247           0 :                     std::cout << " xF=" << o.xFwd << " xB=" << o.xBack << " v=" << o.speed;
    2248             :                 }
    2249           0 :                 if (i == current) {
    2250           0 :                     std::cout << " current";
    2251             :                 }
    2252           0 :                 if (i == other && i != current) {
    2253           0 :                     std::cout << " other";
    2254             :                 }
    2255           0 :                 if (i == chosen) {
    2256           0 :                     std::cout << " chosen";
    2257             :                 }
    2258           0 :                 if (i == next) {
    2259           0 :                     std::cout << " next";
    2260             :                 }
    2261           0 :                 std::cout << "\n";
    2262             :             }
    2263             :         }
    2264             :     }
    2265    49720913 :     myRelX += SPEED2DIST(xSpeed * myDir);
    2266    49720913 :     myRelY += SPEED2DIST(ySpeed);
    2267    49720913 :     mySpeedLat = ySpeed;
    2268    49720913 :     mySpeed = xSpeed;
    2269    49720913 :     if (xSpeed >= SUMO_const_haltingSpeed) {
    2270    25406344 :         myWaitingToEnter = false;
    2271    25406344 :         myWaitingTime = 0;
    2272             :     } else {
    2273    24314569 :         myWaitingTime += DELTA_T;
    2274             :     }
    2275    49720913 :     myAngle = std::numeric_limits<double>::max(); // set on first access or via remote control
    2276    49720913 : }
    2277             : 
    2278             : 
    2279             : double
    2280     9678663 : MSPModel_Striping::PState::getImpatience(SUMOTime now) const {
    2281     9678663 :     return MAX2(0., MIN2(1., myPerson->getVehicleType().getImpatience()
    2282     9678663 :                          + STEPS2TIME(myStage->getWaitingTime(now)) / MAX_WAIT_TOLERANCE));
    2283             : }
    2284             : 
    2285             : 
    2286             : double
    2287    11307954 : MSPModel_Striping::PState::getEdgePos(const MSStageMoving&, SUMOTime) const {
    2288    11307954 :     return myRelX;
    2289             : }
    2290             : 
    2291             : 
    2292             : int
    2293      359922 : MSPModel_Striping::PState::getDirection(const MSStageMoving&, SUMOTime) const {
    2294      359922 :     return myDir;
    2295             : }
    2296             : 
    2297             : 
    2298             : Position
    2299     6734005 : MSPModel_Striping::PState::getPosition(const MSStageMoving& stage, SUMOTime) const {
    2300             :     if (myRemoteXYPos != Position::INVALID) {
    2301         445 :         return myRemoteXYPos;
    2302             :     }
    2303     6733560 :     if (myLane == nullptr) {
    2304             :         // pedestrian has already finished
    2305         244 :         return Position::INVALID;
    2306             :     }
    2307     6733316 :     const double lateral_offset = myRelY + (stripeWidth - myLane->getWidth()) * 0.5;
    2308     6733316 :     if (myWalkingAreaPath == nullptr) {
    2309      827013 :         return stage.getLanePosition(myLane, myRelX, lateral_offset);
    2310             :     } else {
    2311             :         //if DEBUGCOND(*this) {
    2312             :         //    std::cout << SIMTIME
    2313             :         //        << " getPosition (walkingArea)"
    2314             :         //        << " p=" << myPerson->getID()
    2315             :         //        << " x=" << myRelX
    2316             :         //        << " y=" << myRelY
    2317             :         //        << " latOffset=" << lateral_offset
    2318             :         //        << " shape=" << myWalkingAreaPath->shape
    2319             :         //        << " pos=" << myWalkingAreaPath->shape.positionAtOffset(myRelX, lateral_offset)
    2320             :         //        << "\n";
    2321             :         //}
    2322     5906303 :         if (myWalkingAreaPath->angleOverride == INVALID_DOUBLE) {
    2323     5787373 :             return myWalkingAreaPath->shape.positionAtOffset(myRelX, lateral_offset);
    2324             :         } else {
    2325      118930 :             const double rotationOffset = myDir == FORWARD ? 0 : DEG2RAD(180);
    2326      118930 :             return myWalkingAreaPath->shape.sidePositionAtAngle(myRelX, lateral_offset, myWalkingAreaPath->angleOverride + rotationOffset);
    2327             :         }
    2328             :     }
    2329             : }
    2330             : 
    2331             : 
    2332             : double
    2333     2406728 : MSPModel_Striping::PState::getAngle(const MSStageMoving&, SUMOTime) const {
    2334     2406728 :     if (myAngle != std::numeric_limits<double>::max()) {
    2335             :         return myAngle;
    2336             :     }
    2337      555873 :     if (myLane == nullptr) {
    2338             :         // pedestrian has already finished
    2339             :         return 0;
    2340             :     }
    2341      555629 :     if (myWalkingAreaPath != nullptr && myWalkingAreaPath->angleOverride != INVALID_DOUBLE) {
    2342             :         return myWalkingAreaPath->angleOverride;
    2343             :     }
    2344      528331 :     const PositionVector& shp = myWalkingAreaPath == nullptr ? myLane->getShape() : myWalkingAreaPath->shape;
    2345      528331 :     double geomX = myWalkingAreaPath == nullptr ? myLane->interpolateLanePosToGeometryPos(myRelX) : myRelX;
    2346      528331 :     double angle = shp.rotationAtOffset(geomX) + (myDir == MSPModel::BACKWARD ? M_PI : 0);
    2347      528331 :     if (myDir == MSPModel::BACKWARD) {
    2348      146950 :         angle += atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
    2349             :     } else { // myDir == MSPModel::FORWARD
    2350      497286 :         angle -= atan2(mySpeedLat, MAX2(mySpeed, NUMERICAL_EPS));
    2351             :     }
    2352      528331 :     if (angle > M_PI) {
    2353       96573 :         angle -= 2 * M_PI;
    2354             :     }
    2355      528331 :     myAngle = angle;
    2356      528331 :     return angle;
    2357             : }
    2358             : 
    2359             : 
    2360             : SUMOTime
    2361     9679859 : MSPModel_Striping::PState::getWaitingTime(const MSStageMoving&, SUMOTime) const {
    2362     9679859 :     return myWaitingTime;
    2363             : }
    2364             : 
    2365             : 
    2366             : double
    2367      548660 : MSPModel_Striping::PState::getSpeed(const MSStageMoving&) const {
    2368      548660 :     return mySpeed;
    2369             : }
    2370             : 
    2371             : 
    2372             : const MSEdge*
    2373      164052 : MSPModel_Striping::PState::getNextEdge(const MSStageMoving&) const {
    2374      164052 :     return myNLI.lane == nullptr ? nullptr : &myNLI.lane->getEdge();
    2375             : }
    2376             : 
    2377             : 
    2378             : void
    2379          21 : MSPModel_Striping::PState::moveTo(MSPerson* p, MSLane* lane, double lanePos, double lanePosLat, SUMOTime t) {
    2380             :     ConstMSEdgeVector newEdges; // keep route
    2381             :     int routeOffset = 0;
    2382             :     bool laneOnRoute = false;
    2383          21 :     const MSJunction* laneOnJunction = lane->isNormal() ? nullptr : lane->getEdge().getToJunction();
    2384          21 :     for (const MSEdge* edge : myStage->getRoute()) {
    2385             :         if (edge == &lane->getEdge()
    2386          16 :                 || edge->getToJunction() == laneOnJunction
    2387          21 :                 || edge->getFromJunction() == laneOnJunction) {
    2388             :             laneOnRoute = true;
    2389             :             break;
    2390             :         }
    2391           0 :         routeOffset++;
    2392             :     }
    2393          21 :     if (!laneOnRoute) {
    2394           0 :         throw ProcessError("Lane '" + lane->getID() + "' is not on the route of person '" + getID() + "'.");
    2395             :     }
    2396          21 :     Position pos = lane->geometryPositionAtOffset(lanePos, lanePosLat);
    2397          21 :     if (lane->getEdge().isWalkingArea() && (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane)) {
    2398             :         // entered new walkingarea. Determine path to guess position
    2399          10 :         const MSEdge* prevEdge = myStage->getRoute()[routeOffset];
    2400          10 :         const MSEdge* nextEdge = routeOffset + 1 < (int)myStage->getRoute().size() ? myStage->getRoute()[routeOffset + 1] : nullptr;
    2401          10 :         const WalkingAreaPath* guessed = guessPath(&lane->getEdge(), prevEdge, nextEdge);
    2402          10 :         const double maxPos = guessed->shape.length() - NUMERICAL_EPS;
    2403          10 :         if (lanePos > maxPos + POSITION_EPS || lanePos < -POSITION_EPS) {
    2404           0 :             throw ProcessError("Lane position " + toString(lanePos) + " cannot be mapped onto walkingarea '" + lane->getID()
    2405           0 :                                + "' (fromLane='" + guessed->from->getID()
    2406           0 :                                + "' toLane='" + guessed->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
    2407             :         }
    2408             :         // give some slack
    2409          10 :         lanePos = MIN2(maxPos, MAX2(NUMERICAL_EPS, lanePos));
    2410          10 :         pos = guessed->shape.positionAtOffset(lanePos, lanePosLat);
    2411             :     }
    2412          21 :     const double angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
    2413          21 :     moveToXY(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, newEdges, t);
    2414          21 : }
    2415             : 
    2416             : 
    2417             : void
    2418       16360 : MSPModel_Striping::PState::moveToXY(MSPerson* p, Position pos, MSLane* lane, double lanePos,
    2419             :                                     double lanePosLat, double angle, int routeOffset,
    2420             :                                     const ConstMSEdgeVector& edges, SUMOTime t) {
    2421       16360 :     MSPModel_Striping* pm = dynamic_cast<MSPModel_Striping*>(MSNet::getInstance()->getPersonControl().getMovementModel());
    2422             :     assert(p == myPerson);
    2423             :     assert(pm != nullptr);
    2424       16360 :     const double oldAngle = GeomHelper::naviDegree(getAngle(*myStage, t));
    2425             :     // person already walking in this step. undo this to obtain the previous position
    2426       16360 :     const double oldX = myRelX - SPEED2DIST(mySpeed * myDir);
    2427             :     const double tmp = myRelX;
    2428       16360 :     myRelX = oldX;
    2429       16360 :     Position oldPos = getPosition(*myStage, t);
    2430       16360 :     myRelX = tmp;
    2431             :     //if (oldPos == Position::INVALID) {
    2432             :     //    oldPos = pos
    2433             :     //}
    2434       16360 :     myAngle = GeomHelper::fromNaviDegree(angle);
    2435             : #ifdef DEBUG_MOVETOXY
    2436             :     std::cout << SIMTIME << " ped=" << p->getID()
    2437             :               << " moveToXY"
    2438             :               << " pos=" << pos
    2439             :               << " lane=" << lane->getID()
    2440             :               << " lanePos=" << lanePos
    2441             :               << " lanePosLat=" << lanePosLat
    2442             :               << " angle=" << angle
    2443             :               << " routeOffset=" << routeOffset
    2444             :               << " edges=" << toString(edges)
    2445             :               << " oldLane=" << Named::getIDSecure(myLane)
    2446             :               << " path=" << (myWalkingAreaPath == nullptr ? "null" : (myWalkingAreaPath->from->getID() + "->" + myWalkingAreaPath->to->getID())) << "\n";
    2447             : #endif
    2448             : 
    2449       16360 :     if (lane != myLane && myLane != nullptr) {
    2450        1126 :         pm->remove(this);
    2451             :         pm->registerActive();
    2452             :     }
    2453       16360 :     if (lane != nullptr &&
    2454       16360 :             fabs(lanePosLat) < (0.5 * (lane->getWidth() + p->getVehicleType().getWidth()) + SIDEWALK_OFFSET)) {
    2455       16354 :         myRemoteXYPos = Position::INVALID;
    2456       16354 :         const MSEdge* old = myStage->getEdge();
    2457       16354 :         const MSLane* oldLane = myLane;
    2458       16354 :         if (lane != myLane) {
    2459             :             // implicitly adds new active lane if necessary
    2460        1126 :             pm->myActiveLanes[lane].push_back(this);
    2461             :         }
    2462       16354 :         if (edges.empty()) {
    2463             :             // map within route
    2464       16270 :             myStage->setRouteIndex(myPerson, routeOffset);
    2465             :         } else {
    2466          84 :             myStage->replaceRoute(myPerson, edges, routeOffset);
    2467             :         }
    2468       16354 :         if (!lane->getEdge().isNormal()) {
    2469         718 :             myStage->moveToNextEdge(myPerson, t, myDir, &lane->getEdge());
    2470             :         }
    2471             : 
    2472       16354 :         myLane = lane;
    2473       16354 :         const double lateral_offset = (lane->getWidth() - stripeWidth) * 0.5;
    2474       16354 :         if (lane->getEdge().isWalkingArea()) {
    2475         350 :             if (myWalkingAreaPath == nullptr || myWalkingAreaPath->lane != lane) {
    2476             :                 // entered new walkingarea. Determine path
    2477          62 :                 myWalkingAreaPath = guessPath(&lane->getEdge(), old, myStage->getNextRouteEdge());
    2478             : #ifdef DEBUG_MOVETOXY
    2479             :                 std::cout << " guessPath old=" << old->getID() << " next=" << Named::getIDSecure(myStage->getNextRouteEdge())
    2480             :                           << " path=" << myWalkingAreaPath->from->getID() << "->" << myWalkingAreaPath->to->getID() << "\n";
    2481             : #endif
    2482             :             }
    2483             :             // lanePos and lanePosLat are matched onto the circumference of the
    2484             :             // walkingarea. Use pos instead
    2485         350 :             const Position relPos = myWalkingAreaPath->shape.transformToVectorCoordinates(pos);
    2486             :             if (relPos == Position::INVALID) {
    2487         104 :                 WRITE_WARNING("Could not map position " + toString(pos) + " onto lane '" + myLane->getID()
    2488             :                               + "' (fromLane='" + myWalkingAreaPath->from->getID()
    2489             :                               + "' toLane='" + myWalkingAreaPath->to->getID() + "') for person '" + getID() + "' time=" + time2string(t) + ".");
    2490          52 :                 myRemoteXYPos = pos;
    2491             :             } else {
    2492         298 :                 myRelX = relPos.x();
    2493         298 :                 myRelY = lateral_offset + relPos.y();
    2494             :             }
    2495             :         } else {
    2496       16004 :             myWalkingAreaPath = nullptr;
    2497       16004 :             myRelX = lanePos;
    2498       16004 :             myRelY = lateral_offset - lanePosLat;
    2499             :         }
    2500             :         // guess direction
    2501       16354 :         const double angleDiff = GeomHelper::getMinAngleDiff(angle, oldAngle);
    2502       16354 :         if (myStage->getNextRouteEdge() != nullptr) {
    2503       20809 :             if (myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getFromJunction() ||
    2504        6868 :                     myStage->getEdge()->getToJunction() == myStage->getNextRouteEdge()->getToJunction()) {
    2505        7203 :                 myDir = FORWARD;
    2506             :             } else {
    2507        6738 :                 myDir = BACKWARD;
    2508             :             }
    2509             :         } else {
    2510             :             // guess from angle
    2511        2413 :             if (angleDiff <= 90) {
    2512             :                 // keep direction
    2513        2349 :                 if (myDir == UNDEFINED_DIRECTION) {
    2514           0 :                     myDir = FORWARD;
    2515             :                 }
    2516             :             } else {
    2517             :                 // change direction
    2518          64 :                 myDir = (myDir == BACKWARD) ? FORWARD : BACKWARD;
    2519             :             }
    2520             :         }
    2521             :         // update next lane info (after guessing direction)
    2522       16354 :         if (oldLane == nullptr || &oldLane->getEdge() != &myLane->getEdge()) {
    2523        1074 :             const MSLane* sidewalk = getSidewalk<MSEdge, MSLane>(&myLane->getEdge(), p->getVClass());
    2524             :             // assume that we will eventually move back onto the sidewalk if
    2525             :             // there is one
    2526        1074 :             myNLI = getNextLane(*this, sidewalk == nullptr ? myLane : sidewalk, nullptr);
    2527        1074 :             myStage->activateEntryReminders(myPerson);
    2528             : #ifdef DEBUG_MOVETOXY
    2529             :             std::cout << " myNLI=" << Named::getIDSecure(myNLI.lane) << " link=" << (myNLI.link == nullptr ? "NULL" : myNLI.link->getDescription()) << " dir=" << myNLI.dir << "\n";
    2530             : #endif
    2531             :         }
    2532             : #ifdef DEBUG_MOVETOXY
    2533             :         std::cout << " newRelPos=" << Position(myRelX, myRelY) << " edge=" << myPerson->getEdge()->getID() << " newPos=" << myPerson->getPosition()
    2534             :                   << " oldAngle=" << oldAngle << " angleDiff=" << angleDiff << " newDir=" << myDir << "\n";
    2535             : #endif
    2536       16354 :         if (oldLane == myLane) {
    2537       15228 :             mySpeed = DIST2SPEED(fabs(oldX - myRelX));
    2538             :         } else {
    2539             :             //std::cout << SIMTIME << " oldX=" << oldX << " oldSpeed=" << mySpeed << " oldPos=" << oldPos << " pos=" << pos << " dist=" << oldPos.distanceTo2D(pos) << " oldLane=" << Named::getIDSecure(oldLane) << " lane=" << lane->getID() << "\n";
    2540        1126 :             mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
    2541             :         }
    2542             :     } else {
    2543             :         // map outside the network
    2544           6 :         myRemoteXYPos = pos;
    2545           6 :         mySpeed = DIST2SPEED(oldPos.distanceTo2D(pos));
    2546             :     }
    2547             : 
    2548       16360 : }
    2549             : 
    2550             : 
    2551             : bool
    2552     1110602 : MSPModel_Striping::PState::isJammed() const {
    2553     1110602 :     return myAmJammed;
    2554             : }
    2555             : 
    2556             : const MSLane*
    2557      852419 : MSPModel_Striping::PState::getLane() const {
    2558      852419 :     return myLane;
    2559             : }
    2560             : 
    2561             : double
    2562      365577 : MSPModel_Striping::PState::getPathLength() const {
    2563      365577 :     if (myWalkingAreaPath != nullptr) {
    2564      207522 :         return myWalkingAreaPath->length;
    2565             :     } else {
    2566             :         return 0;
    2567             :     }
    2568             : }
    2569             : 
    2570             : double
    2571  1086887096 : MSPModel_Striping::PState::distanceTo(const Obstacle& obs, const bool includeMinGap) const {
    2572             :     // check for overlap
    2573  1086887096 :     const double maxX = getMaxX(includeMinGap);
    2574  1086887096 :     const double minX = getMinX(includeMinGap);
    2575             :     //if (DEBUGCOND(*this)) {
    2576             :     //    std::cout << std::setprecision(2) <<   "   distanceTo=" << obs.description << " maxX=" << maxX << " minX=" << minX << " obs.xFwd=" << obs.xFwd << " obs.xBack=" << obs.xBack << "\n";
    2577             :     //}
    2578  1086887096 :     if ((obs.xFwd >= maxX && obs.xBack <= maxX) || (obs.xFwd <= maxX && obs.xFwd >= minX)) {
    2579             :         // avoid blocking by itself on looped route
    2580   199016739 :         return (obs.type == OBSTACLE_PED && obs.description == myPerson->getID()) ? DIST_FAR_AWAY : DIST_OVERLAP;
    2581             :     }
    2582   887870357 :     if (myDir == FORWARD) {
    2583   600897788 :         return obs.xFwd < minX ? DIST_BEHIND : obs.xBack - maxX;
    2584             :     } else {
    2585   286972569 :         return obs.xBack > maxX ? DIST_BEHIND : minX - obs.xFwd;
    2586             :     }
    2587             : }
    2588             : 
    2589             : 
    2590             : void
    2591    80461596 : MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2) {
    2592   363130700 :     for (int i = 0; i < (int)into.size(); ++i) {
    2593   282669104 :         if (gDebugFlag1) {
    2594           0 :             std::cout << "     i=" << i << " maxX=" << getMaxX(true) << " minX=" << getMinX(true)
    2595           0 :                       << " into=" << into[i].description << " iDist=" << distanceTo(into[i], into[i].type == OBSTACLE_PED)
    2596           0 :                       << " obs2=" << obs2[i].description << " oDist=" << distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED) << "\n";
    2597             :         }
    2598   282669104 :         const double dO = distanceTo(obs2[i], obs2[i].type == OBSTACLE_PED);
    2599   282669104 :         const double dI = distanceTo(into[i], into[i].type == OBSTACLE_PED);
    2600   282669104 :         if (dO < dI) {
    2601             :             into[i] = obs2[i];
    2602             :         } else if (dO == dI
    2603    39882640 :                    && into[i].type != OBSTACLE_PED
    2604    31001122 :                    && into[i].type != OBSTACLE_VEHICLE
    2605   253130246 :                    && (obs2[i].type == OBSTACLE_PED ||
    2606             :                        obs2[i].type == OBSTACLE_VEHICLE)) {
    2607             :             into[i] = obs2[i];
    2608             :         }
    2609             :     }
    2610    80461596 : }
    2611             : 
    2612             : void
    2613       19193 : MSPModel_Striping::PState::mergeObstacles(Obstacles& into, const Obstacles& obs2, int dir, int offset) {
    2614      148734 :     for (int i = 0; i < (int)into.size(); ++i) {
    2615      129541 :         int i2 = i + offset;
    2616      129541 :         if (i2 >= 0 && i2 < (int)obs2.size()) {
    2617      128301 :             if (dir == FORWARD) {
    2618       92778 :                 if (obs2[i2].xBack < into[i].xBack) {
    2619             :                     into[i] = obs2[i2];
    2620             :                 }
    2621             :             } else {
    2622       35523 :                 if (obs2[i2].xFwd > into[i].xFwd) {
    2623             :                     into[i] = obs2[i2];
    2624             :                 }
    2625             :             }
    2626             :         }
    2627             :     }
    2628       19193 : }
    2629             : 
    2630             : 
    2631             : bool
    2632     9678663 : MSPModel_Striping::PState::ignoreRed(const MSLink* link) const {
    2633     9678663 :     if (link->haveRed()) {
    2634      410441 :         const double ignoreRedTime = myPerson->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_DRIVE_AFTER_RED_TIME, -1);
    2635      410441 :         if (ignoreRedTime >= 0) {
    2636          40 :             const double redDuration = STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - link->getLastStateChange());
    2637          40 :             if (DEBUGCOND(*this)) {
    2638           0 :                 std::cout << SIMTIME << "  ignoreRedTime=" << ignoreRedTime << " redDuration=" << redDuration << "\n";
    2639             :             }
    2640          40 :             return ignoreRedTime > redDuration;
    2641             :         } else {
    2642             :             return false;
    2643             :         }
    2644             :     } else {
    2645             :         return false;
    2646             :     }
    2647             : }
    2648             : 
    2649             : const std::string&
    2650  2721765209 : MSPModel_Striping::PState::getID() const {
    2651  2721765209 :     return myPerson->getID();
    2652             : }
    2653             : 
    2654             : double
    2655  1353841339 : MSPModel_Striping::PState::getWidth() const {
    2656  1353841339 :     return myPerson->getVehicleType().getWidth();
    2657             : }
    2658             : 
    2659             : 
    2660             : bool
    2661    99084326 : MSPModel_Striping::PState::isRemoteControlled() const {
    2662    99084326 :     return myPerson->hasInfluencer() && myPerson->getInfluencer().isRemoteControlled();
    2663             : }
    2664             : 
    2665             : // ===========================================================================
    2666             : // MSPModel_Striping::PStateVehicle method definitions
    2667             : // ===========================================================================
    2668             : 
    2669      550197 : MSPModel_Striping::PStateVehicle::PStateVehicle(const MSVehicle* veh, const MSLane* walkingarea, double relX, double relY, double xWidth, double yWidth):
    2670      550197 :     myVehicle(veh), myXWidth(xWidth), myYWidth(yWidth) {
    2671      550197 :     myLane = walkingarea; // to ensure correct limits when calling otherStripe()
    2672             :     // relX is the center but we want it to be the max value if the movement direction is forward
    2673             :     // and the min value otherwise (indicated by xWidth sign)
    2674      550197 :     myRelX = relX + xWidth / 2;
    2675      550197 :     myRelY = relY;
    2676      550197 : }
    2677             : 
    2678             : const std::string&
    2679     2152823 : MSPModel_Striping::PStateVehicle::getID() const {
    2680     2152823 :     return myVehicle->getID();
    2681             : }
    2682             : 
    2683             : double
    2684     1105414 : MSPModel_Striping::PStateVehicle::getWidth() const {
    2685     1105414 :     return myYWidth;
    2686             : }
    2687             : 
    2688             : double
    2689      585143 : MSPModel_Striping::PStateVehicle::getMinX(const bool /*includeMinGap*/) const {
    2690      585143 :     return myXWidth > 0 ? myRelX - myXWidth : myRelX;
    2691             : }
    2692             : 
    2693             : double
    2694      585143 : MSPModel_Striping::PStateVehicle::getMaxX(const bool /*includeMinGap*/) const {
    2695      585143 :     return myXWidth > 0 ? myRelX : myRelX - myXWidth;
    2696             : }
    2697             : 
    2698             : // ===========================================================================
    2699             : // MSPModel_Striping::MovePedestrians method definitions
    2700             : // ===========================================================================
    2701             : 
    2702             : SUMOTime
    2703     1852396 : MSPModel_Striping::MovePedestrians::execute(SUMOTime currentTime) {
    2704             :     std::set<MSPerson*> changedLane;
    2705     1852396 :     myModel->moveInDirection(currentTime, changedLane, FORWARD);
    2706     1852392 :     myModel->moveInDirection(currentTime, changedLane, BACKWARD);
    2707             :     // DEBUG
    2708             : #ifdef LOG_ALL
    2709             :     for (ActiveLanes::const_iterator it_lane = myModel->getActiveLanes().begin(); it_lane != myModel->getActiveLanes().end(); ++it_lane) {
    2710             :         const MSLane* lane = it_lane->first;
    2711             :         Pedestrians pedestrians = it_lane->second;
    2712             :         if (pedestrians.size() == 0) {
    2713             :             continue;
    2714             :         }
    2715             :         sort(pedestrians.begin(), pedestrians.end(), by_xpos_sorter(FORWARD));
    2716             :         std::cout << SIMTIME << " lane=" << lane->getID();
    2717             :         for (int ii = 0; ii < (int)pedestrians.size(); ++ii) {
    2718             :             const PState& p = *pedestrians[ii];
    2719             :             std::cout << " (" << p.myPerson->getID() << " " << p.myRelX << "," << p.myRelY << " " << p.myDir << ")";
    2720             :         }
    2721             :         std::cout << "\n";
    2722             :     }
    2723             : #endif
    2724     1852392 :     return DELTA_T;
    2725             : }

Generated by: LCOV version 1.14