Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/microsim/MSEdge.cpp
193716 views
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
/****************************************************************************/
14
/// @file MSEdge.cpp
15
/// @author Christian Roessel
16
/// @author Jakob Erdmann
17
/// @author Christoph Sommer
18
/// @author Daniel Krajzewicz
19
/// @author Laura Bieker
20
/// @author Michael Behrisch
21
/// @author Sascha Krieg
22
/// @date Tue, 06 Mar 2001
23
///
24
// A road/street connecting two junctions
25
/****************************************************************************/
26
#include <config.h>
27
28
#include <algorithm>
29
#include <iostream>
30
#include <cassert>
31
#ifdef HAVE_FOX
32
#include <utils/common/ScopedLocker.h>
33
#endif
34
#include <utils/common/StringTokenizer.h>
35
#include <utils/options/OptionsCont.h>
36
#include <microsim/devices/MSRoutingEngine.h>
37
#include <mesosim/MELoop.h>
38
#include <mesosim/MESegment.h>
39
#include <mesosim/MEVehicle.h>
40
#include "MSInsertionControl.h"
41
#include "MSJunction.h"
42
#include "MSLane.h"
43
#include "MSLaneChanger.h"
44
#include "MSLaneChangerSublane.h"
45
#include "MSLink.h"
46
#include "MSGlobals.h"
47
#include "MSNet.h"
48
#include "MSVehicle.h"
49
#include "MSLeaderInfo.h"
50
#include <microsim/transportables/MSTransportable.h>
51
#include "MSEdgeWeightsStorage.h"
52
#include "MSEdge.h"
53
54
#define BEST_LANE_LOOKAHEAD 3000.0
55
56
// ===========================================================================
57
// static member definitions
58
// ===========================================================================
59
MSEdge::DictType MSEdge::myDict;
60
MSEdgeVector MSEdge::myEdges;
61
SVCPermissions MSEdge::myMesoIgnoredVClasses(0);
62
DepartLaneDefinition MSEdge::myDefaultDepartLaneDefinition(DepartLaneDefinition::DEFAULT);
63
int MSEdge::myDefaultDepartLane(0);
64
65
// ===========================================================================
66
// member method definitions
67
// ===========================================================================
68
MSEdge::MSEdge(const std::string& id, int numericalID,
69
const SumoXMLEdgeFunc function,
70
const std::string& streetName,
71
const std::string& edgeType,
72
const std::string& routingType,
73
int priority,
74
double distance) :
75
Named(id), myNumericalID(numericalID), myLanes(nullptr),
76
myLaneChanger(nullptr), myFunction(function), myVaporizationRequests(0),
77
myLastFailedInsertionTime(-1),
78
myFromJunction(nullptr), myToJunction(nullptr),
79
myHaveTransientPermissions(false),
80
myOtherTazConnector(nullptr),
81
myStreetName(streetName),
82
myEdgeType(edgeType),
83
myRoutingType(routingType),
84
myPriority(priority),
85
myDistance(distance),
86
myWidth(0.),
87
myLength(0.),
88
myEmptyTraveltime(0.),
89
myTimePenalty(0.),
90
myAmDelayed(false),
91
myAmRoundabout(false),
92
myAmFringe(true),
93
myBidiEdge(nullptr)
94
{ }
95
96
97
MSEdge::~MSEdge() {
98
delete myLaneChanger;
99
delete myReversedRoutingEdge;
100
delete myRailwayRoutingEdge;
101
}
102
103
104
void
105
MSEdge::initialize(const std::vector<MSLane*>* lanes) {
106
assert(lanes != 0);
107
myLanes = std::shared_ptr<const std::vector<MSLane*> >(lanes);
108
if (myFunction == SumoXMLEdgeFunc::CONNECTOR) {
109
myCombinedPermissions = SVCAll;
110
}
111
for (MSLane* const lane : *lanes) {
112
lane->setRightSideOnEdge(myWidth, (int)mySublaneSides.size());
113
MSLeaderInfo ahead(lane->getWidth());
114
for (int j = 0; j < ahead.numSublanes(); ++j) {
115
mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
116
}
117
myWidth += lane->getWidth();
118
}
119
}
120
121
122
void MSEdge::recalcCache() {
123
if (myLanes->empty()) {
124
return;
125
}
126
myLength = myLanes->front()->getLength();
127
myEmptyTraveltime = myLength / MAX2(getSpeedLimit(), NUMERICAL_EPS);
128
if (isNormal() && (MSGlobals::gUseMesoSim || MSGlobals::gTLSPenalty > 0)) {
129
SUMOTime minorPenalty = 0;
130
bool haveTLSPenalty = MSGlobals::gTLSPenalty > 0;
131
if (MSGlobals::gUseMesoSim) {
132
const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
133
minorPenalty = edgeType.minorPenalty;
134
haveTLSPenalty = edgeType.tlsPenalty > 0;
135
}
136
if (haveTLSPenalty || minorPenalty > 0) {
137
// add tls penalties to the minimum travel time
138
SUMOTime minPenalty = -1;
139
for (const MSLane* const l : *myLanes) {
140
for (const MSLink* const link : l->getLinkCont()) {
141
if (link->getLane()->isWalkingArea() && link->getLaneBefore()->isNormal()) {
142
continue;
143
}
144
SUMOTime linkPenalty = link->isTLSControlled() ? link->getMesoTLSPenalty() : (link->havePriority() ? 0 : minorPenalty);
145
if (minPenalty == -1) {
146
minPenalty = linkPenalty;
147
} else {
148
minPenalty = MIN2(minPenalty, linkPenalty);
149
}
150
}
151
}
152
if (minPenalty > 0) {
153
myEmptyTraveltime += STEPS2TIME(minPenalty);
154
myTimePenalty = STEPS2TIME(minPenalty);
155
}
156
}
157
} else if (isCrossing() && MSGlobals::gTLSPenalty > 0) {
158
// penalties are recorded for the entering link
159
for (const auto& ili : myLanes->front()->getIncomingLanes()) {
160
double penalty = STEPS2TIME(ili.viaLink->getMesoTLSPenalty());
161
if (!ili.viaLink->haveOffPriority()) {
162
penalty = MAX2(penalty, MSGlobals::gMinorPenalty);
163
}
164
if (penalty > 0) {
165
myEmptyTraveltime += penalty;
166
myTimePenalty = penalty;
167
}
168
}
169
} else if (isInternal() && MSGlobals::gUsingInternalLanes) {
170
const MSLink* link = myLanes->front()->getIncomingLanes()[0].viaLink;
171
if (!link->isTLSControlled() && !link->havePriority()) {
172
if (link->isTurnaround()) {
173
myEmptyTraveltime += MSGlobals::gTurnaroundPenalty;
174
myTimePenalty = MSGlobals::gTurnaroundPenalty;
175
} else {
176
myEmptyTraveltime += MSGlobals::gMinorPenalty;
177
myTimePenalty = MSGlobals::gMinorPenalty;
178
}
179
}
180
}
181
}
182
183
184
void
185
MSEdge::resetTAZ(MSJunction* junction) {
186
mySuccessors.clear();
187
myPredecessors.clear();
188
for (const MSEdge* edge : junction->getIncoming()) {
189
if (!edge->isInternal()) {
190
MSEdgeVector& succ = const_cast<MSEdgeVector&>(edge->mySuccessors);
191
MSConstEdgePairVector& succVia = const_cast<MSConstEdgePairVector&>(edge->myViaSuccessors);
192
MSEdgeVector& pred = const_cast<MSEdgeVector&>(edge->myPredecessors);
193
auto it = std::find(succ.begin(), succ.end(), this);
194
auto it2 = std::find(succVia.begin(), succVia.end(), std::make_pair(const_cast<const MSEdge*>(this), (const MSEdge*)nullptr));
195
auto it3 = std::find(pred.begin(), pred.end(), this);
196
if (it != succ.end()) {
197
succ.erase(it);
198
succVia.erase(it2);
199
}
200
if (it3 != pred.end()) {
201
pred.erase(it3);
202
}
203
}
204
}
205
}
206
207
void
208
MSEdge::closeBuilding() {
209
for (MSLane* const lane : *myLanes) {
210
for (MSLink* const link : lane->getLinkCont()) {
211
link->initParallelLinks();
212
MSLane* const toL = link->getLane();
213
MSLane* const viaL = link->getViaLane();
214
if (toL != nullptr) {
215
MSEdge& to = toL->getEdge();
216
if (std::find(mySuccessors.begin(), mySuccessors.end(), &to) == mySuccessors.end()) {
217
mySuccessors.push_back(&to);
218
myViaSuccessors.push_back(std::make_pair(&to, (viaL == nullptr ? nullptr : &viaL->getEdge())));
219
}
220
if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
221
to.myPredecessors.push_back(this);
222
}
223
if (link->getDirection() != LinkDirection::TURN) {
224
myAmFringe = false;
225
}
226
}
227
if (viaL != nullptr) {
228
MSEdge& to = viaL->getEdge();
229
if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
230
to.myPredecessors.push_back(this);
231
}
232
}
233
}
234
lane->checkBufferType();
235
}
236
std::sort(mySuccessors.begin(), mySuccessors.end(), by_id_sorter());
237
rebuildAllowedLanes(true);
238
recalcCache();
239
240
// extend lookup table for sublane model after all edges are read
241
if (myLanes->back()->getOpposite() != nullptr) {
242
MSLane* opposite = myLanes->back()->getOpposite();
243
MSLeaderInfo ahead(opposite->getWidth());
244
for (int j = 0; j < ahead.numSublanes(); ++j) {
245
mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
246
}
247
}
248
}
249
250
251
void
252
MSEdge::postLoadInitLaneChanger() {
253
if (myLaneChanger != nullptr) {
254
myLaneChanger->postloadInitLC();
255
}
256
}
257
258
void
259
MSEdge::buildLaneChanger() {
260
if (!myLanes->empty()) {
261
const bool allowChanging = allowsLaneChanging();
262
if (MSGlobals::gLateralResolution > 0) {
263
// may always initiate sublane-change
264
if (!isInternal() || MSGlobals::gUsingInternalLanes) {
265
myLaneChanger = new MSLaneChangerSublane(myLanes.get(), allowChanging);
266
}
267
} else {
268
if (MSGlobals::gLaneChangeDuration > 0) {
269
myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
270
} else if (myLanes->size() > 1 || canChangeToOpposite()) {
271
myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
272
}
273
}
274
}
275
}
276
277
278
bool
279
MSEdge::allowsLaneChanging() const {
280
if (isInternal() && MSGlobals::gUsingInternalLanes) {
281
// allow changing only if all links leading to this internal lane have priority
282
// or they are controlled by a traffic light
283
for (const MSLane* const lane : *myLanes) {
284
const MSLink* const link = lane->getLogicalPredecessorLane()->getLinkTo(lane);
285
assert(link != nullptr);
286
const LinkState state = link->getState();
287
if ((state == LINKSTATE_MINOR && lane->getBidiLane() == nullptr)
288
|| state == LINKSTATE_EQUAL
289
|| state == LINKSTATE_STOP
290
|| state == LINKSTATE_ALLWAY_STOP
291
|| state == LINKSTATE_DEADEND) {
292
return false;
293
}
294
}
295
}
296
return true;
297
}
298
299
300
void
301
MSEdge::addToAllowed(const SVCPermissions permissions, std::shared_ptr<const std::vector<MSLane*> > allowedLanes, AllowedLanesCont& laneCont) const {
302
if (!allowedLanes->empty()) {
303
// recheck whether we had this list to save memory
304
for (auto& allowed : laneCont) {
305
if (*allowed.second == *allowedLanes) {
306
allowed.first |= permissions;
307
return;
308
}
309
}
310
laneCont.push_back(std::make_pair(permissions, allowedLanes));
311
}
312
}
313
314
315
SVCPermissions
316
MSEdge::getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored) {
317
SVCPermissions ignored = myMesoIgnoredVClasses & ~ignoreIgnored;
318
return (p | ignored) == ignored ? 0 : p;
319
}
320
321
322
void
323
MSEdge::rebuildAllowedLanes(const bool onInit, bool updateVehicles) {
324
// rebuild myMinimumPermissions and myCombinedPermissions
325
myMinimumPermissions = SVCAll;
326
myCombinedPermissions = 0;
327
bool lanesChangedPermission = false;
328
for (MSLane* const lane : *myLanes) {
329
// same dedicated lanes are ignored in meso to avoid capacity errors.
330
// Here we have to make sure that vehicles which are set to depart on
331
// such lanes trigger an error.
332
SVCPermissions allow = getMesoPermissions(lane->getPermissions(), SVC_PEDESTRIAN);
333
myMinimumPermissions &= allow;
334
myCombinedPermissions |= allow;
335
lanesChangedPermission |= lane->hadPermissionChanges();
336
}
337
if (!onInit && !myHaveTransientPermissions && lanesChangedPermission) {
338
myHaveTransientPermissions = true;
339
// backup original structures when first needed
340
myOrigAllowed = myAllowed;
341
myOrigAllowedTargets = myAllowedTargets;
342
myOrigClassesViaSuccessorMap = myClassesViaSuccessorMap;
343
}
344
// rebuild myAllowed
345
myAllowed.clear();
346
if (myCombinedPermissions != myMinimumPermissions) {
347
myAllowed.push_back(std::make_pair(SVC_IGNORING, myLanes));
348
for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
349
if ((myCombinedPermissions & vclass) == vclass) {
350
std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
351
for (MSLane* const lane : *myLanes) {
352
if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
353
allowedLanes->push_back(lane);
354
}
355
}
356
addToAllowed(vclass, allowedLanes, myAllowed);
357
}
358
}
359
}
360
if (onInit) {
361
myOriginalMinimumPermissions = myMinimumPermissions;
362
myOriginalCombinedPermissions = myCombinedPermissions;
363
} else {
364
rebuildAllowedTargets(updateVehicles);
365
for (MSEdge* pred : myPredecessors) {
366
if (myHaveTransientPermissions && !pred->myHaveTransientPermissions) {
367
pred->myOrigAllowed = pred->myAllowed;
368
pred->myOrigAllowedTargets = pred->myAllowedTargets;
369
pred->myOrigClassesViaSuccessorMap = pred->myClassesViaSuccessorMap;
370
pred->myHaveTransientPermissions = true;
371
}
372
pred->rebuildAllowedTargets(updateVehicles);
373
}
374
if (MSGlobals::gUseMesoSim) {
375
for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*this); s != nullptr; s = s->getNextSegment()) {
376
s->updatePermissions();
377
}
378
}
379
}
380
}
381
382
383
void
384
MSEdge::rebuildAllowedTargets(const bool updateVehicles) {
385
myAllowedTargets.clear();
386
for (const MSEdge* target : mySuccessors) {
387
bool universalMap = true; // whether the mapping for SVC_IGNORING is also valid for all vehicle classes
388
std::shared_ptr<std::vector<MSLane*> > allLanes = std::make_shared<std::vector<MSLane*> >();
389
// compute the mapping for SVC_IGNORING
390
for (MSLane* const lane : *myLanes) {
391
SVCPermissions combinedTargetPermissions = 0;
392
for (const MSLink* const link : lane->getLinkCont()) {
393
if (&link->getLane()->getEdge() == target) {
394
allLanes->push_back(lane);
395
combinedTargetPermissions |= link->getLane()->getPermissions();
396
if (link->getViaLane() != nullptr &&
397
((lane->getPermissions() & link->getLane()->getPermissions()) != link->getViaLane()->getPermissions())) {
398
// custom connection permissions
399
universalMap = false;
400
}
401
}
402
}
403
if (combinedTargetPermissions == 0 || (lane->getPermissions() & combinedTargetPermissions) != lane->getPermissions()) {
404
universalMap = false;
405
}
406
}
407
if (universalMap) {
408
if (myAllowed.empty()) {
409
// we have no lane specific permissions
410
myAllowedTargets[target].push_back(std::make_pair(myMinimumPermissions, myLanes));
411
} else {
412
for (const auto& i : myAllowed) {
413
addToAllowed(i.first, i.second, myAllowedTargets[target]);
414
}
415
}
416
} else {
417
addToAllowed(SVC_IGNORING, allLanes, myAllowedTargets[target]);
418
// compute the vclass specific mapping
419
for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
420
if ((myCombinedPermissions & vclass) == vclass) {
421
std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
422
for (MSLane* const lane : *myLanes) {
423
if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
424
for (const MSLink* const link : lane->getLinkCont()) {
425
if (link->getLane()->allowsVehicleClass((SUMOVehicleClass)vclass) && &link->getLane()->getEdge() == target && (link->getViaLane() == nullptr || link->getViaLane()->allowsVehicleClass((SUMOVehicleClass)vclass))) {
426
allowedLanes->push_back(lane);
427
}
428
}
429
}
430
}
431
addToAllowed(vclass, allowedLanes, myAllowedTargets[target]);
432
}
433
}
434
}
435
}
436
if (updateVehicles) {
437
for (const MSLane* const lane : *myLanes) {
438
const MSLane::VehCont& vehs = lane->getVehiclesSecure();
439
for (MSVehicle* veh : vehs) {
440
veh->updateBestLanes(true);
441
}
442
lane->releaseVehicles();
443
}
444
}
445
myClassesSuccessorMap.clear();
446
}
447
448
449
// ------------ Access to the edge's lanes
450
MSLane*
451
MSEdge::leftLane(const MSLane* const lane) const {
452
return parallelLane(lane, 1);
453
}
454
455
456
MSLane*
457
MSEdge::rightLane(const MSLane* const lane) const {
458
return parallelLane(lane, -1);
459
}
460
461
462
MSLane*
463
MSEdge::parallelLane(const MSLane* const lane, int offset, bool includeOpposite) const {
464
const int resultIndex = lane->getIndex() + offset;
465
if (resultIndex >= getNumLanes() && includeOpposite) {
466
const MSEdge* opposite = getOppositeEdge();
467
if (opposite != nullptr && resultIndex < getNumLanes() + opposite->getNumLanes()) {
468
return opposite->getLanes()[opposite->getNumLanes() + getNumLanes() - resultIndex - 1];
469
}
470
return nullptr;
471
} else if (resultIndex >= (int)myLanes->size() || resultIndex < 0) {
472
return nullptr;
473
} else {
474
return (*myLanes)[resultIndex];
475
}
476
}
477
478
479
const std::vector<MSLane*>*
480
MSEdge::allowedLanes(const MSEdge& destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
481
const auto& targets = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigAllowedTargets : myAllowedTargets;
482
AllowedLanesByTarget::const_iterator i = targets.find(&destination);
483
if (i != targets.end()) {
484
for (const auto& allowed : i->second) {
485
if ((allowed.first & vclass) == vclass) {
486
return allowed.second.get();
487
}
488
}
489
}
490
return nullptr;
491
}
492
493
494
const std::vector<MSLane*>*
495
MSEdge::allowedLanes(SUMOVehicleClass vclass) const {
496
if ((myMinimumPermissions & vclass) == vclass) {
497
return myLanes.get();
498
} else {
499
if ((myCombinedPermissions & vclass) == vclass) {
500
for (const auto& allowed : myAllowed) {
501
if ((allowed.first & vclass) == vclass) {
502
return allowed.second.get();
503
}
504
}
505
}
506
return nullptr;
507
}
508
}
509
510
511
const std::vector<MSLane*>*
512
MSEdge::allowedLanes(SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
513
const SVCPermissions& minP = ignoreTransientPermissions ? myOriginalMinimumPermissions : myMinimumPermissions;
514
if ((minP & vclass) == vclass) {
515
return myLanes.get();
516
} else {
517
const SVCPermissions comP = ignoreTransientPermissions ? myOriginalCombinedPermissions : myCombinedPermissions;
518
if ((comP & vclass) == vclass) {
519
const AllowedLanesCont& allowedCont = ignoreTransientPermissions ? myOrigAllowed : myAllowed;
520
for (const auto& allowed : allowedCont) {
521
if ((allowed.first & vclass) == vclass) {
522
return allowed.second.get();
523
}
524
}
525
}
526
return nullptr;
527
}
528
}
529
530
531
// ------------
532
SUMOTime
533
MSEdge::incVaporization(SUMOTime) {
534
++myVaporizationRequests;
535
return 0;
536
}
537
538
539
SUMOTime
540
MSEdge::decVaporization(SUMOTime) {
541
--myVaporizationRequests;
542
return 0;
543
}
544
545
546
MSLane*
547
MSEdge::getFreeLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos) const {
548
if (allowed == nullptr) {
549
allowed = allowedLanes(vclass);
550
}
551
MSLane* res = nullptr;
552
if (allowed != nullptr) {
553
double largestGap = 0;
554
MSLane* resByGap = nullptr;
555
double leastOccupancy = std::numeric_limits<double>::max();
556
for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i) {
557
const double occupancy = (*i)->getBruttoOccupancy();
558
if (occupancy < leastOccupancy) {
559
res = (*i);
560
leastOccupancy = occupancy;
561
}
562
const MSVehicle* last = (*i)->getLastFullVehicle();
563
const double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
564
if (lastGap > largestGap) {
565
largestGap = lastGap;
566
resByGap = (*i);
567
}
568
}
569
if (resByGap != nullptr) {
570
//if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
571
res = resByGap;
572
}
573
}
574
return res;
575
}
576
577
578
MSLane*
579
MSEdge::getProbableLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos, double maxSpeed) const {
580
if (allowed == nullptr) {
581
allowed = allowedLanes(vclass);
582
}
583
MSLane* res = nullptr;
584
if (allowed != nullptr) {
585
double largestGap = 0;
586
double largestSpeed = 0;
587
MSLane* resByGap = nullptr;
588
double leastOccupancy = std::numeric_limits<double>::max();
589
int aIndex = 0;
590
for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i, aIndex++) {
591
const double occupancy = (*i)->getBruttoOccupancy();
592
if (occupancy < leastOccupancy) {
593
res = (*i);
594
leastOccupancy = occupancy;
595
}
596
const MSVehicle* last = (*i)->getLastFullVehicle();
597
double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
598
// never insert to the left of a vehicle with a larger speedFactor
599
if (lastGap > largestGap && maxSpeed >= largestSpeed) {
600
largestGap = lastGap;
601
resByGap = (*i);
602
}
603
if (last != nullptr) {
604
largestSpeed = MAX2(largestSpeed, getVehicleMaxSpeed(last));
605
}
606
}
607
if (resByGap != nullptr) {
608
//if (res != resByGap) std::cout << SIMTIME << " edge=" << getID() << " departPos=" << departPos << " res=" << Named::getIDSecure(res) << " resByGap=" << Named::getIDSecure(resByGap) << " largestGap=" << largestGap << "\n";
609
res = resByGap;
610
}
611
}
612
return res;
613
}
614
615
616
double
617
MSEdge::getDepartPosBound(const MSVehicle& veh, bool upper) const {
618
const SUMOVehicleParameter& pars = veh.getParameter();
619
double pos = getLength();
620
// determine the position
621
switch (pars.departPosProcedure) {
622
case DepartPosDefinition::GIVEN:
623
pos = pars.departPos;
624
if (pos < 0.) {
625
pos += myLength;
626
}
627
break;
628
case DepartPosDefinition::RANDOM:
629
// could be any position on the edge
630
break;
631
case DepartPosDefinition::RANDOM_FREE:
632
// could be any position on the edge due to multiple random attempts
633
break;
634
case DepartPosDefinition::FREE:
635
// many candidate positions, upper bound could be computed exactly
636
// with much effort
637
break;
638
case DepartPosDefinition::LAST:
639
if (upper) {
640
for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
641
MSVehicle* last = (*i)->getLastFullVehicle();
642
if (last != nullptr) {
643
pos = MIN2(pos, last->getPositionOnLane());
644
}
645
}
646
} else {
647
pos = 0;
648
}
649
break;
650
case DepartPosDefinition::BASE:
651
case DepartPosDefinition::DEFAULT:
652
if (!upper) {
653
pos = 0;
654
}
655
break;
656
default:
657
pos = MIN2(pos, veh.getVehicleType().getLength());
658
break;
659
}
660
return pos;
661
}
662
663
MSLane*
664
MSEdge::getDepartLaneMeso(SUMOVehicle& veh) const {
665
if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN) {
666
if ((int) myLanes->size() <= veh.getParameter().departLane || !(*myLanes)[veh.getParameter().departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
667
return nullptr;
668
}
669
return (*myLanes)[veh.getParameter().departLane];
670
}
671
return (*myLanes)[0];
672
}
673
674
MSLane*
675
MSEdge::getDepartLane(MSVehicle& veh) const {
676
DepartLaneDefinition dld = veh.getParameter().departLaneProcedure;
677
int departLane = veh.getParameter().departLane;
678
if (dld == DepartLaneDefinition::DEFAULT) {
679
dld = myDefaultDepartLaneDefinition;
680
departLane = myDefaultDepartLane;
681
}
682
switch (dld) {
683
case DepartLaneDefinition::GIVEN:
684
if ((int) myLanes->size() <= departLane || !(*myLanes)[departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
685
return nullptr;
686
}
687
return (*myLanes)[departLane];
688
case DepartLaneDefinition::RANDOM:
689
return RandHelper::getRandomFrom(*allowedLanes(veh.getVehicleType().getVehicleClass()));
690
case DepartLaneDefinition::FREE:
691
return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
692
case DepartLaneDefinition::ALLOWED_FREE:
693
if (veh.getRoute().size() == 1) {
694
return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
695
} else {
696
return getFreeLane(allowedLanes(**(veh.getRoute().begin() + 1), veh.getVehicleType().getVehicleClass()), veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
697
}
698
case DepartLaneDefinition::BEST_FREE:
699
case DepartLaneDefinition::BEST_PROB: {
700
veh.updateBestLanes(false, myLanes->front());
701
const std::vector<MSVehicle::LaneQ>& bl = veh.getBestLanes();
702
double bestLength = -1;
703
for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
704
if ((*i).length > bestLength) {
705
bestLength = (*i).length;
706
}
707
}
708
// beyond a certain length, all lanes are suitable
709
// however, we still need to check departPos to avoid unsuitable insertion
710
// (this is only possible in some cases)
711
double departPos = 0;
712
if (bestLength > BEST_LANE_LOOKAHEAD) {
713
departPos = getDepartPosBound(veh);
714
bestLength = MIN2(bestLength - departPos, BEST_LANE_LOOKAHEAD);
715
}
716
std::vector<MSLane*>* bestLanes = new std::vector<MSLane*>();
717
for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
718
if (((*i).length - departPos) >= bestLength) {
719
if (isInternal()) {
720
for (MSLane* lane : *myLanes) {
721
if (lane->getNormalSuccessorLane() == (*i).lane) {
722
bestLanes->push_back(lane);
723
}
724
}
725
} else {
726
bestLanes->push_back((*i).lane);
727
}
728
}
729
}
730
MSLane* ret = nullptr;
731
if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::BEST_FREE) {
732
ret = getFreeLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
733
} else {
734
ret = getProbableLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false), getVehicleMaxSpeed(&veh));
735
}
736
delete bestLanes;
737
return ret;
738
}
739
case DepartLaneDefinition::DEFAULT:
740
case DepartLaneDefinition::FIRST_ALLOWED:
741
return getFirstAllowed(veh.getVehicleType().getVehicleClass());
742
default:
743
break;
744
}
745
if (!(*myLanes)[0]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
746
return nullptr;
747
}
748
return (*myLanes)[0];
749
}
750
751
752
MSLane*
753
MSEdge::getFirstAllowed(SUMOVehicleClass vClass, bool defaultFirst, int routingMode) const {
754
for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
755
if ((*i)->allowsVehicleClass(vClass, routingMode)) {
756
return *i;
757
}
758
}
759
return defaultFirst && !myLanes->empty() ? myLanes->front() : nullptr;
760
}
761
762
763
bool
764
MSEdge::validateDepartSpeed(SUMOVehicle& v) const {
765
const SUMOVehicleParameter& pars = v.getParameter();
766
const MSVehicleType& type = v.getVehicleType();
767
if (pars.departSpeedProcedure == DepartSpeedDefinition::GIVEN) {
768
// departSpeed could have been rounded down in the output
769
double vMax = getVehicleMaxSpeed(&v) + SPEED_EPS;
770
if (pars.departSpeed > vMax) {
771
// check departLane (getVehicleMaxSpeed checks lane 0)
772
MSLane* departLane = MSGlobals::gMesoNet ? getDepartLaneMeso(v) : getDepartLane(dynamic_cast<MSVehicle&>(v));
773
if (departLane != nullptr) {
774
vMax = departLane->getVehicleMaxSpeed(&v);
775
if (pars.wasSet(VEHPARS_SPEEDFACTOR_SET)) {
776
// speedFactor could have been rounded down in the output
777
vMax *= (1 + SPEED_EPS);
778
}
779
// additive term must come after multiplication!
780
vMax += SPEED_EPS;
781
if (pars.departSpeed > vMax) {
782
if (type.getSpeedFactor().getParameter(1) > 0.) {
783
v.setChosenSpeedFactor(type.computeChosenSpeedDeviation(nullptr, pars.departSpeed / MIN2(getSpeedLimit(), type.getDesiredMaxSpeed() - SPEED_EPS)));
784
if (v.getChosenSpeedFactor() > type.getSpeedFactor().getParameter(0) + 2 * type.getSpeedFactor().getParameter(1)) {
785
// only warn for significant deviation
786
WRITE_WARNINGF(TL("Choosing new speed factor % for vehicle '%' to match departure speed % (max %)."),
787
toString(v.getChosenSpeedFactor()), pars.id, pars.departSpeed, vMax);
788
}
789
} else {
790
return false;
791
}
792
}
793
}
794
}
795
}
796
return true;
797
}
798
799
800
bool
801
MSEdge::insertVehicle(SUMOVehicle& v, SUMOTime time, const bool checkOnly, const bool forceCheck) const {
802
// when vaporizing, no vehicles are inserted, but checking needs to be successful to trigger removal
803
if (isVaporizing() || isTazConnector()
804
|| v.getRouteValidity(true, checkOnly) != MSBaseVehicle::ROUTE_VALID) {
805
return checkOnly;
806
}
807
const SUMOVehicleParameter& pars = v.getParameter();
808
if (!validateDepartSpeed(v)) {
809
if (MSGlobals::gCheckRoutes) {
810
throw ProcessError(TLF("Departure speed for vehicle '%' is too high for the departure edge '%', time=%.",
811
pars.id, getID(), time2string(time)));
812
} else {
813
WRITE_WARNINGF(TL("Departure speed for vehicle '%' is too high for the departure edge '%', time=%."),
814
pars.id, getID(), time2string(time));
815
}
816
}
817
if (MSGlobals::gUseMesoSim) {
818
if (!forceCheck && myLastFailedInsertionTime == time) {
819
return false;
820
}
821
double pos = 0.0;
822
switch (pars.departPosProcedure) {
823
case DepartPosDefinition::GIVEN:
824
if (pars.departPos >= 0.) {
825
pos = pars.departPos;
826
} else {
827
pos = pars.departPos + getLength();
828
}
829
if (pos < 0 || pos > getLength()) {
830
WRITE_WARNINGF(TL("Invalid departPos % given for vehicle '%', time=%. Inserting at lane end instead."),
831
pos, v.getID(), time2string(time));
832
pos = getLength();
833
}
834
break;
835
case DepartPosDefinition::RANDOM:
836
case DepartPosDefinition::RANDOM_FREE:
837
pos = RandHelper::rand(getLength());
838
break;
839
default:
840
break;
841
}
842
bool result = false;
843
MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this, pos);
844
MEVehicle* veh = static_cast<MEVehicle*>(&v);
845
int qIdx;
846
if (pars.departPosProcedure == DepartPosDefinition::FREE) {
847
while (segment != nullptr && !result) {
848
if (checkOnly) {
849
result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
850
} else {
851
result = segment->initialise(veh, time);
852
}
853
segment = segment->getNextSegment();
854
}
855
} else {
856
if (checkOnly) {
857
result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
858
} else {
859
result = segment->initialise(veh, time);
860
}
861
}
862
return result;
863
}
864
if (checkOnly) {
865
switch (v.getParameter().departLaneProcedure) {
866
case DepartLaneDefinition::GIVEN:
867
case DepartLaneDefinition::DEFAULT:
868
case DepartLaneDefinition::FIRST_ALLOWED: {
869
MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
870
if (insertionLane == nullptr) {
871
WRITE_WARNINGF(TL("Could not insert vehicle '%' on any lane of edge '%', time=%."),
872
v.getID(), getID(), time2string(time));
873
return false;
874
}
875
const double occupancy = insertionLane->getBruttoOccupancy();
876
return (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
877
v.getParameter().departProcedure == DepartDefinition::SPLIT);
878
}
879
default:
880
for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
881
const double occupancy = (*i)->getBruttoOccupancy();
882
if (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
883
v.getParameter().departProcedure == DepartDefinition::SPLIT) {
884
return true;
885
}
886
}
887
}
888
return false;
889
}
890
MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
891
if (insertionLane == nullptr) {
892
return false;
893
}
894
895
if (!forceCheck) {
896
if (myLastFailedInsertionTime == time) {
897
if (myFailedInsertionMemory.count(insertionLane->getIndex())) {
898
// A vehicle was already rejected for the proposed insertionLane in this timestep
899
return false;
900
}
901
} else {
902
// last rejection occurred in a previous timestep, clear cache
903
myFailedInsertionMemory.clear();
904
}
905
}
906
907
bool success = insertionLane->insertVehicle(static_cast<MSVehicle&>(v));
908
909
if (!success) {
910
// constraints may enforce explicit re-ordering so we need to try other vehicles after failure
911
if (!insertionLane->hasParameter("insertionOrder" + v.getID())) {
912
myFailedInsertionMemory.insert(insertionLane->getIndex());
913
}
914
}
915
return success;
916
}
917
918
919
void
920
MSEdge::changeLanes(SUMOTime t) const {
921
if (myLaneChanger != nullptr) {
922
myLaneChanger->laneChange(t);
923
}
924
}
925
926
927
const MSEdge*
928
MSEdge::getInternalFollowingEdge(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
929
//@todo to be optimized
930
for (const MSLane* const l : *myLanes) {
931
for (const MSLink* const link : l->getLinkCont()) {
932
if (&link->getLane()->getEdge() == followerAfterInternal) {
933
if (link->getViaLane() != nullptr) {
934
if (link->getViaLane()->allowsVehicleClass(vClass)) {
935
return &link->getViaLane()->getEdge();
936
} else {
937
continue;
938
}
939
} else {
940
return nullptr; // network without internal links
941
}
942
}
943
}
944
}
945
return nullptr;
946
}
947
948
949
double
950
MSEdge::getInternalFollowingLengthTo(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
951
assert(followerAfterInternal != 0);
952
assert(!followerAfterInternal->isInternal());
953
double dist = 0.;
954
const MSEdge* edge = getInternalFollowingEdge(followerAfterInternal, vClass);
955
// Take into account non-internal lengths until next non-internal edge
956
while (edge != nullptr && edge->isInternal()) {
957
dist += edge->getLength();
958
edge = edge->getInternalFollowingEdge(followerAfterInternal, vClass);
959
}
960
return dist;
961
}
962
963
964
const MSEdge*
965
MSEdge::getNormalBefore() const {
966
const MSEdge* result = this;
967
while (result->isInternal() && MSGlobals::gUsingInternalLanes) {
968
assert(result->getPredecessors().size() == 1);
969
result = result->getPredecessors().front();
970
}
971
return result;
972
}
973
974
const MSEdge*
975
MSEdge::getNormalSuccessor() const {
976
const MSEdge* result = this;
977
while (result->isInternal()) {
978
assert(result->getSuccessors().size() == 1);
979
result = result->getSuccessors().front();
980
}
981
return result;
982
}
983
984
double
985
MSEdge::getMeanSpeed() const {
986
double v = 0;
987
double totalNumVehs = 0;
988
if (MSGlobals::gUseMesoSim) {
989
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
990
const int numVehs = segment->getCarNumber();
991
if (numVehs > 0) {
992
v += numVehs * segment->getMeanSpeed();
993
totalNumVehs += numVehs;
994
}
995
}
996
if (totalNumVehs == 0) {
997
return getLength() / myEmptyTraveltime; // may include tls-penalty
998
}
999
} else {
1000
for (const MSLane* const lane : *myLanes) {
1001
int numVehs = lane->getVehicleNumber();
1002
if (numVehs == 0) {
1003
// take speed limit but with lowest possible weight
1004
numVehs = 1;
1005
}
1006
v += numVehs * lane->getMeanSpeed();
1007
totalNumVehs += numVehs;
1008
}
1009
if (myBidiEdge != nullptr) {
1010
for (const MSLane* const lane : myBidiEdge->getLanes()) {
1011
if (lane->getVehicleNumber() > 0) {
1012
// do not route across edges which are already occupied in reverse direction
1013
return 0;
1014
}
1015
}
1016
}
1017
if (totalNumVehs == 0) {
1018
return getSpeedLimit();
1019
}
1020
}
1021
return v / totalNumVehs;
1022
}
1023
1024
1025
double
1026
MSEdge::getMeanFriction() const {
1027
double f = 0.;
1028
for (const MSLane* const lane : *myLanes) {
1029
f += lane->getFrictionCoefficient();
1030
}
1031
if (!myLanes->empty()) {
1032
return f / (double)myLanes->size();
1033
}
1034
return 1.;
1035
}
1036
1037
1038
double
1039
MSEdge::getMeanSpeedBike() const {
1040
if (MSGlobals::gUseMesoSim) {
1041
// no separate bicycle speeds in meso
1042
return getMeanSpeed();
1043
}
1044
double v = 0;
1045
double totalNumVehs = 0;
1046
for (const MSLane* const lane : *myLanes) {
1047
const int numVehs = lane->getVehicleNumber();
1048
v += numVehs * lane->getMeanSpeedBike();
1049
totalNumVehs += numVehs;
1050
}
1051
if (totalNumVehs == 0) {
1052
return getSpeedLimit();
1053
}
1054
return v / totalNumVehs;
1055
}
1056
1057
1058
double
1059
MSEdge::getCurrentTravelTime(double minSpeed) const {
1060
assert(minSpeed > 0);
1061
if (!myAmDelayed) {
1062
return myEmptyTraveltime;
1063
}
1064
return getLength() / MAX2(minSpeed, getMeanSpeed());
1065
}
1066
1067
1068
double
1069
MSEdge::getRoutingSpeed() const {
1070
return MSRoutingEngine::getAssumedSpeed(this, nullptr);
1071
}
1072
1073
1074
bool
1075
MSEdge::dictionary(const std::string& id, MSEdge* ptr) {
1076
const DictType::iterator it = myDict.lower_bound(id);
1077
if (it == myDict.end() || it->first != id) {
1078
// id not in myDict
1079
myDict.emplace_hint(it, id, ptr);
1080
while (ptr->getNumericalID() >= (int)myEdges.size()) {
1081
myEdges.push_back(nullptr);
1082
}
1083
myEdges[ptr->getNumericalID()] = ptr;
1084
return true;
1085
}
1086
return false;
1087
}
1088
1089
1090
MSEdge*
1091
MSEdge::dictionary(const std::string& id) {
1092
const DictType::iterator it = myDict.find(id);
1093
if (it == myDict.end()) {
1094
return nullptr;
1095
}
1096
return it->second;
1097
}
1098
1099
1100
MSEdge*
1101
MSEdge::dictionaryHint(const std::string& id, const int startIdx) {
1102
// this method is mainly useful when parsing connections from the net.xml which are sorted by "from" id
1103
if (myEdges[startIdx] != nullptr && myEdges[startIdx]->getID() == id) {
1104
return myEdges[startIdx];
1105
}
1106
if (startIdx + 1 < (int)myEdges.size() && myEdges[startIdx + 1] != nullptr && myEdges[startIdx + 1]->getID() == id) {
1107
return myEdges[startIdx + 1];
1108
}
1109
return dictionary(id);
1110
}
1111
1112
1113
const MSEdgeVector&
1114
MSEdge::getAllEdges() {
1115
return myEdges;
1116
}
1117
1118
1119
void
1120
MSEdge::clear() {
1121
for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
1122
delete (*i).second;
1123
}
1124
myDict.clear();
1125
myEdges.clear();
1126
}
1127
1128
1129
void
1130
MSEdge::insertIDs(std::vector<std::string>& into) {
1131
for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
1132
into.push_back((*i).first);
1133
}
1134
}
1135
1136
1137
void
1138
MSEdge::parseEdgesList(const std::string& desc, ConstMSEdgeVector& into,
1139
const std::string& rid) {
1140
StringTokenizer st(desc);
1141
parseEdgesList(st.getVector(), into, rid);
1142
}
1143
1144
1145
void
1146
MSEdge::parseEdgesList(const std::vector<std::string>& desc, ConstMSEdgeVector& into,
1147
const std::string& rid) {
1148
for (std::vector<std::string>::const_iterator i = desc.begin(); i != desc.end(); ++i) {
1149
const MSEdge* edge = MSEdge::dictionary(*i);
1150
// check whether the edge exists
1151
if (edge == nullptr) {
1152
throw ProcessError("The edge '" + *i + "' within the route " + rid + " is not known."
1153
+ "\n The route can not be build.");
1154
}
1155
into.push_back(edge);
1156
}
1157
}
1158
1159
1160
double
1161
MSEdge::getDistanceTo(const MSEdge* other, const bool doBoundaryEstimate) const {
1162
assert(this != other);
1163
if (doBoundaryEstimate) {
1164
return myBoundary.distanceTo2D(other->myBoundary);
1165
}
1166
if (isTazConnector()) {
1167
if (other->isTazConnector()) {
1168
return myBoundary.distanceTo2D(other->myBoundary);
1169
}
1170
return myBoundary.distanceTo2D(other->getLanes()[0]->getShape()[0]);
1171
}
1172
if (other->isTazConnector()) {
1173
return other->myBoundary.distanceTo2D(getLanes()[0]->getShape()[-1]);
1174
}
1175
return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
1176
}
1177
1178
1179
const Position
1180
MSEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
1181
return MSLane::dictionary(stop.lane)->geometryPositionAtOffset((stop.endPos + stop.startPos) / 2.);
1182
}
1183
1184
1185
double
1186
MSEdge::getSpeedLimit() const {
1187
// @note lanes might have different maximum speeds in theory
1188
return myLanes->empty() ? 1 : getLanes()[0]->getSpeedLimit();
1189
}
1190
1191
1192
double
1193
MSEdge::getLengthGeometryFactor() const {
1194
return myLanes->empty() ? 1 : getLanes()[0]->getLengthGeometryFactor();
1195
}
1196
1197
double
1198
MSEdge::getVehicleMaxSpeed(const SUMOTrafficObject* const veh) const {
1199
// @note lanes might have different maximum speeds in theory
1200
return myLanes->empty() ? 1 : getLanes()[0]->getVehicleMaxSpeed(veh);
1201
}
1202
1203
1204
void
1205
MSEdge::setMaxSpeed(double val, double jamThreshold) {
1206
assert(val >= 0);
1207
if (myLanes != nullptr) {
1208
for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
1209
(*i)->setMaxSpeed(val, false, false, jamThreshold);
1210
}
1211
}
1212
}
1213
1214
1215
void
1216
MSEdge::addTransportable(MSTransportable* t) const {
1217
if (t->isPerson()) {
1218
myPersons.insert(t);
1219
} else {
1220
myContainers.insert(t);
1221
}
1222
}
1223
1224
void
1225
MSEdge::removeTransportable(MSTransportable* t) const {
1226
std::set<MSTransportable*, ComparatorNumericalIdLess>& tc = t->isPerson() ? myPersons : myContainers;
1227
auto it = tc.find(t);
1228
if (it != tc.end()) {
1229
tc.erase(it);
1230
}
1231
}
1232
1233
std::vector<MSTransportable*>
1234
MSEdge::getSortedPersons(SUMOTime timestep, bool includeRiding) const {
1235
std::vector<MSTransportable*> result(myPersons.begin(), myPersons.end());
1236
if (includeRiding) {
1237
for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
1238
const MSLane::VehCont& vehs = (*i)->getVehiclesSecure();
1239
for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
1240
const std::vector<MSTransportable*>& persons = (*j)->getPersons();
1241
result.insert(result.end(), persons.begin(), persons.end());
1242
}
1243
(*i)->releaseVehicles();
1244
}
1245
}
1246
sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
1247
return result;
1248
}
1249
1250
1251
std::vector<MSTransportable*>
1252
MSEdge::getSortedContainers(SUMOTime timestep, bool /* includeRiding */) const {
1253
std::vector<MSTransportable*> result(myContainers.begin(), myContainers.end());
1254
sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
1255
return result;
1256
}
1257
1258
1259
int
1260
MSEdge::transportable_by_position_sorter::operator()(const MSTransportable* const c1, const MSTransportable* const c2) const {
1261
const double pos1 = c1->getCurrentStage()->getEdgePos(myTime);
1262
const double pos2 = c2->getCurrentStage()->getEdgePos(myTime);
1263
if (pos1 != pos2) {
1264
return pos1 < pos2;
1265
}
1266
return c1->getID() < c2->getID();
1267
}
1268
1269
1270
void
1271
MSEdge::addSuccessor(MSEdge* edge, const MSEdge* via) {
1272
mySuccessors.push_back(edge);
1273
myViaSuccessors.push_back(std::make_pair(edge, via));
1274
if (isTazConnector() && edge->getFromJunction() != nullptr) {
1275
myBoundary.add(edge->getFromJunction()->getPosition());
1276
}
1277
1278
edge->myPredecessors.push_back(this);
1279
if (edge->isTazConnector() && getToJunction() != nullptr) {
1280
edge->myBoundary.add(getToJunction()->getPosition());
1281
}
1282
}
1283
1284
1285
const MSEdgeVector&
1286
MSEdge::getSuccessors(SUMOVehicleClass vClass) const {
1287
if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
1288
return mySuccessors;
1289
}
1290
#ifdef HAVE_FOX
1291
ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
1292
#endif
1293
std::map<SUMOVehicleClass, MSEdgeVector>::iterator i = myClassesSuccessorMap.find(vClass);
1294
if (i == myClassesSuccessorMap.end()) {
1295
// instantiate vector
1296
myClassesSuccessorMap[vClass];
1297
i = myClassesSuccessorMap.find(vClass);
1298
// this vClass is requested for the first time. rebuild all successors
1299
for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
1300
if ((*it)->isTazConnector()) {
1301
i->second.push_back(*it);
1302
} else {
1303
const std::vector<MSLane*>* allowed = allowedLanes(**it, vClass);
1304
if (allowed != nullptr && allowed->size() > 0) {
1305
i->second.push_back(*it);
1306
}
1307
}
1308
}
1309
}
1310
// can use cached value
1311
return i->second;
1312
}
1313
1314
1315
const MSConstEdgePairVector&
1316
MSEdge::getViaSuccessors(SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
1317
if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
1318
return myViaSuccessors;
1319
}
1320
#ifdef HAVE_FOX
1321
ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
1322
#endif
1323
auto& viaMap = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigClassesViaSuccessorMap : myClassesViaSuccessorMap;
1324
auto i = viaMap.find(vClass);
1325
if (i != viaMap.end()) {
1326
// can use cached value
1327
return i->second;
1328
}
1329
// instantiate vector
1330
MSConstEdgePairVector& result = viaMap[vClass];
1331
// this vClass is requested for the first time. rebuild all successors
1332
for (const auto& viaPair : myViaSuccessors) {
1333
if (viaPair.first->isTazConnector()) {
1334
result.push_back(viaPair);
1335
} else {
1336
const std::vector<MSLane*>* allowed = allowedLanes(*viaPair.first, vClass, ignoreTransientPermissions);
1337
if (allowed != nullptr && allowed->size() > 0) {
1338
result.push_back(viaPair);
1339
}
1340
}
1341
}
1342
return result;
1343
}
1344
1345
1346
void
1347
MSEdge::setJunctions(MSJunction* from, MSJunction* to) {
1348
myFromJunction = from;
1349
myToJunction = to;
1350
if (!isTazConnector()) {
1351
myBoundary.add(from->getPosition());
1352
myBoundary.add(to->getPosition());
1353
}
1354
}
1355
1356
1357
bool
1358
MSEdge::canChangeToOpposite() const {
1359
return (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr &&
1360
// do not change on curved internal lanes
1361
(!isInternal()
1362
|| (MSGlobals::gUsingInternalLanes
1363
&& myLanes->back()->getIncomingLanes()[0].viaLink->getDirection() == LinkDirection::STRAIGHT)));
1364
}
1365
1366
1367
const MSEdge*
1368
MSEdge::getOppositeEdge() const {
1369
if (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr) {
1370
return &(myLanes->back()->getOpposite()->getEdge());
1371
} else {
1372
return nullptr;
1373
}
1374
}
1375
1376
1377
bool
1378
MSEdge::hasMinorLink() const {
1379
for (const MSLane* const l : *myLanes) {
1380
for (const MSLink* const link : l->getLinkCont()) {
1381
if (!link->havePriority()) {
1382
return true;
1383
}
1384
}
1385
}
1386
return false;
1387
}
1388
1389
bool
1390
MSEdge::hasChangeProhibitions(SUMOVehicleClass svc, int index) const {
1391
if (myLanes->size() == 1) {
1392
return false;
1393
}
1394
for (const MSLane* const l : *myLanes) {
1395
if (l->getIndex() <= index && !l->allowsChangingRight(svc) && l->getIndex() > 0) {
1396
return true;
1397
} else if (l->getIndex() >= index && !l->allowsChangingLeft(svc) && l->getIndex() < (int)(myLanes->size() - 1)) {
1398
return true;
1399
}
1400
}
1401
return false;
1402
}
1403
1404
void
1405
MSEdge::checkAndRegisterBiDirEdge(const std::string& bidiID) {
1406
if (bidiID != "") {
1407
myBidiEdge = dictionary(bidiID);
1408
if (myBidiEdge == nullptr) {
1409
WRITE_ERRORF(TL("Bidi-edge '%' does not exist"), bidiID);
1410
}
1411
setBidiLanes();
1412
return;
1413
}
1414
if (getFunction() != SumoXMLEdgeFunc::NORMAL) {
1415
return;
1416
}
1417
// legacy networks (no bidi attribute)
1418
ConstMSEdgeVector candidates = myToJunction->getOutgoing();
1419
for (ConstMSEdgeVector::const_iterator it = candidates.begin(); it != candidates.end(); it++) {
1420
if ((*it)->getToJunction() == myFromJunction) { //reverse edge
1421
if (myBidiEdge != nullptr && isSuperposable(*it)) {
1422
WRITE_WARNINGF(TL("Ambiguous superposable edges between junction '%' and '%'."), myToJunction->getID(), myFromJunction->getID());
1423
break;
1424
}
1425
if (isSuperposable(*it)) {
1426
myBidiEdge = *it;
1427
setBidiLanes();
1428
}
1429
}
1430
}
1431
}
1432
1433
1434
void
1435
MSEdge::setBidiLanes() {
1436
assert(myBidiEdge != nullptr);
1437
if (getNumLanes() == 1 && myBidiEdge->getNumLanes() == 1) {
1438
// the other way round is set when this method runs for the bidiEdge
1439
getLanes()[0]->setBidiLane(myBidiEdge->getLanes()[0]);
1440
} else {
1441
// find lanes with matching reversed shapes
1442
int numBidiLanes = 0;
1443
for (MSLane* l1 : *myLanes) {
1444
for (MSLane* l2 : *myBidiEdge->myLanes) {
1445
if (l1->getShape().reverse().almostSame(l2->getShape(), POSITION_EPS * 2)) {
1446
l1->setBidiLane(l2);
1447
numBidiLanes++;
1448
}
1449
}
1450
}
1451
// warn only once for each pair
1452
if (numBidiLanes == 0 && getNumericalID() < myBidiEdge->getNumericalID()) {
1453
WRITE_WARNINGF(TL("Edge '%' and bidi edge '%' have no matching bidi lanes"), getID(), myBidiEdge->getID());
1454
}
1455
}
1456
}
1457
1458
1459
bool
1460
MSEdge::isSuperposable(const MSEdge* other) {
1461
if (other == nullptr || other->getLanes().size() != myLanes->size()) {
1462
return false;
1463
}
1464
std::vector<MSLane*>::const_iterator it1 = myLanes->begin();
1465
std::vector<MSLane*>::const_reverse_iterator it2 = other->getLanes().rbegin();
1466
do {
1467
if ((*it1)->getShape().reverse() != (*it2)->getShape()) {
1468
return false;
1469
}
1470
it1++;
1471
it2++;
1472
} while (it1 != myLanes->end());
1473
1474
return true;
1475
}
1476
1477
1478
void
1479
MSEdge::addWaiting(SUMOVehicle* vehicle) const {
1480
#ifdef HAVE_FOX
1481
ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1482
#endif
1483
myWaiting.push_back(vehicle);
1484
}
1485
1486
1487
void
1488
MSEdge::removeWaiting(const SUMOVehicle* vehicle) const {
1489
#ifdef HAVE_FOX
1490
ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1491
#endif
1492
std::vector<SUMOVehicle*>::iterator it = std::find(myWaiting.begin(), myWaiting.end(), vehicle);
1493
if (it != myWaiting.end()) {
1494
myWaiting.erase(it);
1495
}
1496
}
1497
1498
1499
SUMOVehicle*
1500
MSEdge::getWaitingVehicle(MSTransportable* transportable, const double position) const {
1501
#ifdef HAVE_FOX
1502
ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1503
#endif
1504
for (SUMOVehicle* const vehicle : myWaiting) {
1505
if (transportable->isWaitingFor(vehicle)) {
1506
if (vehicle->isStoppedInRange(position, MSGlobals::gStopTolerance) ||
1507
(!vehicle->hasDeparted() &&
1508
(vehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED ||
1509
vehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED))) {
1510
return vehicle;
1511
}
1512
if (!vehicle->isLineStop(position) && vehicle->allowsBoarding(transportable)) {
1513
WRITE_WARNING((transportable->isPerson() ? "Person '" : "Container '")
1514
+ transportable->getID() + "' at edge '" + getID() + "' position " + toString(position) + " cannot use waiting vehicle '"
1515
+ vehicle->getID() + "' at position " + toString(vehicle->getPositionOnLane()) + " because it is too far away.");
1516
}
1517
}
1518
}
1519
return nullptr;
1520
}
1521
1522
std::vector<const SUMOVehicle*>
1523
MSEdge::getVehicles() const {
1524
std::vector<const SUMOVehicle*> result;
1525
if (MSGlobals::gUseMesoSim) {
1526
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1527
std::vector<const MEVehicle*> segmentVehs = segment->getVehicles();
1528
result.insert(result.end(), segmentVehs.begin(), segmentVehs.end());
1529
}
1530
} else {
1531
for (MSLane* lane : getLanes()) {
1532
for (auto veh : lane->getVehiclesSecure()) {
1533
result.push_back(veh);
1534
}
1535
lane->releaseVehicles();
1536
}
1537
}
1538
return result;
1539
}
1540
1541
int
1542
MSEdge::getNumDrivingLanes() const {
1543
int result = 0;
1544
SVCPermissions filter = SVCAll;
1545
if ((myCombinedPermissions & ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
1546
filter = ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR);
1547
} else if ((myCombinedPermissions & (SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
1548
// filter out green verge
1549
filter = (SVC_PEDESTRIAN | SVC_WHEELCHAIR);
1550
}
1551
for (const MSLane* const l : *myLanes) {
1552
if ((l->getPermissions() & filter) != 0) {
1553
result++;
1554
}
1555
}
1556
return result;
1557
}
1558
1559
int
1560
MSEdge::getVehicleNumber() const {
1561
return (int)getVehicles().size();
1562
}
1563
1564
1565
bool
1566
MSEdge::isEmpty() const {
1567
/// more efficient than retrieving vehicle number
1568
if (MSGlobals::gUseMesoSim) {
1569
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1570
if (segment->getCarNumber() > 0) {
1571
return false;
1572
}
1573
}
1574
} else {
1575
for (MSLane* lane : getLanes()) {
1576
if (lane->getVehicleNumber() > 0) {
1577
return false;
1578
}
1579
}
1580
}
1581
return true;
1582
}
1583
1584
1585
double
1586
MSEdge::getWaitingSeconds() const {
1587
double wtime = 0;
1588
if (MSGlobals::gUseMesoSim) {
1589
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1590
wtime += segment->getWaitingSeconds();
1591
}
1592
} else {
1593
for (MSLane* lane : getLanes()) {
1594
wtime += lane->getWaitingSeconds();
1595
}
1596
}
1597
return wtime;
1598
}
1599
1600
1601
double
1602
MSEdge::getOccupancy() const {
1603
if (myLanes->size() == 0) {
1604
return 0;
1605
}
1606
if (MSGlobals::gUseMesoSim) {
1607
/// @note MESegment only tracks brutto occupancy so we compute this from sratch
1608
double sum = 0;
1609
for (const SUMOVehicle* veh : getVehicles()) {
1610
sum += dynamic_cast<const MEVehicle*>(veh)->getVehicleType().getLength();
1611
}
1612
return sum / (myLength * (double)myLanes->size());
1613
} else {
1614
double sum = 0;
1615
for (auto lane : getLanes()) {
1616
sum += lane->getNettoOccupancy();
1617
}
1618
return sum / (double)myLanes->size();
1619
}
1620
}
1621
1622
1623
double
1624
MSEdge::getFlow() const {
1625
if (myLanes->size() == 0) {
1626
return 0;
1627
}
1628
double flow = 0;
1629
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1630
flow += (double) segment->getCarNumber() * segment->getMeanSpeed();
1631
}
1632
return 3600 * flow / (*myLanes)[0]->getLength();
1633
}
1634
1635
1636
double
1637
MSEdge::getBruttoOccupancy() const {
1638
if (myLanes->size() == 0) {
1639
return 0;
1640
}
1641
double occ = 0;
1642
for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1643
occ += segment->getBruttoOccupancy();
1644
}
1645
return occ / (*myLanes)[0]->getLength() / (double)(myLanes->size());
1646
}
1647
1648
double
1649
MSEdge::getTravelTimeAggregated(const MSEdge* const edge, const SUMOVehicle* const veh, double /*time*/) {
1650
return edge->getLength() / MIN2(MSRoutingEngine::getAssumedSpeed(edge, veh), veh->getMaxSpeed());
1651
}
1652
1653
1654
void
1655
MSEdge::inferEdgeType() {
1656
// @note must be called after closeBuilding() to ensure successors and
1657
// predecessors are set
1658
if (isInternal() && myEdgeType == "") {
1659
const std::string typeBefore = getNormalBefore()->getEdgeType();
1660
if (typeBefore != "") {
1661
const std::string typeAfter = getNormalSuccessor()->getEdgeType();
1662
if (typeBefore == typeAfter) {
1663
myEdgeType = typeBefore;
1664
} else if (typeAfter != "") {
1665
MSNet* net = MSNet::getInstance();
1666
auto resBefore = net->getRestrictions(typeBefore);
1667
auto resAfter = net->getRestrictions(typeAfter);
1668
if (resBefore != nullptr && resAfter != nullptr) {
1669
// create new restrictions for this type-combination
1670
myEdgeType = typeBefore + "|" + typeAfter;
1671
if (net->getRestrictions(myEdgeType) == nullptr) {
1672
for (const auto& item : *resBefore) {
1673
const SUMOVehicleClass svc = item.first;
1674
const double speed = item.second;
1675
const auto it = (*resAfter).find(svc);
1676
if (it != (*resAfter).end()) {
1677
const double speed2 = it->second;
1678
const double newSpeed = (MSNet::getInstance()->hasJunctionHigherSpeeds()
1679
? MAX2(speed, speed2) : (speed + speed2) / 2);
1680
net->addRestriction(myEdgeType, svc, newSpeed);
1681
}
1682
}
1683
}
1684
}
1685
}
1686
}
1687
}
1688
}
1689
1690
1691
double
1692
MSEdge::getDistanceAt(double pos) const {
1693
// negative values of myDistances indicate descending kilometrage
1694
return fabs(myDistance + pos);
1695
}
1696
1697
1698
bool
1699
MSEdge::hasTransientPermissions() const {
1700
return myHaveTransientPermissions;
1701
}
1702
1703
1704
std::pair<double, SUMOTime>
1705
MSEdge::getLastBlocked(int index) const {
1706
if (myLaneChanger != nullptr) {
1707
return myLaneChanger->getLastBlocked(index);
1708
}
1709
return std::make_pair(-1, -1);
1710
}
1711
1712
1713
double
1714
MSEdge::getPreference(const SUMOVTypeParameter& pars) const {
1715
return MSNet::getInstance()->getPreference(getRoutingType(), pars);
1716
}
1717
1718
void
1719
MSEdge::clearState() {
1720
myPersons.clear();
1721
myContainers.clear();
1722
myWaiting.clear();
1723
}
1724
1725
/****************************************************************************/
1726
1727