Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSLane.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
27// Representation of a lane in the micro simulation
28/****************************************************************************/
29#include <config.h>
30
31#include <cmath>
32#include <bitset>
33#include <iostream>
34#include <cassert>
35#include <functional>
36#include <algorithm>
37#include <iterator>
38#include <exception>
39#include <climits>
40#include <set>
45#ifdef HAVE_FOX
47#endif
60#include <mesosim/MELoop.h>
61#include "MSNet.h"
62#include "MSVehicleType.h"
63#include "MSEdge.h"
64#include "MSEdgeControl.h"
65#include "MSJunction.h"
66#include "MSLogicJunction.h"
67#include "MSLink.h"
68#include "MSLane.h"
69#include "MSVehicleTransfer.h"
70#include "MSGlobals.h"
71#include "MSVehicleControl.h"
72#include "MSInsertionControl.h"
73#include "MSVehicleControl.h"
74#include "MSLeaderInfo.h"
75#include "MSVehicle.h"
76#include "MSStop.h"
77
78//#define DEBUG_INSERTION
79//#define DEBUG_PLAN_MOVE
80//#define DEBUG_EXEC_MOVE
81//#define DEBUG_CONTEXT
82//#define DEBUG_PARTIALS
83//#define DEBUG_MANEUVER_RESERVATIONS
84//#define DEBUG_OPPOSITE
85//#define DEBUG_VEHICLE_CONTAINER
86//#define DEBUG_COLLISIONS
87//#define DEBUG_JUNCTION_COLLISIONS
88//#define DEBUG_PEDESTRIAN_COLLISIONS
89//#define DEBUG_LANE_SORTER
90//#define DEBUG_NO_CONNECTION
91//#define DEBUG_SURROUNDING
92//#define DEBUG_EXTRAPOLATE_DEPARTPOS
93//#define DEBUG_ITERATOR
94
95//#define DEBUG_COND (false)
96//#define DEBUG_COND (true)
97#define DEBUG_COND (isSelected())
98#define DEBUG_COND2(obj) ((obj != nullptr && (obj)->isSelected()))
99//#define DEBUG_COND (getID() == "ego")
100//#define DEBUG_COND2(obj) ((obj != 0 && (obj)->getID() == "ego"))
101//#define DEBUG_COND2(obj) (true)
102
103
104// ===========================================================================
105// static member definitions
106// ===========================================================================
116std::vector<SumoRNG> MSLane::myRNGs;
119
120
121// ===========================================================================
122// internal class method definitions
123// ===========================================================================
124void
125MSLane::StoringVisitor::add(const MSLane* const l) const {
126 switch (myDomain) {
128 for (const MSVehicle* veh : l->getVehiclesSecure()) {
129 if (myShape.distance2D(veh->getPosition()) <= myRange) {
130 myObjects.insert(veh);
131 }
132 }
133 for (const MSBaseVehicle* veh : l->getParkingVehicles()) {
134 if (myShape.distance2D(veh->getPosition()) <= myRange) {
135 myObjects.insert(veh);
136 }
137 }
138 l->releaseVehicles();
139 }
140 break;
143 std::vector<MSTransportable*> persons = l->getEdge().getSortedPersons(MSNet::getInstance()->getCurrentTimeStep(), true);
144 for (auto p : persons) {
145 if (myShape.distance2D(p->getPosition()) <= myRange) {
146 myObjects.insert(p);
147 }
148 }
149 l->releaseVehicles();
150 }
151 break;
153 if (myShape.size() != 1 || l->getShape().distance2D(myShape[0]) <= myRange) {
154 myObjects.insert(&l->getEdge());
155 }
156 }
157 break;
159 if (myShape.size() != 1 || l->getShape().distance2D(myShape[0]) <= myRange) {
160 myObjects.insert(l);
161 }
162 }
163 break;
164 default:
165 break;
166
167 }
168}
169
170
173 if (nextIsMyVehicles()) {
174 if (myI1 != myI1End) {
175 myI1 += myDirection;
176 } else if (myI3 != myI3End) {
177 myI3 += myDirection;
178 }
179 // else: already at end
180 } else {
181 myI2 += myDirection;
182 }
183 //if (DEBUG_COND2(myLane)) std::cout << SIMTIME << " AnyVehicleIterator::operator++ lane=" << myLane->getID() << " myI1=" << myI1 << " myI2=" << myI2 << "\n";
184 return *this;
185}
186
187
188const MSVehicle*
190 if (nextIsMyVehicles()) {
191 if (myI1 != myI1End) {
192 return myLane->myVehicles[myI1];
193 } else if (myI3 != myI3End) {
194 return myLane->myTmpVehicles[myI3];
195 } else {
196 assert(myI2 == myI2End);
197 return nullptr;
198 }
199 } else {
200 return myLane->myPartialVehicles[myI2];
201 }
202}
203
204
205bool
207#ifdef DEBUG_ITERATOR
208 if (DEBUG_COND2(myLane)) std::cout << SIMTIME << " AnyVehicleIterator::nextIsMyVehicles lane=" << myLane->getID()
209 << " myDownstream=" << myDownstream
210 << " myI1=" << myI1
211 << " myI1End=" << myI1End
212 << " myI2=" << myI2
213 << " myI2End=" << myI2End
214 << " myI3=" << myI3
215 << " myI3End=" << myI3End
216 << "\n";
217#endif
218 if (myI1 == myI1End && myI3 == myI3End) {
219 if (myI2 != myI2End) {
220 return false;
221 } else {
222 return true; // @note. must be caught
223 }
224 } else {
225 if (myI2 == myI2End) {
226 return true;
227 } else {
228 MSVehicle* cand = myI1 == myI1End ? myLane->myTmpVehicles[myI3] : myLane->myVehicles[myI1];
229#ifdef DEBUG_ITERATOR
230 if (DEBUG_COND2(myLane)) std::cout << " "
231 << " veh1=" << cand->getID()
232 << " isTmp=" << (myI1 == myI1End)
233 << " veh2=" << myLane->myPartialVehicles[myI2]->getID()
234 << " pos1=" << cand->getPositionOnLane(myLane)
235 << " pos2=" << myLane->myPartialVehicles[myI2]->getPositionOnLane(myLane)
236 << "\n";
237#endif
238 if (cand->getPositionOnLane() < myLane->myPartialVehicles[myI2]->getPositionOnLane(myLane)) {
239 return myDownstream;
240 } else {
241 return !myDownstream;
242 }
243 }
244 }
245}
246
247
248// ===========================================================================
249// member method definitions
250// ===========================================================================
251#ifdef _MSC_VER
252#pragma warning(push)
253#pragma warning(disable: 4355) // mask warning about "this" in initializers
254#endif
255MSLane::MSLane(const std::string& id, double maxSpeed, double friction, double length, MSEdge* const edge,
256 int numericalID, const PositionVector& shape, double width,
257 SVCPermissions permissions,
258 SVCPermissions changeLeft, SVCPermissions changeRight,
259 int index, bool isRampAccel,
260 const std::string& type,
261 const PositionVector& outlineShape) :
262 Named(id),
263 myNumericalID(numericalID), myShape(shape), myIndex(index),
264 myVehicles(), myLength(length), myWidth(width),
265 myEdge(edge), myMaxSpeed(maxSpeed),
266 myFrictionCoefficient(friction),
267 mySpeedModified(false),
268 myPermissions(permissions),
269 myChangeLeft(changeLeft),
270 myChangeRight(changeRight),
271 myOriginalPermissions(permissions),
278 myLeaderInfo(width, nullptr, 0.),
279 myFollowerInfo(width, nullptr, 0.),
282 myLengthGeometryFactor(MAX2(POSITION_EPS, myShape.length()) / myLength), // factor should not be 0
283 myIsRampAccel(isRampAccel),
284 myLaneType(type),
285 myRightSideOnEdge(0), // initialized in MSEdge::initialize
288 myOpposite(nullptr),
289 myBidiLane(nullptr),
290#ifdef HAVE_FOX
291 mySimulationTask(*this, 0),
292#endif
293 myStopWatch(3) {
294 // initialized in MSEdge::initialize
295 initRestrictions();// may be reloaded again from initialized in MSEdge::closeBuilding
296 assert(myRNGs.size() > 0);
297 myRNGIndex = numericalID % myRNGs.size();
298 if (outlineShape.size() > 0) {
299 myOutlineShape = new PositionVector(outlineShape);
300 }
301}
302#ifdef _MSC_VER
303#pragma warning(pop)
304#endif
305
306
308 for (MSLink* const l : myLinks) {
309 delete l;
310 }
311 delete myOutlineShape;
312}
313
314
315void
317 // simplify unit testing without MSNet instance
319}
320
321
322void
324 if (MSGlobals::gNumSimThreads <= 1) {
326// } else {
327// this is an idea for better memory locality, lanes with nearby numerical ids get the same rng and thus the same thread
328// first tests show no visible effect though
329// myRNGIndex = myNumericalID * myRNGs.size() / dictSize();
330 }
331}
332
333
334void
336 myLinks.push_back(link);
337}
338
339
340void
342 myOpposite = oppositeLane;
343 if (myOpposite != nullptr && getLength() > myOpposite->getLength()) {
344 WRITE_WARNINGF(TL("Unequal lengths of neigh lane '%' and lane '%' (% != %)."), getID(), myOpposite->getID(), getLength(), myOpposite->getLength());
345 }
346}
347
348void
350 myBidiLane = bidiLane;
351 if (myBidiLane != nullptr && getLength() > myBidiLane->getLength()) {
353 WRITE_WARNINGF(TL("Unequal lengths of bidi lane '%' and lane '%' (% != %)."), getID(), myBidiLane->getID(), getLength(), myBidiLane->getLength());
354 }
355 }
356}
357
358
359
360// ------ interaction with MSMoveReminder ------
361void
362MSLane::addMoveReminder(MSMoveReminder* rem, bool addToVehicles) {
363 myMoveReminders.push_back(rem);
364 if (addToVehicles) {
365 for (MSVehicle* const veh : myVehicles) {
366 veh->addReminder(rem);
367 }
368 }
369 // XXX: Here, the partial occupators are ignored!? Refs. #3255
370}
371
372
373void
375 auto it = std::find(myMoveReminders.begin(), myMoveReminders.end(), rem);
376 if (it != myMoveReminders.end()) {
377 myMoveReminders.erase(it);
378 for (MSVehicle* const veh : myVehicles) {
379 veh->removeReminder(rem);
380 }
381 }
382}
383
384
385double
387 // multithreading: there are concurrent writes to myNeedsCollisionCheck but all of them should set it to true
388 myNeedsCollisionCheck = true; // always check
389#ifdef DEBUG_PARTIALS
390 if (DEBUG_COND2(v)) {
391 std::cout << SIMTIME << " setPartialOccupation. lane=" << getID() << " veh=" << v->getID() << "\n";
392 }
393#endif
394 // XXX update occupancy here?
395#ifdef HAVE_FOX
396 ScopedLocker<> lock(myPartialOccupatorMutex, MSGlobals::gNumSimThreads > 1);
397#endif
398 //assert(std::find(myPartialVehicles.begin(), myPartialVehicles.end(), v) == myPartialVehicles.end());
399 myPartialVehicles.push_back(v);
400 return myLength;
401}
402
403
404void
406#ifdef HAVE_FOX
407 ScopedLocker<> lock(myPartialOccupatorMutex, MSGlobals::gNumSimThreads > 1);
408#endif
409#ifdef DEBUG_PARTIALS
410 if (DEBUG_COND2(v)) {
411 std::cout << SIMTIME << " resetPartialOccupation. lane=" << getID() << " veh=" << v->getID() << "\n";
412 }
413#endif
414 for (VehCont::iterator i = myPartialVehicles.begin(); i != myPartialVehicles.end(); ++i) {
415 if (v == *i) {
416 myPartialVehicles.erase(i);
417 // XXX update occupancy here?
418 //std::cout << " removed from myPartialVehicles\n";
419 return;
420 }
421 }
422 // bluelight eqipped vehicle can teleport onto the intersection without using a connection
423 assert(false || MSGlobals::gClearState || v->getLaneChangeModel().hasBlueLight());
424}
425
426
427void
429#ifdef DEBUG_MANEUVER_RESERVATIONS
430 if (DEBUG_COND2(v)) {
431 std::cout << SIMTIME << " setManeuverReservation. lane=" << getID() << " veh=" << v->getID() << "\n";
432 }
433#endif
434 myManeuverReservations.push_back(v);
435}
436
437
438void
440#ifdef DEBUG_MANEUVER_RESERVATIONS
441 if (DEBUG_COND2(v)) {
442 std::cout << SIMTIME << " resetManeuverReservation(): lane=" << getID() << " veh=" << v->getID() << "\n";
443 }
444#endif
445 for (VehCont::iterator i = myManeuverReservations.begin(); i != myManeuverReservations.end(); ++i) {
446 if (v == *i) {
447 myManeuverReservations.erase(i);
448 return;
449 }
450 }
451 assert(false);
452}
453
454
455// ------ Vehicle emission ------
456void
457MSLane::incorporateVehicle(MSVehicle* veh, double pos, double speed, double posLat, const MSLane::VehCont::iterator& at, MSMoveReminder::Notification notification) {
459 assert(pos <= myLength || notification == MSMoveReminder::NOTIFICATION_LOAD_STATE);
460 bool wasInactive = myVehicles.size() == 0;
461 veh->enterLaneAtInsertion(this, pos, speed, posLat, notification);
462 if (at == myVehicles.end()) {
463 // vehicle will be the first on the lane
464 myVehicles.push_back(veh);
465 } else {
466 myVehicles.insert(at, veh);
467 }
471 if (wasInactive) {
473 }
474 if (getBidiLane() != nullptr && (!isRailway(veh->getVClass()) || (getPermissions() & ~SVC_RAIL_CLASSES) != 0)) {
475 // railways don't need to "see" each other when moving in opposite directions on the same track (efficiency)
477 }
478}
479
480
481bool
482MSLane::lastInsertion(MSVehicle& veh, double mspeed, double posLat, bool patchSpeed) {
483 double pos = getLength() - POSITION_EPS;
484 MSVehicle* leader = getLastAnyVehicle();
485 // back position of leader relative to this lane
486 double leaderBack;
487 if (leader == nullptr) {
489 veh.setTentativeLaneAndPosition(this, pos, posLat);
490 veh.updateBestLanes(false, this);
491 std::pair<MSVehicle* const, double> leaderInfo = getLeader(&veh, pos, veh.getBestLanesContinuation(), veh.getCarFollowModel().brakeGap(mspeed));
492 leader = leaderInfo.first;
493 leaderBack = pos + leaderInfo.second + veh.getVehicleType().getMinGap();
494 } else {
495 leaderBack = leader->getBackPositionOnLane(this);
496 //std::cout << " leaderPos=" << leader->getPositionOnLane(this) << " leaderBack=" << leader->getBackPositionOnLane(this) << " leaderLane=" << leader->getLane()->getID() << "\n";
497 }
498 if (leader == nullptr) {
499 // insert at the end of this lane
500 return isInsertionSuccess(&veh, mspeed, pos, posLat, patchSpeed, MSMoveReminder::NOTIFICATION_DEPARTED);
501 } else {
502 // try to insert behind the leader
503 const double frontGapNeeded = veh.getCarFollowModel().getSecureGap(&veh, leader, mspeed, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel()) + veh.getVehicleType().getMinGap() + POSITION_EPS;
504 if (leaderBack >= frontGapNeeded) {
505 pos = MIN2(pos, leaderBack - frontGapNeeded);
506 bool result = isInsertionSuccess(&veh, mspeed, pos, posLat, patchSpeed, MSMoveReminder::NOTIFICATION_DEPARTED);
507 //if (!result) std::cout << " insertLast failed for " << veh.getID() << " pos=" << pos << " leaderBack=" << leaderBack << " frontGapNeeded=" << frontGapNeeded << "\n";
508 return result;
509 }
510 //std::cout << " insertLast failed for " << veh.getID() << " pos=" << pos << " leaderBack=" << leaderBack << " frontGapNeeded=" << frontGapNeeded << "\n";
511 }
512 return false;
513}
514
515
516bool
517MSLane::freeInsertion(MSVehicle& veh, double mspeed, double posLat,
518 MSMoveReminder::Notification notification) {
519 // try to insert teleporting vehicles fully on this lane
520 double maxPos = myLength;
521 if (veh.hasStops() && veh.getNextStop().edge == veh.getCurrentRouteEdge()) {
522 maxPos = MAX2(0.0, veh.getNextStop().getEndPos(veh));
523 }
524 const double minPos = (notification == MSMoveReminder::NOTIFICATION_TELEPORT ?
525 MIN2(maxPos, veh.getVehicleType().getLength()) : 0);
526 veh.setTentativeLaneAndPosition(this, minPos, 0);
527 if (myVehicles.size() == 0) {
528 // ensure sufficient gap to followers on predecessor lanes
529 const double backOffset = minPos - veh.getVehicleType().getLength();
530 const double missingRearGap = getMissingRearGap(&veh, backOffset, mspeed);
531 if (missingRearGap > 0) {
532 if (minPos + missingRearGap <= maxPos) {
533 // @note. The rear gap is tailored to mspeed. If it changes due
534 // to a leader vehicle (on subsequent lanes) insertion will
535 // still fail. Under the right combination of acceleration and
536 // deceleration values there might be another insertion
537 // positions that would be successful be we do not look for it.
538 //std::cout << SIMTIME << " freeInsertion lane=" << getID() << " veh=" << veh.getID() << " unclear @(340)\n";
539 return isInsertionSuccess(&veh, mspeed, minPos + missingRearGap, posLat, true, notification);
540 }
541 return false;
542 } else {
543 return isInsertionSuccess(&veh, mspeed, minPos, posLat, true, notification);
544 }
545
546 } else {
547 // check whether the vehicle can be put behind the last one if there is such
548 const MSVehicle* const leader = myVehicles.back(); // @todo reproduction of bogus old behavior. see #1961
549 const double leaderPos = leader->getBackPositionOnLane(this);
550 const double speed = leader->getSpeed();
551 const double frontGapNeeded = veh.getCarFollowModel().getSecureGap(&veh, leader, speed, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel()) + veh.getVehicleType().getMinGap();
552 if (leaderPos >= frontGapNeeded) {
553 const double tspeed = MIN2(veh.getCarFollowModel().insertionFollowSpeed(&veh, mspeed, frontGapNeeded, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel(), leader), mspeed);
554 // check whether we can insert our vehicle behind the last vehicle on the lane
555 if (isInsertionSuccess(&veh, tspeed, minPos, posLat, true, notification)) {
556 //std::cout << SIMTIME << " freeInsertion lane=" << getID() << " veh=" << veh.getID() << " pos=" << minPos<< " speed=" << speed << " tspeed=" << tspeed << " frontGapNeeded=" << frontGapNeeded << " lead=" << leader->getID() << " lPos=" << leaderPos << "\n vehsOnLane=" << toString(myVehicles) << " @(358)\n";
557 return true;
558 }
559 }
560 }
561 // go through the lane, look for free positions (starting after the last vehicle)
562 MSLane::VehCont::iterator predIt = myVehicles.begin();
563 while (predIt != myVehicles.end()) {
564 // get leader (may be zero) and follower
565 // @todo compute secure position in regard to sublane-model
566 const MSVehicle* leader = predIt != myVehicles.end() - 1 ? *(predIt + 1) : nullptr;
567 if (leader == nullptr && myPartialVehicles.size() > 0) {
568 leader = myPartialVehicles.front();
569 }
570 const MSVehicle* follower = *predIt;
571
572 // patch speed if allowed
573 double speed = mspeed;
574 if (leader != nullptr) {
575 speed = MIN2(leader->getSpeed(), mspeed);
576 }
577
578 // compute the space needed to not collide with leader
579 double frontMax = maxPos;
580 if (leader != nullptr) {
581 double leaderRearPos = leader->getBackPositionOnLane(this);
582 double frontGapNeeded = veh.getCarFollowModel().getSecureGap(&veh, leader, speed, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel()) + veh.getVehicleType().getMinGap();
583 frontMax = MIN2(maxPos, leaderRearPos - frontGapNeeded);
584 }
585 // compute the space needed to not let the follower collide
586 const double followPos = follower->getPositionOnLane() + follower->getVehicleType().getMinGap();
587 const double backGapNeeded = follower->getCarFollowModel().getSecureGap(follower, &veh, follower->getSpeed(), veh.getSpeed(), veh.getCarFollowModel().getMaxDecel());
588 const double backMin = followPos + backGapNeeded + veh.getVehicleType().getLength();
589
590 // check whether there is enough room (given some extra space for rounding errors)
591 if (frontMax > minPos && backMin + POSITION_EPS < frontMax) {
592 // try to insert vehicle (should be always ok)
593 if (isInsertionSuccess(&veh, speed, backMin + POSITION_EPS, posLat, true, notification)) {
594 //std::cout << SIMTIME << " freeInsertion lane=" << getID() << " veh=" << veh.getID() << " @(393)\n";
595 return true;
596 }
597 }
598 ++predIt;
599 }
600 // first check at lane's begin
601 //std::cout << SIMTIME << " freeInsertion lane=" << getID() << " veh=" << veh.getID() << " fail final\n";
602 return false;
603}
604
605
606double
607MSLane::getDepartSpeed(const MSVehicle& veh, bool& patchSpeed) {
608 double speed = 0;
609 const SUMOVehicleParameter& pars = veh.getParameter();
613 if (dsd == DepartSpeedDefinition::GIVEN) {
614 speed = myDefaultDepartSpeed;
615 }
616 } else if (dsd == DepartSpeedDefinition::GIVEN) {
617 speed = pars.departSpeed;;
618 }
619 switch (dsd) {
621 patchSpeed = false;
622 break;
625 patchSpeed = true;
626 break;
628 speed = getVehicleMaxSpeed(&veh);
629 patchSpeed = true;
630 break;
632 speed = getVehicleMaxSpeed(&veh);
633 patchSpeed = false;
634 break;
636 speed = getVehicleMaxSpeed(&veh) / veh.getChosenSpeedFactor();
637 patchSpeed = false;
638 break;
641 speed = getVehicleMaxSpeed(&veh);
642 if (last != nullptr) {
643 speed = MIN2(speed, last->getSpeed());
644 patchSpeed = false;
645 }
646 break;
647 }
649 speed = MIN2(getVehicleMaxSpeed(&veh), getMeanSpeed());
650 if (getLastAnyVehicle() != nullptr) {
651 patchSpeed = false;
652 }
653 break;
654 }
656 default:
657 // speed = 0 was set before
658 patchSpeed = false; // @todo check
659 break;
660 }
661 return speed;
662}
663
664
665double
667 const SUMOVehicleParameter& pars = veh.getParameter();
668 switch (pars.departPosLatProcedure) {
670 return pars.departPosLat;
672 return -getWidth() * 0.5 + veh.getVehicleType().getWidth() * 0.5;
674 return getWidth() * 0.5 - veh.getVehicleType().getWidth() * 0.5;
676 const double raw = RandHelper::rand(getWidth() - veh.getVehicleType().getWidth()) - getWidth() * 0.5 + veh.getVehicleType().getWidth() * 0.5;
677 return roundDecimal(raw, gPrecisionRandom);
678 }
681 // @note:
682 // case DepartPosLatDefinition::FREE
683 // case DepartPosLatDefinition::RANDOM_FREE
684 // are not handled here because they involve multiple insertion attempts
685 default:
686 return 0;
687 }
688}
689
690
691bool
693 double pos = 0;
694 bool patchSpeed = true; // whether the speed shall be adapted to infrastructure/traffic in front
695 const SUMOVehicleParameter& pars = veh.getParameter();
696 double speed = getDepartSpeed(veh, patchSpeed);
697 double posLat = getDepartPosLat(veh);
698
699 // determine the position
700 switch (pars.departPosProcedure) {
702 pos = pars.departPos;
703 if (pos < 0.) {
704 pos += myLength;
705 }
706 break;
709 break;
711 for (int i = 0; i < 10; i++) {
712 // we will try some random positions ...
714 posLat = getDepartPosLat(veh); // could be random as well
715 if (isInsertionSuccess(&veh, speed, pos, posLat, patchSpeed, MSMoveReminder::NOTIFICATION_DEPARTED)) {
717 return true;
718 }
719 }
720 // ... and if that doesn't work, we put the vehicle to the free position
721 bool success = freeInsertion(veh, speed, posLat);
722 if (success) {
724 }
725 return success;
726 }
728 return freeInsertion(veh, speed, posLat);
730 return lastInsertion(veh, speed, posLat, patchSpeed);
732 if (veh.hasStops() && veh.getNextStop().edge == veh.getCurrentRouteEdge()) {
733 // getLastFreePos of stopping place could return negative position to avoid blocking the stop
734 pos = MAX2(0.0, veh.getNextStop().getEndPos(veh));
735 break;
736 }
741 default:
743 pos = getLength();
744 // find the vehicle from which we are splitting off (should only be a single lane to check)
746 for (AnyVehicleIterator it = anyVehiclesBegin(); it != end; ++it) {
747 const MSVehicle* cand = *it;
748 if (cand->isStopped() && cand->getNextStopParameter()->split == veh.getID()) {
750 pos = cand->getPositionOnLane() + cand->getVehicleType().getMinGap() + veh.getLength();
751 } else {
752 pos = cand->getBackPositionOnLane() - veh.getVehicleType().getMinGap();
753 }
754 break;
755 }
756 }
757 } else {
758 pos = veh.basePos(myEdge);
759 }
760 break;
761 }
762 // determine the lateral position for special cases
764 switch (pars.departPosLatProcedure) {
766 for (int i = 0; i < 10; i++) {
767 // we will try some random positions ...
768 posLat = RandHelper::rand(getWidth()) - getWidth() * 0.5;
769 if (isInsertionSuccess(&veh, speed, pos, posLat, patchSpeed, MSMoveReminder::NOTIFICATION_DEPARTED)) {
770 return true;
771 }
772 }
774 }
775 // no break! continue with DepartPosLatDefinition::FREE
777 // systematically test all positions until a free lateral position is found
778 double posLatMin = -getWidth() * 0.5 + veh.getVehicleType().getWidth() * 0.5;
779 double posLatMax = getWidth() * 0.5 - veh.getVehicleType().getWidth() * 0.5;
780 for (posLat = posLatMin; posLat < posLatMax; posLat += MSGlobals::gLateralResolution) {
781 if (isInsertionSuccess(&veh, speed, pos, posLat, patchSpeed, MSMoveReminder::NOTIFICATION_DEPARTED)) {
782 return true;
783 }
784 }
785 return false;
786 }
787 default:
788 break;
789 }
790 }
791 // try to insert
792 const bool success = isInsertionSuccess(&veh, speed, pos, posLat, patchSpeed, MSMoveReminder::NOTIFICATION_DEPARTED);
793#ifdef DEBUG_EXTRAPOLATE_DEPARTPOS
794 if (DEBUG_COND2(&veh)) {
795 std::cout << SIMTIME << " veh=" << veh.getID() << " success=" << success << " extrapolate=" << myExtrapolateSubstepDepart << " delay=" << veh.getDepartDelay() << " speed=" << speed << "\n";
796 }
797#endif
798 if (success && myExtrapolateSubstepDepart && veh.getDepartDelay() > 0) {
799 SUMOTime relevantDelay = MIN2(DELTA_T, veh.getDepartDelay());
800 // try to compensate sub-step depart delay by moving the vehicle forward
801 speed = veh.getSpeed(); // may have been adapted in isInsertionSuccess
802 double dist = speed * STEPS2TIME(relevantDelay);
803 std::pair<MSVehicle* const, double> leaderInfo = getLeader(&veh, pos, veh.getBestLanesContinuation());
804 if (leaderInfo.first != nullptr) {
805 MSVehicle* leader = leaderInfo.first;
806 const double frontGapNeeded = veh.getCarFollowModel().getSecureGap(&veh, leader, speed, leader->getSpeed(),
807 leader->getCarFollowModel().getMaxDecel());
808 dist = MIN2(dist, leaderInfo.second - frontGapNeeded);
809 }
810 if (dist > 0) {
811 veh.executeFractionalMove(dist);
812 }
813 }
814 return success;
815}
816
817
818bool
819MSLane::checkFailure(const MSVehicle* aVehicle, double& speed, double& dist, const double nspeed, const bool patchSpeed, const std::string errorMsg, InsertionCheck check) const {
820 if (nspeed < speed) {
821 if (patchSpeed) {
822 speed = MIN2(nspeed, speed);
823 dist = aVehicle->getCarFollowModel().brakeGap(speed) + aVehicle->getVehicleType().getMinGap();
824 } else if (speed > 0) {
825 if ((aVehicle->getInsertionChecks() & (int)check) == 0) {
826 return false;
827 }
829 // Check whether vehicle can stop at the given distance when applying emergency braking
830 double emergencyBrakeGap = 0.5 * speed * speed / aVehicle->getCarFollowModel().getEmergencyDecel();
831 if (emergencyBrakeGap <= dist) {
832 // Vehicle may stop in time with emergency deceleration
833 // still, emit a warning
834 WRITE_WARNINGF(TL("Vehicle '%' is inserted in an emergency situation, time=%."), aVehicle->getID(), time2string(SIMSTEP));
835 return false;
836 }
837 }
838
839 if (errorMsg != "") {
840 WRITE_ERRORF(TL("Vehicle '%' will not be able to depart on lane '%' with speed % (%), time=%."),
841 aVehicle->getID(), getID(), speed, errorMsg, time2string(SIMSTEP));
843 }
844 return true;
845 }
846 }
847 return false;
848}
849
850
851bool
853 double speed, double pos, double posLat, bool patchSpeed,
854 MSMoveReminder::Notification notification) {
855 int insertionChecks = aVehicle->getInsertionChecks();
856 if (pos < 0 || pos > myLength) {
857 // we may not start there
858 WRITE_WARNINGF(TL("Invalid departPos % given for vehicle '%', time=%. Inserting at lane end instead."),
859 pos, aVehicle->getID(), time2string(SIMSTEP));
860 pos = myLength;
861 }
862
863#ifdef DEBUG_INSERTION
864 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
865 std::cout << "\nIS_INSERTION_SUCCESS\n"
866 << SIMTIME << " lane=" << getID()
867 << " veh '" << aVehicle->getID()
868 << " bestLanes=" << toString(aVehicle->getBestLanesContinuation(this))
869 << " pos=" << pos
870 << " speed=" << speed
871 << " patchSpeed=" << patchSpeed
872 << "'\n";
873 }
874#endif
875
876 aVehicle->setTentativeLaneAndPosition(this, pos, posLat);
877 aVehicle->updateBestLanes(false, this);
878 const MSCFModel& cfModel = aVehicle->getCarFollowModel();
879 const std::vector<MSLane*>& bestLaneConts = aVehicle->getBestLanesContinuation(this);
880 std::vector<MSLane*>::const_iterator ri = bestLaneConts.begin();
881 double seen = getLength() - pos; // == distance from insertion position until the end of the currentLane
882 double dist = cfModel.brakeGap(speed) + aVehicle->getVehicleType().getMinGap();
883 const bool isRail = aVehicle->isRail();
884 if (isRail && insertionChecks != (int)InsertionCheck::NONE
888 const MSDriveWay* dw = MSDriveWay::getDepartureDriveway(aVehicle);
889 MSEdgeVector occupied;
890#ifdef DEBUG_INSERTION
891 gDebugFlag4 = DEBUG_COND2(aVehicle) || DEBUG_COND;
892#endif
893 if (dw->foeDriveWayOccupied(false, aVehicle, occupied)) {
894 setParameter("insertionBlocked:" + aVehicle->getID(), dw->getID());
895#ifdef DEBUG_INSERTION
896 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
897 std::cout << " foe of driveway " + dw->getID() + " has occupied edges " + toString(occupied) << "\n";
898 }
899 gDebugFlag4 = false;
900#endif
901 return false;
902 }
903#ifdef DEBUG_INSERTION
904 gDebugFlag4 = false;
905#endif
906 }
907 if (getBidiLane() != nullptr && isRail) {
908 // do not insert if the bidirectional edge is occupied
909 if (getBidiLane()->getVehicleNumberWithPartials() > 0 && (insertionChecks & (int)InsertionCheck::BIDI) != 0) {
910#ifdef DEBUG_INSERTION
911 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
912 std::cout << " bidi-lane occupied\n";
913 }
914#endif
915 return false;
916 }
917 // do not insert the back of the train would be put onto an occupied bidi-lane
918 double backLength = aVehicle->getLength() - pos;
919 if (backLength > 0 && (insertionChecks & (int)InsertionCheck::BIDI) != 0) {
921 MSLane* bidi = pred == nullptr ? nullptr : pred->getBidiLane();
922 while (backLength > 0 && bidi != nullptr) {
923 if (bidi->getVehicleNumberWithPartials() > 0) {
924#ifdef DEBUG_INSERTION
925 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
926 std::cout << " bidi-lane furtherLanes occupied\n";
927 }
928#endif
929 return false;
930 }
931 backLength -= bidi->getLength();
932 pred = pred->getLogicalPredecessorLane();
933 bidi = pred == nullptr ? nullptr : pred->getBidiLane();
934 }
935 }
936 }
937 MSLink* firstRailSignal = nullptr;
938 double firstRailSignalDist = -1;
939 // whether speed may be patched for unavoidable reasons (stops, speedLimits, ...)
940 const bool patchSpeedSpecial = patchSpeed || aVehicle->getParameter().departSpeedProcedure != DepartSpeedDefinition::GIVEN;
941
942 // before looping through the continuation lanes, check if a stop is scheduled on this lane
943 // (the code is duplicated in the loop)
944 if (aVehicle->hasStops()) {
945 const MSStop& nextStop = aVehicle->getNextStop();
946 if (nextStop.lane == this) {
947 std::stringstream msg;
948 double distToStop, safeSpeed;
949 if (nextStop.pars.speed > 0) {
950 msg << "scheduled waypoint on lane '" << myID << "' too close";
951 distToStop = MAX2(0.0, nextStop.pars.startPos - pos);
952 safeSpeed = cfModel.freeSpeed(aVehicle, speed, distToStop, nextStop.pars.speed, true, MSCFModel::CalcReason::FUTURE);
953 } else {
954 msg << "scheduled stop on lane '" << myID << "' too close";
955 distToStop = nextStop.pars.endPos - pos;
956 safeSpeed = cfModel.stopSpeed(aVehicle, speed, distToStop, MSCFModel::CalcReason::FUTURE);
957 }
958 if (checkFailure(aVehicle, speed, dist, MAX2(0.0, safeSpeed), patchSpeedSpecial, msg.str(), InsertionCheck::STOP)) {
959 // we may not drive with the given velocity - we cannot stop at the stop
960 return false;
961 }
962 }
963 }
964 // check leader vehicle first because it could have influenced the departSpeed (for departSpeed=avg)
965 // get the pointer to the vehicle next in front of the given position
966 const MSLeaderInfo leaders = getLastVehicleInformation(aVehicle, 0, pos);
967 //if (aVehicle->getID() == "disabled") std::cout << " leaders=" << leaders.toString() << "\n";
968 const double nspeed = safeInsertionSpeed(aVehicle, -pos, leaders, speed);
969 if (nspeed == INVALID_SPEED || checkFailure(aVehicle, speed, dist, nspeed, patchSpeed, "", InsertionCheck::LEADER_GAP)) {
970 // we may not drive with the given velocity - we crash into the leader
971#ifdef DEBUG_INSERTION
972 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
973 std::cout << SIMTIME << " isInsertionSuccess lane=" << getID()
974 << " veh=" << aVehicle->getID()
975 << " pos=" << pos
976 << " posLat=" << posLat
977 << " patchSpeed=" << patchSpeed
978 << " speed=" << speed
979 << " nspeed=" << nspeed
980 << " leaders=" << leaders.toString()
981 << " failed (@700)!\n";
982 }
983#endif
984 return false;
985 }
986#ifdef DEBUG_INSERTION
987 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
988 std::cout << SIMTIME << " speed = " << speed << " nspeed = " << nspeed << " leaders=" << leaders.toString() << "\n";
989 }
990#endif
991
992 const MSRoute& r = aVehicle->getRoute();
993 MSRouteIterator ce = r.begin();
994 int nRouteSuccs = 1;
995 MSLane* currentLane = this;
996 MSLane* nextLane = this;
998 while ((seen < dist || (isRail && firstRailSignal == nullptr)) && ri != bestLaneConts.end()) {
999 // get the next link used...
1000 std::vector<MSLink*>::const_iterator link = succLinkSec(*aVehicle, nRouteSuccs, *currentLane, bestLaneConts);
1001 // get the next used lane (including internal)
1002 if (currentLane->isLinkEnd(link)) {
1003 if (&currentLane->getEdge() == r.getLastEdge()) {
1004 // reached the end of the route
1006 const double remaining = seen + aVehicle->getArrivalPos() - currentLane->getLength();
1007 const double fspeed = cfModel.freeSpeed(aVehicle, speed, remaining, aVehicle->getParameter().arrivalSpeed, true, MSCFModel::CalcReason::FUTURE);
1008 if (checkFailure(aVehicle, speed, dist, fspeed,
1009 patchSpeedSpecial, "arrival speed too low", InsertionCheck::ARRIVAL_SPEED)) {
1010 // we may not drive with the given velocity - we cannot match the specified arrival speed
1011 return false;
1012 }
1013 }
1014 if (mayContinue(aVehicle) && hasUnsafeLink()) {
1015 // since the route is likely to continue we must be prepared for braking
1016 if (checkFailure(aVehicle, speed, dist, cfModel.insertionStopSpeed(aVehicle, speed, seen),
1017 patchSpeedSpecial, "junction '" + currentLane->getEdge().getToJunction()->getID() + "' too close", InsertionCheck::JUNCTION)) {
1018 // we may not drive with the given velocity - we cannot stop at the junction
1019 return false;
1020 }
1021 }
1022 } else {
1023 // lane does not continue
1024 if (checkFailure(aVehicle, speed, dist, cfModel.insertionStopSpeed(aVehicle, speed, seen),
1025 patchSpeedSpecial, "junction '" + currentLane->getEdge().getToJunction()->getID() + "' too close", InsertionCheck::JUNCTION)) {
1026 // we may not drive with the given velocity - we cannot stop at the junction
1027 return false;
1028 }
1029 }
1030 break;
1031 }
1032 if (isRail && firstRailSignal == nullptr) {
1033 std::string constraintInfo;
1034 bool isInsertionOrder;
1035 if (MSRailSignal::hasInsertionConstraint(*link, aVehicle, constraintInfo, isInsertionOrder)) {
1036 setParameter((isInsertionOrder ? "insertionOrder" : "insertionConstraint:")
1037 + aVehicle->getID(), constraintInfo);
1038#ifdef DEBUG_INSERTION
1039 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1040 std::cout << " insertion constraint at link " << (*link)->getDescription() << " not cleared \n";
1041 }
1042#endif
1043 return false;
1044 }
1045 }
1046
1047 // might also by a regular traffic_light instead of a rail_signal
1048 if (firstRailSignal == nullptr && (*link)->getTLLogic() != nullptr) {
1049 firstRailSignal = *link;
1050 firstRailSignalDist = seen;
1051 }
1052 nextLane = (*link)->getViaLaneOrLane();
1053 if (!(*link)->opened(arrivalTime, speed, speed, aVehicle->getVehicleType().getLength(), aVehicle->getImpatience(),
1054 cfModel.getMaxDecel(), 0, posLat, nullptr, false, aVehicle)
1055 || (*link)->railSignalWasPassed()
1056 || !(*link)->havePriority()
1057 || (*link)->getState() == LINKSTATE_ZIPPER) {
1058 // have to stop at junction
1059 std::string errorMsg = "";
1060 const LinkState state = (*link)->getState();
1061 if (state == LINKSTATE_MINOR
1062 || state == LINKSTATE_EQUAL
1063 || state == LINKSTATE_STOP
1064 || state == LINKSTATE_ALLWAY_STOP) {
1065 // no sense in trying later
1066 errorMsg = "unpriorised junction too close";
1067 } else if ((*link)->getTLLogic() != nullptr && !(*link)->getTLLogic()->getsMajorGreen((*link)->getTLIndex())) {
1068 // traffic light never turns 'G'?
1069 errorMsg = "tlLogic '" + (*link)->getTLLogic()->getID() + "' link " + toString((*link)->getTLIndex()) + " never switches to 'G'";
1070 }
1071 const double laneStopOffset = MAX2(getVehicleStopOffset(aVehicle),
1072 aVehicle->getVehicleType().getParameter().getJMParam(SUMO_ATTR_JM_STOPLINE_CROSSING_GAP, MSPModel::SAFETY_GAP) - (*link)->getDistToFoePedCrossing());
1073 const double remaining = seen - laneStopOffset;
1074 if (checkFailure(aVehicle, speed, dist, cfModel.insertionStopSpeed(aVehicle, speed, remaining),
1075 patchSpeedSpecial, errorMsg, InsertionCheck::JUNCTION)) {
1076 // we may not drive with the given velocity - we cannot stop at the junction in time
1077#ifdef DEBUG_INSERTION
1078 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1079 std::cout << SIMTIME << " isInsertionSuccess lane=" << getID()
1080 << " veh=" << aVehicle->getID()
1081 << " patchSpeed=" << patchSpeed
1082 << " speed=" << speed
1083 << " remaining=" << remaining
1084 << " leader=" << currentLane->getLastVehicleInformation(aVehicle, 0, 0).toString()
1085 << " last=" << Named::getIDSecure(getLastAnyVehicle())
1086 << " meanSpeed=" << getMeanSpeed()
1087 << " failed (@926)!\n";
1088 }
1089#endif
1090 return false;
1091 }
1092#ifdef DEBUG_INSERTION
1093 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1094 std::cout << "trying insertion before minor link: "
1095 << "insertion speed = " << speed << " dist=" << dist
1096 << "\n";
1097 }
1098#endif
1099 if (seen >= aVehicle->getVehicleType().getMinGap()) {
1100 break;
1101 }
1102 } else if (nextLane->isInternal()) {
1103 double tmp = 0;
1104 bool dummyReq = true;
1105#ifdef DEBUG_INSERTION
1106 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1107 std::cout << "checking linkLeader for lane '" << nextLane->getID() << "'\n";
1108 gDebugFlag1 = true;
1109 }
1110#endif
1111 double nSpeed = speed;
1112 aVehicle->checkLinkLeader(nextLane->getLinkCont()[0], nextLane, seen + nextLane->getLength(), nullptr, nSpeed, tmp, tmp, dummyReq);
1113#ifdef DEBUG_INSERTION
1114 gDebugFlag1 = false;
1115#endif
1116 if (checkFailure(aVehicle, speed, dist, nSpeed, patchSpeed, "", InsertionCheck::LEADER_GAP)) {
1117 // we may not drive with the given velocity - there is a junction leader
1118#ifdef DEBUG_INSERTION
1119 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1120 std::cout << " linkLeader nSpeed=" << nSpeed << " failed (@1058)!\n";
1121 }
1122#endif
1123 return false;
1124 }
1125 }
1126 // check how next lane affects the journey
1127 if (nextLane != nullptr) {
1128
1129 // do not insert if the bidirectional edge is occupied before a railSignal has been encountered
1130 if (firstRailSignal == nullptr && nextLane->getBidiLane() != nullptr && nextLane->getBidiLane()->getVehicleNumberWithPartials() > 0) {
1131 if ((insertionChecks & (int)InsertionCheck::ONCOMING_TRAIN) != 0) {
1132#ifdef DEBUG_INSERTION
1133 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1134 std::cout << " nextLane=" << nextLane->getID() << " occupiedBidi\n";
1135 }
1136#endif
1137 return false;
1138 }
1139 }
1140
1141 // check if there are stops on the next lane that should be regarded
1142 // (this block is duplicated before the loop to deal with the insertion lane)
1143 if (aVehicle->hasStops()) {
1144 const MSStop& nextStop = aVehicle->getNextStop();
1145 if (nextStop.lane == nextLane) {
1146 std::stringstream msg;
1147 msg << "scheduled stop on lane '" << nextStop.lane->getID() << "' too close";
1148 const double distToStop = seen + nextStop.pars.endPos;
1149 if (checkFailure(aVehicle, speed, dist, cfModel.insertionStopSpeed(aVehicle, speed, distToStop),
1150 patchSpeedSpecial, msg.str(), InsertionCheck::STOP)) {
1151 // we may not drive with the given velocity - we cannot stop at the stop
1152 return false;
1153 }
1154 }
1155 }
1156
1157 // check leader on next lane
1158 const MSLeaderInfo nextLeaders = nextLane->getLastVehicleInformation(aVehicle, 0, 0);
1159 if (nextLeaders.hasVehicles()) {
1160 const double nextLaneSpeed = nextLane->safeInsertionSpeed(aVehicle, seen, nextLeaders, speed);
1161#ifdef DEBUG_INSERTION
1162 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1163 std::cout << SIMTIME << " leader on lane '" << nextLane->getID() << "': " << nextLeaders.toString() << " nspeed=" << nextLaneSpeed << "\n";
1164 }
1165#endif
1166 if (nextLaneSpeed == INVALID_SPEED || checkFailure(aVehicle, speed, dist, nextLaneSpeed, patchSpeed, "", InsertionCheck::LEADER_GAP)) {
1167 // we may not drive with the given velocity - we crash into the leader
1168#ifdef DEBUG_INSERTION
1169 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1170 std::cout << " isInsertionSuccess lane=" << getID()
1171 << " veh=" << aVehicle->getID()
1172 << " pos=" << pos
1173 << " posLat=" << posLat
1174 << " patchSpeed=" << patchSpeed
1175 << " speed=" << speed
1176 << " nspeed=" << nextLaneSpeed
1177 << " nextLane=" << nextLane->getID()
1178 << " lead=" << nextLeaders.toString()
1179 << " failed (@641)!\n";
1180 }
1181#endif
1182 return false;
1183 }
1184 }
1185 if (!nextLane->checkForPedestrians(aVehicle, speed, dist, -seen, patchSpeed)) {
1186 return false;
1187 }
1188 // check next lane's maximum velocity
1189 const double freeSpeed = cfModel.freeSpeed(aVehicle, speed, seen, nextLane->getVehicleMaxSpeed(aVehicle), true, MSCFModel::CalcReason::FUTURE);
1190 if (freeSpeed < speed) {
1191 if (patchSpeedSpecial) {
1192 speed = freeSpeed;
1193 dist = cfModel.brakeGap(speed) + aVehicle->getVehicleType().getMinGap();
1194 } else {
1195 if ((insertionChecks & (int)InsertionCheck::SPEED_LIMIT) != 0) {
1197 WRITE_WARNINGF(TL("Vehicle '%' is inserted too fast and will violate the speed limit on a lane '%', time=%."),
1198 aVehicle->getID(), nextLane->getID(), time2string(SIMSTEP));
1199 } else {
1200 // we may not drive with the given velocity - we would be too fast on the next lane
1201 WRITE_ERRORF(TL("Vehicle '%' will not be able to depart using the given velocity (slow lane ahead), time=%."), aVehicle->getID(), time2string(SIMSTEP));
1203 return false;
1204 }
1205 }
1206 }
1207 }
1208 // check traffic on next junction
1209 // we cannot use (*link)->opened because a vehicle without priority
1210 // may already be comitted to blocking the link and unable to stop
1211 const SUMOTime leaveTime = (*link)->getLeaveTime(arrivalTime, speed, speed, aVehicle->getVehicleType().getLength());
1212 if ((*link)->hasApproachingFoe(arrivalTime, leaveTime, speed, cfModel.getMaxDecel())) {
1213 if (checkFailure(aVehicle, speed, dist, cfModel.insertionStopSpeed(aVehicle, speed, seen), patchSpeed, "", InsertionCheck::JUNCTION)) {
1214 // we may not drive with the given velocity - we crash at the junction
1215 return false;
1216 }
1217 }
1218 arrivalTime += TIME2STEPS(nextLane->getLength() / MAX2(speed, NUMERICAL_EPS));
1219 seen += nextLane->getLength();
1220 currentLane = nextLane;
1221 if ((*link)->getViaLane() == nullptr) {
1222 nRouteSuccs++;
1223 ++ce;
1224 ++ri;
1225 }
1226 }
1227 }
1228
1229 const MSLeaderDistanceInfo& followers = getFollowersOnConsecutive(aVehicle, aVehicle->getBackPositionOnLane(), false);
1230 for (int i = 0; i < followers.numSublanes(); ++i) {
1231 const MSVehicle* follower = followers[i].first;
1232 if (follower != nullptr) {
1233 const double backGapNeeded = follower->getCarFollowModel().getSecureGap(follower, aVehicle, follower->getSpeed(), speed, cfModel.getMaxDecel());
1234 if (followers[i].second < backGapNeeded
1235 && ((insertionChecks & (int)InsertionCheck::FOLLOWER_GAP) != 0
1236 || (followers[i].second < 0 && (insertionChecks & (int)InsertionCheck::COLLISION) != 0))) {
1237 // too close to the follower on this lane
1238#ifdef DEBUG_INSERTION
1239 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1240 std::cout << SIMTIME << " isInsertionSuccess lane=" << getID()
1241 << " veh=" << aVehicle->getID()
1242 << " pos=" << pos
1243 << " posLat=" << posLat
1244 << " speed=" << speed
1245 << " nspeed=" << nspeed
1246 << " follower=" << follower->getID()
1247 << " backGapNeeded=" << backGapNeeded
1248 << " gap=" << followers[i].second
1249 << " failure (@719)!\n";
1250 }
1251#endif
1252 return false;
1253 }
1254 }
1255 }
1256
1257 if (!checkForPedestrians(aVehicle, speed, dist, pos, patchSpeed)) {
1258 return false;
1259 }
1260
1261 MSLane* shadowLane = aVehicle->getLaneChangeModel().getShadowLane(this);
1262#ifdef DEBUG_INSERTION
1263 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1264 std::cout << " shadowLane=" << Named::getIDSecure(shadowLane) << "\n";
1265 }
1266#endif
1267 if (shadowLane != nullptr) {
1268 const MSLeaderDistanceInfo& shadowFollowers = shadowLane->getFollowersOnConsecutive(aVehicle, aVehicle->getBackPositionOnLane(), false);
1269 for (int i = 0; i < shadowFollowers.numSublanes(); ++i) {
1270 const MSVehicle* follower = shadowFollowers[i].first;
1271 if (follower != nullptr) {
1272 const double backGapNeeded = follower->getCarFollowModel().getSecureGap(follower, aVehicle, follower->getSpeed(), speed, cfModel.getMaxDecel());
1273 if (shadowFollowers[i].second < backGapNeeded
1274 && ((insertionChecks & (int)InsertionCheck::FOLLOWER_GAP) != 0
1275 || (shadowFollowers[i].second < 0 && (insertionChecks & (int)InsertionCheck::COLLISION) != 0))) {
1276 // too close to the follower on this lane
1277#ifdef DEBUG_INSERTION
1278 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1279 std::cout << SIMTIME
1280 << " isInsertionSuccess shadowlane=" << shadowLane->getID()
1281 << " veh=" << aVehicle->getID()
1282 << " pos=" << pos
1283 << " posLat=" << posLat
1284 << " speed=" << speed
1285 << " nspeed=" << nspeed
1286 << " follower=" << follower->getID()
1287 << " backGapNeeded=" << backGapNeeded
1288 << " gap=" << shadowFollowers[i].second
1289 << " failure (@812)!\n";
1290 }
1291#endif
1292 return false;
1293 }
1294 }
1295 }
1296 const MSLeaderInfo& ahead = shadowLane->getLastVehicleInformation(nullptr, 0, aVehicle->getPositionOnLane(), false);
1297 for (int i = 0; i < ahead.numSublanes(); ++i) {
1298 const MSVehicle* veh = ahead[i];
1299 if (veh != nullptr) {
1300 const double gap = veh->getBackPositionOnLane(shadowLane) - aVehicle->getPositionOnLane() - aVehicle->getVehicleType().getMinGap();
1301 const double gapNeeded = aVehicle->getCarFollowModel().getSecureGap(aVehicle, veh, speed, veh->getSpeed(), veh->getCarFollowModel().getMaxDecel());
1302 if (gap < gapNeeded
1303 && ((insertionChecks & (int)InsertionCheck::LEADER_GAP) != 0
1304 || (gap < 0 && (insertionChecks & (int)InsertionCheck::COLLISION) != 0))) {
1305 // too close to the shadow leader
1306#ifdef DEBUG_INSERTION
1307 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1308 std::cout << SIMTIME
1309 << " isInsertionSuccess shadowlane=" << shadowLane->getID()
1310 << " veh=" << aVehicle->getID()
1311 << " pos=" << pos
1312 << " posLat=" << posLat
1313 << " speed=" << speed
1314 << " nspeed=" << nspeed
1315 << " leader=" << veh->getID()
1316 << " gapNeeded=" << gapNeeded
1317 << " gap=" << gap
1318 << " failure (@842)!\n";
1319 }
1320#endif
1321 return false;
1322 }
1323 }
1324 }
1325 }
1326 if (followers.numFreeSublanes() > 0) {
1327 // check approaching vehicles to prevent rear-end collisions
1328 const double backOffset = pos - aVehicle->getVehicleType().getLength();
1329 const double missingRearGap = getMissingRearGap(aVehicle, backOffset, speed);
1330 if (missingRearGap > 0
1331 && (insertionChecks & (int)InsertionCheck::LEADER_GAP) != 0) {
1332 // too close to a follower
1333#ifdef DEBUG_INSERTION
1334 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1335 std::cout << SIMTIME
1336 << " isInsertionSuccess lane=" << getID()
1337 << " veh=" << aVehicle->getID()
1338 << " pos=" << pos
1339 << " posLat=" << posLat
1340 << " speed=" << speed
1341 << " nspeed=" << nspeed
1342 << " missingRearGap=" << missingRearGap
1343 << " failure (@728)!\n";
1344 }
1345#endif
1346 return false;
1347 }
1348 }
1349 if (insertionChecks == (int)InsertionCheck::NONE) {
1350 speed = MAX2(0.0, speed);
1351 }
1352 // may got negative while adaptation
1353 if (speed < 0) {
1354#ifdef DEBUG_INSERTION
1355 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1356 std::cout << SIMTIME
1357 << " isInsertionSuccess lane=" << getID()
1358 << " veh=" << aVehicle->getID()
1359 << " pos=" << pos
1360 << " posLat=" << posLat
1361 << " speed=" << speed
1362 << " nspeed=" << nspeed
1363 << " failed (@733)!\n";
1364 }
1365#endif
1366 return false;
1367 }
1368 const int bestLaneOffset = aVehicle->getBestLaneOffset();
1369 const double extraReservation = aVehicle->getLaneChangeModel().getExtraReservation(bestLaneOffset);
1370 if (extraReservation > 0) {
1371 std::stringstream msg;
1372 msg << "too many lane changes required on lane '" << myID << "'";
1373 // we need to take into acount one extra actionStep of delay due to #3665
1374 double distToStop = aVehicle->getBestLaneDist() - pos - extraReservation - speed * aVehicle->getActionStepLengthSecs();
1375 if (distToStop >= 0) {
1376 double stopSpeed = cfModel.stopSpeed(aVehicle, speed, distToStop, MSCFModel::CalcReason::FUTURE);
1377#ifdef DEBUG_INSERTION
1378 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1379 std::cout << "\nIS_INSERTION_SUCCESS\n"
1380 << SIMTIME << " veh=" << aVehicle->getID() << " bestLaneOffset=" << bestLaneOffset << " bestLaneDist=" << aVehicle->getBestLaneDist() << " extraReservation=" << extraReservation
1381 << " distToStop=" << distToStop << " v=" << speed << " v2=" << stopSpeed << "\n";
1382 }
1383#endif
1384 if (checkFailure(aVehicle, speed, distToStop, MAX2(0.0, stopSpeed),
1385 patchSpeedSpecial, msg.str(), InsertionCheck::LANECHANGE)) {
1386 // we may not drive with the given velocity - we cannot reserve enough space for lane changing
1387 return false;
1388 }
1389 }
1390 }
1391 // enter
1392 incorporateVehicle(aVehicle, pos, speed, posLat, find_if(myVehicles.begin(), myVehicles.end(), [&](MSVehicle * const v) {
1393 return v->getPositionOnLane() >= pos;
1394 }), notification);
1395#ifdef DEBUG_INSERTION
1396 if (DEBUG_COND2(aVehicle) || DEBUG_COND) {
1397 std::cout << SIMTIME
1398 << " isInsertionSuccess lane=" << getID()
1399 << " veh=" << aVehicle->getID()
1400 << " pos=" << pos
1401 << " posLat=" << posLat
1402 << " speed=" << speed
1403 << " nspeed=" << nspeed
1404 << "\n myVehicles=" << toString(myVehicles)
1405 << " myPartial=" << toString(myPartialVehicles)
1406 << " myManeuverReservations=" << toString(myManeuverReservations)
1407 << "\n success!\n";
1408 }
1409#endif
1410 if (isRail) {
1411 unsetParameter("insertionConstraint:" + aVehicle->getID());
1412 unsetParameter("insertionOrder:" + aVehicle->getID());
1413 unsetParameter("insertionBlocked:" + aVehicle->getID());
1414 // rail_signal (not traffic_light) requires approach information for
1415 // switching correctly at the start of the next simulation step
1416 if (firstRailSignal != nullptr && firstRailSignal->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1417 aVehicle->registerInsertionApproach(firstRailSignal, firstRailSignalDist);
1418 }
1419 }
1420 return true;
1421}
1422
1423
1424void
1425MSLane::forceVehicleInsertion(MSVehicle* veh, double pos, MSMoveReminder::Notification notification, double posLat) {
1426 veh->updateBestLanes(true, this);
1427 bool dummy;
1428 const double speed = veh->hasDeparted() ? veh->getSpeed() : getDepartSpeed(*veh, dummy);
1429 incorporateVehicle(veh, pos, speed, posLat, find_if(myVehicles.begin(), myVehicles.end(), [&](MSVehicle * const v) {
1430 return v->getPositionOnLane() >= pos;
1431 }), notification);
1432}
1433
1434
1435double
1436MSLane::safeInsertionSpeed(const MSVehicle* veh, double seen, const MSLeaderInfo& leaders, double speed) {
1437 double nspeed = speed;
1438#ifdef DEBUG_INSERTION
1439 if (DEBUG_COND2(veh)) {
1440 std::cout << SIMTIME << " safeInsertionSpeed veh=" << veh->getID() << " speed=" << speed << "\n";
1441 }
1442#endif
1443 for (int i = 0; i < leaders.numSublanes(); ++i) {
1444 const MSVehicle* leader = leaders[i];
1445 if (leader != nullptr) {
1446 double gap = leader->getBackPositionOnLane(this) + seen - veh->getVehicleType().getMinGap();
1447 if (leader->getLane() == getBidiLane()) {
1448 // use distance to front position and account for movement
1449 gap -= (leader->getLength() + leader->getBrakeGap(true));
1450 }
1451 if (gap < 0) {
1452#ifdef DEBUG_INSERTION
1453 if (DEBUG_COND2(veh)) {
1454 std::cout << " leader=" << leader->getID() << " bPos=" << leader->getBackPositionOnLane(this) << " gap=" << gap << "\n";
1455 }
1456#endif
1457 if ((veh->getInsertionChecks() & (int)InsertionCheck::COLLISION) != 0) {
1458 return INVALID_SPEED;
1459 } else {
1460 return 0;
1461 }
1462 }
1463 nspeed = MIN2(nspeed,
1464 veh->getCarFollowModel().insertionFollowSpeed(veh, speed, gap, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel(), leader));
1465#ifdef DEBUG_INSERTION
1466 if (DEBUG_COND2(veh)) {
1467 std::cout << " leader=" << leader->getID() << " bPos=" << leader->getBackPositionOnLane(this) << " gap=" << gap << " nspeed=" << nspeed << "\n";
1468 }
1469#endif
1470 }
1471 }
1472 return nspeed;
1473}
1474
1475
1476// ------ Handling vehicles lapping into lanes ------
1477const MSLeaderInfo
1478MSLane::getLastVehicleInformation(const MSVehicle* ego, double latOffset, double minPos, bool allowCached, const MSVehicle* ignore) const {
1479#ifdef DEBUG_SURROUNDING
1480 if (DEBUG_COND2(ego) || DEBUG_COND) {
1481 std::cout << " getLastVehicleInformation lane=" << getID() << " ego=" << Named::getIDSecure(ego) << " latOffset=" << latOffset << " minPos=" << minPos << " allowCached=" << allowCached
1482 << " hasCache=" << (myLeaderInfoTime >= MSNet::getInstance()->getCurrentTimeStep()) << "\n";
1483 }
1484#endif
1485 if (myLeaderInfoTime < MSNet::getInstance()->getCurrentTimeStep() || ego != nullptr || minPos > 0 || !allowCached) {
1486 MSLeaderInfo leaderTmp(myWidth, ego, latOffset);
1488 int freeSublanes = 1; // number of sublanes for which no leader was found
1489 //if (ego->getID() == "disabled" && SIMTIME == 58) {
1490 // std::cout << "DEBUG\n";
1491 //}
1492 const MSVehicle* veh = *last;
1493 while (freeSublanes > 0 && veh != nullptr) {
1494#ifdef DEBUG_PLAN_MOVE
1495 if (DEBUG_COND2(ego) || DEBUG_COND) {
1496 gDebugFlag1 = true;
1497 std::cout << " getLastVehicleInformation lane=" << getID() << " minPos=" << minPos << " veh=" << veh->getID() << " pos=" << veh->getPositionOnLane(this) << "\n";
1498 }
1499#endif
1500 if (veh != ego && veh != ignore && MAX2(0.0, veh->getPositionOnLane(this)) >= minPos) {
1501 const double vehLatOffset = veh->getLatOffset(this);
1502 freeSublanes = leaderTmp.addLeader(veh, true, vehLatOffset);
1503#ifdef DEBUG_PLAN_MOVE
1504 if (DEBUG_COND2(ego) || DEBUG_COND) {
1505 std::cout << " latOffset=" << vehLatOffset << " newLeaders=" << leaderTmp.toString() << "\n";
1506 }
1507#endif
1508 }
1509 veh = *(++last);
1510 }
1511 if (ego == nullptr && minPos == 0) {
1512#ifdef HAVE_FOX
1513 ScopedLocker<> lock(myLeaderInfoMutex, MSGlobals::gNumSimThreads > 1);
1514#endif
1515 // update cached value
1516 myLeaderInfo = leaderTmp;
1518 }
1519#ifdef DEBUG_PLAN_MOVE
1520 //if (DEBUG_COND2(ego)) std::cout << SIMTIME
1521 // << " getLastVehicleInformation lane=" << getID()
1522 // << " ego=" << Named::getIDSecure(ego)
1523 // << "\n"
1524 // << " vehicles=" << toString(myVehicles)
1525 // << " partials=" << toString(myPartialVehicles)
1526 // << "\n"
1527 // << " result=" << leaderTmp.toString()
1528 // << " cached=" << myLeaderInfo.toString()
1529 // << " myLeaderInfoTime=" << myLeaderInfoTime
1530 // << "\n";
1531 gDebugFlag1 = false;
1532#endif
1533 return leaderTmp;
1534 }
1535 return myLeaderInfo;
1536}
1537
1538
1539const MSLeaderInfo
1540MSLane::getFirstVehicleInformation(const MSVehicle* ego, double latOffset, bool onlyFrontOnLane, double maxPos, bool allowCached) const {
1541#ifdef HAVE_FOX
1542 ScopedLocker<> lock(myFollowerInfoMutex, MSGlobals::gNumSimThreads > 1);
1543#endif
1544 if (myFollowerInfoTime < MSNet::getInstance()->getCurrentTimeStep() || ego != nullptr || maxPos < myLength || !allowCached || onlyFrontOnLane) {
1545 // XXX separate cache for onlyFrontOnLane = true
1546 MSLeaderInfo followerTmp(myWidth, ego, latOffset);
1548 int freeSublanes = 1; // number of sublanes for which no leader was found
1549 const MSVehicle* veh = *first;
1550 while (freeSublanes > 0 && veh != nullptr) {
1551#ifdef DEBUG_PLAN_MOVE
1552 if (DEBUG_COND2(ego)) {
1553 std::cout << " veh=" << veh->getID() << " pos=" << veh->getPositionOnLane(this) << " maxPos=" << maxPos << "\n";
1554 }
1555#endif
1556 if (veh != ego && veh->getPositionOnLane(this) <= maxPos
1557 && (!onlyFrontOnLane || veh->isFrontOnLane(this))) {
1558 //const double vehLatOffset = veh->getLane()->getRightSideOnEdge() - getRightSideOnEdge();
1559 const double vehLatOffset = veh->getLatOffset(this);
1560#ifdef DEBUG_PLAN_MOVE
1561 if (DEBUG_COND2(ego)) {
1562 std::cout << " veh=" << veh->getID() << " latOffset=" << vehLatOffset << "\n";
1563 }
1564#endif
1565 freeSublanes = followerTmp.addLeader(veh, true, vehLatOffset);
1566 }
1567 veh = *(++first);
1568 }
1569 if (ego == nullptr && maxPos == std::numeric_limits<double>::max()) {
1570 // update cached value
1571 myFollowerInfo = followerTmp;
1573 }
1574#ifdef DEBUG_PLAN_MOVE
1575 //if (DEBUG_COND2(ego)) std::cout << SIMTIME
1576 // << " getFirstVehicleInformation lane=" << getID()
1577 // << " ego=" << Named::getIDSecure(ego)
1578 // << "\n"
1579 // << " vehicles=" << toString(myVehicles)
1580 // << " partials=" << toString(myPartialVehicles)
1581 // << "\n"
1582 // << " result=" << followerTmp.toString()
1583 // //<< " cached=" << myFollowerInfo.toString()
1584 // << " myLeaderInfoTime=" << myLeaderInfoTime
1585 // << "\n";
1586#endif
1587 return followerTmp;
1588 }
1589 return myFollowerInfo;
1590}
1591
1592
1593// ------ ------
1594void
1596 assert(myVehicles.size() != 0);
1597 double cumulatedVehLength = 0.;
1598 MSLeaderInfo leaders(myWidth);
1599
1600 // iterate over myVehicles, myPartialVehicles, and myManeuverReservations merge-sort style
1601 VehCont::reverse_iterator veh = myVehicles.rbegin();
1602 VehCont::reverse_iterator vehPart = myPartialVehicles.rbegin();
1603 VehCont::reverse_iterator vehRes = myManeuverReservations.rbegin();
1604#ifdef DEBUG_PLAN_MOVE
1605 if (DEBUG_COND) std::cout
1606 << "\n"
1607 << SIMTIME
1608 << " planMovements() lane=" << getID()
1609 << "\n vehicles=" << toString(myVehicles)
1610 << "\n partials=" << toString(myPartialVehicles)
1611 << "\n reservations=" << toString(myManeuverReservations)
1612 << "\n";
1613#endif
1615 for (; veh != myVehicles.rend(); ++veh) {
1616#ifdef DEBUG_PLAN_MOVE
1617 if (DEBUG_COND2((*veh))) {
1618 std::cout << " plan move for: " << (*veh)->getID();
1619 }
1620#endif
1621 updateLeaderInfo(*veh, vehPart, vehRes, leaders); // 36ns with 8 threads, 9ns with 1
1622#ifdef DEBUG_PLAN_MOVE
1623 if (DEBUG_COND2((*veh))) {
1624 std::cout << " leaders=" << leaders.toString() << "\n";
1625 }
1626#endif
1627 (*veh)->planMove(t, leaders, cumulatedVehLength); // 4800ns with 8 threads, 3100 with 1
1628 cumulatedVehLength += (*veh)->getVehicleType().getLengthWithGap();
1629 leaders.addLeader(*veh, false, 0);
1630 }
1631}
1632
1633
1634void
1636 for (MSVehicle* const veh : myVehicles) {
1637 veh->setApproachingForAllLinks();
1638 }
1639}
1640
1641
1642void
1643MSLane::updateLeaderInfo(const MSVehicle* veh, VehCont::reverse_iterator& vehPart, VehCont::reverse_iterator& vehRes, MSLeaderInfo& ahead) const {
1644 bool morePartialVehsAhead = vehPart != myPartialVehicles.rend();
1645 bool moreReservationsAhead = vehRes != myManeuverReservations.rend();
1646 bool nextToConsiderIsPartial;
1647
1648 // Determine relevant leaders for veh
1649 while (moreReservationsAhead || morePartialVehsAhead) {
1650 if ((!moreReservationsAhead || (*vehRes)->getPositionOnLane(this) <= veh->getPositionOnLane())
1651 && (!morePartialVehsAhead || (*vehPart)->getPositionOnLane(this) <= veh->getPositionOnLane())) {
1652 // All relevant downstream vehicles have been collected.
1653 break;
1654 }
1655
1656 // Check whether next farthest relevant vehicle downstream is a partial vehicle or a maneuver reservation
1657 if (moreReservationsAhead && !morePartialVehsAhead) {
1658 nextToConsiderIsPartial = false;
1659 } else if (morePartialVehsAhead && !moreReservationsAhead) {
1660 nextToConsiderIsPartial = true;
1661 } else {
1662 assert(morePartialVehsAhead && moreReservationsAhead);
1663 // Add farthest downstream vehicle first
1664 nextToConsiderIsPartial = (*vehPart)->getPositionOnLane(this) > (*vehRes)->getPositionOnLane(this);
1665 }
1666 // Add appropriate leader information
1667 if (nextToConsiderIsPartial) {
1668 const double latOffset = (*vehPart)->getLatOffset(this);
1669#ifdef DEBUG_PLAN_MOVE
1670 if (DEBUG_COND) {
1671 std::cout << " partial ahead: " << (*vehPart)->getID() << " latOffset=" << latOffset << "\n";
1672 }
1673#endif
1674 if (!(MSGlobals::gLaneChangeDuration > 0 && (*vehPart)->getLaneChangeModel().isOpposite()
1675 && !(*vehPart)->getLaneChangeModel().isChangingLanes())) {
1676 ahead.addLeader(*vehPart, false, latOffset);
1677 }
1678 ++vehPart;
1679 morePartialVehsAhead = vehPart != myPartialVehicles.rend();
1680 } else {
1681 const double latOffset = (*vehRes)->getLatOffset(this);
1682#ifdef DEBUG_PLAN_MOVE
1683 if (DEBUG_COND) {
1684 std::cout << " reservation ahead: " << (*vehRes)->getID() << " latOffset=" << latOffset << "\n";
1685 }
1686#endif
1687 ahead.addLeader(*vehRes, false, latOffset);
1688 ++vehRes;
1689 moreReservationsAhead = vehRes != myManeuverReservations.rend();
1690 }
1691 }
1692}
1693
1694
1695void
1696MSLane::detectCollisions(SUMOTime timestep, const std::string& stage) {
1697 myNeedsCollisionCheck = false;
1698#ifdef DEBUG_COLLISIONS
1699 if (DEBUG_COND) {
1700 std::vector<const MSVehicle*> all;
1701 for (AnyVehicleIterator last = anyVehiclesBegin(); last != anyVehiclesEnd(); ++last) {
1702 all.push_back(*last);
1703 }
1704 std::cout << SIMTIME << " detectCollisions stage=" << stage << " lane=" << getID() << ":\n"
1705 << " vehs=" << toString(myVehicles) << "\n"
1706 << " part=" << toString(myPartialVehicles) << "\n"
1707 << " all=" << toString(all) << "\n"
1708 << "\n";
1709 }
1710#endif
1711
1713 return;
1714 }
1715
1716 std::set<const MSVehicle*, ComparatorNumericalIdLess> toRemove;
1717 std::set<const MSVehicle*, ComparatorNumericalIdLess> toTeleport;
1719 myNeedsCollisionCheck = true; // always check
1720#ifdef DEBUG_JUNCTION_COLLISIONS
1721 if (DEBUG_COND) {
1722 std::cout << SIMTIME << " detect junction Collisions stage=" << stage << " lane=" << getID() << ":\n"
1723 << " vehs=" << toString(myVehicles) << "\n"
1724 << " part=" << toString(myPartialVehicles) << "\n"
1725 << "\n";
1726 }
1727#endif
1728 assert(myLinks.size() == 1);
1729 const std::vector<const MSLane*>& foeLanes = myLinks.front()->getFoeLanes();
1730 // save the iterator, it might get modified, see #8842
1732 for (AnyVehicleIterator veh = anyVehiclesBegin(); veh != end; ++veh) {
1733 const MSVehicle* const collider = *veh;
1734 //std::cout << " collider " << collider->getID() << "\n";
1735 PositionVector colliderBoundary = collider->getBoundingBox(myCheckJunctionCollisionMinGap);
1736 for (const MSLane* const foeLane : foeLanes) {
1737#ifdef DEBUG_JUNCTION_COLLISIONS
1738 if (DEBUG_COND) {
1739 std::cout << " foeLane " << foeLane->getID()
1740 << " foeVehs=" << toString(foeLane->myVehicles)
1741 << " foePart=" << toString(foeLane->myPartialVehicles) << "\n";
1742 }
1743#endif
1744 MSLane::AnyVehicleIterator foeEnd = foeLane->anyVehiclesEnd();
1745 for (MSLane::AnyVehicleIterator it_veh = foeLane->anyVehiclesBegin(); it_veh != foeEnd; ++it_veh) {
1746 const MSVehicle* const victim = *it_veh;
1747 if (victim == collider) {
1748 // may happen if the vehicles lane and shadow lane are siblings
1749 continue;
1750 }
1751#ifdef DEBUG_JUNCTION_COLLISIONS
1752 if (DEBUG_COND && DEBUG_COND2(collider)) {
1753 std::cout << SIMTIME << " foe=" << victim->getID()
1754 << " bound=" << colliderBoundary << " foeBound=" << victim->getBoundingBox()
1755 << " overlaps=" << colliderBoundary.overlapsWith(victim->getBoundingBox())
1756 << " poly=" << collider->getBoundingPoly()
1757 << " foePoly=" << victim->getBoundingPoly()
1758 << " overlaps2=" << collider->getBoundingPoly().overlapsWith(victim->getBoundingPoly())
1759 << "\n";
1760 }
1761#endif
1762 if (MSGlobals::gIgnoreJunctionBlocker < std::numeric_limits<SUMOTime>::max()) {
1765 // ignored vehicles should not tigger collision
1766 continue;
1767 }
1768 }
1769
1770 if (colliderBoundary.overlapsWith(victim->getBoundingBox())) {
1771 // make a detailed check
1772 PositionVector boundingPoly = collider->getBoundingPoly();
1774 // junction leader is the victim (collider must still be on junction)
1775 assert(isInternal());
1776 if (victim->getLane()->isInternal() && victim->isLeader(myLinks.front(), collider, -1)) {
1777 foeLane->handleCollisionBetween(timestep, stage, victim, collider, -1, 0, toRemove, toTeleport);
1778 } else {
1779 handleCollisionBetween(timestep, stage, collider, victim, -1, 0, toRemove, toTeleport);
1780 }
1781 }
1782 }
1783 }
1784 detectPedestrianJunctionCollision(collider, colliderBoundary, foeLane, timestep, stage, toRemove, toTeleport);
1785 }
1786 if (myLinks.front()->getWalkingAreaFoe() != nullptr) {
1787 detectPedestrianJunctionCollision(collider, colliderBoundary, myLinks.front()->getWalkingAreaFoe(), timestep, stage, toRemove, toTeleport);
1788 }
1789 if (myLinks.front()->getWalkingAreaFoeExit() != nullptr) {
1790 detectPedestrianJunctionCollision(collider, colliderBoundary, myLinks.front()->getWalkingAreaFoeExit(), timestep, stage, toRemove, toTeleport);
1791 }
1792 }
1793 }
1794
1795
1797#ifdef DEBUG_PEDESTRIAN_COLLISIONS
1798 if (DEBUG_COND) {
1799 std::cout << SIMTIME << " detect pedestrian collisions stage=" << stage << " lane=" << getID() << "\n";
1800 }
1801#endif
1803 for (AnyVehicleIterator it_v = anyVehiclesBegin(); it_v != v_end; ++it_v) {
1804 const MSVehicle* v = *it_v;
1805 double back = v->getBackPositionOnLane(this);
1806 const double length = v->getVehicleType().getLength();
1807 const double right = v->getRightSideOnEdge(this) - getRightSideOnEdge();
1808 if (v->getLane() == getBidiLane()) {
1809 // use the front position for checking
1810 back -= length;
1811 }
1812 PersonDist leader = nextBlocking(back, right, right + v->getVehicleType().getWidth());
1813#ifdef DEBUG_PEDESTRIAN_COLLISIONS
1814 if (DEBUG_COND && DEBUG_COND2(v)) {
1815 std::cout << SIMTIME << " back=" << back << " right=" << right << " person=" << Named::getIDSecure(leader.first)
1816 << " dist=" << leader.second << " jammed=" << (leader.first == nullptr ? false : leader.first->isJammed()) << "\n";
1817 }
1818#endif
1819 if (leader.first != 0 && leader.second < length && !leader.first->isJammed()) {
1821 // aircraft wings and body are above walking level
1822 continue;
1823 }
1824 const double gap = leader.second - length;
1825 handleIntermodalCollisionBetween(timestep, stage, v, leader.first, gap, "sharedLane", toRemove, toTeleport);
1826 }
1827 }
1828 }
1829
1830 if (myVehicles.size() == 0) {
1831 return;
1832 }
1833 if (!MSGlobals::gSublane) {
1834 // no sublanes
1835 VehCont::reverse_iterator lastVeh = myVehicles.rend() - 1;
1836 for (VehCont::reverse_iterator pred = myVehicles.rbegin(); pred != lastVeh; ++pred) {
1837 VehCont::reverse_iterator veh = pred + 1;
1838 detectCollisionBetween(timestep, stage, *veh, *pred, toRemove, toTeleport);
1839 }
1840 if (myPartialVehicles.size() > 0) {
1841 detectCollisionBetween(timestep, stage, *lastVeh, myPartialVehicles.front(), toRemove, toTeleport);
1842 }
1843 if (getBidiLane() != nullptr) {
1844 // bidirectional railway
1845 MSLane* bidiLane = getBidiLane();
1846 if (bidiLane->getVehicleNumberWithPartials() > 0) {
1847 for (auto veh = myVehicles.begin(); veh != myVehicles.end(); ++veh) {
1848 double high = (*veh)->getPositionOnLane(this);
1849 double low = (*veh)->getBackPositionOnLane(this);
1850 if (stage == MSNet::STAGE_MOVEMENTS) {
1851 // use previous back position to catch trains that
1852 // "jump" through each other
1853 low -= SPEED2DIST((*veh)->getSpeed());
1854 }
1855 for (AnyVehicleIterator veh2 = bidiLane->anyVehiclesBegin(); veh2 != bidiLane->anyVehiclesEnd(); ++veh2) {
1856 // self-collisions might legitemately occur when a long train loops back on itself
1857 if (*veh == *veh2 && !(*veh)->isRail()) {
1858 continue;
1859 }
1860 if ((*veh)->getLane() == (*veh2)->getLane() ||
1861 (*veh)->getLane() == (*veh2)->getBackLane() ||
1862 (*veh)->getBackLane() == (*veh2)->getLane()) {
1863 // vehicles are not in a bidi relation
1864 continue;
1865 }
1866 double low2 = myLength - (*veh2)->getPositionOnLane(bidiLane);
1867 double high2 = myLength - (*veh2)->getBackPositionOnLane(bidiLane);
1868 if (stage == MSNet::STAGE_MOVEMENTS) {
1869 // use previous back position to catch trains that
1870 // "jump" through each other
1871 high2 += SPEED2DIST((*veh2)->getSpeed());
1872 }
1873 if (!(high < low2 || high2 < low)) {
1874#ifdef DEBUG_COLLISIONS
1875 if (DEBUG_COND) {
1876 std::cout << SIMTIME << " bidi-collision veh=" << (*veh)->getID() << " bidiVeh=" << (*veh2)->getID()
1877 << " vehFurther=" << toString((*veh)->getFurtherLanes())
1878 << " high=" << high << " low=" << low << " high2=" << high2 << " low2=" << low2 << "\n";
1879 }
1880#endif
1881 // the faster vehicle is at fault
1882 MSVehicle* collider = const_cast<MSVehicle*>(*veh);
1883 MSVehicle* victim = const_cast<MSVehicle*>(*veh2);
1884 if (collider->getSpeed() < victim->getSpeed()) {
1885 std::swap(victim, collider);
1886 }
1887 handleCollisionBetween(timestep, stage, collider, victim, -1, 0, toRemove, toTeleport);
1888 }
1889 }
1890 }
1891 }
1892 }
1893 } else {
1894 // in the sublane-case it is insufficient to check the vehicles ordered
1895 // by their front position as there might be more than 2 vehicles next to each
1896 // other on the same lane
1897 // instead, a moving-window approach is used where all vehicles that
1898 // overlap in the longitudinal direction receive pairwise checks
1899 // XXX for efficiency, all lanes of an edge should be checked together
1900 // (lanechanger-style)
1901
1902 // XXX quick hack: check each in myVehicles against all others
1903 for (AnyVehicleIterator veh = anyVehiclesBegin(); veh != anyVehiclesEnd(); ++veh) {
1904 MSVehicle* follow = (MSVehicle*)*veh;
1905 for (AnyVehicleIterator veh2 = anyVehiclesBegin(); veh2 != anyVehiclesEnd(); ++veh2) {
1906 MSVehicle* lead = (MSVehicle*)*veh2;
1907 if (lead == follow) {
1908 continue;
1909 }
1910 if (lead->getPositionOnLane(this) < follow->getPositionOnLane(this)) {
1911 continue;
1912 }
1913 if (detectCollisionBetween(timestep, stage, follow, lead, toRemove, toTeleport)) {
1914 // XXX what about collisions with multiple leaders at once?
1915 break;
1916 }
1917 }
1918 }
1919 }
1920
1921
1922 for (std::set<const MSVehicle*, ComparatorNumericalIdLess>::iterator it = toRemove.begin(); it != toRemove.end(); ++it) {
1923 MSVehicle* veh = const_cast<MSVehicle*>(*it);
1924 MSLane* vehLane = veh->getMutableLane();
1926 if (toTeleport.count(veh) > 0) {
1927 MSVehicleTransfer::getInstance()->add(timestep, veh);
1928 } else {
1931 }
1932 }
1933}
1934
1935
1936void
1937MSLane::detectPedestrianJunctionCollision(const MSVehicle* collider, const PositionVector& colliderBoundary, const MSLane* foeLane,
1938 SUMOTime timestep, const std::string& stage,
1939 std::set<const MSVehicle*, ComparatorNumericalIdLess>& toRemove,
1940 std::set<const MSVehicle*, ComparatorNumericalIdLess>& toTeleport) {
1941 if (myIntermodalCollisionAction != COLLISION_ACTION_NONE && foeLane->getEdge().getPersons().size() > 0 && foeLane->hasPedestrians()) {
1942#ifdef DEBUG_PEDESTRIAN_COLLISIONS
1943 if (DEBUG_COND) {
1944 std::cout << SIMTIME << " detect pedestrian junction collisions stage=" << stage << " lane=" << getID() << " foeLane=" << foeLane->getID() << "\n";
1945 }
1946#endif
1947 const std::vector<MSTransportable*>& persons = foeLane->getEdge().getSortedPersons(timestep);
1948 for (std::vector<MSTransportable*>::const_iterator it_p = persons.begin(); it_p != persons.end(); ++it_p) {
1949#ifdef DEBUG_PEDESTRIAN_COLLISIONS
1950 if (DEBUG_COND) {
1951 std::cout << " collider=" << collider->getID()
1952 << " ped=" << (*it_p)->getID()
1953 << " jammed=" << (*it_p)->isJammed()
1954 << " colliderBoundary=" << colliderBoundary
1955 << " pedBoundary=" << (*it_p)->getBoundingBox()
1956 << "\n";
1957 }
1958#endif
1959 if ((*it_p)->isJammed()) {
1960 continue;
1961 }
1962 if (colliderBoundary.overlapsWith((*it_p)->getBoundingBox())
1963 && collider->getBoundingPoly().overlapsWith((*it_p)->getBoundingBox())) {
1964 std::string collisionType = "junctionPedestrian";
1965 if (foeLane->isCrossing()) {
1966 collisionType = "crossing";
1967 } else if (foeLane->isWalkingArea()) {
1968 collisionType = "walkingarea";
1969 }
1970 handleIntermodalCollisionBetween(timestep, stage, collider, *it_p, 0, collisionType, toRemove, toTeleport);
1971 }
1972 }
1973 }
1974}
1975
1976
1977bool
1978MSLane::detectCollisionBetween(SUMOTime timestep, const std::string& stage, MSVehicle* collider, MSVehicle* victim,
1979 std::set<const MSVehicle*, ComparatorNumericalIdLess>& toRemove,
1980 std::set<const MSVehicle*, ComparatorNumericalIdLess>& toTeleport) const {
1981 if (myCollisionAction == COLLISION_ACTION_TELEPORT && ((victim->hasInfluencer() && victim->getInfluencer().isRemoteAffected(timestep)) ||
1982 (collider->hasInfluencer() && collider->getInfluencer().isRemoteAffected(timestep)))) {
1983 return false;
1984 }
1985
1986 // No self-collisions! (This is assumed to be ensured at caller side)
1987 if (collider == victim) {
1988 return false;
1989 }
1990
1991 const bool colliderOpposite = collider->getLaneChangeModel().isOpposite() || collider->isBidiOn(this);
1992 const bool victimOpposite = victim->getLaneChangeModel().isOpposite() || victim->isBidiOn(this);
1993 const bool bothOpposite = victimOpposite && colliderOpposite;
1994 if (bothOpposite) {
1995 std::swap(victim, collider);
1996 }
1997 const double colliderPos = colliderOpposite && !bothOpposite ? collider->getBackPositionOnLane(this) : collider->getPositionOnLane(this);
1998 const double minGapFactor = myCollisionMinGapFactor >= 0 ? myCollisionMinGapFactor : collider->getCarFollowModel().getCollisionMinGapFactor();
1999 double victimBack = victimOpposite && !bothOpposite ? victim->getPositionOnLane(this) : victim->getBackPositionOnLane(this);
2000 if (victim->getLateralOverlap() > 0 || collider->getLateralOverlap() > 0) {
2001 if (&collider->getLane()->getEdge() == myEdge && collider->getLane()->getLength() > getLength()) {
2002 // interpret victim position on the longer lane
2003 victimBack *= collider->getLane()->getLength() / getLength();
2004 }
2005 }
2006 double gap = victimBack - colliderPos - minGapFactor * collider->getVehicleType().getMinGap();
2007 if (bothOpposite) {
2008 gap = colliderPos - victimBack - minGapFactor * collider->getVehicleType().getMinGap();
2009 } else if (colliderOpposite) {
2010 // vehicles are back to back so (frontal) minGap doesn't apply
2011 gap += minGapFactor * collider->getVehicleType().getMinGap();
2012 }
2013#ifdef DEBUG_COLLISIONS
2014 if (DEBUG_COND && (DEBUG_COND2(collider) || DEBUG_COND2(victim))) {
2015 std::cout << SIMTIME
2016 << " thisLane=" << getID()
2017 << " collider=" << collider->getID()
2018 << " victim=" << victim->getID()
2019 << " colOpposite=" << colliderOpposite
2020 << " vicOpposite=" << victimOpposite
2021 << " colLane=" << collider->getLane()->getID()
2022 << " vicLane=" << victim->getLane()->getID()
2023 << " colPos=" << colliderPos
2024 << " vicBack=" << victimBack
2025 << " colLat=" << collider->getCenterOnEdge(this)
2026 << " vicLat=" << victim->getCenterOnEdge(this)
2027 << " minGap=" << collider->getVehicleType().getMinGap()
2028 << " minGapFactor=" << minGapFactor
2029 << " gap=" << gap
2030 << "\n";
2031 }
2032#endif
2033 if (victimOpposite && gap < -(collider->getLength() + victim->getLength())) {
2034 // already past each other
2035 return false;
2036 }
2037 if (gap < -NUMERICAL_EPS) {
2038 double latGap = 0;
2039 if (MSGlobals::gSublane) {
2040 latGap = (fabs(victim->getCenterOnEdge(this) - collider->getCenterOnEdge(this))
2041 - 0.5 * fabs(victim->getVehicleType().getWidth() + collider->getVehicleType().getWidth()));
2042 if (latGap + NUMERICAL_EPS > 0) {
2043 return false;
2044 }
2045 // account for ambiguous gap computation related to partial
2046 // occupation of lanes with different lengths
2047 if (isInternal() && getEdge().getNumLanes() > 1 && victim->getLane() != collider->getLane()) {
2048 double gapDelta = 0;
2049 const MSVehicle* otherLaneVeh = collider->getLane() == this ? victim : collider;
2050 if (otherLaneVeh->getLaneChangeModel().getShadowLane() == this) {
2051 gapDelta = getLength() - otherLaneVeh->getLane()->getLength();
2052 } else {
2053 for (const MSLane* cand : otherLaneVeh->getFurtherLanes()) {
2054 if (&cand->getEdge() == &getEdge()) {
2055 gapDelta = getLength() - cand->getLength();
2056 break;
2057 }
2058 }
2059 }
2060 if (gap + gapDelta >= 0) {
2061 return false;
2062 }
2063 }
2064 }
2066 && collider->getLaneChangeModel().isChangingLanes()
2067 && victim->getLaneChangeModel().isChangingLanes()
2068 && victim->getLane() != this) {
2069 // synchroneous lane change maneuver
2070 return false;
2071 }
2072#ifdef DEBUG_COLLISIONS
2073 if (DEBUG_COND && (DEBUG_COND2(collider) || DEBUG_COND2(victim))) {
2074 std::cout << SIMTIME << " detectedCollision gap=" << gap << " latGap=" << latGap << "\n";
2075 }
2076#endif
2077 handleCollisionBetween(timestep, stage, collider, victim, gap, latGap, toRemove, toTeleport);
2078 return true;
2079 }
2080 return false;
2081}
2082
2083
2084void
2085MSLane::handleCollisionBetween(SUMOTime timestep, const std::string& stage, const MSVehicle* collider, const MSVehicle* victim,
2086 double gap, double latGap, std::set<const MSVehicle*, ComparatorNumericalIdLess>& toRemove,
2087 std::set<const MSVehicle*, ComparatorNumericalIdLess>& toTeleport) const {
2088 if (collider->ignoreCollision() || victim->ignoreCollision()) {
2089 return;
2090 }
2091 std::string collisionType;
2092 std::string collisionText;
2093 if (isFrontalCollision(collider, victim)) {
2094 collisionType = "frontal";
2095 collisionText = TL("frontal collision");
2096 } else if (stage == MSNet::STAGE_LANECHANGE) {
2097 collisionType = "side";
2098 collisionText = TL("side collision");
2099 } else if (isInternal()) {
2100 collisionType = "junction";
2101 collisionText = TL("junction collision");
2102 } else {
2103 collisionType = "collision";
2104 collisionText = TL("collision");
2105 }
2106
2107 // in frontal collisions the opposite vehicle is the collider
2108 if (victim->getLaneChangeModel().isOpposite() && !collider->getLaneChangeModel().isOpposite()) {
2109 std::swap(collider, victim);
2110 }
2111 std::string prefix = TLF("Vehicle '%'; % with vehicle '%", collider->getID(), collisionText, victim->getID());
2112 if (myCollisionStopTime > 0) {
2113 if (collider->collisionStopTime() >= 0 && victim->collisionStopTime() >= 0) {
2114 return;
2115 }
2116 std::string dummyError;
2120 const double collisionAngle = RAD2DEG(fabs(GeomHelper::angleDiff(victim->getAngle(), collider->getAngle())));
2121 // determine new speeds from collision angle (@todo account for vehicle mass)
2122 double victimSpeed = victim->getSpeed();
2123 double colliderSpeed = collider->getSpeed();
2124 // double victimOrigSpeed = victim->getSpeed();
2125 // double colliderOrigSpeed = collider->getSpeed();
2126 if (collisionAngle < 45) {
2127 // rear-end collisions
2128 colliderSpeed = MIN2(colliderSpeed, victimSpeed);
2129 } else if (collisionAngle < 135) {
2130 // side collision
2131 colliderSpeed /= 2;
2132 victimSpeed /= 2;
2133 } else {
2134 // frontal collision
2135 colliderSpeed = 0;
2136 victimSpeed = 0;
2137 }
2138 const double victimStopPos = MIN2(victim->getLane()->getLength(),
2139 victim->getPositionOnLane() + victim->getCarFollowModel().brakeGap(victimSpeed, victim->getCarFollowModel().getEmergencyDecel(), 0));
2140 if (victim->collisionStopTime() < 0) {
2141 stop.collision = true;
2142 stop.lane = victim->getLane()->getID();
2143 // @todo: push victim forward?
2144 stop.startPos = victimStopPos;
2145 stop.endPos = stop.startPos;
2147 ((MSBaseVehicle*)victim)->addStop(stop, dummyError, 0);
2148 }
2149 if (collider->collisionStopTime() < 0) {
2150 stop.collision = true;
2151 stop.lane = collider->getLane()->getID();
2152 stop.startPos = MIN2(collider->getPositionOnLane() + collider->getCarFollowModel().brakeGap(colliderSpeed, collider->getCarFollowModel().getEmergencyDecel(), 0),
2153 MAX3(0.0, victimStopPos - 0.75 * victim->getVehicleType().getLength(),
2154 collider->getPositionOnLane() - SPEED2DIST(collider->getSpeed())));
2155 stop.endPos = stop.startPos;
2157 ((MSBaseVehicle*)collider)->addStop(stop, dummyError, 0);
2158 }
2159 //std::cout << " collisionAngle=" << collisionAngle
2160 // << "\n vPos=" << victim->getPositionOnLane() << " vStop=" << victimStopPos << " vSpeed=" << victimOrigSpeed << " vSpeed2=" << victimSpeed << " vSpeed3=" << victim->getSpeed()
2161 // << "\n cPos=" << collider->getPositionOnLane() << " cStop=" << stop.startPos << " cSpeed=" << colliderOrigSpeed << " cSpeed2=" << colliderSpeed << " cSpeed3=" << collider->getSpeed()
2162 // << "\n";
2163 } else {
2164 switch (myCollisionAction) {
2166 break;
2168 prefix = TLF("Teleporting vehicle '%'; % with vehicle '%", collider->getID(), collisionText, victim->getID());
2169 toRemove.insert(collider);
2170 toTeleport.insert(collider);
2171 break;
2173 prefix = TLF("Removing % participants: vehicle '%', vehicle '%", collisionText, collider->getID(), victim->getID());
2174 bool removeCollider = true;
2175 bool removeVictim = true;
2176 removeVictim = !(victim->hasInfluencer() && victim->getInfluencer()->isRemoteAffected(timestep));
2177 removeCollider = !(collider->hasInfluencer() && collider->getInfluencer()->isRemoteAffected(timestep));
2178 if (removeVictim) {
2179 toRemove.insert(victim);
2180 }
2181 if (removeCollider) {
2182 toRemove.insert(collider);
2183 }
2184 if (!removeVictim) {
2185 if (!removeCollider) {
2186 prefix = TLF("Keeping remote-controlled % participants: vehicle '%', vehicle '%", collisionText, collider->getID(), victim->getID());
2187 } else {
2188 prefix = TLF("Removing % participant: vehicle '%', keeping remote-controlled vehicle '%", collisionText, collider->getID(), victim->getID());
2189 }
2190 } else if (!removeCollider) {
2191 prefix = TLF("Keeping remote-controlled % participant: vehicle '%', removing vehicle '%", collisionText, collider->getID(), victim->getID());
2192 }
2193 break;
2194 }
2195 default:
2196 break;
2197 }
2198 }
2199 const bool newCollision = MSNet::getInstance()->registerCollision(collider, victim, collisionType, this, collider->getPositionOnLane(this));
2200 if (newCollision) {
2201 WRITE_WARNINGF(prefix + "', lane='%', gap=%%, time=%, stage=%.",
2202 getID(), toString(gap), (MSGlobals::gSublane ? TL(", latGap=") + toString(latGap) : ""),
2203 time2string(timestep), stage);
2207 }
2208#ifdef DEBUG_COLLISIONS
2209 if (DEBUG_COND2(collider)) {
2210 toRemove.erase(collider);
2211 toTeleport.erase(collider);
2212 }
2213 if (DEBUG_COND2(victim)) {
2214 toRemove.erase(victim);
2215 toTeleport.erase(victim);
2216 }
2217#endif
2218}
2219
2220
2221void
2222MSLane::handleIntermodalCollisionBetween(SUMOTime timestep, const std::string& stage, const MSVehicle* collider, const MSTransportable* victim,
2223 double gap, const std::string& collisionType,
2224 std::set<const MSVehicle*, ComparatorNumericalIdLess>& toRemove,
2225 std::set<const MSVehicle*, ComparatorNumericalIdLess>& toTeleport) const {
2226 if (collider->ignoreCollision()) {
2227 return;
2228 }
2229 std::string prefix = TLF("Vehicle '%'", collider->getID());
2231 if (collider->collisionStopTime() >= 0) {
2232 return;
2233 }
2234 std::string dummyError;
2238 // determine new speeds from collision angle (@todo account for vehicle mass)
2239 double colliderSpeed = collider->getSpeed();
2240 const double victimStopPos = victim->getEdgePos();
2241 // double victimOrigSpeed = victim->getSpeed();
2242 // double colliderOrigSpeed = collider->getSpeed();
2243 if (collider->collisionStopTime() < 0) {
2244 stop.collision = true;
2245 stop.lane = collider->getLane()->getID();
2246 stop.startPos = MIN2(collider->getPositionOnLane() + collider->getCarFollowModel().brakeGap(colliderSpeed, collider->getCarFollowModel().getEmergencyDecel(), 0),
2247 MAX3(0.0, victimStopPos - 0.75 * victim->getVehicleType().getLength(),
2248 collider->getPositionOnLane() - SPEED2DIST(collider->getSpeed())));
2249 stop.endPos = stop.startPos;
2251 ((MSBaseVehicle*)collider)->addStop(stop, dummyError, 0);
2252 }
2253 } else {
2256 break;
2258 prefix = TLF("Teleporting vehicle '%' after", collider->getID());
2259 toRemove.insert(collider);
2260 toTeleport.insert(collider);
2261 break;
2263 prefix = TLF("Removing vehicle '%' after", collider->getID());
2264 bool removeCollider = true;
2265 removeCollider = !(collider->hasInfluencer() && collider->getInfluencer()->isRemoteAffected(timestep));
2266 if (!removeCollider) {
2267 prefix = TLF("Keeping remote-controlled vehicle '%' after", collider->getID());
2268 } else {
2269 toRemove.insert(collider);
2270 }
2271 break;
2272 }
2273 default:
2274 break;
2275 }
2276 }
2277 const bool newCollision = MSNet::getInstance()->registerCollision(collider, victim, collisionType, this, victim->getEdgePos());
2278 if (newCollision) {
2279 if (gap != 0) {
2280 WRITE_WARNING(prefix + TLF(" collision with person '%', lane='%', gap=%, time=%, stage=%.",
2281 victim->getID(), getID(), gap, time2string(timestep), stage));
2282 } else {
2283 WRITE_WARNING(prefix + TLF(" collision with person '%', lane='%', time=%, stage=%.",
2284 victim->getID(), getID(), time2string(timestep), stage));
2285 }
2288 }
2289#ifdef DEBUG_COLLISIONS
2290 if (DEBUG_COND2(collider)) {
2291 toRemove.erase(collider);
2292 toTeleport.erase(collider);
2293 }
2294#endif
2295}
2296
2297
2298bool
2299MSLane::isFrontalCollision(const MSVehicle* collider, const MSVehicle* victim) {
2300 if (collider->getLaneChangeModel().isOpposite() != victim->getLaneChangeModel().isOpposite()) {
2301 return true;
2302 } else {
2303 const MSEdge* victimBidi = victim->getLane()->getEdge().getBidiEdge();
2304 if (&collider->getLane()->getEdge() == victimBidi) {
2305 return true;
2306 } else {
2307 for (MSLane* further : collider->getFurtherLanes()) {
2308 if (&further->getEdge() == victimBidi) {
2309 return true;
2310 }
2311 }
2312 }
2313 }
2314 return false;
2315}
2316
2317void
2319 // multithreading: there are concurrent writes to myNeedsCollisionCheck but all of them should set it to true
2320 myNeedsCollisionCheck = true;
2321 MSLane* bidi = getBidiLane();
2322 if (bidi != nullptr && bidi->getVehicleNumber() == 0) {
2324 }
2325 MSVehicle* firstNotStopped = nullptr;
2326 // iterate over vehicles in reverse so that move reminders will be called in the correct order
2327 for (VehCont::reverse_iterator i = myVehicles.rbegin(); i != myVehicles.rend();) {
2328 MSVehicle* veh = *i;
2329 // length is needed later when the vehicle may not exist anymore
2330 const double length = veh->getVehicleType().getLengthWithGap();
2331 const double nettoLength = veh->getVehicleType().getLength();
2332 const bool moved = veh->executeMove();
2333 MSLane* const target = veh->getMutableLane();
2334 if (veh->hasArrived()) {
2335 // vehicle has reached its arrival position
2336#ifdef DEBUG_EXEC_MOVE
2337 if DEBUG_COND2(veh) {
2338 std::cout << SIMTIME << " veh " << veh->getID() << " has arrived." << std::endl;
2339 }
2340#endif
2343 } else if (target != nullptr && moved) {
2344 if (target->getEdge().isVaporizing()) {
2345 // vehicle has reached a vaporizing edge
2348 } else {
2349 // vehicle has entered a new lane (leaveLane and workOnMoveReminders were already called in MSVehicle::executeMove)
2350 target->myVehBuffer.push_back(veh);
2352 if (MSGlobals::gSublane && veh->getLaneChangeModel().getShadowLane() != nullptr) {
2353 // trigger sorting of partial vehicles as their order may have changed (lane might not be active and only contain partial vehicles)
2355 }
2356 }
2357 } else if (veh->isParking()) {
2358 // vehicle started to park
2360 myParkingVehicles.insert(veh);
2361 } else if (veh->brokeDown()) {
2362 veh->resumeFromStopping();
2363 WRITE_WARNINGF(TL("Removing vehicle '%' after breaking down, lane='%', time=%."),
2364 veh->getID(), veh->getLane()->getID(), time2string(t));
2367 } else if (veh->isJumping()) {
2368 // vehicle jumps to next route edge
2370 } else if (veh->getPositionOnLane() > getLength()) {
2371 // for any reasons the vehicle is beyond its lane...
2372 // this should never happen because it is handled in MSVehicle::executeMove
2373 assert(false);
2374 WRITE_WARNINGF(TL("Teleporting vehicle '%'; beyond end of lane, target lane='%', time=%."),
2375 veh->getID(), getID(), time2string(t));
2378
2379 } else if (veh->collisionStopTime() == 0) {
2380 veh->resumeFromStopping();
2382 WRITE_WARNINGF(TL("Removing vehicle '%' after earlier collision, lane='%', time=%."),
2383 veh->getID(), veh->getLane()->getID(), time2string(t));
2387 WRITE_WARNINGF(TL("Teleporting vehicle '%' after earlier collision, lane='%', time=%."),
2388 veh->getID(), veh->getLane()->getID(), time2string(t));
2390 } else {
2391 if (firstNotStopped == nullptr && !(*i)->isStopped() && (*i)->getLane() == this) {
2392 firstNotStopped = *i;
2393 }
2394 ++i;
2395 continue;
2396 }
2397 } else {
2398 if (firstNotStopped == nullptr && !(*i)->isStopped() && (*i)->getLane() == this) {
2399 firstNotStopped = *i;
2400 }
2401 ++i;
2402 continue;
2403 }
2405 myNettoVehicleLengthSumToRemove += nettoLength;
2406 ++i;
2407 i = VehCont::reverse_iterator(myVehicles.erase(i.base()));
2408 }
2409 if (firstNotStopped != nullptr) {
2413 const bool wrongLane = !appropriate(firstNotStopped);
2414 const bool disconnected = (MSGlobals::gTimeToTeleportDisconnected >= 0
2415 && firstNotStopped->succEdge(1) != nullptr
2416 && firstNotStopped->getEdge()->allowedLanes(*firstNotStopped->succEdge(1), firstNotStopped->getVClass()) == nullptr);
2417
2418 const bool r1 = ttt > 0 && firstNotStopped->getWaitingTime() > ttt && !disconnected
2419 // never teleport a taxi on the last edge of it's route (where it would exit the simulation)
2420 && (firstNotStopped->getDevice(typeid(MSDevice_Taxi)) == nullptr || firstNotStopped->getRoutePosition() < (firstNotStopped->getRoute().size() - 1));
2421 const bool r2 = !r1 && MSGlobals::gTimeToGridlockHighways > 0
2424 && !disconnected;
2425 const bool r3 = disconnected && firstNotStopped->getWaitingTime() > MSGlobals::gTimeToTeleportDisconnected;
2426 const bool r4 = !r1 && !r2 && !r3 && tttb > 0
2427 && firstNotStopped->getWaitingTime() > tttb && getBidiLane() && !disconnected;
2428 const bool r5 = MSGlobals::gTimeToTeleportRSDeadlock > 0 && MSRailSignalControl::hasInstance() && !r1 && !r2 && !r3 && !r4
2430 if (r1 || r2 || r3 || r4 || r5) {
2431 const std::vector<MSLink*>::const_iterator link = succLinkSec(*firstNotStopped, 1, *this, firstNotStopped->getBestLanesContinuation());
2432 const bool minorLink = !wrongLane && (link != myLinks.end()) && !((*link)->havePriority());
2433 std::string reason = (wrongLane ? " (wrong lane" : (minorLink ? " (yield" : " (jam"));
2436 if (firstNotStopped == myVehicles.back()) {
2437 myVehicles.pop_back();
2438 } else {
2439 myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), firstNotStopped));
2440 reason = " (blocked";
2441 }
2442 WRITE_WARNINGF("Teleporting vehicle '%'; waited too long" + reason
2443 + (r2 ? ", highway" : "")
2444 + (r3 ? ", disconnected" : "")
2445 + (r4 ? ", bidi" : "")
2446 + (r5 ? ", railSignal" : "")
2447 + "), lane='%', time=%.", firstNotStopped->getID(), getID(), time2string(t));
2448 if (wrongLane) {
2450 } else if (minorLink) {
2452 } else {
2454 }
2458 } else {
2459 MSVehicleTransfer::getInstance()->add(t, firstNotStopped);
2460 }
2461 }
2462 }
2463 }
2464 if (MSGlobals::gSublane) {
2465 // trigger sorting of vehicles as their order may have changed
2467 }
2468}
2469
2470
2471void
2475
2476
2477void
2483 if (myVehicles.empty()) {
2484 // avoid numerical instability
2487 } else if (myRecalculateBruttoSum) {
2489 for (VehCont::const_iterator i = myVehicles.begin(); i != myVehicles.end(); ++i) {
2490 myBruttoVehicleLengthSum += (*i)->getVehicleType().getLengthWithGap();
2491 }
2492 myRecalculateBruttoSum = false;
2493 }
2494}
2495
2496
2497void
2501
2502
2503const MSEdge*
2505 return myEdge->getNormalSuccessor();
2506}
2507
2508
2509const MSLane*
2511 if (!this->isInternal()) {
2512 return nullptr;
2513 }
2514 offset = 0.;
2515 const MSLane* firstInternal = this;
2517 while (pred != nullptr && pred->isInternal()) {
2518 firstInternal = pred;
2519 offset += pred->getLength();
2520 pred = firstInternal->getCanonicalPredecessorLane();
2521 }
2522 return firstInternal;
2523}
2524
2525
2526// ------ Static (sic!) container methods ------
2527bool
2528MSLane::dictionary(const std::string& id, MSLane* ptr) {
2529 const DictType::iterator it = myDict.lower_bound(id);
2530 if (it == myDict.end() || it->first != id) {
2531 // id not in myDict
2532 myDict.emplace_hint(it, id, ptr);
2533 return true;
2534 }
2535 return false;
2536}
2537
2538
2539MSLane*
2540MSLane::dictionary(const std::string& id) {
2541 const DictType::iterator it = myDict.find(id);
2542 if (it == myDict.end()) {
2543 // id not in myDict
2544 return nullptr;
2545 }
2546 return it->second;
2547}
2548
2549
2550void
2552 for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
2553 delete (*i).second;
2554 }
2555 myDict.clear();
2556}
2557
2558
2559void
2560MSLane::insertIDs(std::vector<std::string>& into) {
2561 for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
2562 into.push_back((*i).first);
2563 }
2564}
2565
2566
2567template<class RTREE> void
2568MSLane::fill(RTREE& into) {
2569 for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
2570 MSLane* l = (*i).second;
2571 Boundary b = l->getShape().getBoxBoundary();
2572 b.grow(3.);
2573 const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
2574 const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
2575 into.Insert(cmin, cmax, l);
2576 }
2577}
2578
2579template void MSLane::fill<NamedRTree>(NamedRTree& into);
2580template void MSLane::fill<LANE_RTREE_QUAL>(LANE_RTREE_QUAL& into);
2581
2582// ------ ------
2583bool
2585 if (veh->getLaneChangeModel().isOpposite()) {
2586 return false;
2587 }
2588 if (myEdge->isInternal()) {
2589 return true;
2590 }
2591 if (veh->succEdge(1) == nullptr) {
2592 assert((int)veh->getBestLanes().size() > veh->getLaneIndex());
2593 if (veh->getBestLanes()[veh->getLaneIndex()].bestLaneOffset == 0) {
2594 return true;
2595 } else {
2596 return false;
2597 }
2598 }
2599 std::vector<MSLink*>::const_iterator link = succLinkSec(*veh, 1, *this, veh->getBestLanesContinuation());
2600 return (link != myLinks.end());
2601}
2602
2603
2604void
2606 myNeedsCollisionCheck = true;
2607 std::vector<MSVehicle*>& buffered = myVehBuffer.getContainer();
2608 sort(buffered.begin(), buffered.end(), vehicle_position_sorter(this));
2609 for (MSVehicle* const veh : buffered) {
2610 assert(veh->getLane() == this);
2611 myVehicles.insert(myVehicles.begin(), veh);
2612 myBruttoVehicleLengthSum += veh->getVehicleType().getLengthWithGap();
2613 myNettoVehicleLengthSum += veh->getVehicleType().getLength();
2614 //if (true) std::cout << SIMTIME << " integrateNewVehicle lane=" << getID() << " veh=" << veh->getID() << " (on lane " << veh->getLane()->getID() << ") into lane=" << getID() << " myBrutto=" << myBruttoVehicleLengthSum << "\n";
2616 }
2617 buffered.clear();
2619 //std::cout << SIMTIME << " integrateNewVehicle lane=" << getID() << " myVehicles1=" << toString(myVehicles);
2620 if (MSGlobals::gLateralResolution > 0 || myOpposite != nullptr) {
2621 sort(myVehicles.begin(), myVehicles.end(), vehicle_natural_position_sorter(this));
2622 }
2624#ifdef DEBUG_VEHICLE_CONTAINER
2625 if (DEBUG_COND) std::cout << SIMTIME << " integrateNewVehicle lane=" << getID()
2626 << " vehicles=" << toString(myVehicles) << " partials=" << toString(myPartialVehicles) << "\n";
2627#endif
2628}
2629
2630
2631void
2633 if (myPartialVehicles.size() > 1) {
2635 }
2636}
2637
2638
2639void
2641 if (myManeuverReservations.size() > 1) {
2642#ifdef DEBUG_CONTEXT
2643 if (DEBUG_COND) {
2644 std::cout << "sortManeuverReservations on lane " << getID()
2645 << "\nBefore sort: " << toString(myManeuverReservations) << std::endl;
2646 }
2647#endif
2649#ifdef DEBUG_CONTEXT
2650 if (DEBUG_COND) {
2651 std::cout << "After sort: " << toString(myManeuverReservations) << std::endl;
2652 }
2653#endif
2654 }
2655}
2656
2657
2658bool
2660 return myEdge->isInternal();
2661}
2662
2663
2664bool
2666 return myEdge->isNormal();
2667}
2668
2669
2670bool
2672 return myEdge->isCrossing();
2673}
2674
2675
2676bool
2678 return isCrossing() && getIncomingLanes()[0].viaLink->getOffState() == LINKSTATE_MAJOR;
2679}
2680
2681
2682bool
2684 return myEdge->isWalkingArea();
2685}
2686
2687
2688MSVehicle*
2690 if (myVehicles.size() == 0) {
2691 return nullptr;
2692 }
2693 return myVehicles.front();
2694}
2695
2696
2697MSVehicle*
2699 if (myVehicles.size() == 0) {
2700 return nullptr;
2701 }
2702 return myVehicles.back();
2703}
2704
2705
2706MSVehicle*
2708 // all vehicles in myVehicles should have positions smaller or equal to
2709 // those in myPartialVehicles (unless we're on a bidi-lane)
2710 if (myVehicles.size() > 0) {
2711 if (myBidiLane != nullptr && myPartialVehicles.size() > 0) {
2712 if (myVehicles.front()->getPositionOnLane() > myPartialVehicles.front()->getPositionOnLane(this)) {
2713 return myPartialVehicles.front();
2714 }
2715 }
2716 return myVehicles.front();
2717 }
2718 if (myPartialVehicles.size() > 0) {
2719 return myPartialVehicles.front();
2720 }
2721 return nullptr;
2722}
2723
2724
2725MSVehicle*
2727 MSVehicle* result = nullptr;
2728 if (myVehicles.size() > 0) {
2729 result = myVehicles.back();
2730 }
2731 if (myPartialVehicles.size() > 0
2732 && (result == nullptr || result->getPositionOnLane(this) < myPartialVehicles.back()->getPositionOnLane(this))) {
2733 result = myPartialVehicles.back();
2734 }
2735 return result;
2736}
2737
2738
2739std::vector<MSLink*>::const_iterator
2740MSLane::succLinkSec(const SUMOVehicle& veh, int nRouteSuccs,
2741 const MSLane& succLinkSource, const std::vector<MSLane*>& conts) {
2742 const MSEdge* nRouteEdge = veh.succEdge(nRouteSuccs);
2743 // check whether the vehicle tried to look beyond its route
2744 if (nRouteEdge == nullptr) {
2745 // return end (no succeeding link) if so
2746 return succLinkSource.myLinks.end();
2747 }
2748 // if we are on an internal lane there should only be one link and it must be allowed
2749 if (succLinkSource.isInternal()) {
2750 assert(succLinkSource.myLinks.size() == 1);
2751 // could have been disallowed dynamically with a rerouter or via TraCI
2752 // assert(succLinkSource.myLinks[0]->getLane()->allowsVehicleClass(veh.getVehicleType().getVehicleClass()));
2753 return succLinkSource.myLinks.begin();
2754 }
2755 // a link may be used if
2756 // 1) there is a destination lane ((*link)->getLane()!=0)
2757 // 2) the destination lane belongs to the next edge in route ((*link)->getLane()->myEdge == nRouteEdge)
2758 // 3) the destination lane allows the vehicle's class ((*link)->getLane()->allowsVehicleClass(veh.getVehicleClass()))
2759
2760 // there should be a link which leads to the next desired lane our route in "conts" (built in "getBestLanes")
2761 // "conts" stores the best continuations of our current lane
2762 // we should never return an arbitrary link since this may cause collisions
2763
2764 if (nRouteSuccs < (int)conts.size()) {
2765 // we go through the links in our list and return the matching one
2766 for (std::vector<MSLink*>::const_iterator link = succLinkSource.myLinks.begin(); link != succLinkSource.myLinks.end(); ++link) {
2767 if ((*link)->getLane() != nullptr && (*link)->getLane()->myEdge == nRouteEdge
2768 && (*link)->getLane()->allowsVehicleClass(veh.getVClass())
2769 && ((*link)->getViaLane() == nullptr || (*link)->getViaLane()->allowsVehicleClass(veh.getVClass()))) {
2770 // we should use the link if it connects us to the best lane
2771 if ((*link)->getLane() == conts[nRouteSuccs]) {
2772 return link;
2773 }
2774 }
2775 }
2776 } else {
2777 // the source lane is a dead end (no continuations exist)
2778 return succLinkSource.myLinks.end();
2779 }
2780 // the only case where this should happen is for a disconnected route (deliberately ignored)
2781#ifdef DEBUG_NO_CONNECTION
2782 // the "'" around the ids are missing intentionally in the message below because it slows messaging down, resulting in test timeouts
2783 WRITE_WARNING("Could not find connection between lane " + succLinkSource.getID() + " and lane " + conts[nRouteSuccs]->getID() +
2784 " for vehicle " + veh.getID() + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
2785#endif
2786 return succLinkSource.myLinks.end();
2787}
2788
2789
2790const MSLink*
2791MSLane::getLinkTo(const MSLane* const target) const {
2792 const bool internal = target->isInternal();
2793 for (const MSLink* const l : myLinks) {
2794 if ((internal && l->getViaLane() == target) || (!internal && l->getLane() == target)) {
2795 return l;
2796 }
2797 }
2798 return nullptr;
2799}
2800
2801
2802const MSLane*
2803MSLane::getInternalFollowingLane(const MSLane* const target) const {
2804 for (const MSLink* const l : myLinks) {
2805 if (l->getLane() == target) {
2806 return l->getViaLane();
2807 }
2808 }
2809 return nullptr;
2810}
2811
2812
2813const MSLink*
2815 if (!isInternal()) {
2816 return nullptr;
2817 }
2818 const MSLane* internal = this;
2819 const MSLane* lane = this->getCanonicalPredecessorLane();
2820 assert(lane != nullptr);
2821 while (lane->isInternal()) {
2822 internal = lane;
2823 lane = lane->getCanonicalPredecessorLane();
2824 assert(lane != nullptr);
2825 }
2826 return lane->getLinkTo(internal);
2827}
2828
2829
2830void
2831MSLane::setMaxSpeed(const double val, const bool modified, const double jamThreshold) {
2832 myMaxSpeed = val;
2833 mySpeedModified = modified;
2837 while (first != nullptr) {
2838 first->setSpeed(val, SIMSTEP, jamThreshold, myIndex);
2839 first = first->getNextSegment();
2840 }
2841 }
2842}
2843
2844
2845void
2850
2851
2852void
2854 myLength = val;
2856}
2857
2858
2859void
2861 //if (getID() == "disabled_lane") std::cout << SIMTIME << " swapAfterLaneChange lane=" << getID() << " myVehicles=" << toString(myVehicles) << " myTmpVehicles=" << toString(myTmpVehicles) << "\n";
2863 myTmpVehicles.clear();
2864 // this needs to be done after finishing lane-changing for all lanes on the
2865 // current edge (MSLaneChanger::updateLanes())
2867 if (MSGlobals::gSublane && getOpposite() != nullptr) {
2869 }
2870 if (myBidiLane != nullptr) {
2872 }
2873}
2874
2875
2876MSVehicle*
2877MSLane::removeVehicle(MSVehicle* remVehicle, MSMoveReminder::Notification notification, bool notify) {
2878 assert(remVehicle->getLane() == this);
2879 for (MSLane::VehCont::iterator it = myVehicles.begin(); it < myVehicles.end(); it++) {
2880 if (remVehicle == *it) {
2881 if (notify) {
2882 remVehicle->leaveLane(notification);
2883 }
2884 myVehicles.erase(it);
2887 break;
2888 }
2889 }
2890 return remVehicle;
2891}
2892
2893
2894MSLane*
2895MSLane::getParallelLane(int offset, bool includeOpposite) const {
2896 return myEdge->parallelLane(this, offset, includeOpposite);
2897}
2898
2899
2900void
2902 IncomingLaneInfo ili;
2903 ili.lane = lane;
2904 ili.viaLink = viaLink;
2905 ili.length = lane->getLength();
2906 myIncomingLanes.push_back(ili);
2907}
2908
2909
2910void
2911MSLane::addApproachingLane(MSLane* lane, bool warnMultiCon) {
2912 MSEdge* approachingEdge = &lane->getEdge();
2913 if (myApproachingLanes.find(approachingEdge) == myApproachingLanes.end()) {
2914 myApproachingLanes[approachingEdge] = std::vector<MSLane*>();
2915 } else if (!approachingEdge->isInternal() && warnMultiCon) {
2916 // whenever a normal edge connects twice, there is a corresponding
2917 // internal edge wich connects twice, one warning is sufficient
2918 WRITE_WARNINGF(TL("Lane '%' is approached multiple times from edge '%'. This may cause collisions."),
2919 getID(), approachingEdge->getID());
2920 }
2921 myApproachingLanes[approachingEdge].push_back(lane);
2922}
2923
2924
2925bool
2927 for (MSLink* link : lane->getLinkCont()) {
2928 if (link->getLane() == this && (link->getPermissions() & svc) == svc) {
2929 return true;
2930 }
2931 }
2932 return false;
2933}
2934
2935
2936double MSLane::getMissingRearGap(const MSVehicle* leader, double backOffset, double leaderSpeed) const {
2937 // this follows the same logic as getFollowerOnConsecutive. we do a tree
2938 // search and check for the vehicle with the largest missing rear gap within
2939 // relevant range
2940 double result = 0;
2941 const double leaderDecel = leader->getCarFollowModel().getMaxDecel();
2942 CLeaderDist followerInfo = getFollowersOnConsecutive(leader, backOffset, false)[0];
2943 const MSVehicle* v = followerInfo.first;
2944 if (v != nullptr) {
2945 result = v->getCarFollowModel().getSecureGap(v, leader, v->getSpeed(), leaderSpeed, leaderDecel) - followerInfo.second;
2946 }
2947 return result;
2948}
2949
2950
2951double
2954 const double maxSpeed = getSpeedLimit() * vc.getMaxSpeedFactor();
2955 // NOTE: For the euler update this is an upper bound on the actual braking distance (see ticket #860)
2956 // impose a hard bound due to visibility / common sense to avoid unnecessary computation if there are strange vehicles in the fleet
2957 const double minDecel = isRailway(myPermissions) ? vc.getMinDecelerationRail() : vc.getMinDeceleration();
2958 return MIN2(maxSpeed * maxSpeed * 0.5 / minDecel + vc.getMaxMinGap(),
2959 myPermissions == SVC_SHIP ? 10000.0 : 1000.0);
2960}
2961
2962
2963std::pair<MSVehicle* const, double>
2964MSLane::getLeader(const MSVehicle* veh, const double vehPos, const std::vector<MSLane*>& bestLaneConts, double dist, bool checkTmpVehicles) const {
2965 // get the leading vehicle for (shadow) veh
2966 // XXX this only works as long as all lanes of an edge have equal length
2967#ifdef DEBUG_CONTEXT
2968 if (DEBUG_COND2(veh)) {
2969 std::cout << " getLeader lane=" << getID() << " ego=" << veh->getID() << " vehs=" << toString(myVehicles) << " tmpVehs=" << toString(myTmpVehicles) << "\n";
2970 }
2971#endif
2972 if (checkTmpVehicles) {
2973 for (VehCont::const_iterator last = myTmpVehicles.begin(); last != myTmpVehicles.end(); ++last) {
2974 // XXX refactor leaderInfo to use a const vehicle all the way through the call hierarchy
2975 MSVehicle* pred = (MSVehicle*)*last;
2976 if (pred == veh) {
2977 continue;
2978 }
2979#ifdef DEBUG_CONTEXT
2980 if (DEBUG_COND2(veh)) {
2981 std::cout << std::setprecision(gPrecision) << " getLeader lane=" << getID() << " ego=" << veh->getID() << " egoPos=" << vehPos << " pred=" << pred->getID() << " predPos=" << pred->getPositionOnLane() << "\n";
2982 }
2983#endif
2984 if (pred->getPositionOnLane() >= vehPos) {
2985 return std::pair<MSVehicle* const, double>(pred, pred->getBackPositionOnLane(this) - veh->getVehicleType().getMinGap() - vehPos);
2986 }
2987 }
2988 } else {
2989 for (AnyVehicleIterator last = anyVehiclesBegin(); last != anyVehiclesEnd(); ++last) {
2990 // XXX refactor leaderInfo to use a const vehicle all the way through the call hierarchy
2991 MSVehicle* pred = (MSVehicle*)*last;
2992 if (pred == veh) {
2993 continue;
2994 }
2995#ifdef DEBUG_CONTEXT
2996 if (DEBUG_COND2(veh)) {
2997 std::cout << " getLeader lane=" << getID() << " ego=" << veh->getID() << " egoPos=" << vehPos
2998 << " pred=" << pred->getID() << " predPos=" << pred->getPositionOnLane(this) << " predBack=" << pred->getBackPositionOnLane(this) << "\n";
2999 }
3000#endif
3001 if (pred->getPositionOnLane(this) >= vehPos) {
3003 && pred->getLaneChangeModel().isOpposite()
3005 && pred->getLaneChangeModel().getShadowLane() == this) {
3006 // skip non-overlapping shadow
3007 continue;
3008 }
3009 return std::pair<MSVehicle* const, double>(pred, pred->getBackPositionOnLane(this) - veh->getVehicleType().getMinGap() - vehPos);
3010 }
3011 }
3012 }
3013 // XXX from here on the code mirrors MSLaneChanger::getRealLeader
3014 if (bestLaneConts.size() > 0) {
3015 double seen = getLength() - vehPos;
3016 double speed = veh->getSpeed();
3017 if (dist < 0) {
3018 dist = veh->getCarFollowModel().brakeGap(speed) + veh->getVehicleType().getMinGap();
3019 }
3020#ifdef DEBUG_CONTEXT
3021 if (DEBUG_COND2(veh)) {
3022 std::cout << " getLeader lane=" << getID() << " seen=" << seen << " dist=" << dist << "\n";
3023 }
3024#endif
3025 if (seen > dist) {
3026 return std::pair<MSVehicle* const, double>(static_cast<MSVehicle*>(nullptr), -1);
3027 }
3028 return getLeaderOnConsecutive(dist, seen, speed, *veh, bestLaneConts);
3029 } else {
3030 return std::make_pair(static_cast<MSVehicle*>(nullptr), -1);
3031 }
3032}
3033
3034
3035std::pair<MSVehicle* const, double>
3036MSLane::getLeaderOnConsecutive(double dist, double seen, double speed, const MSVehicle& veh,
3037 const std::vector<MSLane*>& bestLaneConts, bool considerCrossingFoes) const {
3038#ifdef DEBUG_CONTEXT
3039 if (DEBUG_COND2(&veh)) {
3040 std::cout << " getLeaderOnConsecutive lane=" << getID() << " ego=" << veh.getID() << " seen=" << seen << " dist=" << dist << " conts=" << toString(bestLaneConts) << "\n";
3041 }
3042#endif
3043 if (seen > dist && !isInternal()) {
3044 return std::make_pair(static_cast<MSVehicle*>(nullptr), -1);
3045 }
3046 int view = 1;
3047 // loop over following lanes
3048 if (myPartialVehicles.size() > 0) {
3049 // XXX
3050 MSVehicle* pred = myPartialVehicles.front();
3051 const double gap = seen - (getLength() - pred->getBackPositionOnLane(this)) - veh.getVehicleType().getMinGap();
3052#ifdef DEBUG_CONTEXT
3053 if (DEBUG_COND2(&veh)) {
3054 std::cout << " predGap=" << gap << " partials=" << toString(myPartialVehicles) << "\n";
3055 }
3056#endif
3057 // make sure pred is really a leader and not doing continous lane-changing behind ego
3058 if (gap > 0) {
3059 return std::pair<MSVehicle* const, double>(pred, gap);
3060 }
3061 }
3062#ifdef DEBUG_CONTEXT
3063 if (DEBUG_COND2(&veh)) {
3064 gDebugFlag1 = true;
3065 }
3066#endif
3067 const MSLane* nextLane = this;
3068 do {
3069 nextLane->getVehiclesSecure(); // lock against running sim when called from GUI for time gap coloring
3070 // get the next link used
3071 std::vector<MSLink*>::const_iterator link = succLinkSec(veh, view, *nextLane, bestLaneConts);
3072 if (nextLane->isLinkEnd(link) && view < veh.getRoute().size() - veh.getRoutePosition()) {
3073 const MSEdge* nextEdge = *(veh.getCurrentRouteEdge() + view);
3074 if (nextEdge->getNumLanes() == 1) {
3075 // lanes are unambiguous on the next route edge, continue beyond bestLaneConts
3076 for (link = nextLane->getLinkCont().begin(); link < nextLane->getLinkCont().end(); link++) {
3077 if ((*link)->getLane() == nextEdge->getLanes().front()) {
3078 break;
3079 }
3080 }
3081 }
3082 }
3083 if (nextLane->isLinkEnd(link)) {
3084#ifdef DEBUG_CONTEXT
3085 if (DEBUG_COND2(&veh)) {
3086 std::cout << " cannot continue after nextLane=" << nextLane->getID() << "\n";
3087 }
3088#endif
3089 nextLane->releaseVehicles();
3090 break;
3091 }
3092 // check for link leaders
3093 const bool laneChanging = veh.getLane() != this;
3094 const MSLink::LinkLeaders linkLeaders = (*link)->getLeaderInfo(&veh, seen);
3095 nextLane->releaseVehicles();
3096 if (linkLeaders.size() > 0) {
3097 std::pair<MSVehicle*, double> result;
3098 double shortestGap = std::numeric_limits<double>::max();
3099 for (auto ll : linkLeaders) {
3100 double gap = ll.vehAndGap.second;
3101 MSVehicle* lVeh = ll.vehAndGap.first;
3102 if (lVeh != nullptr) {
3103 // leader is a vehicle, not a pedestrian
3104 gap += lVeh->getCarFollowModel().brakeGap(lVeh->getSpeed(), lVeh->getCarFollowModel().getMaxDecel(), 0);
3105 }
3106#ifdef DEBUG_CONTEXT
3107 if (DEBUG_COND2(&veh)) {
3108 std::cout << " linkLeader candidate " << Named::getIDSecure(lVeh)
3109 << " isLeader=" << veh.isLeader(*link, lVeh, ll.vehAndGap.second)
3110 << " gap=" << ll.vehAndGap.second
3111 << " gap+brakeing=" << gap
3112 << "\n";
3113 }
3114#endif
3115 // skip vehicles which do not share the outgoing edge (to get only real leader vehicles in TraCI #13842)
3116 if (!considerCrossingFoes && !ll.sameTarget()) {
3117 continue;
3118 }
3119 // in the context of lane-changing, all candidates are leaders
3120 if (lVeh != nullptr && !laneChanging && !veh.isLeader(*link, lVeh, ll.vehAndGap.second)) {
3121 continue;
3122 }
3123 if (gap < shortestGap) {
3124 shortestGap = gap;
3125 if (ll.vehAndGap.second < 0 && !MSGlobals::gComputeLC) {
3126 // can always continue up to the stop line or crossing point
3127 // @todo: figure out whether this should also impact lane changing
3128 ll.vehAndGap.second = MAX2(seen - nextLane->getLength(), ll.distToCrossing);
3129 }
3130 result = ll.vehAndGap;
3131 }
3132 }
3133 if (shortestGap != std::numeric_limits<double>::max()) {
3134#ifdef DEBUG_CONTEXT
3135 if (DEBUG_COND2(&veh)) {
3136 std::cout << " found linkLeader after nextLane=" << nextLane->getID() << "\n";
3137 gDebugFlag1 = false;
3138 }
3139#endif
3140 return result;
3141 }
3142 }
3143 bool nextInternal = (*link)->getViaLane() != nullptr;
3144 nextLane = (*link)->getViaLaneOrLane();
3145 if (nextLane == nullptr) {
3146 break;
3147 }
3148 nextLane->getVehiclesSecure(); // lock against running sim when called from GUI for time gap coloring
3149 MSVehicle* leader = nextLane->getLastAnyVehicle();
3150 if (leader != nullptr) {
3151#ifdef DEBUG_CONTEXT
3152 if (DEBUG_COND2(&veh)) {
3153 std::cout << " found leader " << leader->getID() << " on nextLane=" << nextLane->getID() << "\n";
3154 }
3155#endif
3156 const double leaderDist = seen + leader->getBackPositionOnLane(nextLane) - veh.getVehicleType().getMinGap();
3157 nextLane->releaseVehicles();
3158 return std::make_pair(leader, leaderDist);
3159 }
3160 nextLane->releaseVehicles();
3161 if (nextLane->getVehicleMaxSpeed(&veh) < speed) {
3162 dist = veh.getCarFollowModel().brakeGap(nextLane->getVehicleMaxSpeed(&veh));
3163 }
3164 seen += nextLane->getLength();
3165 if (!nextInternal) {
3166 view++;
3167 }
3168 } while (seen <= dist || nextLane->isInternal());
3169#ifdef DEBUG_CONTEXT
3170 gDebugFlag1 = false;
3171#endif
3172 return std::make_pair(static_cast<MSVehicle*>(nullptr), -1);
3173}
3174
3175
3176std::pair<MSVehicle* const, double>
3177MSLane::getCriticalLeader(double dist, double seen, double speed, const MSVehicle& veh) const {
3178#ifdef DEBUG_CONTEXT
3179 if (DEBUG_COND2(&veh)) {
3180 std::cout << SIMTIME << " getCriticalLeader. lane=" << getID() << " veh=" << veh.getID() << "\n";
3181 }
3182#endif
3183 const std::vector<MSLane*>& bestLaneConts = veh.getBestLanesContinuation(this);
3184 std::pair<MSVehicle*, double> result = std::make_pair(static_cast<MSVehicle*>(nullptr), -1);
3185 double safeSpeed = std::numeric_limits<double>::max();
3186 int view = 1;
3187 // loop over following lanes
3188 // @note: we don't check the partial occupator for this lane since it was
3189 // already checked in MSLaneChanger::getRealLeader()
3190 const MSLane* nextLane = this;
3191 SUMOTime arrivalTime = MSNet::getInstance()->getCurrentTimeStep() + TIME2STEPS(seen / MAX2(speed, NUMERICAL_EPS));
3192 do {
3193 // get the next link used
3194 std::vector<MSLink*>::const_iterator link = succLinkSec(veh, view, *nextLane, bestLaneConts);
3195 if (nextLane->isLinkEnd(link) || !(*link)->opened(arrivalTime, speed, speed, veh.getVehicleType().getLength(),
3196 veh.getImpatience(), veh.getCarFollowModel().getMaxDecel(), 0, veh.getLateralPositionOnLane(), nullptr, false, &veh) || (*link)->haveRed()) {
3197 return result;
3198 }
3199 // check for link leaders
3200#ifdef DEBUG_CONTEXT
3201 if (DEBUG_COND2(&veh)) {
3202 gDebugFlag1 = true; // See MSLink::getLeaderInfo
3203 }
3204#endif
3205 const MSLink::LinkLeaders linkLeaders = (*link)->getLeaderInfo(&veh, seen);
3206#ifdef DEBUG_CONTEXT
3207 if (DEBUG_COND2(&veh)) {
3208 gDebugFlag1 = false; // See MSLink::getLeaderInfo
3209 }
3210#endif
3211 for (MSLink::LinkLeaders::const_iterator it = linkLeaders.begin(); it != linkLeaders.end(); ++it) {
3212 const MSVehicle* leader = (*it).vehAndGap.first;
3213 if (leader != nullptr && leader != result.first) {
3214 // XXX ignoring pedestrians here!
3215 // XXX ignoring the fact that the link leader may alread by following us
3216 // XXX ignoring the fact that we may drive up to the crossing point
3217 double tmpSpeed = safeSpeed;
3218 veh.adaptToJunctionLeader((*it).vehAndGap, seen, nullptr, nextLane, tmpSpeed, tmpSpeed, (*it).distToCrossing);
3219#ifdef DEBUG_CONTEXT
3220 if (DEBUG_COND2(&veh)) {
3221 std::cout << " linkLeader=" << leader->getID() << " gap=" << result.second << " tmpSpeed=" << tmpSpeed << " safeSpeed=" << safeSpeed << "\n";
3222 }
3223#endif
3224 if (tmpSpeed < safeSpeed) {
3225 safeSpeed = tmpSpeed;
3226 result = (*it).vehAndGap;
3227 }
3228 }
3229 }
3230 bool nextInternal = (*link)->getViaLane() != nullptr;
3231 nextLane = (*link)->getViaLaneOrLane();
3232 if (nextLane == nullptr) {
3233 break;
3234 }
3235 MSVehicle* leader = nextLane->getLastAnyVehicle();
3236 if (leader != nullptr && leader != result.first) {
3237 const double gap = seen + leader->getBackPositionOnLane(nextLane) - veh.getVehicleType().getMinGap();
3238 const double tmpSpeed = veh.getCarFollowModel().insertionFollowSpeed(&veh, speed, gap, leader->getSpeed(), leader->getCarFollowModel().getMaxDecel(), leader);
3239 if (tmpSpeed < safeSpeed) {
3240 safeSpeed = tmpSpeed;
3241 result = std::make_pair(leader, gap);
3242 }
3243 }
3244 if (nextLane->getVehicleMaxSpeed(&veh) < speed) {
3245 dist = veh.getCarFollowModel().brakeGap(nextLane->getVehicleMaxSpeed(&veh));
3246 }
3247 seen += nextLane->getLength();
3248 if (seen <= dist) {
3249 // delaying the update of arrivalTime and making it conditional to avoid possible integer overflows
3250 arrivalTime += TIME2STEPS(nextLane->getLength() / MAX2(speed, NUMERICAL_EPS));
3251 }
3252 if (!nextInternal) {
3253 view++;
3254 }
3255 } while (seen <= dist || nextLane->isInternal());
3256 return result;
3257}
3258
3259
3260MSLane*
3262 if (myLogicalPredecessorLane == nullptr) {
3264 // get only those edges which connect to this lane
3265 for (MSEdgeVector::iterator i = pred.begin(); i != pred.end();) {
3266 std::vector<IncomingLaneInfo>::const_iterator j = find_if(myIncomingLanes.begin(), myIncomingLanes.end(), edge_finder(*i));
3267 if (j == myIncomingLanes.end()) {
3268 i = pred.erase(i);
3269 } else {
3270 ++i;
3271 }
3272 }
3273 // get the lane with the "straightest" connection
3274 if (pred.size() != 0) {
3275 std::sort(pred.begin(), pred.end(), by_connections_to_sorter(&getEdge()));
3276 MSEdge* best = *pred.begin();
3277 std::vector<IncomingLaneInfo>::const_iterator j = find_if(myIncomingLanes.begin(), myIncomingLanes.end(), edge_finder(best));
3278 myLogicalPredecessorLane = j->lane;
3279 }
3280 }
3282}
3283
3284
3285const MSLane*
3287 if (isInternal()) {
3289 } else {
3290 return this;
3291 }
3292}
3293
3294
3295const MSLane*
3297 if (isInternal()) {
3299 } else {
3300 return this;
3301 }
3302}
3303
3304
3305MSLane*
3307 for (const IncomingLaneInfo& cand : myIncomingLanes) {
3308 if (&(cand.lane->getEdge()) == &fromEdge) {
3309 return cand.lane;
3310 }
3311 }
3312 return nullptr;
3313}
3314
3315
3316MSLane*
3318 if (myCanonicalPredecessorLane != nullptr) {
3320 }
3321 if (myIncomingLanes.empty()) {
3322 return nullptr;
3323 }
3324 // myCanonicalPredecessorLane has not yet been determined and there exist incoming lanes
3325 // get the lane with the priorized (or if this does not apply the "straightest") connection
3326 const auto bestLane = std::min_element(myIncomingLanes.begin(), myIncomingLanes.end(), incoming_lane_priority_sorter(this));
3327 {
3328#ifdef HAVE_FOX
3329 ScopedLocker<> lock(myLeaderInfoMutex, MSGlobals::gNumSimThreads > 1);
3330#endif
3331 myCanonicalPredecessorLane = bestLane->lane;
3332 }
3333#ifdef DEBUG_LANE_SORTER
3334 std::cout << "\nBest predecessor lane for lane '" << myID << "': '" << myCanonicalPredecessorLane->getID() << "'" << std::endl;
3335#endif
3337}
3338
3339
3340MSLane*
3342 if (myCanonicalSuccessorLane != nullptr) {
3344 }
3345 if (myLinks.empty()) {
3346 return nullptr;
3347 }
3348 // myCanonicalSuccessorLane has not yet been determined and there exist outgoing links
3349 std::vector<MSLink*> candidateLinks = myLinks;
3350 // get the lane with the priorized (or if this does not apply the "straightest") connection
3351 std::sort(candidateLinks.begin(), candidateLinks.end(), outgoing_lane_priority_sorter(this));
3352 MSLane* best = (*candidateLinks.begin())->getViaLaneOrLane();
3353#ifdef DEBUG_LANE_SORTER
3354 std::cout << "\nBest successor lane for lane '" << myID << "': '" << best->getID() << "'" << std::endl;
3355#endif
3358}
3359
3360
3363 const MSLane* const pred = getLogicalPredecessorLane();
3364 if (pred == nullptr) {
3365 return LINKSTATE_DEADEND;
3366 } else {
3367 return pred->getLinkTo(this)->getState();
3368 }
3369}
3370
3371
3372const std::vector<std::pair<const MSLane*, const MSEdge*> >
3374 std::vector<std::pair<const MSLane*, const MSEdge*> > result;
3375 for (const MSLink* link : myLinks) {
3376 assert(link->getLane() != nullptr);
3377 result.push_back(std::make_pair(link->getLane(), link->getViaLane() == nullptr ? nullptr : &link->getViaLane()->getEdge()));
3378 }
3379 return result;
3380}
3381
3382std::vector<const MSLane*>
3384 std::vector<const MSLane*> result = {};
3385 for (std::map<MSEdge*, std::vector<MSLane*> >::const_iterator it = myApproachingLanes.begin(); it != myApproachingLanes.end(); ++it) {
3386 for (std::vector<MSLane*>::const_iterator it_lane = (*it).second.begin(); it_lane != (*it).second.end(); ++it_lane) {
3387 if (!((*it_lane)->isInternal())) {
3388 result.push_back(*it_lane);
3389 }
3390 }
3391 }
3392 return result;
3393}
3394
3395
3396void
3401
3402
3403void
3408
3409
3410int
3412 for (std::vector<MSLink*>::const_iterator i = myLinks.begin(); i != myLinks.end(); ++i) {
3413 if ((*i)->getLane()->isCrossing()) {
3414 return (int)(i - myLinks.begin());
3415 }
3416 }
3417 return -1;
3418}
3419
3420// ------------ Current state retrieval
3421double
3423 double sum = 0;
3424 if (myPartialVehicles.size() > 0) {
3425 const MSLane* bidi = getBidiLane();
3426 for (MSVehicle* cand : myPartialVehicles) {
3427 if (MSGlobals::gSublane && cand->getLaneChangeModel().getShadowLane() == this) {
3428 continue;
3429 }
3430 if (cand->getLane() == bidi) {
3431 sum += (brutto ? cand->getVehicleType().getLengthWithGap() : cand->getVehicleType().getLength());
3432 } else {
3433 sum += myLength - cand->getBackPositionOnLane(this);
3434 }
3435 }
3436 }
3437 return sum;
3438}
3439
3440double
3443 double fractions = getFractionalVehicleLength(true);
3444 if (myVehicles.size() != 0) {
3445 MSVehicle* lastVeh = myVehicles.front();
3446 if (lastVeh->getPositionOnLane() < lastVeh->getVehicleType().getLength()) {
3447 fractions -= (lastVeh->getVehicleType().getLength() - lastVeh->getPositionOnLane());
3448 }
3449 }
3451 return MIN2(1., (myBruttoVehicleLengthSum + fractions) / myLength);
3452}
3453
3454
3455double
3458 double fractions = getFractionalVehicleLength(false);
3459 if (myVehicles.size() != 0) {
3460 MSVehicle* lastVeh = myVehicles.front();
3461 if (lastVeh->getPositionOnLane() < lastVeh->getVehicleType().getLength()) {
3462 fractions -= (lastVeh->getVehicleType().getLength() - lastVeh->getPositionOnLane());
3463 }
3464 }
3466 return (myNettoVehicleLengthSum + fractions) / myLength;
3467}
3468
3469
3470double
3472 if (myVehicles.size() == 0) {
3473 return 0;
3474 }
3475 double wtime = 0;
3476 for (VehCont::const_iterator i = myVehicles.begin(); i != myVehicles.end(); ++i) {
3477 wtime += (*i)->getWaitingSeconds();
3478 }
3479 return wtime;
3480}
3481
3482
3483double
3485 if (myVehicles.size() == 0) {
3486 return myMaxSpeed;
3487 }
3488 double v = 0;
3489 int numVehs = 0;
3490 for (const MSVehicle* const veh : getVehiclesSecure()) {
3491 if (!veh->isStopped() || !myEdge->hasLaneChanger()) {
3492 v += veh->getSpeed();
3493 numVehs++;
3494 }
3495 }
3497 if (numVehs == 0) {
3498 return myMaxSpeed;
3499 }
3500 return v / numVehs;
3501}
3502
3503
3504double
3506 // @note: redundant code with getMeanSpeed to avoid extra checks in a function that is called very often
3507 if (myVehicles.size() == 0) {
3508 return myMaxSpeed;
3509 }
3510 double v = 0;
3511 int numBikes = 0;
3512 for (MSVehicle* veh : getVehiclesSecure()) {
3513 if (veh->getVClass() == SVC_BICYCLE) {
3514 v += veh->getSpeed();
3515 numBikes++;
3516 }
3517 }
3518 double ret;
3519 if (numBikes > 0) {
3520 ret = v / (double) myVehicles.size();
3521 } else {
3522 ret = myMaxSpeed;
3523 }
3525 return ret;
3526}
3527
3528
3529double
3531 double ret = 0;
3532 const MSLane::VehCont& vehs = getVehiclesSecure();
3533 if (vehs.size() == 0) {
3535 return 0;
3536 }
3537 for (MSLane::VehCont::const_iterator i = vehs.begin(); i != vehs.end(); ++i) {
3538 double sv = (*i)->getHarmonoise_NoiseEmissions();
3539 ret += (double) pow(10., (sv / 10.));
3540 }
3542 return HelpersHarmonoise::sum(ret);
3543}
3544
3545
3546int
3548 const double pos1 = v1->getBackPositionOnLane(myLane);
3549 const double pos2 = v2->getBackPositionOnLane(myLane);
3550 if (pos1 != pos2) {
3551 return pos1 > pos2;
3552 } else {
3553 return v1->getNumericalID() > v2->getNumericalID();
3554 }
3555}
3556
3557
3558int
3560 const double pos1 = v1->getBackPositionOnLane(myLane);
3561 const double pos2 = v2->getBackPositionOnLane(myLane);
3562 if (pos1 != pos2) {
3563 return pos1 < pos2;
3564 } else {
3566 }
3567}
3568
3569
3571 myEdge(e),
3572 myLaneDir(e->getLanes()[0]->getShape().angleAt2D(0)) {
3573}
3574
3575
3576int
3577MSLane::by_connections_to_sorter::operator()(const MSEdge* const e1, const MSEdge* const e2) const {
3578// std::cout << "\nby_connections_to_sorter()";
3579
3580 const std::vector<MSLane*>* ae1 = e1->allowedLanes(*myEdge);
3581 const std::vector<MSLane*>* ae2 = e2->allowedLanes(*myEdge);
3582 double s1 = 0;
3583 if (ae1 != nullptr && ae1->size() != 0) {
3584// std::cout << "\nsize 1 = " << ae1->size()
3585// << " anglediff 1 = " << fabs(GeomHelper::angleDiff((*ae1)[0]->getShape().angleAt2D(0), myLaneDir)) / M_PI / 2.
3586// << "\nallowed lanes: ";
3587// for (std::vector<MSLane*>::const_iterator j = ae1->begin(); j != ae1->end(); ++j){
3588// std::cout << "\n" << (*j)->getID();
3589// }
3590 s1 = (double) ae1->size() + fabs(GeomHelper::angleDiff((*ae1)[0]->getShape().angleAt2D(0), myLaneDir)) / M_PI / 2.;
3591 }
3592 double s2 = 0;
3593 if (ae2 != nullptr && ae2->size() != 0) {
3594// std::cout << "\nsize 2 = " << ae2->size()
3595// << " anglediff 2 = " << fabs(GeomHelper::angleDiff((*ae2)[0]->getShape().angleAt2D(0), myLaneDir)) / M_PI / 2.
3596// << "\nallowed lanes: ";
3597// for (std::vector<MSLane*>::const_iterator j = ae2->begin(); j != ae2->end(); ++j){
3598// std::cout << "\n" << (*j)->getID();
3599// }
3600 s2 = (double) ae2->size() + fabs(GeomHelper::angleDiff((*ae2)[0]->getShape().angleAt2D(0), myLaneDir)) / M_PI / 2.;
3601 }
3602
3603// std::cout << "\ne1 = " << e1->getID() << " e2 = " << e2->getID()
3604// << "\ns1 = " << s1 << " s2 = " << s2
3605// << std::endl;
3606
3607 return s1 < s2;
3608}
3609
3610
3612 myLane(targetLane),
3613 myLaneDir(targetLane->getShape().angleAt2D(0)) {}
3614
3615int
3617 const MSLane* noninternal1 = laneInfo1.lane;
3618 while (noninternal1->isInternal()) {
3619 assert(noninternal1->getIncomingLanes().size() == 1);
3620 noninternal1 = noninternal1->getIncomingLanes()[0].lane;
3621 }
3622 MSLane* noninternal2 = laneInfo2.lane;
3623 while (noninternal2->isInternal()) {
3624 assert(noninternal2->getIncomingLanes().size() == 1);
3625 noninternal2 = noninternal2->getIncomingLanes()[0].lane;
3626 }
3627
3628 const MSLink* link1 = noninternal1->getLinkTo(myLane);
3629 const MSLink* link2 = noninternal2->getLinkTo(myLane);
3630
3631#ifdef DEBUG_LANE_SORTER
3632 std::cout << "\nincoming_lane_priority sorter()\n"
3633 << "noninternal predecessor for lane '" << laneInfo1.lane->getID()
3634 << "': '" << noninternal1->getID() << "'\n"
3635 << "noninternal predecessor for lane '" << laneInfo2.lane->getID()
3636 << "': '" << noninternal2->getID() << "'\n";
3637#endif
3638
3639 assert(laneInfo1.lane->isInternal() || link1 == laneInfo1.viaLink);
3640 assert(link1 != 0);
3641 assert(link2 != 0);
3642
3643 // check priority between links
3644 bool priorized1 = true;
3645 bool priorized2 = true;
3646
3647#ifdef DEBUG_LANE_SORTER
3648 std::cout << "FoeLinks of '" << noninternal1->getID() << "'" << std::endl;
3649#endif
3650 for (const MSLink* const foeLink : link1->getFoeLinks()) {
3651#ifdef DEBUG_LANE_SORTER
3652 std::cout << foeLink->getLaneBefore()->getID() << std::endl;
3653#endif
3654 if (foeLink == link2) {
3655 priorized1 = false;
3656 break;
3657 }
3658 }
3659
3660#ifdef DEBUG_LANE_SORTER
3661 std::cout << "FoeLinks of '" << noninternal2->getID() << "'" << std::endl;
3662#endif
3663 for (const MSLink* const foeLink : link2->getFoeLinks()) {
3664#ifdef DEBUG_LANE_SORTER
3665 std::cout << foeLink->getLaneBefore()->getID() << std::endl;
3666#endif
3667 // either link1 is priorized, or it should not appear in link2's foes
3668 if (foeLink == link1) {
3669 priorized2 = false;
3670 break;
3671 }
3672 }
3673 // if one link is subordinate, the other must be priorized (except for
3674 // traffic lights where mutual response is permitted to handle stuck-on-red
3675 // situation)
3676 if (priorized1 != priorized2) {
3677 return priorized1;
3678 }
3679
3680 // both are priorized, compare angle difference
3681 double d1 = fabs(GeomHelper::angleDiff(noninternal1->getShape().angleAt2D(0), myLaneDir));
3682 double d2 = fabs(GeomHelper::angleDiff(noninternal2->getShape().angleAt2D(0), myLaneDir));
3683
3684 return d2 > d1;
3685}
3686
3687
3688
3690 myLaneDir(sourceLane->getShape().angleAt2D(0)) {}
3691
3692int
3694 const MSLane* target1 = link1->getLane();
3695 const MSLane* target2 = link2->getLane();
3696 if (target2 == nullptr) {
3697 return true;
3698 }
3699 if (target1 == nullptr) {
3700 return false;
3701 }
3702
3703#ifdef DEBUG_LANE_SORTER
3704 std::cout << "\noutgoing_lane_priority sorter()\n"
3705 << "noninternal successors for lane '" << myLane->getID()
3706 << "': '" << target1->getID() << "' and "
3707 << "'" << target2->getID() << "'\n";
3708#endif
3709
3710 // priority of targets
3711 int priority1 = target1->getEdge().getPriority();
3712 int priority2 = target2->getEdge().getPriority();
3713
3714 if (priority1 != priority2) {
3715 return priority1 > priority2;
3716 }
3717
3718 // if priority of targets coincides, use angle difference
3719
3720 // both are priorized, compare angle difference
3721 double d1 = fabs(GeomHelper::angleDiff(target1->getShape().angleAt2D(0), myLaneDir));
3722 double d2 = fabs(GeomHelper::angleDiff(target2->getShape().angleAt2D(0), myLaneDir));
3723
3724 return d2 > d1;
3725}
3726
3727void
3731
3732
3733void
3737
3738bool
3740 for (const MSLink* link : myLinks) {
3741 if (link->getApproaching().size() > 0) {
3742 return true;
3743 }
3744 }
3745 return false;
3746}
3747
3748void
3750 const bool toRailJunction = myLinks.size() > 0 && (
3753 const bool hasVehicles = myVehicles.size() > 0;
3754 if (hasVehicles || (toRailJunction && hasApproaching())) {
3757 if (hasVehicles) {
3760 out.closeTag();
3761 }
3762 if (toRailJunction) {
3763 for (const MSLink* link : myLinks) {
3764 if (link->getApproaching().size() > 0) {
3766 out.writeAttr(SUMO_ATTR_TO, link->getViaLaneOrLane()->getID());
3767 for (auto item : link->getApproaching()) {
3769 out.writeAttr(SUMO_ATTR_ID, item.first->getID());
3770 out.writeAttr(SUMO_ATTR_ARRIVALTIME, item.second.arrivalTime);
3771 out.writeAttr(SUMO_ATTR_ARRIVALSPEED, item.second.arrivalSpeed);
3772 out.writeAttr(SUMO_ATTR_DEPARTSPEED, item.second.leaveSpeed);
3773 out.writeAttr(SUMO_ATTR_REQUEST, item.second.willPass);
3774 out.writeAttr(SUMO_ATTR_ARRIVALSPEEDBRAKING, item.second.arrivalSpeedBraking);
3775 out.writeAttr(SUMO_ATTR_WAITINGTIME, item.second.waitingTime);
3776 out.writeAttr(SUMO_ATTR_DISTANCE, item.second.dist);
3777 if (item.second.latOffset != 0) {
3778 out.writeAttr(SUMO_ATTR_POSITION_LAT, item.second.latOffset);
3779 }
3780 out.closeTag();
3781 }
3782 out.closeTag();
3783 }
3784 }
3785 }
3786 out.closeTag();
3787 }
3788}
3789
3790void
3792 myVehicles.clear();
3793 myParkingVehicles.clear();
3794 myPartialVehicles.clear();
3795 myManeuverReservations.clear();
3802 for (MSLink* link : myLinks) {
3803 link->clearState();
3804 }
3805}
3806
3807void
3808MSLane::loadState(const std::vector<SUMOVehicle*>& vehs) {
3809 for (SUMOVehicle* veh : vehs) {
3810 MSVehicle* v = dynamic_cast<MSVehicle*>(veh);
3811 v->updateBestLanes(false, this);
3812 // incorporateVehicle resets the lastActionTime (which has just been loaded from state) so we must restore it
3813 const SUMOTime lastActionTime = v->getLastActionTime();
3816 v->resetActionOffset(lastActionTime - MSNet::getInstance()->getCurrentTimeStep());
3817 }
3818}
3819
3820
3821double
3823 if (!myLaneStopOffset.isDefined()) {
3824 return 0;
3825 }
3826 if ((myLaneStopOffset.getPermissions() & veh->getVClass()) != 0) {
3827 return myLaneStopOffset.getOffset();
3828 } else {
3829 return 0;
3830 }
3831}
3832
3833
3834const StopOffset&
3838
3839
3840void
3842 myLaneStopOffset = stopOffset;
3843}
3844
3845
3847MSLane::getFollowersOnConsecutive(const MSVehicle* ego, double backOffset,
3848 bool allSublanes, double searchDist, MinorLinkMode mLinkMode, bool maxSearchDist) const {
3849 assert(ego != 0);
3850 // get the follower vehicle on the lane to change to
3851 const double egoPos = backOffset + ego->getVehicleType().getLength();
3852 const double egoLatDist = ego->getLane()->getRightSideOnEdge() - getRightSideOnEdge();
3853 const bool getOppositeLeaders = ((ego->getLaneChangeModel().isOpposite() && ego->getLane() == this)
3854 || (!ego->getLaneChangeModel().isOpposite() && &ego->getLane()->getEdge() != &getEdge()));
3855#ifdef DEBUG_CONTEXT
3856 if (DEBUG_COND2(ego)) {
3857 std::cout << SIMTIME << " getFollowers lane=" << getID() << " ego=" << ego->getID()
3858 << " backOffset=" << backOffset << " pos=" << egoPos
3859 << " allSub=" << allSublanes << " searchDist=" << searchDist << " ignoreMinor=" << mLinkMode
3860 << " maxSearchDist=" << maxSearchDist
3861 << " egoLatDist=" << egoLatDist
3862 << " getOppositeLeaders=" << getOppositeLeaders
3863 << "\n";
3864 }
3865#endif
3866 MSCriticalFollowerDistanceInfo result(myWidth, allSublanes ? nullptr : ego, allSublanes ? 0 : egoLatDist, getOppositeLeaders);
3867 if (MSGlobals::gLateralResolution > 0 && egoLatDist == 0) {
3868 // check whether ego is outside lane bounds far enough so that another vehicle might
3869 // be between itself and the first "actual" sublane
3870 // shift the offset so that we "see" this vehicle
3875 }
3876#ifdef DEBUG_CONTEXT
3877 if (DEBUG_COND2(ego)) {
3878 std::cout << SIMTIME << " getFollowers lane=" << getID() << " ego=" << ego->getID()
3879 << " egoPosLat=" << ego->getLateralPositionOnLane()
3880 << " egoLatDist=" << ego->getLane()->getRightSideOnEdge() - getRightSideOnEdge()
3881 << " extraOffset=" << result.getSublaneOffset()
3882 << "\n";
3883 }
3884#endif
3885 }
3887 for (AnyVehicleIterator last = anyVehiclesBegin(); last != anyVehiclesEnd(); ++last) {
3888 const MSVehicle* veh = *last;
3889#ifdef DEBUG_CONTEXT
3890 if (DEBUG_COND2(ego)) {
3891 std::cout << " veh=" << veh->getID() << " lane=" << veh->getLane()->getID() << " pos=" << veh->getPositionOnLane(this) << "\n";
3892 }
3893#endif
3894 if (veh != ego && veh->getPositionOnLane(this) < egoPos) {
3895 //const double latOffset = veh->getLane()->getRightSideOnEdge() - getRightSideOnEdge();
3896 const double latOffset = veh->getLatOffset(this);
3897 double dist = backOffset - veh->getPositionOnLane(this) - veh->getVehicleType().getMinGap();
3898 if (veh->isBidiOn(this)) {
3899 dist -= veh->getLength();
3900 }
3901 result.addFollower(veh, ego, dist, latOffset);
3902#ifdef DEBUG_CONTEXT
3903 if (DEBUG_COND2(ego)) {
3904 std::cout << " (1) added veh=" << veh->getID() << " latOffset=" << latOffset << " result=" << result.toString() << "\n";
3905 }
3906#endif
3907 }
3908 }
3909#ifdef DEBUG_CONTEXT
3910 if (DEBUG_COND2(ego)) {
3911 std::cout << " result.numFreeSublanes=" << result.numFreeSublanes() << "\n";
3912 }
3913#endif
3914 if (result.numFreeSublanes() > 0) {
3915 // do a tree search among all follower lanes and check for the most
3916 // important vehicle (the one requiring the largest reargap)
3917 // to get a safe bound on the necessary search depth, we need to consider the maximum speed and minimum
3918 // deceleration of potential follower vehicles
3919 if (searchDist == -1) {
3920 searchDist = getMaximumBrakeDist() - backOffset;
3921#ifdef DEBUG_CONTEXT
3922 if (DEBUG_COND2(ego)) {
3923 std::cout << " computed searchDist=" << searchDist << "\n";
3924 }
3925#endif
3926 }
3927 std::set<const MSEdge*> egoFurther;
3928 for (MSLane* further : ego->getFurtherLanes()) {
3929 egoFurther.insert(&further->getEdge());
3930 }
3931 if (ego->getPositionOnLane() < ego->getVehicleType().getLength() && egoFurther.size() == 0
3932 && ego->getLane()->getLogicalPredecessorLane() != nullptr) {
3933 // on insertion
3934 egoFurther.insert(&ego->getLane()->getLogicalPredecessorLane()->getEdge());
3935 }
3936
3937 // avoid loops
3938 std::set<const MSLane*> visited(myEdge->getLanes().begin(), myEdge->getLanes().end());
3939 if (myEdge->getBidiEdge() != nullptr) {
3940 visited.insert(myEdge->getBidiEdge()->getLanes().begin(), myEdge->getBidiEdge()->getLanes().end());
3941 }
3942 std::vector<MSLane::IncomingLaneInfo> newFound;
3943 std::vector<MSLane::IncomingLaneInfo> toExamine = myIncomingLanes;
3944 while (toExamine.size() != 0) {
3945 for (std::vector<MSLane::IncomingLaneInfo>::iterator it = toExamine.begin(); it != toExamine.end(); ++it) {
3946 MSLane* next = (*it).lane;
3947 searchDist = maxSearchDist
3948 ? MAX2(searchDist, next->getMaximumBrakeDist() - backOffset)
3949 : MIN2(searchDist, next->getMaximumBrakeDist() - backOffset);
3950 MSLeaderInfo first = next->getFirstVehicleInformation(nullptr, 0, false, std::numeric_limits<double>::max(), false);
3951 MSLeaderInfo firstFront = next->getFirstVehicleInformation(nullptr, 0, true);
3952#ifdef DEBUG_CONTEXT
3953 if (DEBUG_COND2(ego)) {
3954 std::cout << " next=" << next->getID() << " seen=" << (*it).length << " first=" << first.toString() << " firstFront=" << firstFront.toString() << " backOffset=" << backOffset << "\n";
3955 gDebugFlag1 = true; // for calling getLeaderInfo
3956 }
3957#endif
3958 if (backOffset + (*it).length - next->getLength() < 0
3959 && egoFurther.count(&next->getEdge()) != 0
3960 ) {
3961 // check for junction foes that would interfere with lane changing
3962 // @note: we are passing the back of ego as its front position so
3963 // we need to add this back to the returned gap
3964 const MSLink::LinkLeaders linkLeaders = (*it).viaLink->getLeaderInfo(ego, -backOffset);
3965 for (const auto& ll : linkLeaders) {
3966 if (ll.vehAndGap.first != nullptr) {
3967 const bool bidiFoe = (*it).viaLink->getLane() == ll.vehAndGap.first->getLane()->getNormalPredecessorLane()->getBidiLane();
3968 const bool egoIsLeader = !bidiFoe && ll.vehAndGap.first->isLeader((*it).viaLink, ego, ll.vehAndGap.second);
3969 // if ego is leader the returned gap still assumes that ego follows the leader
3970 // if the foe vehicle follows ego we need to deduce that gap
3971 const double gap = (egoIsLeader
3972 ? -ll.vehAndGap.second - ll.vehAndGap.first->getVehicleType().getLengthWithGap() - ego->getVehicleType().getMinGap()
3973 : ll.vehAndGap.second + ego->getVehicleType().getLength());
3974 result.addFollower(ll.vehAndGap.first, ego, gap);
3975#ifdef DEBUG_CONTEXT
3976 if (DEBUG_COND2(ego)) {
3977 std::cout << SIMTIME << " ego=" << ego->getID() << " link=" << (*it).viaLink->getViaLaneOrLane()->getID()
3978 << " (3) added veh=" << Named::getIDSecure(ll.vehAndGap.first)
3979 << " gap=" << ll.vehAndGap.second << " dtC=" << ll.distToCrossing
3980 << " bidiFoe=" << bidiFoe
3981 << " egoIsLeader=" << egoIsLeader << " gap2=" << gap
3982 << "\n";
3983 }
3984#endif
3985 }
3986 }
3987 }
3988#ifdef DEBUG_CONTEXT
3989 if (DEBUG_COND2(ego)) {
3990 gDebugFlag1 = false;
3991 }
3992#endif
3993
3994 for (int i = 0; i < first.numSublanes(); ++i) {
3995 const MSVehicle* v = first[i] == ego ? firstFront[i] : first[i];
3996 double agap = 0;
3997
3998 if (v != nullptr && v != ego) {
3999 if (!v->isFrontOnLane(next)) {
4000 // the front of v is already on divergent trajectory from the ego vehicle
4001 // for which this method is called (in the context of MSLaneChanger).
4002 // Therefore, technically v is not a follower but only an obstruction and
4003 // the gap is not between the front of v and the back of ego
4004 // but rather between the flank of v and the back of ego.
4005 agap = (*it).length - next->getLength() + backOffset;
4007 // ego should have left the intersection still occupied by v
4008 agap -= v->getVehicleType().getMinGap();
4009 }
4010#ifdef DEBUG_CONTEXT
4011 if (DEBUG_COND2(ego)) {
4012 std::cout << " agap1=" << agap << "\n";
4013 }
4014#endif
4015 const bool differentEdge = &v->getLane()->getEdge() != &ego->getLane()->getEdge();
4016 if (agap > 0 && differentEdge) {
4017 // Only if ego overlaps we treat v as if it were a real follower
4018 // Otherwise we ignore it and look for another follower
4019 if (!getOppositeLeaders) {
4020 // even if the vehicle is not a real
4021 // follower, it still forms a real
4022 // obstruction in opposite direction driving
4023 v = firstFront[i];
4024 if (v != nullptr && v != ego) {
4025 agap = (*it).length - v->getPositionOnLane() + backOffset - v->getVehicleType().getMinGap();
4026 } else {
4027 v = nullptr;
4028 }
4029 }
4030 } else if (differentEdge && result.hasVehicle(v)) {
4031 // ignore this vehicle as it was already seen on another lane
4032 agap = 0;
4033 }
4034 } else {
4035 if (next->getBidiLane() != nullptr && v->isBidiOn(next)) {
4036 agap = v->getPositionOnLane() + backOffset - v->getVehicleType().getLengthWithGap();
4037 } else {
4038 agap = (*it).length - v->getPositionOnLane() + backOffset - v->getVehicleType().getMinGap();
4039 }
4040 if (!(*it).viaLink->havePriority() && egoFurther.count(&(*it).lane->getEdge()) == 0
4041 && ego->isOnRoad() // during insertion, this can lead to collisions because ego's further lanes are not set (see #3053)
4042 && !ego->getLaneChangeModel().isOpposite()
4044 ) {
4045 // if v is stopped on a minor side road it should not block lane changing
4046 agap = MAX2(agap, 0.0);
4047 }
4048 }
4049 result.addFollower(v, ego, agap, 0, i);
4050#ifdef DEBUG_CONTEXT
4051 if (DEBUG_COND2(ego)) {
4052 std::cout << " (2) added veh=" << Named::getIDSecure(v) << " agap=" << agap << " next=" << next->getID() << " result=" << result.toString() << "\n";
4053 }
4054#endif
4055 }
4056 }
4057 if ((*it).length < searchDist) {
4058 const std::vector<MSLane::IncomingLaneInfo>& followers = next->getIncomingLanes();
4059 for (std::vector<MSLane::IncomingLaneInfo>::const_iterator j = followers.begin(); j != followers.end(); ++j) {
4060 if (visited.find((*j).lane) == visited.end() && (((*j).viaLink->havePriority() && !(*j).viaLink->isTurnaround())
4061 || mLinkMode == MinorLinkMode::FOLLOW_ALWAYS
4062 || (mLinkMode == MinorLinkMode::FOLLOW_ONCOMING && (*j).viaLink->getDirection() == LinkDirection::STRAIGHT))) {
4063 visited.insert((*j).lane);
4065 ili.lane = (*j).lane;
4066 ili.length = (*j).length + (*it).length;
4067 ili.viaLink = (*j).viaLink;
4068 newFound.push_back(ili);
4069 }
4070 }
4071 }
4072 }
4073 toExamine.clear();
4074 swap(newFound, toExamine);
4075 }
4076 //return result;
4077
4078 }
4079 return result;
4080}
4081
4082
4083void
4084MSLane::getLeadersOnConsecutive(double dist, double seen, double speed, const MSVehicle* ego,
4085 const std::vector<MSLane*>& bestLaneConts, MSLeaderDistanceInfo& result,
4086 bool oppositeDirection) const {
4087#ifdef DEBUG_CONTEXT
4088 if (DEBUG_COND2(ego)) {
4089 std::cout << " getLeadersOnConsecutive " << getID() << " ego=" << Named::getIDSecure(ego) << " dist=" << dist << " seen=" << seen << "\n";
4090 }
4091#endif
4092 if (seen > dist && !(isInternal() && MSGlobals::gComputeLC)) {
4093 return;
4094 }
4095 // check partial vehicles (they might be on a different route and thus not
4096 // found when iterating along bestLaneConts)
4097 for (VehCont::const_iterator it = myPartialVehicles.begin(); it != myPartialVehicles.end(); ++it) {
4098 MSVehicle* veh = *it;
4099 if (!veh->isFrontOnLane(this)) {
4100 result.addLeader(veh, seen, veh->getLatOffset(this));
4101 } else {
4102 break;
4103 }
4104 }
4105#ifdef DEBUG_CONTEXT
4106 if (DEBUG_COND2(ego)) {
4107 gDebugFlag1 = true;
4108 }
4109#endif
4110 const MSLane* nextLane = this;
4111 int view = 1;
4112 // loop over following lanes
4113 while ((seen < dist && result.numFreeSublanes() > 0) || nextLane->isInternal()) {
4114 if (nextLane != this) {
4115 seen += nextLane->getLength();
4116 }
4117 // get the next link used
4118 bool nextInternal = false;
4119 if (oppositeDirection) {
4120 if (view >= (int)bestLaneConts.size()) {
4121 break;
4122 }
4123 nextLane = bestLaneConts[view];
4124 } else {
4125 std::vector<MSLink*>::const_iterator link = succLinkSec(*ego, view, *nextLane, bestLaneConts);
4126 if (nextLane->isLinkEnd(link)) {
4127 break;
4128 }
4129#ifdef DEBUG_CONTEXT
4130 if (DEBUG_COND2(ego)) {
4131 std::cout << " link=" << (*link)->getDescription() << " debugflag=" << gDebugFlag1 << "\n";
4132 }
4133#endif
4134 // check for link leaders
4135 const MSLink::LinkLeaders linkLeaders = (*link)->getLeaderInfo(ego, seen);
4136 if (DEBUG_COND2(ego)) {
4137 std::cout << " numLinkLeaders=" << linkLeaders.size() << "\n";
4138 }
4139 for (const MSLink::LinkLeader& ll : linkLeaders) {
4140 MSVehicle* veh = ll.vehAndGap.first;
4141 // in the context of lane changing all junction leader candidates must be respected
4142#ifdef DEBUG_CONTEXT
4143 if (DEBUG_COND2(ego)) {
4144 std::cout << " linkleader=" << veh->getID() << " gap=" << ll.vehAndGap.second << " leaderOffset=" << ll.latOffset << " flags=" << ll.llFlags << "\n";
4145 }
4146#endif
4147 if (veh != 0 && (ego->isLeader(*link, veh, ll.vehAndGap.second)
4150 < veh->getCarFollowModel().brakeGap(veh->getSpeed())))) {
4151 if (ll.sameTarget() || ll.sameSource()) {
4152 result.addLeader(veh, ll.vehAndGap.second, ll.latOffset);
4153#ifdef DEBUG_CONTEXT
4154 if (DEBUG_COND2(ego)) {
4155 std::cout << " added selective: result=" << result.toString() << "\n";
4156 }
4157#endif
4158 } else {
4159 // add link leader to all sublanes and return
4160 for (int i = 0; i < result.numSublanes(); ++i) {
4161 result.addLeader(veh, ll.vehAndGap.second, 0, i);
4162 }
4163#ifdef DEBUG_CONTEXT
4164 if (DEBUG_COND2(ego)) {
4165 std::cout << " added allSublanes: result=" << result.toString() << "\n";
4166 }
4167#endif
4168 }
4169 } // XXX else, deal with pedestrians
4170 }
4171 nextInternal = (*link)->getViaLane() != nullptr;
4172 nextLane = (*link)->getViaLaneOrLane();
4173 if (nextLane == nullptr) {
4174 break;
4175 }
4176 }
4177
4178 MSLeaderInfo leaders = nextLane->getLastVehicleInformation(nullptr, 0, 0, false);
4179#ifdef DEBUG_CONTEXT
4180 if (DEBUG_COND2(ego)) {
4181 std::cout << SIMTIME << " getLeadersOnConsecutive lane=" << getID() << " nextLane=" << nextLane->getID() << " leaders=" << leaders.toString() << "\n";
4182 }
4183#endif
4184 // @todo check alignment issues if the lane width changes
4185 const int iMax = MIN2(leaders.numSublanes(), result.numSublanes());
4186 for (int i = 0; i < iMax; ++i) {
4187 const MSVehicle* veh = leaders[i];
4188 if (veh != nullptr) {
4189#ifdef DEBUG_CONTEXT
4190 if (DEBUG_COND2(ego)) std::cout << " lead=" << veh->getID()
4191 << " seen=" << seen
4192 << " minGap=" << ego->getVehicleType().getMinGap()
4193 << " backPos=" << veh->getBackPositionOnLane(nextLane)
4194 << " gap=" << seen - ego->getVehicleType().getMinGap() + veh->getBackPositionOnLane(nextLane)
4195 << "\n";
4196#endif
4197 result.addLeader(veh, seen - ego->getVehicleType().getMinGap() + veh->getBackPositionOnLane(nextLane), 0, i);
4198 }
4199 }
4200
4201 if (nextLane->getVehicleMaxSpeed(ego) < speed) {
4202 dist = ego->getCarFollowModel().brakeGap(nextLane->getVehicleMaxSpeed(ego));
4203 }
4204#ifdef DEBUG_CONTEXT
4205 if (DEBUG_COND2(ego)) std::cout << " newDist=" << dist << " newSeen=" << seen << "\n";
4206#endif
4207 if (!nextInternal) {
4208 view++;
4209 }
4210 }
4211#ifdef DEBUG_CONTEXT
4212 gDebugFlag1 = false;
4213#endif
4214}
4215
4216
4217void
4218MSLane::addLeaders(const MSVehicle* vehicle, double vehPos, MSLeaderDistanceInfo& result, bool opposite) {
4219 // if there are vehicles on the target lane with the same position as ego,
4220 // they may not have been added to 'ahead' yet
4221#ifdef DEBUG_SURROUNDING
4222 if (DEBUG_COND || DEBUG_COND2(vehicle)) {
4223 std::cout << " addLeaders lane=" << getID() << " veh=" << vehicle->getID() << " vehPos=" << vehPos << " opposite=" << opposite << "\n";
4224 }
4225#endif
4226 const MSLeaderInfo& aheadSamePos = getLastVehicleInformation(nullptr, 0, vehPos, false, vehicle);
4227 for (int i = 0; i < aheadSamePos.numSublanes(); ++i) {
4228 const MSVehicle* veh = aheadSamePos[i];
4229 if (veh != nullptr && veh != vehicle) {
4230 const double gap = veh->getBackPositionOnLane(this) - vehPos - vehicle->getVehicleType().getMinGap();
4231#ifdef DEBUG_SURROUNDING
4232 if (DEBUG_COND || DEBUG_COND2(vehicle)) {
4233 std::cout << " further lead=" << veh->getID() << " leadBack=" << veh->getBackPositionOnLane(this) << " gap=" << gap << "\n";
4234 }
4235#endif
4236 result.addLeader(veh, gap, 0, i);
4237 }
4238 }
4239
4240 // we must consider linkLeaders (via getLeadersOnConsecutive) while on a junction
4241 if (result.numFreeSublanes() > 0 || isInternal()) {
4242 double seen = vehicle->getLane()->getLength() - vehPos;
4243 double speed = vehicle->getSpeed();
4244 // leader vehicle could be link leader on the next junction
4245 double dist = MAX2(vehicle->getCarFollowModel().brakeGap(speed), 10.0) + vehicle->getVehicleType().getMinGap();
4246 if (getBidiLane() != nullptr) {
4247 dist = MAX2(dist, myMaxSpeed * 20);
4248 }
4249 // check for link leaders when on internal
4250 if (seen > dist && !(isInternal() && MSGlobals::gComputeLC)) {
4251#ifdef DEBUG_SURROUNDING
4252 if (DEBUG_COND || DEBUG_COND2(vehicle)) {
4253 std::cout << " aborting forward search. dist=" << dist << " seen=" << seen << "\n";
4254 }
4255#endif
4256 return;
4257 }
4258#ifdef DEBUG_SURROUNDING
4259 if (DEBUG_COND || DEBUG_COND2(vehicle)) {
4260 std::cout << " add consecutive before=" << result.toString() << " seen=" << seen << " dist=" << dist;
4261 }
4262#endif
4263 if (opposite) {
4264 const std::vector<MSLane*> bestLaneConts = vehicle->getUpstreamOppositeLanes();
4265#ifdef DEBUG_SURROUNDING
4266 if (DEBUG_COND || DEBUG_COND2(vehicle)) {
4267 std::cout << " upstreamOpposite=" << toString(bestLaneConts);
4268 }
4269#endif
4270 getLeadersOnConsecutive(dist, seen, speed, vehicle, bestLaneConts, result, opposite);
4271 } else {
4272 const std::vector<MSLane*>& bestLaneConts = vehicle->getBestLanesContinuation(this);
4273 getLeadersOnConsecutive(dist, seen, speed, vehicle, bestLaneConts, result);
4274 }
4275#ifdef DEBUG_SURROUNDING
4276 if (DEBUG_COND || DEBUG_COND2(vehicle)) {
4277 std::cout << " after=" << result.toString() << "\n";
4278 }
4279#endif
4280 }
4281}
4282
4283
4284MSVehicle*
4286 for (VehCont::const_reverse_iterator i = myPartialVehicles.rbegin(); i != myPartialVehicles.rend(); ++i) {
4287 MSVehicle* veh = *i;
4288 if (veh->isFrontOnLane(this)
4289 && veh != ego
4290 && veh->getPositionOnLane() <= ego->getPositionOnLane()) {
4291#ifdef DEBUG_CONTEXT
4292 if (DEBUG_COND2(ego)) {
4293 std::cout << SIMTIME << " getPartialBehind lane=" << getID() << " ego=" << ego->getID() << " found=" << veh->getID() << "\n";
4294 }
4295#endif
4296 return veh;
4297 }
4298 }
4299#ifdef DEBUG_CONTEXT
4300 if (DEBUG_COND2(ego)) {
4301 std::cout << SIMTIME << " getPartialBehind lane=" << getID() << " ego=" << ego->getID() << " nothing found. partials=" << toString(myPartialVehicles) << "\n";
4302 }
4303#endif
4304 return nullptr;
4305}
4306
4309 MSLeaderInfo result(myWidth);
4310 for (VehCont::const_iterator it = myPartialVehicles.begin(); it != myPartialVehicles.end(); ++it) {
4311 MSVehicle* veh = *it;
4312 if (!veh->isFrontOnLane(this)) {
4313 result.addLeader(veh, false, veh->getLatOffset(this));
4314 } else {
4315 break;
4316 }
4317 }
4318 return result;
4319}
4320
4321
4322std::set<MSVehicle*>
4323MSLane::getSurroundingVehicles(double startPos, double downstreamDist, double upstreamDist, std::shared_ptr<LaneCoverageInfo> checkedLanes) const {
4324 assert(checkedLanes != nullptr);
4325 if (checkedLanes->find(this) != checkedLanes->end()) {
4326#ifdef DEBUG_SURROUNDING
4327 std::cout << "Skipping previously scanned lane: " << getID() << std::endl;
4328#endif
4329 return std::set<MSVehicle*>();
4330 } else {
4331 // Add this lane's coverage to the lane coverage info
4332 (*checkedLanes)[this] = std::make_pair(MAX2(0.0, startPos - upstreamDist), MIN2(startPos + downstreamDist, getLength()));
4333 }
4334#ifdef DEBUG_SURROUNDING
4335 std::cout << "Scanning on lane " << myID << "(downstr. " << downstreamDist << ", upstr. " << upstreamDist << ", startPos " << startPos << "): " << std::endl;
4336#endif
4337 std::set<MSVehicle*> foundVehicles = getVehiclesInRange(MAX2(0., startPos - upstreamDist), MIN2(myLength, startPos + downstreamDist));
4338 if (startPos < upstreamDist) {
4339 // scan incoming lanes
4340 for (const IncomingLaneInfo& incomingInfo : getIncomingLanes()) {
4341 MSLane* incoming = incomingInfo.lane;
4342#ifdef DEBUG_SURROUNDING
4343 std::cout << "Checking on incoming: " << incoming->getID() << std::endl;
4344 if (checkedLanes->find(incoming) != checkedLanes->end()) {
4345 std::cout << "Skipping previous: " << incoming->getID() << std::endl;
4346 }
4347#endif
4348 std::set<MSVehicle*> newVehs = incoming->getSurroundingVehicles(incoming->getLength(), 0.0, upstreamDist - startPos, checkedLanes);
4349 foundVehicles.insert(newVehs.begin(), newVehs.end());
4350 }
4351 }
4352
4353 if (getLength() < startPos + downstreamDist) {
4354 // scan successive lanes
4355 const std::vector<MSLink*>& lc = getLinkCont();
4356 for (MSLink* l : lc) {
4357#ifdef DEBUG_SURROUNDING
4358 std::cout << "Checking on outgoing: " << l->getViaLaneOrLane()->getID() << std::endl;
4359#endif
4360 std::set<MSVehicle*> newVehs = l->getViaLaneOrLane()->getSurroundingVehicles(0.0, downstreamDist - (myLength - startPos), upstreamDist, checkedLanes);
4361 foundVehicles.insert(newVehs.begin(), newVehs.end());
4362 }
4363 }
4364#ifdef DEBUG_SURROUNDING
4365 std::cout << "On lane (2) " << myID << ": \nFound vehicles: " << std::endl;
4366 for (MSVehicle* v : foundVehicles) {
4367 std::cout << v->getID() << " pos = " << v->getPositionOnLane() << std::endl;
4368 }
4369#endif
4370 return foundVehicles;
4371}
4372
4373
4374std::set<MSVehicle*>
4375MSLane::getVehiclesInRange(const double a, const double b) const {
4376 std::set<MSVehicle*> res;
4377 const VehCont& vehs = getVehiclesSecure();
4378
4379 if (!vehs.empty()) {
4380 for (MSVehicle* const veh : vehs) {
4381 if (veh->getPositionOnLane() >= a) {
4382 if (veh->getBackPositionOnLane() > b) {
4383 break;
4384 }
4385 res.insert(veh);
4386 }
4387 }
4388 }
4390 return res;
4391}
4392
4393
4394std::vector<const MSJunction*>
4395MSLane::getUpcomingJunctions(double pos, double range, const std::vector<MSLane*>& contLanes) const {
4396 // set of upcoming junctions and the corresponding conflict links
4397 std::vector<const MSJunction*> junctions;
4398 for (auto l : getUpcomingLinks(pos, range, contLanes)) {
4399 junctions.insert(junctions.end(), l->getJunction());
4400 }
4401 return junctions;
4402}
4403
4404
4405std::vector<const MSLink*>
4406MSLane::getUpcomingLinks(double pos, double range, const std::vector<MSLane*>& contLanes) const {
4407#ifdef DEBUG_SURROUNDING
4408 std::cout << "getUpcoming links on lane '" << getID() << "' with pos=" << pos
4409 << " range=" << range << std::endl;
4410#endif
4411 // set of upcoming junctions and the corresponding conflict links
4412 std::vector<const MSLink*> links;
4413
4414 // Currently scanned lane
4415 const MSLane* lane = this;
4416
4417 // continuation lanes for the vehicle
4418 std::vector<MSLane*>::const_iterator contLanesIt = contLanes.begin();
4419 // scanned distance so far
4420 double dist = 0.0;
4421 // link to be crossed by the vehicle
4422 const MSLink* link = nullptr;
4423 if (lane->isInternal()) {
4424 assert(*contLanesIt == nullptr); // is called with vehicle's bestLane structure
4425 link = lane->getEntryLink();
4426 links.insert(links.end(), link);
4427 dist += link->getInternalLengthsAfter();
4428 // next non-internal lane behind junction
4429 lane = link->getLane();
4430 pos = 0.0;
4431 assert(*(contLanesIt + 1) == lane);
4432 }
4433 while (++contLanesIt != contLanes.end()) {
4434 assert(!lane->isInternal());
4435 dist += lane->getLength() - pos;
4436 pos = 0.;
4437#ifdef DEBUG_SURROUNDING
4438 std::cout << "Distance until end of lane '" << lane->getID() << "' is " << dist << "." << std::endl;
4439#endif
4440 if (dist > range) {
4441 break;
4442 }
4443 link = lane->getLinkTo(*contLanesIt);
4444 if (link != nullptr) {
4445 links.insert(links.end(), link);
4446 }
4447 lane = *contLanesIt;
4448 }
4449 return links;
4450}
4451
4452
4453MSLane*
4455 return myOpposite;
4456}
4457
4458
4459MSLane*
4461 return myEdge->getLanes().back()->getOpposite();
4462}
4463
4464
4465double
4466MSLane::getOppositePos(double pos) const {
4467 return MAX2(0., myLength - pos);
4468}
4469
4470std::pair<MSVehicle* const, double>
4471MSLane::getFollower(const MSVehicle* ego, double egoPos, double dist, MinorLinkMode mLinkMode, bool maxSearchDist) const {
4472 for (AnyVehicleIterator first = anyVehiclesUpstreamBegin(); first != anyVehiclesUpstreamEnd(); ++first) {
4473 // XXX refactor leaderInfo to use a const vehicle all the way through the call hierarchy
4474 MSVehicle* pred = (MSVehicle*)*first;
4475#ifdef DEBUG_CONTEXT
4476 if (DEBUG_COND2(ego)) {
4477 std::cout << " getFollower lane=" << getID() << " egoPos=" << egoPos << " pred=" << pred->getID() << " predPos=" << pred->getPositionOnLane(this) << "\n";
4478 }
4479#endif
4480 if (pred != ego && pred->getPositionOnLane(this) < egoPos) {
4481 return std::pair<MSVehicle* const, double>(pred, egoPos - pred->getPositionOnLane(this) - ego->getVehicleType().getLength() - pred->getVehicleType().getMinGap());
4482 }
4483 }
4484 const double backOffset = egoPos - ego->getVehicleType().getLength();
4485 if (dist > 0 && backOffset > dist) {
4486 return std::make_pair(nullptr, -1);
4487 }
4488 const MSLeaderDistanceInfo followers = getFollowersOnConsecutive(ego, backOffset, true, dist, mLinkMode, maxSearchDist);
4489 CLeaderDist result = followers.getClosest();
4490 return std::make_pair(const_cast<MSVehicle*>(result.first), result.second);
4491}
4492
4493std::pair<MSVehicle* const, double>
4494MSLane::getOppositeLeader(const MSVehicle* ego, double dist, bool oppositeDir, MinorLinkMode mLinkMode) const {
4495#ifdef DEBUG_OPPOSITE
4496 if (DEBUG_COND2(ego)) std::cout << SIMTIME << " getOppositeLeader lane=" << getID()
4497 << " ego=" << ego->getID()
4498 << " pos=" << ego->getPositionOnLane()
4499 << " posOnOpposite=" << getOppositePos(ego->getPositionOnLane())
4500 << " dist=" << dist
4501 << " oppositeDir=" << oppositeDir
4502 << "\n";
4503#endif
4504 if (!oppositeDir) {
4505 return getLeader(ego, getOppositePos(ego->getPositionOnLane()), ego->getBestLanesContinuation(this));
4506 } else {
4507 const double egoLength = ego->getVehicleType().getLength();
4508 const double egoPos = ego->getLaneChangeModel().isOpposite() ? ego->getPositionOnLane() : getOppositePos(ego->getPositionOnLane());
4509 std::pair<MSVehicle* const, double> result = getFollower(ego, egoPos + egoLength, dist, mLinkMode, true);
4510 if (result.first != nullptr) {
4511 result.second -= ego->getVehicleType().getMinGap();
4512 if (result.first->getLaneChangeModel().isOpposite()) {
4513 result.second -= result.first->getVehicleType().getLength();
4514 }
4515 }
4516 return result;
4517 }
4518}
4519
4520
4521std::pair<MSVehicle* const, double>
4523#ifdef DEBUG_OPPOSITE
4524 if (DEBUG_COND2(ego)) std::cout << SIMTIME << " getOppositeFollower lane=" << getID()
4525 << " ego=" << ego->getID()
4526 << " backPos=" << ego->getBackPositionOnLane()
4527 << " posOnOpposite=" << getOppositePos(ego->getBackPositionOnLane())
4528 << "\n";
4529#endif
4530 if (ego->getLaneChangeModel().isOpposite()) {
4531 std::pair<MSVehicle* const, double> result = getFollower(ego, getOppositePos(ego->getPositionOnLane()), -1, MinorLinkMode::FOLLOW_NEVER);
4532 return result;
4533 } else {
4534 double vehPos = getOppositePos(ego->getPositionOnLane() - ego->getVehicleType().getLength());
4535 std::pair<MSVehicle*, double> result = getLeader(ego, vehPos, std::vector<MSLane*>());
4536 double dist = getMaximumBrakeDist() + getOppositePos(ego->getPositionOnLane() - getLength());
4537 MSLane* next = const_cast<MSLane*>(this);
4538 while (result.first == nullptr && dist > 0) {
4539 // cannot call getLeadersOnConsecutive because succLinkSec doesn't
4540 // uses the vehicle's route and doesn't work on the opposite side
4541 vehPos -= next->getLength();
4542 next = next->getCanonicalSuccessorLane();
4543 if (next == nullptr) {
4544 break;
4545 }
4546 dist -= next->getLength();
4547 result = next->getLeader(ego, vehPos, std::vector<MSLane*>());
4548 }
4549 if (result.first != nullptr) {
4550 if (result.first->getLaneChangeModel().isOpposite()) {
4551 result.second -= result.first->getVehicleType().getLength();
4552 } else {
4553 if (result.second > POSITION_EPS) {
4554 // follower can be safely ignored since it is going the other way
4555 return std::make_pair(static_cast<MSVehicle*>(nullptr), -1);
4556 }
4557 }
4558 }
4559 return result;
4560 }
4561}
4562
4563void
4564MSLane::initCollisionAction(const OptionsCont& oc, const std::string& option, CollisionAction& myAction) {
4565 const std::string action = oc.getString(option);
4566 if (action == "none") {
4567 myAction = COLLISION_ACTION_NONE;
4568 } else if (action == "warn") {
4569 myAction = COLLISION_ACTION_WARN;
4570 } else if (action == "teleport") {
4571 myAction = COLLISION_ACTION_TELEPORT;
4572 } else if (action == "remove") {
4573 myAction = COLLISION_ACTION_REMOVE;
4574 } else {
4575 WRITE_ERROR(TLF("Invalid % '%'.", option, action));
4576 }
4577}
4578
4579void
4581 initCollisionAction(oc, "collision.action", myCollisionAction);
4582 initCollisionAction(oc, "intermodal-collision.action", myIntermodalCollisionAction);
4583 myCheckJunctionCollisions = oc.getBool("collision.check-junctions");
4584 myCheckJunctionCollisionMinGap = oc.getFloat("collision.check-junctions.mingap");
4585 myCollisionStopTime = string2time(oc.getString("collision.stoptime"));
4586 myIntermodalCollisionStopTime = string2time(oc.getString("intermodal-collision.stoptime"));
4587 myCollisionMinGapFactor = oc.getFloat("collision.mingap-factor");
4588 myExtrapolateSubstepDepart = oc.getBool("extrapolate-departpos");
4589}
4590
4591
4592void
4593MSLane::setPermissions(SVCPermissions permissions, long long transientID) {
4594 if (transientID == CHANGE_PERMISSIONS_PERMANENT) {
4595 myPermissions = permissions;
4596 myOriginalPermissions = permissions;
4597 } else {
4598 myPermissionChanges[transientID] = permissions;
4600 }
4601}
4602
4603
4604void
4605MSLane::resetPermissions(long long transientID) {
4606 myPermissionChanges.erase(transientID);
4607 if (myPermissionChanges.empty()) {
4609 } else {
4610 // combine all permission changes
4612 for (const auto& item : myPermissionChanges) {
4613 myPermissions &= item.second;
4614 }
4615 }
4616}
4617
4618
4619bool
4621 return !myPermissionChanges.empty();
4622}
4623
4624
4625void
4627 myChangeLeft = permissions;
4628}
4629
4630
4631void
4633 myChangeRight = permissions;
4634}
4635
4636
4637bool
4639 MSNet* const net = MSNet::getInstance();
4640 return net->hasPersons() && net->getPersonControl().getMovementModel()->hasPedestrians(this);
4641}
4642
4643
4645MSLane::nextBlocking(double minPos, double minRight, double maxLeft, double stopTime, bool bidi) const {
4646 return MSNet::getInstance()->getPersonControl().getMovementModel()->nextBlocking(this, minPos, minRight, maxLeft, stopTime, bidi);
4647}
4648
4649
4650bool
4651MSLane::checkForPedestrians(const MSVehicle* aVehicle, double& speed, double& dist, double pos, bool patchSpeed) const {
4652 if (getEdge().getPersons().size() > 0 && hasPedestrians()) {
4653#ifdef DEBUG_INSERTION
4654 if (DEBUG_COND2(aVehicle)) {
4655 std::cout << SIMTIME << " check for pedestrians on lane=" << getID() << " pos=" << pos << "\n";
4656 }
4657#endif
4658 PersonDist leader = nextBlocking(pos - aVehicle->getVehicleType().getLength(),
4659 aVehicle->getRightSideOnLane(), aVehicle->getRightSideOnLane() + aVehicle->getVehicleType().getWidth(), ceil(speed / aVehicle->getCarFollowModel().getMaxDecel()));
4660 if (leader.first != 0) {
4661 const double gap = leader.second - aVehicle->getVehicleType().getLengthWithGap();
4662 const double stopSpeed = aVehicle->getCarFollowModel().stopSpeed(aVehicle, speed, gap, MSCFModel::CalcReason::FUTURE);
4663 if ((gap < 0 && (aVehicle->getInsertionChecks() & ((int)InsertionCheck::COLLISION | (int)InsertionCheck::PEDESTRIAN)) != 0)
4664 || checkFailure(aVehicle, speed, dist, stopSpeed, patchSpeed, "", InsertionCheck::PEDESTRIAN)) {
4665 // we may not drive with the given velocity - we crash into the pedestrian
4666#ifdef DEBUG_INSERTION
4667 if (DEBUG_COND2(aVehicle)) std::cout << SIMTIME
4668 << " isInsertionSuccess lane=" << getID()
4669 << " veh=" << aVehicle->getID()
4670 << " pos=" << pos
4671 << " posLat=" << aVehicle->getLateralPositionOnLane()
4672 << " patchSpeed=" << patchSpeed
4673 << " speed=" << speed
4674 << " stopSpeed=" << stopSpeed
4675 << " pedestrianLeader=" << leader.first->getID()
4676 << " failed (@796)!\n";
4677#endif
4678 return false;
4679 }
4680 }
4681 }
4682 double backLength = aVehicle->getLength() - pos;
4683 if (backLength > 0 && MSNet::getInstance()->hasPersons()) {
4684 // look upstream for pedestrian crossings
4685 const MSLane* prev = getLogicalPredecessorLane();
4686 const MSLane* cur = this;
4687 while (backLength > 0 && prev != nullptr) {
4688 const MSLink* link = prev->getLinkTo(cur);
4689 if (link->hasFoeCrossing()) {
4690 for (const MSLane* foe : link->getFoeLanes()) {
4691 if (foe->isCrossing() && (foe->hasPedestrians() ||
4692 (foe->getIncomingLanes()[0].viaLink->getApproachingPersons() != nullptr
4693 && foe->getIncomingLanes()[0].viaLink->getApproachingPersons()->size() > 0))) {
4694#ifdef DEBUG_INSERTION
4695 if (DEBUG_COND2(aVehicle)) std::cout << SIMTIME
4696 << " isInsertionSuccess lane=" << getID()
4697 << " veh=" << aVehicle->getID()
4698 << " pos=" << pos
4699 << " backCrossing=" << foe->getID()
4700 << " peds=" << joinNamedToString(foe->getEdge().getPersons(), " ")
4701 << " approaching=" << foe->getIncomingLanes()[0].viaLink->getApproachingPersons()->size()
4702 << " failed (@4550)!\n";
4703#endif
4704 return false;
4705 }
4706 }
4707 }
4708 backLength -= prev->getLength();
4709 cur = prev;
4710 prev = prev->getLogicalPredecessorLane();
4711 }
4712 }
4713 return true;
4714}
4715
4716
4717void
4719 myRNGs.clear();
4720 const int numRNGs = oc.getInt("thread-rngs");
4721 const bool random = oc.getBool("random");
4722 int seed = oc.getInt("seed");
4723 myRNGs.reserve(numRNGs); // this is needed for stable pointers on debugging
4724 for (int i = 0; i < numRNGs; i++) {
4725 myRNGs.push_back(SumoRNG("lanes_" + toString(i)));
4726 RandHelper::initRand(&myRNGs.back(), random, seed++);
4727 }
4728}
4729
4730void
4732 for (int i = 0; i < getNumRNGs(); i++) {
4734 out.writeAttr(SUMO_ATTR_INDEX, i);
4736 out.closeTag();
4737 }
4738}
4739
4740void
4741MSLane::loadRNGState(int index, const std::string& state) {
4742 if (index >= getNumRNGs()) {
4743 throw ProcessError(TLF("State was saved with more than % threads. Change the number of threads or do not load RNG state", toString(getNumRNGs())));
4744 }
4745 RandHelper::loadState(state, &myRNGs[index]);
4746}
4747
4748
4749MSLane*
4751 return myBidiLane;
4752}
4753
4754
4755bool
4758 myLinks.front()->getFoeLanes().size() > 0
4759 || myLinks.front()->getWalkingAreaFoe() != nullptr
4760 || myLinks.front()->getWalkingAreaFoeExit() != nullptr);
4761}
4762
4763
4764double
4765MSLane::getSpaceTillLastStanding(const MSVehicle* ego, bool& foundStopped) const {
4767 double lengths = 0;
4768 for (const MSVehicle* last : myVehicles) {
4769 if (last->getSpeed() < SUMO_const_haltingSpeed && !last->getLane()->getEdge().isRoundabout()
4770 && last != ego
4771 // @todo recheck
4772 && last->isFrontOnLane(this)) {
4773 foundStopped = true;
4774 const double lastBrakeGap = last->getCarFollowModel().brakeGap(last->getSpeed());
4775 const double ret = last->getBackPositionOnLane() + lastBrakeGap - lengths;
4776 return ret;
4777 }
4778 if (MSGlobals::gSublane && ego->getVehicleType().getWidth() + last->getVehicleType().getWidth() < getWidth()) {
4779 lengths += last->getVehicleType().getLengthWithGap() * (last->getVehicleType().getWidth() + last->getVehicleType().getMinGapLat()) / getWidth();
4780 } else {
4781 lengths += last->getVehicleType().getLengthWithGap();
4782 }
4783 }
4784 return getLength() - lengths;
4785}
4786
4787
4788bool
4789MSLane::allowsVehicleClass(SUMOVehicleClass vclass, int routingMode) const {
4790 return (((routingMode & libsumo::ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS) ? myOriginalPermissions : myPermissions) & vclass) == vclass;
4791}
4792
4793
4794const MSJunction*
4796 return myEdge->getFromJunction();
4797}
4798
4799
4800const MSJunction*
4802 return myEdge->getToJunction();
4803}
4804
4805
4806bool
4808 if (veh->getDevice(typeid(MSDevice_Taxi)) != nullptr) {
4809 // taxi device may assign a new route that continues past the end of the initial route
4810 return true;
4811 }
4812 for (const MSMoveReminder* rem : myMoveReminders) {
4813 if (dynamic_cast<const MSTriggeredRerouter*>(rem) != nullptr) {
4814 return true;
4815 }
4816 }
4817 return false;
4818}
4819
4820
4821bool
4823 for (const MSLink* link : myLinks) {
4824 if (!link->havePriority() || link->getState() == LINKSTATE_ZIPPER) {
4825 return true;
4826 }
4827 }
4828 return false;
4829}
4830
4831/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define RAD2DEG(x)
Definition GeomHelper.h:36
#define DEBUG_COND2(obj)
#define INVALID_SPEED
Definition MSCFModel.h:33
std::vector< MSEdge * > MSEdgeVector
Definition MSEdge.h:73
#define LANE_RTREE_QUAL
Definition MSLane.h:1841
std::pair< const MSVehicle *, double > CLeaderDist
std::pair< const MSPerson *, double > PersonDist
Definition MSPModel.h:41
ConstMSEdgeVector::const_iterator MSRouteIterator
Definition MSRoute.h:57
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define WRITE_ERROR(msg)
Definition MsgHandler.h:295
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SPEED2DIST(x)
Definition SUMOTime.h:48
#define SIMSTEP
Definition SUMOTime.h:64
#define SUMOTime_MIN
Definition SUMOTime.h:35
#define SIMTIME
Definition SUMOTime.h:65
#define TIME2STEPS(x)
Definition SUMOTime.h:60
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a (exclusive) railway edge.
bool isRailwayOrShared(SVCPermissions permissions)
Returns whether an edge with the given permissions is a railway edge or a shared road/rail edge.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ AIRCRAFT
render as aircraft
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_SHIP
is an arbitrary ship
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_BICYCLE
vehicle is a bicycle
const int STOP_DURATION_SET
@ GIVEN
The speed is given.
@ RANDOM
The lateral position is chosen randomly.
@ RIGHT
At the rightmost side of the lane.
@ GIVEN
The position is given.
@ DEFAULT
No information given; use default.
@ LEFT
At the leftmost side of the lane.
@ FREE
A free lateral position is chosen.
@ CENTER
At the center of the lane.
@ RANDOM_FREE
If a fixed number of random choices fails, a free lateral position is chosen.
@ RANDOM
A random position is chosen.
@ GIVEN
The position is given.
@ DEFAULT
No information given; use default.
@ STOP
depart position is endPos of first stop
@ FREE
A free position is chosen.
@ SPLIT_FRONT
depart position for a split vehicle is in front of the continuing vehicle
@ BASE
Back-at-zero position.
@ LAST
Insert behind the last vehicle as close as possible to still allow the specified departSpeed....
@ RANDOM_FREE
If a fixed number of random choices fails, a free position is chosen.
DepartSpeedDefinition
Possible ways to choose the departure speed.
@ RANDOM
The speed is chosen randomly.
@ MAX
The maximum safe speed is used.
@ GIVEN
The speed is given.
@ LIMIT
The maximum lane speed is used (speedLimit)
@ DEFAULT
No information given; use default.
@ DESIRED
The maximum lane speed is used (speedLimit * speedFactor)
@ LAST
The speed of the last vehicle. Fallback to DepartSpeedDefinition::DESIRED if there is no vehicle on t...
@ AVG
The average speed on the lane. Fallback to DepartSpeedDefinition::DESIRED if there is no vehicle on t...
const int STOP_START_SET
const int STOP_END_SET
@ SPLIT
The departure is triggered by a train split.
InsertionCheck
different checking levels for vehicle insertion
@ SUMO_TAG_LINK
Link information for state-saving.
@ SUMO_TAG_APPROACHING
Link-approaching vehicle information for state-saving.
@ SUMO_TAG_RNGLANE
@ SUMO_TAG_VIEWSETTINGS_VEHICLES
@ SUMO_TAG_LANE
begin/end of the description of a single lane
@ STRAIGHT
The link is a straight direction.
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_ALLWAY_STOP
This is an uncontrolled, all-way stop link.
@ LINKSTATE_MAJOR
This is an uncontrolled, major link, may pass.
@ LINKSTATE_STOP
This is an uncontrolled, minor link, has to stop.
@ LINKSTATE_EQUAL
This is an uncontrolled, right-before-left link.
@ LINKSTATE_DEADEND
This is a dead end link.
@ LINKSTATE_ZIPPER
This is an uncontrolled, zipper-merge link.
@ LINKSTATE_MINOR
This is an uncontrolled, minor link, has to brake.
@ SUMO_ATTR_ARRIVALSPEED
@ SUMO_ATTR_JM_STOPLINE_CROSSING_GAP
@ SUMO_ATTR_ARRIVALTIME
@ SUMO_ATTR_WAITINGTIME
@ SUMO_ATTR_VALUE
@ SUMO_ATTR_POSITION_LAT
@ SUMO_ATTR_ARRIVALSPEEDBRAKING
@ SUMO_ATTR_INDEX
@ SUMO_ATTR_DEPARTSPEED
@ SUMO_ATTR_TO
@ SUMO_ATTR_DISTANCE
@ SUMO_ATTR_ID
@ SUMO_ATTR_REQUEST
@ SUMO_ATTR_STATE
The state of a link.
int gPrecision
the precision for floating point outputs
Definition StdDefs.cpp:27
int gPrecisionRandom
Definition StdDefs.cpp:30
double roundDecimal(double x, int precision)
round to the given number of decimal digits
Definition StdDefs.cpp:61
bool gDebugFlag4
Definition StdDefs.cpp:47
bool gDebugFlag1
global utility flags for debugging
Definition StdDefs.cpp:44
#define FALLTHROUGH
Definition StdDefs.h:39
T MIN2(T a, T b)
Definition StdDefs.h:80
const double SUMO_const_haltingSpeed
the speed threshold at which vehicles are considered as halting
Definition StdDefs.h:62
T MAX2(T a, T b)
Definition StdDefs.h:86
T MAX3(T a, T b, T c)
Definition StdDefs.h:100
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition ToString.h:357
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:49
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:127
double xmin() const
Returns minimum x-coordinate.
Definition Boundary.cpp:115
Boundary & grow(double by)
extends the boundary by the given amount
Definition Boundary.cpp:340
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:133
double xmax() const
Returns maximum x-coordinate.
Definition Boundary.cpp:121
static double angleDiff(const double angle1, const double angle2)
Returns the difference of the second angle to the first angle in radiants.
static double sum(double val)
Computes the resulting noise.
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition MELoop.cpp:344
A single mesoscopic segment (cell)
Definition MESegment.h:50
void setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh=DO_NOT_PATCH_JAM_THRESHOLD, int qIdx=-1)
reset mySpeed and patch the speed of all vehicles in it. Also set/recompute myJamThreshold
MESegment * getNextSegment() const
Returns the following segment on the same edge (0 if it is the last).
Definition MESegment.h:246
Container & getContainer()
Definition MFXSynchQue.h:84
void unlock()
Definition MFXSynchQue.h:99
void unsetCondition()
Definition MFXSynchQue.h:79
void push_back(T what)
virtual double getExtraReservation(int bestLaneOffset, double neighExtraDist=0) const
MSLane * getShadowLane() const
Returns the lane the vehicle's shadow is on during continuous/sublane lane change.
bool isChangingLanes() const
return true if the vehicle currently performs a lane change maneuver
The base class for microscopic and mesoscopic vehicles.
double getImpatience() const
Returns this vehicles impatience.
const MSEdge * succEdge(int nSuccs) const
Returns the nSuccs'th successor of edge the vehicle is currently at.
virtual double getArrivalPos() const
Returns this vehicle's desired arrivalPos for its current route (may change on reroute)
int getInsertionChecks() const
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
double getChosenSpeedFactor() const
Returns the precomputed factor by which the driver wants to be faster than the speed limit.
const SUMOVehicleParameter::Stop * getNextStopParameter() const
return parameters for the next stop (SUMOVehicle Interface)
bool isRail() const
bool isJumping() const
Returns whether the vehicle is perform a jump.
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
double getLength() const
Returns the vehicle's length.
bool isParking() const
Returns whether the vehicle is parking.
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
bool hasDeparted() const
Returns whether this vehicle has already departed.
double basePos(const MSEdge *edge) const
departure position where the vehicle fits fully onto the edge (if possible)
bool hasStops() const
Returns whether the vehicle has to stop somewhere.
const MSStop & getNextStop() const
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
NumericalID getNumericalID() const
return the numerical ID which is only for internal usage
const MSRoute & getRoute() const
Returns the current route.
int getRoutePosition() const
return index of edge within route
SUMOTime getDepartDelay() const
Returns the depart delay.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
bool isStopped() const
Returns whether the vehicle is at a stop.
MSDevice * getDevice(const std::type_info &type) const
Returns a device of the given type if it exists, nullptr otherwise.
The car-following model abstraction.
Definition MSCFModel.h:59
double getCollisionMinGapFactor() const
Get the factor of minGap that must be maintained to avoid a collision event.
Definition MSCFModel.h:337
double getEmergencyDecel() const
Get the vehicle type's maximal physically possible deceleration [m/s^2].
Definition MSCFModel.h:293
virtual double freeSpeed(const MSVehicle *const veh, double speed, double seen, double maxSpeed, const bool onInsertion=false, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed without a leader.
virtual double insertionFollowSpeed(const MSVehicle *const veh, double speed, double gap2pred, double predSpeed, double predMaxDecel, const MSVehicle *const pred=0) const
Computes the vehicle's safe speed (no dawdling) This method is used during the insertion stage....
@ FUTURE
the return value is used for calculating future speeds
Definition MSCFModel.h:99
virtual double getSecureGap(const MSVehicle *const veh, const MSVehicle *const, const double speed, const double leaderSpeed, const double leaderMaxDecel) const
Returns the minimum gap to reserve if the leader is braking at maximum (>=0)
double brakeGap(const double speed) const
Returns the distance the vehicle needs to halt including driver's reaction time tau (i....
Definition MSCFModel.h:424
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition MSCFModel.h:285
double stopSpeed(const MSVehicle *const veh, const double speed, double gap, const CalcReason usage=CalcReason::CURRENT) const
Computes the vehicle's safe speed for approaching a non-moving obstacle (no dawdling)
Definition MSCFModel.h:189
virtual double insertionStopSpeed(const MSVehicle *const veh, double speed, double gap) const
Computes the vehicle's safe speed for approaching an obstacle at insertion without constraints due to...
std::string toString() const
print a debugging representation
int addFollower(const MSVehicle *veh, const MSVehicle *ego, double gap, double latOffset=0, int sublane=-1)
A device which collects info on the vehicle trip (mainly on departure and arrival)
static const MSDriveWay * getDepartureDriveway(const SUMOVehicle *veh, bool init=false)
bool foeDriveWayOccupied(bool store, const SUMOVehicle *ego, MSEdgeVector &occupied) const
whether any of myFoes is occupied (vehicles that are the target of a join must be ignored)
void gotActive(MSLane *l)
Informs the control that the given lane got active.
void checkCollisionForInactive(MSLane *l)
trigger collision checking for inactive lane
void needsVehicleIntegration(MSLane *const l)
A road/street connecting two junctions.
Definition MSEdge.h:77
void changeLanes(SUMOTime t) const
Performs lane changing on this edge.
Definition MSEdge.cpp:934
bool isCrossing() const
return whether this edge is a pedestrian crossing
Definition MSEdge.h:274
int getPriority() const
Returns the priority of the edge.
Definition MSEdge.h:337
const std::set< MSTransportable *, ComparatorNumericalIdLess > & getPersons() const
Returns this edge's persons set.
Definition MSEdge.h:204
bool isWalkingArea() const
return whether this edge is walking area
Definition MSEdge.h:288
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:168
const MSEdge * getNormalSuccessor() const
if this edge is an internal edge, return its first normal successor, otherwise the edge itself
Definition MSEdge.cpp:989
const std::vector< MSLane * > * allowedLanes(const MSEdge &destination, SUMOVehicleClass vclass=SVC_IGNORING, bool ignoreTransientPermissions=false) const
Get the allowed lanes to reach the destination-edge.
Definition MSEdge.cpp:488
const MSEdge * getBidiEdge() const
return opposite superposable/congruent edge, if it exist and 0 else
Definition MSEdge.h:283
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:264
std::vector< MSTransportable * > getSortedPersons(SUMOTime timestep, bool includeRiding=false) const
Returns this edge's persons sorted by pos.
Definition MSEdge.cpp:1255
void recalcCache()
Recalculates the cached values.
Definition MSEdge.cpp:122
bool hasLaneChanger() const
Definition MSEdge.h:759
const MSJunction * getToJunction() const
Definition MSEdge.h:427
const MSJunction * getFromJunction() const
Definition MSEdge.h:423
int getNumLanes() const
Definition MSEdge.h:172
bool isInternal() const
return whether this edge is an internal edge
Definition MSEdge.h:269
bool isVaporizing() const
Returns whether vehicles on this edge shall be vaporized.
Definition MSEdge.h:443
MSLane * parallelLane(const MSLane *const lane, int offset, bool includeOpposite=true) const
Returns the lane with the given offset parallel to the given lane one or 0 if it does not exist.
Definition MSEdge.cpp:471
const std::string & getEdgeType() const
Returns the type of the edge.
Definition MSEdge.h:320
void markDelayed() const
Definition MSEdge.h:750
const MSEdgeVector & getPredecessors() const
Definition MSEdge.h:418
static SUMOTime gTimeToTeleportDisconnected
Definition MSGlobals.h:66
static bool gUseMesoSim
Definition MSGlobals.h:106
static SUMOTime gTimeToGridlockHighways
Definition MSGlobals.h:60
static bool gCheckRoutes
Definition MSGlobals.h:91
static double gGridlockHighwaysSpeed
Definition MSGlobals.h:63
static bool gRemoveGridlocked
Definition MSGlobals.h:75
static SUMOTime gTimeToTeleportBidi
Definition MSGlobals.h:69
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition MSGlobals.h:115
static double gLateralResolution
Definition MSGlobals.h:100
static SUMOTime gTimeToTeleportRSDeadlock
Definition MSGlobals.h:72
static bool gClearState
whether the simulation is in the process of clearing state (MSNet::clearState)
Definition MSGlobals.h:146
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition MSGlobals.h:143
static bool gEmergencyInsert
Definition MSGlobals.h:94
static int gNumSimThreads
how many threads to use for simulation
Definition MSGlobals.h:149
static SUMOTime gIgnoreJunctionBlocker
Definition MSGlobals.h:85
static bool gSublane
whether sublane simulation is enabled (sublane model or continuous lanechanging)
Definition MSGlobals.h:168
static SUMOTime gLaneChangeDuration
Definition MSGlobals.h:97
static bool gUnitTests
whether unit tests are being run
Definition MSGlobals.h:140
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition MSGlobals.h:81
static SUMOTime gTimeToGridlock
Definition MSGlobals.h:57
void retractDescheduleDeparture(const SUMOVehicle *veh)
reverts a previous call to descheduleDeparture (only needed for departPos="random_free")
void descheduleDeparture(const SUMOVehicle *veh)
stops trying to emit the given vehicle (and delete it)
The base class for an intersection.
Definition MSJunction.h:58
SumoXMLNodeType getType() const
return the type of this Junction
Definition MSJunction.h:133
AnyVehicleIterator is a structure, which manages the iteration through all vehicles on the lane,...
Definition MSLane.h:129
bool nextIsMyVehicles() const
Definition MSLane.cpp:206
AnyVehicleIterator & operator++()
Definition MSLane.cpp:172
const MSVehicle * operator*()
Definition MSLane.cpp:189
void add(const MSLane *const l) const
Adds the given object to the container.
Definition MSLane.cpp:125
std::set< const Named * > & myObjects
The container.
Definition MSLane.h:98
const double myRange
Definition MSLane.h:100
const PositionVector & myShape
Definition MSLane.h:99
Sorts edges by their angle relative to the given edge (straight comes first)
Definition MSLane.h:1728
by_connections_to_sorter(const MSEdge *const e)
constructor
Definition MSLane.cpp:3570
int operator()(const MSEdge *const e1, const MSEdge *const e2) const
comparing operator
Definition MSLane.cpp:3577
Sorts lanes (IncomingLaneInfos) by their priority or, if this doesn't apply, wrt. the angle differenc...
Definition MSLane.h:1747
incoming_lane_priority_sorter(const MSLane *targetLane)
constructor
Definition MSLane.cpp:3611
int operator()(const IncomingLaneInfo &lane1, const IncomingLaneInfo &lane2) const
comparing operator
Definition MSLane.cpp:3616
Sorts lanes (their origin link) by the priority of their noninternal target edges or,...
Definition MSLane.h:1765
outgoing_lane_priority_sorter(const MSLane *sourceLane)
constructor
Definition MSLane.cpp:3689
int operator()(const MSLink *link1, const MSLink *link2) const
comparing operator
Definition MSLane.cpp:3693
int operator()(MSVehicle *v1, MSVehicle *v2) const
Comparing operator.
Definition MSLane.cpp:3559
Sorts vehicles by their position (descending)
Definition MSLane.h:1682
int operator()(MSVehicle *v1, MSVehicle *v2) const
Comparing operator.
Definition MSLane.cpp:3547
Representation of a lane in the micro simulation.
Definition MSLane.h:84
void addApproachingLane(MSLane *lane, bool warnMultiCon)
Definition MSLane.cpp:2911
void loadState(const std::vector< SUMOVehicle * > &vehs)
Loads the state of this segment with the given parameters.
Definition MSLane.cpp:3808
bool detectCollisionBetween(SUMOTime timestep, const std::string &stage, MSVehicle *collider, MSVehicle *victim, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toRemove, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toTeleport) const
detect whether there is a collision between the two vehicles
Definition MSLane.cpp:1978
static SUMOTime myIntermodalCollisionStopTime
Definition MSLane.h:1673
MFXSynchQue< MSVehicle *, std::vector< MSVehicle * > > myVehBuffer
Buffer for vehicles that moved from their previous lane onto this one. Integrated after all vehicles ...
Definition MSLane.h:1527
SVCPermissions myPermissions
The vClass permissions for this lane.
Definition MSLane.h:1565
MSLane * myLogicalPredecessorLane
Definition MSLane.h:1581
static void initCollisionAction(const OptionsCont &oc, const std::string &option, CollisionAction &myAction)
Definition MSLane.cpp:4564
std::set< const MSBaseVehicle * > myParkingVehicles
Definition MSLane.h:1540
bool checkForPedestrians(const MSVehicle *aVehicle, double &speed, double &dist, double pos, bool patchSpeed) const
check whether pedestrians on this lane interfere with vehicle insertion
Definition MSLane.cpp:4651
static double myDefaultDepartSpeed
Definition MSLane.h:1677
std::pair< const MSPerson *, double > nextBlocking(double minPos, double minRight, double maxLeft, double stopTime=0, bool bidi=false) const
This is just a wrapper around MSPModel::nextBlocking. You should always check using hasPedestrians be...
Definition MSLane.cpp:4645
MSLane * getParallelLane(int offset, bool includeOpposite=true) const
Returns the lane with the given offset parallel to this one or 0 if it does not exist.
Definition MSLane.cpp:2895
double myRightSideOnEdge
the combined width of all lanes with lower index on myEdge
Definition MSLane.h:1631
const StopOffset & getLaneStopOffsets() const
Returns vehicle class specific stopOffsets.
Definition MSLane.cpp:3835
virtual void removeParking(MSBaseVehicle *veh)
remove parking vehicle. This must be syncrhonized when running with GUI
Definition MSLane.cpp:3734
virtual ~MSLane()
Destructor.
Definition MSLane.cpp:307
bool insertVehicle(MSVehicle &v)
Tries to insert the given vehicle.
Definition MSLane.cpp:692
bool mySpeedModified
Whether the current speed limit is set by a variable speed sign (VSS), TraCI or a MSCalibrator.
Definition MSLane.h:1562
const MSLeaderInfo getFirstVehicleInformation(const MSVehicle *ego, double latOffset, bool onlyFrontOnLane, double maxPos=std::numeric_limits< double >::max(), bool allowCached=true) const
analogue to getLastVehicleInformation but in the upstream direction
Definition MSLane.cpp:1540
virtual void integrateNewVehicles()
Insert buffered vehicle into the real lane.
Definition MSLane.cpp:2605
double myLength
Lane length [m].
Definition MSLane.h:1543
bool isApproachedFrom(MSEdge *const edge)
Definition MSLane.h:987
double getNettoOccupancy() const
Returns the netto (excluding minGaps) occupancy of this lane during the last step (including minGaps)
Definition MSLane.cpp:3456
virtual MSVehicle * removeVehicle(MSVehicle *remVehicle, MSMoveReminder::Notification notification, bool notify=true)
Definition MSLane.cpp:2877
int getCrossingIndex() const
return the index of the link to the next crossing if this is walkingArea, else -1
Definition MSLane.cpp:3411
PositionVector myShape
The shape of the lane.
Definition MSLane.h:1488
PositionVector * myOutlineShape
the outline of the lane (optional)
Definition MSLane.h:1491
std::map< long long, SVCPermissions > myPermissionChanges
Definition MSLane.h:1645
const std::map< SUMOVehicleClass, double > * myRestrictions
The vClass speed restrictions for this lane.
Definition MSLane.h:1575
virtual void incorporateVehicle(MSVehicle *veh, double pos, double speed, double posLat, const MSLane::VehCont::iterator &at, MSMoveReminder::Notification notification=MSMoveReminder::NOTIFICATION_DEPARTED)
Inserts the vehicle into this lane, and informs it about entering the network.
Definition MSLane.cpp:457
void initRestrictions()
initialized vClass-specific speed limits
Definition MSLane.cpp:316
std::vector< MSMoveReminder * > myMoveReminders
This lane's move reminder.
Definition MSLane.h:1665
bool hasApproaching() const
Definition MSLane.cpp:3739
void addParking(MSBaseVehicle *veh)
add parking vehicle. This should only used during state loading
Definition MSLane.cpp:3728
VehCont myTmpVehicles
Container for lane-changing vehicles. After completion of lane-change- process, the containers will b...
Definition MSLane.h:1523
static DepartSpeedDefinition myDefaultDepartSpeedDefinition
Definition MSLane.h:1676
MSLane(const std::string &id, double maxSpeed, double friction, double length, MSEdge *const edge, int numericalID, const PositionVector &shape, double width, SVCPermissions permissions, SVCPermissions changeLeft, SVCPermissions changeRight, int index, bool isRampAccel, const std::string &type, const PositionVector &outlineShape)
Constructor.
Definition MSLane.cpp:255
double getDepartSpeed(const MSVehicle &veh, bool &patchSpeed)
Definition MSLane.cpp:607
MSLeaderInfo myFollowerInfo
followers on all sublanes as seen by vehicles on consecutive lanes (cached)
Definition MSLane.h:1614
const MSLane * getNormalSuccessorLane() const
get normal lane following this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3296
int getVehicleNumber() const
Returns the number of vehicles on this lane (for which this lane is responsible)
Definition MSLane.h:457
static SUMOTime myCollisionStopTime
Definition MSLane.h:1672
static CollisionAction myCollisionAction
the action to take on collisions
Definition MSLane.h:1668
MSLane * myCanonicalSuccessorLane
Main successor lane,.
Definition MSLane.h:1587
SVCPermissions myChangeLeft
The vClass permissions for changing from this lane.
Definition MSLane.h:1568
void getLeadersOnConsecutive(double dist, double seen, double speed, const MSVehicle *ego, const std::vector< MSLane * > &bestLaneConts, MSLeaderDistanceInfo &result, bool oppositeDirection=false) const
Returns the immediate leaders and the distance to them (as getLeaderOnConsecutive but for the sublane...
Definition MSLane.cpp:4084
std::vector< IncomingLaneInfo > myIncomingLanes
All direct predecessor lanes.
Definition MSLane.h:1578
AnyVehicleIterator anyVehiclesEnd() const
end iterator for iterating over all vehicles touching this lane in downstream direction
Definition MSLane.h:496
static void insertIDs(std::vector< std::string > &into)
Adds the ids of all stored lanes into the given vector.
Definition MSLane.cpp:2560
bool hadPermissionChanges() const
Definition MSLane.cpp:4620
void sortPartialVehicles()
sorts myPartialVehicles
Definition MSLane.cpp:2632
double myFrictionCoefficient
Lane-wide friction coefficient [0..1].
Definition MSLane.h:1559
MSVehicle * getFirstAnyVehicle() const
returns the first vehicle that is fully or partially on this lane
Definition MSLane.cpp:2726
const MSLink * getEntryLink() const
Returns the entry link if this is an internal lane, else nullptr.
Definition MSLane.cpp:2814
int getVehicleNumberWithPartials() const
Returns the number of vehicles on this lane (including partial occupators)
Definition MSLane.h:465
static bool myCheckJunctionCollisions
Definition MSLane.h:1670
static void clear()
Clears the dictionary.
Definition MSLane.cpp:2551
virtual void resetManeuverReservation(MSVehicle *v)
Unregisters a vehicle, which previously registered for maneuvering into this lane.
Definition MSLane.cpp:439
SVCPermissions myOriginalPermissions
The original vClass permissions for this lane (before temporary modifications)
Definition MSLane.h:1572
MSEdge *const myEdge
The lane's edge, for routing only.
Definition MSLane.h:1554
double myNettoVehicleLengthSum
The current length of all vehicles on this lane, excluding their minGaps.
Definition MSLane.h:1593
std::pair< MSVehicle *const, double > getFollower(const MSVehicle *ego, double egoPos, double dist, MinorLinkMode mLinkMode, bool maxSearchDist=false) const
Find follower vehicle for the given ego vehicle (which may be on the opposite direction lane)
Definition MSLane.cpp:4471
static std::vector< MSLink * >::const_iterator succLinkSec(const SUMOVehicle &veh, int nRouteSuccs, const MSLane &succLinkSource, const std::vector< MSLane * > &conts)
Definition MSLane.cpp:2740
void detectPedestrianJunctionCollision(const MSVehicle *collider, const PositionVector &colliderBoundary, const MSLane *foeLane, SUMOTime timestep, const std::string &stage, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toRemove, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toTeleport)
detect whether a vehicle collids with pedestrians on the junction
Definition MSLane.cpp:1937
double getMissingRearGap(const MSVehicle *leader, double backOffset, double leaderSpeed) const
return by how much further the leader must be inserted to avoid rear end collisions
Definition MSLane.cpp:2936
double myMaxSpeed
Lane-wide speed limit [m/s].
Definition MSLane.h:1557
void saveState(OutputDevice &out)
Saves the state of this lane into the given stream.
Definition MSLane.cpp:3749
void markRecalculateBruttoSum()
Set a flag to recalculate the brutto (including minGaps) occupancy of this lane (used if mingap is ch...
Definition MSLane.cpp:2472
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2791
int myRightmostSublane
the index of the rightmost sublane of this lane on myEdge
Definition MSLane.h:1633
void setChangeRight(SVCPermissions permissions)
Sets the permissions for changing to the right neighbour lane.
Definition MSLane.cpp:4632
const MSLeaderInfo getLastVehicleInformation(const MSVehicle *ego, double latOffset, double minPos=0, bool allowCached=true, const MSVehicle *ignore=nullptr) const
Returns the last vehicles on the lane.
Definition MSLane.cpp:1478
const bool myIsRampAccel
whether this lane is an acceleration lane
Definition MSLane.h:1625
virtual void planMovements(const SUMOTime t)
Compute safe velocities for all vehicles based on positions and speeds from the last time step....
Definition MSLane.cpp:1595
MSLeaderDistanceInfo getFollowersOnConsecutive(const MSVehicle *ego, double backOffset, bool allSublanes, double searchDist=-1, MinorLinkMode mLinkMode=FOLLOW_ALWAYS, bool maxSearchDist=false) const
return the sublane followers with the largest missing rear gap among all predecessor lanes (within di...
Definition MSLane.cpp:3847
static void saveRNGStates(OutputDevice &out)
save random number generator states to the given output device
Definition MSLane.cpp:4731
SUMOTime myFollowerInfoTime
time step for which myFollowerInfo was last updated
Definition MSLane.h:1619
MSLeaderInfo myLeaderInfo
leaders on all sublanes as seen by approaching vehicles (cached)
Definition MSLane.h:1612
bool isInsertionSuccess(MSVehicle *vehicle, double speed, double pos, double posLat, bool recheckNextLanes, MSMoveReminder::Notification notification)
Tries to insert the given vehicle with the given state (speed and pos)
Definition MSLane.cpp:852
void forceVehicleInsertion(MSVehicle *veh, double pos, MSMoveReminder::Notification notification, double posLat=0)
Inserts the given vehicle at the given position.
Definition MSLane.cpp:1425
double getVehicleStopOffset(const MSVehicle *veh) const
Returns vehicle class specific stopOffset for the vehicle.
Definition MSLane.cpp:3822
static void initCollisionOptions(const OptionsCont &oc)
Definition MSLane.cpp:4580
int myNumericalID
Unique numerical ID (set on reading by netload)
Definition MSLane.h:1485
VehCont myVehicles
The lane's vehicles. This container holds all vehicles that have their front (longitudinally) and the...
Definition MSLane.h:1507
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:602
MSLeaderInfo getPartialBeyond() const
get all vehicles that are inlapping from consecutive edges
Definition MSLane.cpp:4308
std::vector< MSVehicle * > VehCont
Container for vehicles.
Definition MSLane.h:119
bool checkFailure(const MSVehicle *aVehicle, double &speed, double &dist, const double nspeed, const bool patchSpeed, const std::string errorMsg, InsertionCheck check) const
Definition MSLane.cpp:819
static DictType myDict
Static dictionary to associate string-ids with objects.
Definition MSLane.h:1659
static void fill(RTREE &into)
Fills the given RTree with lane instances.
Definition MSLane.cpp:2568
double safeInsertionSpeed(const MSVehicle *veh, double seen, const MSLeaderInfo &leaders, double speed)
return the maximum safe speed for insertion behind leaders (a negative value indicates that safe inse...
Definition MSLane.cpp:1436
MSLane * myBidiLane
Definition MSLane.h:1642
std::vector< const MSJunction * > getUpcomingJunctions(double pos, double range, const std::vector< MSLane * > &contLanes) const
Returns all upcoming junctions within given range along the given (non-internal) continuation lanes m...
Definition MSLane.cpp:4395
void addIncomingLane(MSLane *lane, MSLink *viaLink)
Definition MSLane.cpp:2901
bool isWalkingArea() const
Definition MSLane.cpp:2683
const MSEdge * getNextNormal() const
Returns the lane's follower if it is an internal lane, the edge of the lane otherwise.
Definition MSLane.cpp:2504
void addLink(MSLink *link)
Delayed initialization.
Definition MSLane.cpp:335
std::set< MSVehicle * > getVehiclesInRange(const double a, const double b) const
Returns all vehicles on the lane overlapping with the interval [a,b].
Definition MSLane.cpp:4375
void enteredByLaneChange(MSVehicle *v)
Definition MSLane.cpp:3404
double getDepartPosLat(const MSVehicle &veh)
Definition MSLane.cpp:666
std::pair< MSVehicle *const, double > getOppositeLeader(const MSVehicle *ego, double dist, bool oppositeDir, MinorLinkMode mLinkMode=MinorLinkMode::FOLLOW_NEVER) const
Definition MSLane.cpp:4494
SVCPermissions getPermissions() const
Returns the vehicle class permissions for this lane.
Definition MSLane.h:640
LinkState getIncomingLinkState() const
get the state of the link from the logical predecessor to this lane
Definition MSLane.cpp:3362
void updateLengthSum()
updated current vehicle length sum (delayed to avoid lane-order-dependency)
Definition MSLane.cpp:2478
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:981
static const long CHANGE_PERMISSIONS_PERMANENT
Definition MSLane.h:1405
virtual void addMoveReminder(MSMoveReminder *rem, bool addToVehicles=true)
Add a move-reminder to move-reminder container.
Definition MSLane.cpp:362
MSLane * getCanonicalPredecessorLane() const
Definition MSLane.cpp:3317
void resetPermissions(long long transientID)
Definition MSLane.cpp:4605
bool isPriorityCrossing() const
Definition MSLane.cpp:2677
MSVehicle * getLastFullVehicle() const
returns the last vehicle for which this lane is responsible or 0
Definition MSLane.cpp:2689
static void loadRNGState(int index, const std::string &state)
load random number generator state for the given rng index
Definition MSLane.cpp:4741
const std::string myLaneType
the type of this lane
Definition MSLane.h:1628
int myRNGIndex
Definition MSLane.h:1648
VehCont myManeuverReservations
The vehicles which registered maneuvering into the lane within their current action step....
Definition MSLane.h:1535
const MSJunction * getToJunction() const
Definition MSLane.cpp:4801
void addLeaders(const MSVehicle *vehicle, double vehPos, MSLeaderDistanceInfo &result, bool oppositeDirection=false)
get leaders for ego on the given lane
Definition MSLane.cpp:4218
static double myCheckJunctionCollisionMinGap
Definition MSLane.h:1671
double getLength() const
Returns the lane's length.
Definition MSLane.h:632
double myBruttoVehicleLengthSum
The current length of all vehicles on this lane, including their minGaps.
Definition MSLane.h:1590
bool mayContinue(const MSVehicle *veh) const
whether the route of the give vehicle might be extended on insertion
Definition MSLane.cpp:4807
const PositionVector & getShape() const
Returns this lane's shape.
Definition MSLane.h:534
static bool isFrontalCollision(const MSVehicle *collider, const MSVehicle *victim)
detect frontal collisions
Definition MSLane.cpp:2299
void setChangeLeft(SVCPermissions permissions)
Sets the permissions for changing to the left neighbour lane.
Definition MSLane.cpp:4626
std::vector< const MSLink * > getUpcomingLinks(double pos, double range, const std::vector< MSLane * > &contLanes) const
Returns all upcoming links within given range along the given (non-internal) continuation lanes measu...
Definition MSLane.cpp:4406
const MSLane * getFirstInternalInConnection(double &offset) const
Returns 0 if the lane is not internal. Otherwise the first part of the connection (sequence of intern...
Definition MSLane.cpp:2510
const MSJunction * getFromJunction() const
Definition MSLane.cpp:4795
static int getNumRNGs()
return the number of RNGs
Definition MSLane.h:251
void handleCollisionBetween(SUMOTime timestep, const std::string &stage, const MSVehicle *collider, const MSVehicle *victim, double gap, double latGap, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toRemove, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toTeleport) const
take action upon collision
Definition MSLane.cpp:2085
double getMaximumBrakeDist() const
compute maximum braking distance on this lane
Definition MSLane.cpp:2952
static CollisionAction myIntermodalCollisionAction
Definition MSLane.h:1669
const MSLane * getInternalFollowingLane(const MSLane *const) const
returns the internal lane leading to the given lane or nullptr, if there is none
Definition MSLane.cpp:2803
static std::vector< SumoRNG > myRNGs
Definition MSLane.h:1661
virtual void swapAfterLaneChange(SUMOTime t)
moves myTmpVehicles int myVehicles after a lane change procedure
Definition MSLane.cpp:2860
std::pair< MSVehicle *const, double > getCriticalLeader(double dist, double seen, double speed, const MSVehicle &veh) const
Returns the most dangerous leader and the distance to him.
Definition MSLane.cpp:3177
StopOffset myLaneStopOffset
Definition MSLane.h:1551
static void initRNGs(const OptionsCont &oc)
initialize rngs
Definition MSLane.cpp:4718
std::pair< MSVehicle *const, double > getLeaderOnConsecutive(double dist, double seen, double speed, const MSVehicle &veh, const std::vector< MSLane * > &bestLaneConts, bool considerCrossingFoes=true) const
Returns the immediate leader and the distance to him.
Definition MSLane.cpp:3036
std::set< MSVehicle * > getSurroundingVehicles(double startPos, double downstreamDist, double upstreamDist, std::shared_ptr< LaneCoverageInfo > checkedLanes) const
Returns all vehicles closer than downstreamDist along the road network starting on the given position...
Definition MSLane.cpp:4323
bool myRecalculateBruttoSum
Flag to recalculate the occupancy (including minGaps) after a change in minGap.
Definition MSLane.h:1602
virtual void removeMoveReminder(MSMoveReminder *rem)
Remove a move-reminder from move-reminder container.
Definition MSLane.cpp:374
void clearState()
Remove all vehicles before quick-loading state.
Definition MSLane.cpp:3791
MSLane * myCanonicalPredecessorLane
Similar to LogicalPredecessorLane,.
Definition MSLane.h:1584
bool myNeedsCollisionCheck
whether a collision check is currently needed
Definition MSLane.h:1636
bool isLinkEnd(std::vector< MSLink * >::const_iterator &i) const
Definition MSLane.h:881
bool allowsVehicleClass(SUMOVehicleClass vclass) const
Definition MSLane.h:956
virtual double setPartialOccupation(MSVehicle *v)
Sets the information about a vehicle lapping into this lane.
Definition MSLane.cpp:386
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the lane's maximum speed, given a vehicle's speed limit adaptation.
Definition MSLane.h:575
void setBidiLane(MSLane *bidyLane)
Adds the (overlapping) reverse direction lane to this lane.
Definition MSLane.cpp:349
double getRightSideOnEdge() const
Definition MSLane.h:1226
void checkBufferType()
Definition MSLane.cpp:323
std::pair< MSVehicle *const, double > getOppositeFollower(const MSVehicle *ego) const
Definition MSLane.cpp:4522
bool hasPedestrians() const
whether the lane has pedestrians on it
Definition MSLane.cpp:4638
const std::vector< std::pair< const MSLane *, const MSEdge * > > getOutgoingViaLanes() const
get the list of outgoing lanes
Definition MSLane.cpp:3373
MSVehicle * getPartialBehind(const MSVehicle *ego) const
Definition MSLane.cpp:4285
void setLaneStopOffset(const StopOffset &stopOffset)
Set vehicle class specific stopOffsets.
Definition MSLane.cpp:3841
double myBruttoVehicleLengthSumToRemove
The length of all vehicles that have left this lane in the current step (this lane,...
Definition MSLane.h:1596
void leftByLaneChange(MSVehicle *v)
Definition MSLane.cpp:3397
MSLane * getCanonicalSuccessorLane() const
Definition MSLane.cpp:3341
std::vector< StopWatch< std::chrono::nanoseconds > > myStopWatch
Definition MSLane.h:1828
void setPermissions(SVCPermissions permissions, long long transientID)
Sets the permissions to the given value. If a transientID is given, the permissions are recored as te...
Definition MSLane.cpp:4593
const double myWidth
Lane width [m].
Definition MSLane.h:1546
bool lastInsertion(MSVehicle &veh, double mspeed, double posLat, bool patchSpeed)
inserts vehicle as close as possible to the last vehicle on this lane (or at the end of the lane if t...
Definition MSLane.cpp:482
void changeLanes(const SUMOTime time)
Definition MSLane.cpp:2498
double getOppositePos(double pos) const
return the corresponding position on the opposite lane
Definition MSLane.cpp:4466
SVCPermissions myChangeRight
Definition MSLane.h:1569
const double myLengthGeometryFactor
precomputed myShape.length / myLength
Definition MSLane.h:1622
virtual void executeMovements(const SUMOTime t)
Executes planned vehicle movements with regards to right-of-way.
Definition MSLane.cpp:2318
const std::set< const MSBaseVehicle * > & getParkingVehicles() const
retrieve the parking vehicles (see GUIParkingArea)
Definition MSLane.h:1285
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3261
double getBruttoOccupancy() const
Returns the brutto (including minGaps) occupancy of this lane during the last step.
Definition MSLane.cpp:3441
AnyVehicleIterator anyVehiclesUpstreamEnd() const
end iterator for iterating over all vehicles touching this lane in upstream direction
Definition MSLane.h:508
int myIndex
The lane index.
Definition MSLane.h:1494
bool isNormal() const
Definition MSLane.cpp:2665
bool isCrossing() const
Definition MSLane.cpp:2671
double getMeanSpeedBike() const
get the mean speed of all bicycles on this lane
Definition MSLane.cpp:3505
void updateLeaderInfo(const MSVehicle *veh, VehCont::reverse_iterator &vehPart, VehCont::reverse_iterator &vehRes, MSLeaderInfo &ahead) const
This updates the MSLeaderInfo argument with respect to the given MSVehicle. All leader-vehicles on th...
Definition MSLane.cpp:1643
double getWaitingSeconds() const
Returns the overall waiting time on this lane.
Definition MSLane.cpp:3471
bool hasUnsafeLink() const
whether any link from this lane is unsafe
Definition MSLane.cpp:4822
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition MSLane.cpp:2528
virtual void detectCollisions(SUMOTime timestep, const std::string &stage)
Check if vehicles are too close.
Definition MSLane.cpp:1696
std::vector< MSLink * > myLinks
Definition MSLane.h:1606
MSVehicle * getLastAnyVehicle() const
returns the last vehicle that is fully or partially on this lane
Definition MSLane.cpp:2707
bool isInternal() const
Definition MSLane.cpp:2659
VehCont myPartialVehicles
The lane's partial vehicles. This container holds all vehicles that are partially on this lane but wh...
Definition MSLane.h:1519
void sortManeuverReservations()
sorts myManeuverReservations
Definition MSLane.cpp:2640
MinorLinkMode
determine whether/how getFollowers looks upstream beyond minor links
Definition MSLane.h:1004
@ FOLLOW_ONCOMING
Definition MSLane.h:1007
@ FOLLOW_ALWAYS
Definition MSLane.h:1006
@ FOLLOW_NEVER
Definition MSLane.h:1005
void setMaxSpeed(const double val, const bool modified=true, const double jamThreshold=-1)
Sets a new maximum speed for the lane (used by TraCI, MSLaneSpeedTrigger (VSS) and MSCalibrator)
Definition MSLane.cpp:2831
AnyVehicleIterator anyVehiclesUpstreamBegin() const
begin iterator for iterating over all vehicles touching this lane in upstream direction
Definition MSLane.h:502
std::vector< const MSLane * > getNormalIncomingLanes() const
get the list of all direct (disregarding internal predecessors) non-internal predecessor lanes of thi...
Definition MSLane.cpp:3383
virtual void resetPartialOccupation(MSVehicle *v)
Removes the information about a vehicle lapping into this lane.
Definition MSLane.cpp:405
void setOpposite(MSLane *oppositeLane)
Adds a neighbor to this lane.
Definition MSLane.cpp:341
AnyVehicleIterator anyVehiclesBegin() const
begin iterator for iterating over all vehicles touching this lane in downstream direction
Definition MSLane.h:490
double getHarmonoise_NoiseEmissions() const
Returns the sum of last step noise emissions.
Definition MSLane.cpp:3530
std::pair< MSVehicle *const, double > getLeader(const MSVehicle *veh, const double vehPos, const std::vector< MSLane * > &bestLaneConts, double dist=-1, bool checkTmpVehicles=false) const
Returns the immediate leader of veh and the distance to veh starting on this lane.
Definition MSLane.cpp:2964
void handleIntermodalCollisionBetween(SUMOTime timestep, const std::string &stage, const MSVehicle *collider, const MSTransportable *victim, double gap, const std::string &collisionType, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toRemove, std::set< const MSVehicle *, ComparatorNumericalIdLess > &toTeleport) const
Definition MSLane.cpp:2222
static bool myExtrapolateSubstepDepart
Definition MSLane.h:1675
MSLane * getOpposite() const
return the neighboring opposite direction lane for lane changing or nullptr
Definition MSLane.cpp:4454
void setLength(double val)
Sets a new length for the lane (used by TraCI only)
Definition MSLane.cpp:2853
std::map< MSEdge *, std::vector< MSLane * > > myApproachingLanes
All direct internal and direct (disregarding internal predecessors) non-internal predecessor lanes of...
Definition MSLane.h:1609
virtual const VehCont & getVehiclesSecure() const
Returns the vehicles container; locks it for microsimulation.
Definition MSLane.h:484
virtual void releaseVehicles() const
Allows to use the container for microsimulation again.
Definition MSLane.h:514
bool mustCheckJunctionCollisions() const
whether this lane must check for junction collisions
Definition MSLane.cpp:4756
virtual void setManeuverReservation(MSVehicle *v)
Registers the lane change intentions (towards this lane) for the given vehicle.
Definition MSLane.cpp:428
virtual void setJunctionApproaches() const
Register junction approaches for all vehicles after velocities have been planned.
Definition MSLane.cpp:1635
MSLane * getBidiLane() const
retrieve bidirectional lane or nullptr
Definition MSLane.cpp:4750
static double myCollisionMinGapFactor
Definition MSLane.h:1674
SUMOTime myLeaderInfoTime
time step for which myLeaderInfo was last updated
Definition MSLane.h:1617
MSLane * myOpposite
Definition MSLane.h:1639
CollisionAction
Definition MSLane.h:201
@ COLLISION_ACTION_NONE
Definition MSLane.h:202
@ COLLISION_ACTION_WARN
Definition MSLane.h:203
@ COLLISION_ACTION_TELEPORT
Definition MSLane.h:204
@ COLLISION_ACTION_REMOVE
Definition MSLane.h:205
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSLane * getParallelOpposite() const
return the opposite direction lane of this lanes edge or nullptr
Definition MSLane.cpp:4460
std::map< std::string, MSLane * > DictType
definition of the static dictionary type
Definition MSLane.h:1651
double getFractionalVehicleLength(bool brutto) const
return length of fractional vehicles on this lane
Definition MSLane.cpp:3422
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:790
double getSpaceTillLastStanding(const MSVehicle *ego, bool &foundStopped) const
return the empty space up to the last standing vehicle or the empty space on the whole lane if no veh...
Definition MSLane.cpp:4765
const MSLane * getNormalPredecessorLane() const
get normal lane leading to this internal lane, for normal lanes, the lane itself is returned
Definition MSLane.cpp:3286
virtual bool appropriate(const MSVehicle *veh) const
Definition MSLane.cpp:2584
double getWidth() const
Returns the lane's width.
Definition MSLane.h:661
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:750
bool freeInsertion(MSVehicle &veh, double speed, double posLat, MSMoveReminder::Notification notification=MSMoveReminder::NOTIFICATION_DEPARTED)
Tries to insert the given vehicle on any place.
Definition MSLane.cpp:517
MSVehicle * getFirstFullVehicle() const
returns the first vehicle for which this lane is responsible or 0
Definition MSLane.cpp:2698
double getMeanSpeed() const
Returns the mean speed on this lane.
Definition MSLane.cpp:3484
double myNettoVehicleLengthSumToRemove
The length of all vehicles that have left this lane in the current step (this lane,...
Definition MSLane.h:1599
void setFrictionCoefficient(double val)
Sets a new friction coefficient for the lane [to be later (used by TraCI and MSCalibrator)].
Definition MSLane.cpp:2846
static CollisionAction getCollisionAction()
Definition MSLane.h:1388
saves leader/follower vehicles and their distances relative to an ego vehicle
virtual std::string toString() const
print a debugging representation
CLeaderDist getClosest() const
return vehicle with the smalles gap
virtual int addLeader(const MSVehicle *veh, double gap, double latOffset=0, int sublane=-1)
bool hasVehicle(const MSVehicle *veh) const
whether the given vehicle is part of this leaderInfo
void setSublaneOffset(int offset)
set number of sublanes by which to shift positions
int numFreeSublanes() const
int numSublanes() const
virtual int addLeader(const MSVehicle *veh, bool beyond, double latOffset=0.)
virtual std::string toString() const
print a debugging representation
bool hasVehicles() const
int getSublaneOffset() const
Something on a lane to be noticed about vehicle movement.
Notification
Definition of a vehicle state.
@ NOTIFICATION_ARRIVED
The vehicle arrived at its destination (is deleted)
@ NOTIFICATION_TELEPORT_ARRIVED
The vehicle was teleported out of the net.
@ NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
@ NOTIFICATION_VAPORIZED_VAPORIZER
The vehicle got vaporized with a vaporizer.
@ NOTIFICATION_VAPORIZED_BREAKDOWN
The vehicle got removed via stationfinder device.
@ NOTIFICATION_VAPORIZED_COLLISION
The vehicle got removed by a collision.
@ NOTIFICATION_LOAD_STATE
The vehicle has been loaded from a state file.
@ NOTIFICATION_TELEPORT
The vehicle is being teleported.
The simulated network and simulation perfomer.
Definition MSNet.h:89
@ COLLISION
The vehicle is involved in a collision.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:199
static const std::string STAGE_MOVEMENTS
Definition MSNet.h:870
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
const std::map< SUMOVehicleClass, double > * getRestrictions(const std::string &id) const
Returns the restrictions for an edge type If no restrictions are present, 0 is returned.
Definition MSNet.cpp:374
void informVehicleStateListener(const SUMOVehicle *const vehicle, VehicleState to, const std::string &info="")
Informs all added listeners about a vehicle's state change.
Definition MSNet.cpp:1388
bool hasPersons() const
Returns whether persons are simulated.
Definition MSNet.h:419
MSInsertionControl & getInsertionControl()
Returns the insertion control.
Definition MSNet.h:455
static const std::string STAGE_LANECHANGE
Definition MSNet.h:871
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:402
virtual MSTransportableControl & getPersonControl()
Returns the person control.
Definition MSNet.cpp:1303
bool registerCollision(const SUMOTrafficObject *collider, const SUMOTrafficObject *victim, const std::string &collisionType, const MSLane *lane, double pos)
register collision and return whether it was the first one involving these vehicles
Definition MSNet.cpp:1427
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition MSNet.h:445
virtual PersonDist nextBlocking(const MSLane *lane, double minPos, double minRight, double maxLeft, double stopTime=0, bool bidi=false)
returns the next pedestrian beyond minPos that is laterally between minRight and maxLeft or nullptr
Definition MSPModel.h:124
virtual bool hasPedestrians(const MSLane *lane)
whether the given lane has pedestrians on it
Definition MSPModel.h:110
static const double SAFETY_GAP
Definition MSPModel.h:59
static bool isSignalized(SUMOVehicleClass svc)
static MSRailSignalControl & getInstance()
bool haveDeadlock(const SUMOVehicle *veh) const
whether there is a circle in the waiting-for relationships that contains the given vehicle
static bool hasInsertionConstraint(MSLink *link, const MSVehicle *veh, std::string &info, bool &isInsertionOrder)
int size() const
Returns the number of edges to pass.
Definition MSRoute.cpp:85
const MSEdge * getLastEdge() const
returns the destination edge
Definition MSRoute.cpp:91
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition MSRoute.cpp:73
const MSLane * lane
The lane to stop at (microsim only)
Definition MSStop.h:50
MSRouteIterator edge
The edge in the route to stop at.
Definition MSStop.h:48
double getEndPos(const SUMOVehicle &veh) const
return halting position for upcoming stop;
Definition MSStop.cpp:36
const SUMOVehicleParameter::Stop pars
The stop parameter.
Definition MSStop.h:65
MSPModel * getMovementModel()
Returns the default movement model for this kind of transportables.
virtual double getEdgePos() const
Return the position on the edge.
const MSVehicleType & getVehicleType() const override
Returns the object's "vehicle" type.
Reroutes traffic objects passing an edge.
bool isRemoteAffected(SUMOTime t) const
The class responsible for building and deletion of vehicles.
void registerTeleportYield()
register one non-collision-related teleport
double getMinDeceleration() const
return the minimum deceleration capability for all road vehicles that ever entered the network
void countCollision(bool teleport)
registers one collision-related teleport
double getMaxMinGap() const
return the maximum minGap for all vehicles that ever entered the network
void registerTeleportJam()
register one non-collision-related teleport
double getMaxSpeedFactor() const
return the maximum speed factor for all vehicles that ever entered the network
double getMinDecelerationRail() const
return the minimum deceleration capability for all ral vehicles that ever entered the network
void scheduleVehicleRemoval(SUMOVehicle *veh, bool checkDuplicate=false)
Removes a vehicle after it has ended.
void registerTeleportWrongLane()
register one non-collision-related teleport
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
double getRightSideOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
void checkLinkLeader(const MSLink *link, const MSLane *lane, double seen, DriveProcessItem *const lastLink, double &v, double &vLinkPass, double &vLinkWait, bool &setRequest, bool isShadowLink=false) const
checks for link leaders on the given link
void updateBestLanes(bool forceRebuild=false, const MSLane *startLane=0)
computes the best lanes to use in order to continue the route
bool isOnRoad() const
Returns the information whether the vehicle is on a road (is simulated)
Definition MSVehicle.h:605
SUMOTime getLastActionTime() const
Returns the time of the vehicle's last action point.
Definition MSVehicle.h:541
PositionVector getBoundingPoly(double offset=0) const
get bounding polygon
void setTentativeLaneAndPosition(MSLane *lane, double pos, double posLat=0)
set tentative lane and position during insertion to ensure that all cfmodels work (some of them requi...
bool brokeDown() const
Returns how long the vehicle has been stopped already due to lack of energy.
void registerInsertionApproach(MSLink *link, double dist)
register approach on insertion
void enterLaneAtInsertion(MSLane *enteredLane, double pos, double speed, double posLat, MSMoveReminder::Notification notification)
Update when the vehicle enters a new lane in the emit step.
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the SUMOTime waited (speed was lesser than 0.1m/s)
Definition MSVehicle.h:670
bool isFrontOnLane(const MSLane *lane) const
Returns the information whether the front of the vehicle is on the given lane.
MSAbstractLaneChangeModel & getLaneChangeModel()
double getLeftSideOnLane() const
Get the lateral position of the vehicles left side on the lane:
double getActionStepLengthSecs() const
Returns the vehicle's action step length in secs, i.e. the interval between two action points.
Definition MSVehicle.h:533
const std::vector< MSLane * > getUpstreamOppositeLanes() const
Returns the sequence of opposite lanes corresponding to past lanes.
PositionVector getBoundingBox(double offset=0) const
get bounding rectangle
Position getPosition(const double offset=0) const
Return current position (x/y, cartesian)
const std::vector< MSLane * > & getBestLanesContinuation() const
Returns the best sequence of lanes to continue the route starting at myLane.
bool ignoreCollision() const
whether this vehicle is except from collision checks
void onRemovalFromNet(const MSMoveReminder::Notification reason)
Called when the vehicle is removed from the network.
bool resumeFromStopping()
int getBestLaneOffset() const
void adaptToJunctionLeader(const std::pair< const MSVehicle *, double > leaderInfo, const double seen, DriveProcessItem *const lastLink, const MSLane *const lane, double &v, double &vLinkPass, double distToCrossing=-1) const
double getBackPositionOnLane(const MSLane *lane) const
Get the vehicle's position relative to the given lane.
Definition MSVehicle.h:398
void resetActionOffset(const SUMOTime timeUntilNextAction=0)
Resets the action offset for the vehicle.
void leaveLane(const MSMoveReminder::Notification reason, const MSLane *approachedLane=0)
Update of members if vehicle leaves a new lane in the lane change step or at arrival.
double getLatOffset(const MSLane *lane) const
Get the offset that that must be added to interpret myState.myPosLat for the given lane.
bool hasArrived() const
Returns whether this vehicle has already arrived (reached the arrivalPosition on its final edge)
SUMOTime collisionStopTime() const
Returns the remaining time a vehicle needs to stop due to a collision. A negative value indicates tha...
double getBestLaneDist() const
returns the distance that can be driven without lane change
bool executeMove()
Executes planned vehicle movements with regards to right-of-way.
const MSLane * getLane() const
Returns the lane the vehicle is on.
Definition MSVehicle.h:581
bool isLeader(const MSLink *link, const MSVehicle *veh, const double gap) const
whether the given vehicle must be followed at the given junction
MSLane * getMutableLane() const
Returns the lane the vehicle is on Non const version indicates that something volatile is going on.
Definition MSVehicle.h:589
Influencer & getInfluencer()
bool isBidiOn(const MSLane *lane) const
whether this vehicle is driving against lane
double getRightSideOnLane() const
Get the lateral position of the vehicles right side on the lane:
double getLateralPositionOnLane() const
Get the vehicle's lateral position on the lane.
Definition MSVehicle.h:413
double getSpeed() const
Returns the vehicle's current speed.
Definition MSVehicle.h:490
const std::vector< MSLane * > & getFurtherLanes() const
Definition MSVehicle.h:839
const std::vector< LaneQ > & getBestLanes() const
Returns the description of best lanes to use in order to continue the route.
const MSCFModel & getCarFollowModel() const
Returns the vehicle's car following model definition.
Definition MSVehicle.h:973
double getPositionOnLane() const
Get the vehicle's position along the lane.
Definition MSVehicle.h:374
double getLateralOverlap() const
return the amount by which the vehicle extends laterally outside it's primary lane
double getAngle() const
Returns the vehicle's direction in radians.
Definition MSVehicle.h:735
bool hasInfluencer() const
whether the vehicle is individually influenced (via TraCI or special parameters)
Definition MSVehicle.h:1706
double getBrakeGap(bool delayed=false) const
get distance for coming to a stop (used for rerouting checks)
void executeFractionalMove(double dist)
move vehicle forward by the given distance during insertion
double getCenterOnEdge(const MSLane *lane=0) const
Get the vehicle's lateral position on the edge of the given lane (or its current edge if lane == 0)
int getLaneIndex() const
static MSVehicleTransfer * getInstance()
Returns the instance of this object.
void add(const SUMOTime t, MSVehicle *veh)
Adds a vehicle to this transfer object.
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getMinGap() const
Get the free space in front of vehicles of this class.
double getLength() const
Get vehicle's length [m].
SUMOVehicleShape getGuiShape() const
Get this vehicle type's shape.
const SUMOVTypeParameter & getParameter() const
Base class for objects which have an id.
Definition Named.h:53
std::string myID
The name of the object.
Definition Named.h:124
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition Named.h:66
const std::string & getID() const
Returns the id.
Definition Named.h:73
A RT-tree for efficient storing of SUMO's Named objects.
Definition NamedRTree.h:61
A storage for options typed value containers)
Definition OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
Static storage of an output device and its base (abstract) implementation.
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const ATTR_TYPE &attr, const T &val, const bool isNull=false, const bool escape=false)
writes a named attribute
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
void unsetParameter(const std::string &key)
Removes a parameter.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:273
A list of positions.
bool overlapsWith(const AbstractPoly &poly, double offset=0) const
Returns the information whether the given polygon overlaps with this.
double distance2D(const Position &p, bool perpendicular=false) const
closest 2D-distance to point p (or -1 if perpendicular is true and the point is beyond this vector)
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
double angleAt2D(int pos) const
get angle in certain position of position vector (in radians between -M_PI and M_PI)
static void loadState(const std::string &state, SumoRNG *rng=nullptr)
load rng state from string
Definition RandHelper.h:244
static void initRand(SumoRNG *which=nullptr, const bool random=false, const int seed=23423)
Initialises the random number generator with hardware randomness or seed.
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
static std::string saveState(SumoRNG *rng=nullptr)
save rng state to string
Definition RandHelper.h:231
virtual SUMOVehicleClass getVClass() const =0
Returns the object's access class.
SUMOTime getTimeToTeleport(SUMOTime defaultValue) const
return time-to-teleport (either custom or default)
SUMOTime getTimeToTeleportBidi(SUMOTime defaultValue) const
return time-to-teleport.bidi (either custom or default)
double getJMParam(const SumoXMLAttr attr, const double defaultValue) const
Returns the named value from the map, or the default if it is not contained there.
Representation of a vehicle.
Definition SUMOVehicle.h:63
virtual const MSEdge * succEdge(int nSuccs) const =0
Returns the nSuccs'th successor of edge the vehicle is currently at.
Definition of vehicle stop (position and duration)
std::string lane
The lane to stop at.
double speed
the speed at which this stop counts as reached (waypoint mode)
std::string split
the id of the vehicle (train portion) that splits of upon reaching this stop
double startPos
The stopping position start.
int parametersSet
Information for the output which parameter were set.
double endPos
The stopping position end.
bool collision
Whether this stop was triggered by a collision.
SUMOTime duration
The stopping duration.
Structure representing possible vehicle parameter.
double departPosLat
(optional) The lateral position the vehicle shall depart from
ArrivalSpeedDefinition arrivalSpeedProcedure
Information how the vehicle's end speed shall be chosen.
double departSpeed
(optional) The initial speed of the vehicle
DepartPosLatDefinition departPosLatProcedure
Information how the vehicle shall choose the lateral departure position.
double departPos
(optional) The position the vehicle shall depart from
DepartSpeedDefinition departSpeedProcedure
Information how the vehicle's initial speed shall be chosen.
double arrivalSpeed
(optional) The final speed of the vehicle (not used yet)
DepartDefinition departProcedure
Information how the vehicle shall choose the depart time.
DepartPosDefinition departPosProcedure
Information how the vehicle shall choose the departure position.
A scoped lock which only triggers on condition.
stop offset
bool isDefined() const
check if stopOffset was defined
SVCPermissions getPermissions() const
get permissions
double getOffset() const
get offset
#define DEBUG_COND
TRACI_CONST int CMD_GET_VEHICLE_VARIABLE
TRACI_CONST int CMD_GET_EDGE_VARIABLE
TRACI_CONST int CMD_GET_PERSON_VARIABLE
TRACI_CONST int CMD_GET_LANE_VARIABLE
TRACI_CONST int ROUTING_MODE_IGNORE_TRANSIENT_PERMISSIONS
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:21884
#define M_PI
Definition odrSpiral.cpp:45