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