Line data Source code
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 1897347 : 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 1897347 : double distance) :
75 1897347 : Named(id), myNumericalID(numericalID), myLanes(nullptr),
76 1897347 : myLaneChanger(nullptr), myFunction(function), myVaporizationRequests(0),
77 1897347 : myLastFailedInsertionTime(-1),
78 1897347 : myFromJunction(nullptr), myToJunction(nullptr),
79 1897347 : myHaveTransientPermissions(false),
80 1897347 : myOtherTazConnector(nullptr),
81 1897347 : myStreetName(streetName),
82 1897347 : myEdgeType(edgeType),
83 1897347 : myRoutingType(routingType),
84 1897347 : myPriority(priority),
85 1897347 : myDistance(distance),
86 1897347 : myWidth(0.),
87 1897347 : myLength(0.),
88 1897347 : myEmptyTraveltime(0.),
89 1897347 : myTimePenalty(0.),
90 1897347 : myAmDelayed(false),
91 1897347 : myAmRoundabout(false),
92 1897347 : myAmFringe(true),
93 3794694 : myBidiEdge(nullptr)
94 1897347 : { }
95 :
96 :
97 3276406 : MSEdge::~MSEdge() {
98 1882298 : delete myLaneChanger;
99 1882298 : delete myReversedRoutingEdge;
100 1882298 : delete myRailwayRoutingEdge;
101 10805598 : }
102 :
103 :
104 : void
105 1770600 : MSEdge::initialize(const std::vector<MSLane*>* lanes) {
106 : assert(lanes != 0);
107 1770600 : myLanes = std::shared_ptr<const std::vector<MSLane*> >(lanes);
108 1770600 : if (myFunction == SumoXMLEdgeFunc::CONNECTOR) {
109 61226 : myCombinedPermissions = SVCAll;
110 : }
111 3830274 : for (MSLane* const lane : *lanes) {
112 2059674 : lane->setRightSideOnEdge(myWidth, (int)mySublaneSides.size());
113 2059674 : MSLeaderInfo ahead(lane->getWidth());
114 4820373 : for (int j = 0; j < ahead.numSublanes(); ++j) {
115 2760699 : mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
116 : }
117 2059674 : myWidth += lane->getWidth();
118 2059674 : }
119 1770600 : }
120 :
121 :
122 1792548 : void MSEdge::recalcCache() {
123 1792548 : if (myLanes->empty()) {
124 : return;
125 : }
126 1792548 : myLength = myLanes->front()->getLength();
127 3585096 : myEmptyTraveltime = myLength / MAX2(getSpeedLimit(), NUMERICAL_EPS);
128 1792548 : if (isNormal() && (MSGlobals::gUseMesoSim || MSGlobals::gTLSPenalty > 0)) {
129 : SUMOTime minorPenalty = 0;
130 171315 : bool haveTLSPenalty = MSGlobals::gTLSPenalty > 0;
131 171315 : if (MSGlobals::gUseMesoSim) {
132 171200 : const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
133 171200 : minorPenalty = edgeType.minorPenalty;
134 171200 : haveTLSPenalty = edgeType.tlsPenalty > 0;
135 : }
136 171315 : if (haveTLSPenalty || minorPenalty > 0) {
137 : // add tls penalties to the minimum travel time
138 : SUMOTime minPenalty = -1;
139 2555 : for (const MSLane* const l : *myLanes) {
140 4099 : for (const MSLink* const link : l->getLinkCont()) {
141 2387 : if (link->getLane()->isWalkingArea() && link->getLaneBefore()->isNormal()) {
142 60 : continue;
143 : }
144 2327 : SUMOTime linkPenalty = link->isTLSControlled() ? link->getMesoTLSPenalty() : (link->havePriority() ? 0 : minorPenalty);
145 2327 : if (minPenalty == -1) {
146 : minPenalty = linkPenalty;
147 : } else {
148 : minPenalty = MIN2(minPenalty, linkPenalty);
149 : }
150 : }
151 : }
152 843 : if (minPenalty > 0) {
153 285 : myEmptyTraveltime += STEPS2TIME(minPenalty);
154 285 : myTimePenalty = STEPS2TIME(minPenalty);
155 : }
156 : }
157 1621233 : } else if (isCrossing() && MSGlobals::gTLSPenalty > 0) {
158 : // penalties are recorded for the entering link
159 80 : for (const auto& ili : myLanes->front()->getIncomingLanes()) {
160 40 : double penalty = STEPS2TIME(ili.viaLink->getMesoTLSPenalty());
161 40 : if (!ili.viaLink->haveOffPriority()) {
162 0 : penalty = MAX2(penalty, MSGlobals::gMinorPenalty);
163 : }
164 40 : if (penalty > 0) {
165 20 : myEmptyTraveltime += penalty;
166 20 : myTimePenalty = penalty;
167 : }
168 : }
169 1621193 : } else if (isInternal() && MSGlobals::gUsingInternalLanes) {
170 739091 : const MSLink* link = myLanes->front()->getIncomingLanes()[0].viaLink;
171 739091 : if (!link->isTLSControlled() && !link->havePriority()) {
172 352477 : if (link->isTurnaround()) {
173 131812 : myEmptyTraveltime += MSGlobals::gTurnaroundPenalty;
174 131812 : myTimePenalty = MSGlobals::gTurnaroundPenalty;
175 : } else {
176 220665 : myEmptyTraveltime += MSGlobals::gMinorPenalty;
177 220665 : myTimePenalty = MSGlobals::gMinorPenalty;
178 : }
179 : }
180 : }
181 : }
182 :
183 :
184 : void
185 42 : MSEdge::resetTAZ(MSJunction* junction) {
186 : mySuccessors.clear();
187 : myPredecessors.clear();
188 728 : for (const MSEdge* edge : junction->getIncoming()) {
189 686 : if (!edge->isInternal()) {
190 126 : MSEdgeVector& succ = const_cast<MSEdgeVector&>(edge->mySuccessors);
191 : MSConstEdgePairVector& succVia = const_cast<MSConstEdgePairVector&>(edge->myViaSuccessors);
192 126 : MSEdgeVector& pred = const_cast<MSEdgeVector&>(edge->myPredecessors);
193 126 : auto it = std::find(succ.begin(), succ.end(), this);
194 126 : auto it2 = std::find(succVia.begin(), succVia.end(), std::make_pair(const_cast<const MSEdge*>(this), (const MSEdge*)nullptr));
195 126 : auto it3 = std::find(pred.begin(), pred.end(), this);
196 126 : if (it != succ.end()) {
197 : succ.erase(it);
198 : succVia.erase(it2);
199 : }
200 126 : if (it3 != pred.end()) {
201 : pred.erase(it3);
202 : }
203 : }
204 : }
205 42 : }
206 :
207 : void
208 1706856 : MSEdge::closeBuilding() {
209 3763589 : for (MSLane* const lane : *myLanes) {
210 4693658 : for (MSLink* const link : lane->getLinkCont()) {
211 2636925 : link->initParallelLinks();
212 : MSLane* const toL = link->getLane();
213 : MSLane* const viaL = link->getViaLane();
214 2636925 : if (toL != nullptr) {
215 : MSEdge& to = toL->getEdge();
216 2636925 : if (std::find(mySuccessors.begin(), mySuccessors.end(), &to) == mySuccessors.end()) {
217 2451530 : mySuccessors.push_back(&to);
218 4903060 : myViaSuccessors.push_back(std::make_pair(&to, (viaL == nullptr ? nullptr : &viaL->getEdge())));
219 : }
220 2636925 : if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
221 2451530 : to.myPredecessors.push_back(this);
222 : }
223 2636925 : if (link->getDirection() != LinkDirection::TURN) {
224 2050365 : myAmFringe = false;
225 : }
226 : }
227 2636925 : if (viaL != nullptr) {
228 : MSEdge& to = viaL->getEdge();
229 809718 : if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
230 738908 : to.myPredecessors.push_back(this);
231 : }
232 : }
233 : }
234 2056733 : lane->checkBufferType();
235 : }
236 1706856 : std::sort(mySuccessors.begin(), mySuccessors.end(), by_id_sorter());
237 1706856 : rebuildAllowedLanes(true);
238 1706856 : recalcCache();
239 :
240 : // extend lookup table for sublane model after all edges are read
241 1706856 : if (myLanes->back()->getOpposite() != nullptr) {
242 7556 : MSLane* opposite = myLanes->back()->getOpposite();
243 7556 : MSLeaderInfo ahead(opposite->getWidth());
244 21286 : for (int j = 0; j < ahead.numSublanes(); ++j) {
245 13730 : mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
246 : }
247 7556 : }
248 1706856 : }
249 :
250 :
251 : void
252 1706848 : MSEdge::postLoadInitLaneChanger() {
253 1706848 : if (myLaneChanger != nullptr) {
254 430746 : myLaneChanger->postloadInitLC();
255 : }
256 1706848 : }
257 :
258 : void
259 1706856 : MSEdge::buildLaneChanger() {
260 1706856 : if (!myLanes->empty()) {
261 1706856 : const bool allowChanging = allowsLaneChanging();
262 1706856 : if (MSGlobals::gLateralResolution > 0) {
263 : // may always initiate sublane-change
264 179856 : if (!isInternal() || MSGlobals::gUsingInternalLanes) {
265 179665 : myLaneChanger = new MSLaneChangerSublane(myLanes.get(), allowChanging);
266 : }
267 : } else {
268 1527000 : if (MSGlobals::gLaneChangeDuration > 0) {
269 3717 : myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
270 1523283 : } else if (myLanes->size() > 1 || canChangeToOpposite()) {
271 247372 : myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
272 : }
273 : }
274 : }
275 1706856 : }
276 :
277 :
278 : bool
279 1706856 : MSEdge::allowsLaneChanging() const {
280 1706856 : 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 1193218 : for (const MSLane* const lane : *myLanes) {
284 806998 : const MSLink* const link = lane->getLogicalPredecessorLane()->getLinkTo(lane);
285 : assert(link != nullptr);
286 : const LinkState state = link->getState();
287 344000 : if ((state == LINKSTATE_MINOR && lane->getBidiLane() == nullptr)
288 463234 : || state == LINKSTATE_EQUAL
289 463234 : || state == LINKSTATE_STOP
290 : || state == LINKSTATE_ALLWAY_STOP
291 806998 : || state == LINKSTATE_DEADEND) {
292 : return false;
293 : }
294 : }
295 : }
296 : return true;
297 : }
298 :
299 :
300 : void
301 17468961 : MSEdge::addToAllowed(const SVCPermissions permissions, std::shared_ptr<const std::vector<MSLane*> > allowedLanes, AllowedLanesCont& laneCont) const {
302 17468961 : if (!allowedLanes->empty()) {
303 : // recheck whether we had this list to save memory
304 17651882 : for (auto& allowed : laneCont) {
305 16661911 : if (*allowed.second == *allowedLanes) {
306 12443306 : allowed.first |= permissions;
307 : return;
308 : }
309 : }
310 989971 : laneCont.push_back(std::make_pair(permissions, allowedLanes));
311 : }
312 : }
313 :
314 :
315 : SVCPermissions
316 2808093 : MSEdge::getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored) {
317 2808093 : SVCPermissions ignored = myMesoIgnoredVClasses & ~ignoreIgnored;
318 2808093 : return (p | ignored) == ignored ? 0 : p;
319 : }
320 :
321 :
322 : void
323 1708309 : MSEdge::rebuildAllowedLanes(const bool onInit, bool updateVehicles) {
324 : // rebuild myMinimumPermissions and myCombinedPermissions
325 1708309 : myMinimumPermissions = SVCAll;
326 1708309 : myCombinedPermissions = 0;
327 : bool lanesChangedPermission = false;
328 3767033 : 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 2058724 : SVCPermissions allow = getMesoPermissions(lane->getPermissions(), SVC_PEDESTRIAN);
333 2058724 : myMinimumPermissions &= allow;
334 2058724 : myCombinedPermissions |= allow;
335 2058724 : lanesChangedPermission |= lane->hadPermissionChanges();
336 : }
337 1708309 : if (!onInit && !myHaveTransientPermissions && lanesChangedPermission) {
338 1000 : myHaveTransientPermissions = true;
339 : // backup original structures when first needed
340 1000 : myOrigAllowed = myAllowed;
341 : myOrigAllowedTargets = myAllowedTargets;
342 : myOrigClassesViaSuccessorMap = myClassesViaSuccessorMap;
343 : }
344 : // rebuild myAllowed
345 : myAllowed.clear();
346 1708309 : if (myCombinedPermissions != myMinimumPermissions) {
347 165621 : myAllowed.push_back(std::make_pair(SVC_IGNORING, myLanes));
348 5631114 : for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
349 5465493 : if ((myCombinedPermissions & vclass) == vclass) {
350 : std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
351 11504529 : for (MSLane* const lane : *myLanes) {
352 7792022 : if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
353 3924576 : allowedLanes->push_back(lane);
354 : }
355 : }
356 7425014 : addToAllowed(vclass, allowedLanes, myAllowed);
357 : }
358 : }
359 : }
360 1708309 : if (onInit) {
361 1706856 : myOriginalMinimumPermissions = myMinimumPermissions;
362 1706856 : myOriginalCombinedPermissions = myCombinedPermissions;
363 : } else {
364 1453 : rebuildAllowedTargets(updateVehicles);
365 3699 : for (MSEdge* pred : myPredecessors) {
366 2246 : if (myHaveTransientPermissions && !pred->myHaveTransientPermissions) {
367 1389 : pred->myOrigAllowed = pred->myAllowed;
368 : pred->myOrigAllowedTargets = pred->myAllowedTargets;
369 : pred->myOrigClassesViaSuccessorMap = pred->myClassesViaSuccessorMap;
370 1389 : pred->myHaveTransientPermissions = true;
371 : }
372 2246 : pred->rebuildAllowedTargets(updateVehicles);
373 : }
374 1453 : if (MSGlobals::gUseMesoSim) {
375 2256 : for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*this); s != nullptr; s = s->getNextSegment()) {
376 1888 : s->updatePermissions();
377 : }
378 : }
379 : }
380 1708309 : }
381 :
382 :
383 : void
384 1711567 : MSEdge::rebuildAllowedTargets(const bool updateVehicles) {
385 : myAllowedTargets.clear();
386 4170057 : 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 5625827 : for (MSLane* const lane : *myLanes) {
391 : SVCPermissions combinedTargetPermissions = 0;
392 9143642 : for (const MSLink* const link : lane->getLinkCont()) {
393 5976305 : if (&link->getLane()->getEdge() == target) {
394 2644982 : allLanes->push_back(lane);
395 2644982 : combinedTargetPermissions |= link->getLane()->getPermissions();
396 2644982 : if (link->getViaLane() != nullptr &&
397 811963 : ((lane->getPermissions() & link->getLane()->getPermissions()) != link->getViaLane()->getPermissions())) {
398 : // custom connection permissions
399 : universalMap = false;
400 : }
401 : }
402 : }
403 3167337 : if (combinedTargetPermissions == 0 || (lane->getPermissions() & combinedTargetPermissions) != lane->getPermissions()) {
404 : universalMap = false;
405 : }
406 : }
407 2458490 : if (universalMap) {
408 1986548 : if (myAllowed.empty()) {
409 : // we have no lane specific permissions
410 3905374 : myAllowedTargets[target].push_back(std::make_pair(myMinimumPermissions, myLanes));
411 : } else {
412 133554 : for (const auto& i : myAllowed) {
413 299079 : addToAllowed(i.first, i.second, myAllowedTargets[target]);
414 : }
415 : }
416 : } else {
417 943884 : addToAllowed(SVC_IGNORING, allLanes, myAllowedTargets[target]);
418 : // compute the vclass specific mapping
419 16046028 : for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
420 15574086 : if ((myCombinedPermissions & vclass) == vclass) {
421 : std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
422 40981690 : for (MSLane* const lane : *myLanes) {
423 27796871 : if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
424 52700730 : for (const MSLink* const link : lane->getLinkCont()) {
425 34314852 : if (link->getLane()->allowsVehicleClass((SUMOVehicleClass)vclass) && &link->getLane()->getEdge() == target && (link->getViaLane() == nullptr || link->getViaLane()->allowsVehicleClass((SUMOVehicleClass)vclass))) {
426 9503512 : allowedLanes->push_back(lane);
427 : }
428 : }
429 : }
430 : }
431 39554457 : addToAllowed(vclass, allowedLanes, myAllowedTargets[target]);
432 : }
433 : }
434 : }
435 : }
436 1711567 : if (updateVehicles) {
437 3073 : for (const MSLane* const lane : *myLanes) {
438 1814 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
439 4498 : for (MSVehicle* veh : vehs) {
440 2684 : veh->updateBestLanes(true);
441 : }
442 1814 : lane->releaseVehicles();
443 : }
444 : }
445 : myClassesSuccessorMap.clear();
446 1711567 : }
447 :
448 :
449 : // ------------ Access to the edge's lanes
450 : MSLane*
451 870 : MSEdge::leftLane(const MSLane* const lane) const {
452 870 : return parallelLane(lane, 1);
453 : }
454 :
455 :
456 : MSLane*
457 448 : MSEdge::rightLane(const MSLane* const lane) const {
458 448 : return parallelLane(lane, -1);
459 : }
460 :
461 :
462 : MSLane*
463 88449158 : MSEdge::parallelLane(const MSLane* const lane, int offset, bool includeOpposite) const {
464 88449158 : const int resultIndex = lane->getIndex() + offset;
465 88449158 : if (resultIndex >= getNumLanes() && includeOpposite) {
466 20345491 : const MSEdge* opposite = getOppositeEdge();
467 20345491 : if (opposite != nullptr && resultIndex < getNumLanes() + opposite->getNumLanes()) {
468 1384641 : return opposite->getLanes()[opposite->getNumLanes() + getNumLanes() - resultIndex - 1];
469 : }
470 : return nullptr;
471 68103667 : } else if (resultIndex >= (int)myLanes->size() || resultIndex < 0) {
472 : return nullptr;
473 : } else {
474 44885659 : return (*myLanes)[resultIndex];
475 : }
476 : }
477 :
478 :
479 : const std::vector<MSLane*>*
480 79515437 : MSEdge::allowedLanes(const MSEdge& destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
481 79515437 : const auto& targets = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigAllowedTargets : myAllowedTargets;
482 : AllowedLanesByTarget::const_iterator i = targets.find(&destination);
483 79515437 : if (i != targets.end()) {
484 79518390 : for (const auto& allowed : i->second) {
485 79409916 : 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 730323044 : MSEdge::allowedLanes(SUMOVehicleClass vclass) const {
496 730323044 : if ((myMinimumPermissions & vclass) == vclass) {
497 43893887 : return myLanes.get();
498 : } else {
499 686429157 : if ((myCombinedPermissions & vclass) == vclass) {
500 1372855255 : for (const auto& allowed : myAllowed) {
501 1372855255 : if ((allowed.first & vclass) == vclass) {
502 : return allowed.second.get();
503 : }
504 : }
505 : }
506 1989 : return nullptr;
507 : }
508 : }
509 :
510 :
511 : const std::vector<MSLane*>*
512 7031884081 : MSEdge::allowedLanes(SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
513 7031884081 : const SVCPermissions& minP = ignoreTransientPermissions ? myOriginalMinimumPermissions : myMinimumPermissions;
514 7031884081 : if ((minP & vclass) == vclass) {
515 634221371 : return myLanes.get();
516 : } else {
517 6397662710 : const SVCPermissions comP = ignoreTransientPermissions ? myOriginalCombinedPermissions : myCombinedPermissions;
518 6397662710 : if ((comP & vclass) == vclass) {
519 6397662637 : const AllowedLanesCont& allowedCont = ignoreTransientPermissions ? myOrigAllowed : myAllowed;
520 12801025296 : for (const auto& allowed : allowedCont) {
521 12801025296 : if ((allowed.first & vclass) == vclass) {
522 : return allowed.second.get();
523 : }
524 : }
525 : }
526 73 : return nullptr;
527 : }
528 : }
529 :
530 :
531 : // ------------
532 : SUMOTime
533 433 : MSEdge::incVaporization(SUMOTime) {
534 433 : ++myVaporizationRequests;
535 433 : return 0;
536 : }
537 :
538 :
539 : SUMOTime
540 282 : MSEdge::decVaporization(SUMOTime) {
541 282 : --myVaporizationRequests;
542 282 : return 0;
543 : }
544 :
545 :
546 : MSLane*
547 580261824 : MSEdge::getFreeLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos) const {
548 580261824 : if (allowed == nullptr) {
549 540546523 : allowed = allowedLanes(vclass);
550 : }
551 : MSLane* res = nullptr;
552 540546523 : if (allowed != nullptr) {
553 : double largestGap = 0;
554 : MSLane* resByGap = nullptr;
555 : double leastOccupancy = std::numeric_limits<double>::max();
556 1185702159 : for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i) {
557 605442316 : const double occupancy = (*i)->getBruttoOccupancy();
558 605442316 : if (occupancy < leastOccupancy) {
559 588650552 : res = (*i);
560 : leastOccupancy = occupancy;
561 : }
562 605442316 : const MSVehicle* last = (*i)->getLastFullVehicle();
563 605442316 : const double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
564 605442316 : if (lastGap > largestGap) {
565 : largestGap = lastGap;
566 67920558 : resByGap = (*i);
567 : }
568 : }
569 580259843 : 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 580261824 : return res;
575 : }
576 :
577 :
578 : MSLane*
579 3267458 : MSEdge::getProbableLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos, double maxSpeed) const {
580 3267458 : if (allowed == nullptr) {
581 0 : allowed = allowedLanes(vclass);
582 : }
583 : MSLane* res = nullptr;
584 0 : 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 11511999 : for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i, aIndex++) {
591 8244541 : const double occupancy = (*i)->getBruttoOccupancy();
592 8244541 : if (occupancy < leastOccupancy) {
593 7552371 : res = (*i);
594 : leastOccupancy = occupancy;
595 : }
596 8244541 : const MSVehicle* last = (*i)->getLastFullVehicle();
597 8244541 : double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
598 : // never insert to the left of a vehicle with a larger speedFactor
599 8244541 : if (lastGap > largestGap && maxSpeed >= largestSpeed) {
600 : largestGap = lastGap;
601 4450922 : resByGap = (*i);
602 : }
603 8244541 : if (last != nullptr) {
604 8243633 : largestSpeed = MAX2(largestSpeed, getVehicleMaxSpeed(last));
605 : }
606 : }
607 3267458 : 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 3267458 : return res;
613 : }
614 :
615 :
616 : double
617 583604633 : MSEdge::getDepartPosBound(const MSVehicle& veh, bool upper) const {
618 583604633 : const SUMOVehicleParameter& pars = veh.getParameter();
619 : double pos = getLength();
620 : // determine the position
621 583604633 : switch (pars.departPosProcedure) {
622 1794481 : case DepartPosDefinition::GIVEN:
623 1794481 : pos = pars.departPos;
624 1794481 : if (pos < 0.) {
625 1699610 : 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 315849 : case DepartPosDefinition::LAST:
639 315849 : if (upper) {
640 472974 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
641 321528 : MSVehicle* last = (*i)->getLastFullVehicle();
642 321528 : if (last != nullptr) {
643 278494 : pos = MIN2(pos, last->getPositionOnLane());
644 : }
645 : }
646 : } else {
647 : pos = 0;
648 : }
649 : break;
650 61061700 : case DepartPosDefinition::BASE:
651 : case DepartPosDefinition::DEFAULT:
652 61061700 : if (!upper) {
653 : pos = 0;
654 : }
655 : break;
656 20 : default:
657 20 : pos = MIN2(pos, veh.getVehicleType().getLength());
658 : break;
659 : }
660 583604633 : return pos;
661 : }
662 :
663 : MSLane*
664 42 : MSEdge::getDepartLaneMeso(SUMOVehicle& veh) const {
665 42 : if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN) {
666 2 : if ((int) myLanes->size() <= veh.getParameter().departLane || !(*myLanes)[veh.getParameter().departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
667 0 : return nullptr;
668 : }
669 2 : return (*myLanes)[veh.getParameter().departLane];
670 : }
671 40 : return (*myLanes)[0];
672 : }
673 :
674 : MSLane*
675 6936637007 : MSEdge::getDepartLane(MSVehicle& veh) const {
676 6936637007 : DepartLaneDefinition dld = veh.getParameter().departLaneProcedure;
677 6936637007 : int departLane = veh.getParameter().departLane;
678 6936637007 : if (dld == DepartLaneDefinition::DEFAULT) {
679 6058687371 : dld = myDefaultDepartLaneDefinition;
680 6058687371 : departLane = myDefaultDepartLane;
681 : }
682 6936637007 : switch (dld) {
683 100838483 : case DepartLaneDefinition::GIVEN:
684 100838483 : if ((int) myLanes->size() <= departLane || !(*myLanes)[departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
685 61 : return nullptr;
686 : }
687 100838422 : return (*myLanes)[departLane];
688 189747773 : case DepartLaneDefinition::RANDOM:
689 379495546 : return RandHelper::getRandomFrom(*allowedLanes(veh.getVehicleType().getVehicleClass()));
690 540445479 : case DepartLaneDefinition::FREE:
691 540445479 : return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
692 8219758 : case DepartLaneDefinition::ALLOWED_FREE:
693 8219758 : if (veh.getRoute().size() == 1) {
694 5960 : return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
695 : } else {
696 8213798 : return getFreeLane(allowedLanes(**(veh.getRoute().begin() + 1), veh.getVehicleType().getVehicleClass()), veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
697 : }
698 34574306 : case DepartLaneDefinition::BEST_FREE:
699 : case DepartLaneDefinition::BEST_PROB: {
700 34574306 : veh.updateBestLanes(false, myLanes->front());
701 34574306 : const std::vector<MSVehicle::LaneQ>& bl = veh.getBestLanes();
702 : double bestLength = -1;
703 109025159 : for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
704 74450853 : 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 34574306 : if (bestLength > BEST_LANE_LOOKAHEAD) {
713 365090 : departPos = getDepartPosBound(veh);
714 365090 : bestLength = MIN2(bestLength - departPos, BEST_LANE_LOOKAHEAD);
715 : }
716 34574306 : std::vector<MSLane*>* bestLanes = new std::vector<MSLane*>();
717 109025159 : for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
718 74450853 : if (((*i).length - departPos) >= bestLength) {
719 42195249 : if (isInternal()) {
720 32 : for (MSLane* lane : *myLanes) {
721 20 : if (lane->getNormalSuccessorLane() == (*i).lane) {
722 12 : bestLanes->push_back(lane);
723 : }
724 : }
725 : } else {
726 42195237 : bestLanes->push_back((*i).lane);
727 : }
728 : }
729 : }
730 : MSLane* ret = nullptr;
731 34574306 : if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::BEST_FREE) {
732 31306848 : ret = getFreeLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
733 : } else {
734 3267458 : ret = getProbableLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false), getVehicleMaxSpeed(&veh));
735 : }
736 34574306 : delete bestLanes;
737 34574306 : return ret;
738 : }
739 6062811208 : case DepartLaneDefinition::DEFAULT:
740 : case DepartLaneDefinition::FIRST_ALLOWED:
741 6062811208 : return getFirstAllowed(veh.getVehicleType().getVehicleClass());
742 : default:
743 : break;
744 : }
745 0 : if (!(*myLanes)[0]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
746 : return nullptr;
747 : }
748 0 : return (*myLanes)[0];
749 : }
750 :
751 :
752 : MSLane*
753 6063568424 : MSEdge::getFirstAllowed(SUMOVehicleClass vClass, bool defaultFirst, int routingMode) const {
754 11597412915 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
755 11597407915 : if ((*i)->allowsVehicleClass(vClass, routingMode)) {
756 6063563424 : return *i;
757 : }
758 : }
759 5000 : return defaultFirst && !myLanes->empty() ? myLanes->front() : nullptr;
760 : }
761 :
762 :
763 : bool
764 7584717177 : MSEdge::validateDepartSpeed(SUMOVehicle& v) const {
765 7584717177 : const SUMOVehicleParameter& pars = v.getParameter();
766 7584717177 : const MSVehicleType& type = v.getVehicleType();
767 7584717177 : if (pars.departSpeedProcedure == DepartSpeedDefinition::GIVEN) {
768 : // departSpeed could have been rounded down in the output
769 308013633 : double vMax = getVehicleMaxSpeed(&v) + SPEED_EPS;
770 308013633 : if (pars.departSpeed > vMax) {
771 : // check departLane (getVehicleMaxSpeed checks lane 0)
772 22599 : MSLane* departLane = MSGlobals::gMesoNet ? getDepartLaneMeso(v) : getDepartLane(dynamic_cast<MSVehicle&>(v));
773 22599 : if (departLane != nullptr) {
774 22599 : vMax = departLane->getVehicleMaxSpeed(&v);
775 22599 : if (pars.wasSet(VEHPARS_SPEEDFACTOR_SET)) {
776 : // speedFactor could have been rounded down in the output
777 7 : vMax *= (1 + SPEED_EPS);
778 : }
779 : // additive term must come after multiplication!
780 22599 : vMax += SPEED_EPS;
781 22599 : if (pars.departSpeed > vMax) {
782 22585 : if (type.getSpeedFactor().getParameter(1) > 0.) {
783 45132 : v.setChosenSpeedFactor(type.computeChosenSpeedDeviation(nullptr, pars.departSpeed / MIN2(getSpeedLimit(), type.getDesiredMaxSpeed() - SPEED_EPS)));
784 22566 : if (v.getChosenSpeedFactor() > type.getSpeedFactor().getParameter(0) + 2 * type.getSpeedFactor().getParameter(1)) {
785 : // only warn for significant deviation
786 37152 : 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 7585290419 : 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 7585271633 : if (isVaporizing() || isTazConnector()
804 15169984921 : || v.getRouteValidity(true, checkOnly) != MSBaseVehicle::ROUTE_VALID) {
805 595984 : return checkOnly;
806 : }
807 7584694253 : const SUMOVehicleParameter& pars = v.getParameter();
808 7584694253 : if (!validateDepartSpeed(v)) {
809 14 : if (MSGlobals::gCheckRoutes) {
810 21 : throw ProcessError(TLF("Departure speed for vehicle '%' is too high for the departure edge '%', time=%.",
811 21 : pars.id, getID(), time2string(time)));
812 : } else {
813 21 : WRITE_WARNINGF(TL("Departure speed for vehicle '%' is too high for the departure edge '%', time=%."),
814 : pars.id, getID(), time2string(time));
815 : }
816 : }
817 7584694246 : if (MSGlobals::gUseMesoSim) {
818 503954651 : if (!forceCheck && myLastFailedInsertionTime == time) {
819 : return false;
820 : }
821 : double pos = 0.0;
822 28066841 : switch (pars.departPosProcedure) {
823 589278 : case DepartPosDefinition::GIVEN:
824 589278 : if (pars.departPos >= 0.) {
825 : pos = pars.departPos;
826 : } else {
827 8375 : pos = pars.departPos + getLength();
828 : }
829 589278 : if (pos < 0 || pos > getLength()) {
830 6 : 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 50392 : break;
839 : default:
840 : break;
841 : }
842 : bool result = false;
843 28066841 : MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this, pos);
844 : MEVehicle* veh = static_cast<MEVehicle*>(&v);
845 : int qIdx;
846 28066841 : if (pars.departPosProcedure == DepartPosDefinition::FREE) {
847 486418 : while (segment != nullptr && !result) {
848 447912 : if (checkOnly) {
849 6 : result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
850 : } else {
851 447906 : result = segment->initialise(veh, time);
852 : }
853 : segment = segment->getNextSegment();
854 : }
855 : } else {
856 28028335 : if (checkOnly) {
857 26470348 : result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
858 : } else {
859 1557987 : result = segment->initialise(veh, time);
860 : }
861 : }
862 28066838 : return result;
863 : }
864 7080739595 : if (checkOnly) {
865 2338221468 : switch (v.getParameter().departLaneProcedure) {
866 2143665442 : case DepartLaneDefinition::GIVEN:
867 : case DepartLaneDefinition::DEFAULT:
868 : case DepartLaneDefinition::FIRST_ALLOWED: {
869 2143665442 : MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
870 2143665442 : if (insertionLane == nullptr) {
871 0 : WRITE_WARNINGF(TL("Could not insert vehicle '%' on any lane of edge '%', time=%."),
872 : v.getID(), getID(), time2string(time));
873 0 : return false;
874 : }
875 2143665442 : const double occupancy = insertionLane->getBruttoOccupancy();
876 2143665442 : return (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
877 27576119 : v.getParameter().departProcedure == DepartDefinition::SPLIT);
878 : }
879 194556026 : default:
880 212151727 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
881 203935770 : const double occupancy = (*i)->getBruttoOccupancy();
882 203935770 : if (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
883 17595701 : v.getParameter().departProcedure == DepartDefinition::SPLIT) {
884 : return true;
885 : }
886 : }
887 : }
888 : return false;
889 : }
890 4742518127 : MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
891 4742518127 : if (insertionLane == nullptr) {
892 : return false;
893 : }
894 :
895 4742513127 : if (!forceCheck) {
896 4742512950 : 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 14621358 : bool success = insertionLane->insertVehicle(static_cast<MSVehicle&>(v));
908 :
909 14621355 : if (!success) {
910 : // constraints may enforce explicit re-ordering so we need to try other vehicles after failure
911 21817498 : if (!insertionLane->hasParameter("insertionOrder" + v.getID())) {
912 10908602 : myFailedInsertionMemory.insert(insertionLane->getIndex());
913 : }
914 : }
915 : return success;
916 : }
917 :
918 :
919 : void
920 45861868 : MSEdge::changeLanes(SUMOTime t) const {
921 45861868 : if (myLaneChanger != nullptr) {
922 45861868 : myLaneChanger->laneChange(t);
923 : }
924 45861868 : }
925 :
926 :
927 : const MSEdge*
928 2420353 : MSEdge::getInternalFollowingEdge(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
929 : //@todo to be optimized
930 2936095 : for (const MSLane* const l : *myLanes) {
931 3528283 : for (const MSLink* const link : l->getLinkCont()) {
932 3012541 : if (&link->getLane()->getEdge() == followerAfterInternal) {
933 2122517 : if (link->getViaLane() != nullptr) {
934 1102405 : if (link->getViaLane()->allowsVehicleClass(vClass)) {
935 1099726 : return &link->getViaLane()->getEdge();
936 : } else {
937 2679 : continue;
938 : }
939 : } else {
940 : return nullptr; // network without internal links
941 : }
942 : }
943 : }
944 : }
945 : return nullptr;
946 : }
947 :
948 :
949 : double
950 1232870 : MSEdge::getInternalFollowingLengthTo(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
951 : assert(followerAfterInternal != 0);
952 : assert(!followerAfterInternal->isInternal());
953 : double dist = 0.;
954 1232870 : const MSEdge* edge = getInternalFollowingEdge(followerAfterInternal, vClass);
955 : // Take into account non-internal lengths until next non-internal edge
956 2271311 : while (edge != nullptr && edge->isInternal()) {
957 1038441 : dist += edge->getLength();
958 1038441 : edge = edge->getInternalFollowingEdge(followerAfterInternal, vClass);
959 : }
960 1232870 : return dist;
961 : }
962 :
963 :
964 : const MSEdge*
965 145448 : MSEdge::getNormalBefore() const {
966 : const MSEdge* result = this;
967 153902 : while (result->isInternal() && MSGlobals::gUsingInternalLanes) {
968 : assert(result->getPredecessors().size() == 1);
969 8454 : result = result->getPredecessors().front();
970 : }
971 145448 : return result;
972 : }
973 :
974 : const MSEdge*
975 6446394 : MSEdge::getNormalSuccessor() const {
976 : const MSEdge* result = this;
977 12238400 : while (result->isInternal()) {
978 : assert(result->getSuccessors().size() == 1);
979 5792006 : result = result->getSuccessors().front();
980 : }
981 6446394 : return result;
982 : }
983 :
984 : double
985 150746256 : MSEdge::getMeanSpeed() const {
986 : double v = 0;
987 : double totalNumVehs = 0;
988 150746256 : if (MSGlobals::gUseMesoSim) {
989 164144516 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
990 : const int numVehs = segment->getCarNumber();
991 139041270 : if (numVehs > 0) {
992 23989981 : v += numVehs * segment->getMeanSpeed();
993 23989981 : totalNumVehs += numVehs;
994 : }
995 : }
996 25103246 : if (totalNumVehs == 0) {
997 17069842 : return getLength() / myEmptyTraveltime; // may include tls-penalty
998 : }
999 : } else {
1000 289493253 : for (const MSLane* const lane : *myLanes) {
1001 : int numVehs = lane->getVehicleNumber();
1002 163850243 : if (numVehs == 0) {
1003 : // take speed limit but with lowest possible weight
1004 : numVehs = 1;
1005 : }
1006 163850243 : v += numVehs * lane->getMeanSpeed();
1007 163850243 : totalNumVehs += numVehs;
1008 : }
1009 125643010 : if (myBidiEdge != nullptr) {
1010 8307279 : for (const MSLane* const lane : myBidiEdge->getLanes()) {
1011 4304944 : if (lane->getVehicleNumber() > 0) {
1012 : // do not route across edges which are already occupied in reverse direction
1013 : return 0;
1014 : }
1015 : }
1016 : }
1017 125340545 : if (totalNumVehs == 0) {
1018 0 : return getSpeedLimit();
1019 : }
1020 : }
1021 133373949 : return v / totalNumVehs;
1022 : }
1023 :
1024 :
1025 : double
1026 8 : MSEdge::getMeanFriction() const {
1027 : double f = 0.;
1028 32 : for (const MSLane* const lane : *myLanes) {
1029 24 : f += lane->getFrictionCoefficient();
1030 : }
1031 8 : if (!myLanes->empty()) {
1032 8 : return f / (double)myLanes->size();
1033 : }
1034 : return 1.;
1035 : }
1036 :
1037 :
1038 : double
1039 1272 : MSEdge::getMeanSpeedBike() const {
1040 1272 : if (MSGlobals::gUseMesoSim) {
1041 : // no separate bicycle speeds in meso
1042 362 : return getMeanSpeed();
1043 : }
1044 : double v = 0;
1045 : double totalNumVehs = 0;
1046 3005 : for (const MSLane* const lane : *myLanes) {
1047 : const int numVehs = lane->getVehicleNumber();
1048 2095 : v += numVehs * lane->getMeanSpeedBike();
1049 2095 : totalNumVehs += numVehs;
1050 : }
1051 910 : if (totalNumVehs == 0) {
1052 455 : return getSpeedLimit();
1053 : }
1054 455 : return v / totalNumVehs;
1055 : }
1056 :
1057 :
1058 : double
1059 55220 : MSEdge::getCurrentTravelTime(double minSpeed) const {
1060 : assert(minSpeed > 0);
1061 55220 : if (!myAmDelayed) {
1062 36852 : return myEmptyTraveltime;
1063 : }
1064 36736 : return getLength() / MAX2(minSpeed, getMeanSpeed());
1065 : }
1066 :
1067 :
1068 : double
1069 0 : MSEdge::getRoutingSpeed() const {
1070 0 : return MSRoutingEngine::getAssumedSpeed(this, nullptr);
1071 : }
1072 :
1073 :
1074 : bool
1075 1770598 : MSEdge::dictionary(const std::string& id, MSEdge* ptr) {
1076 : const DictType::iterator it = myDict.lower_bound(id);
1077 1770598 : if (it == myDict.end() || it->first != id) {
1078 : // id not in myDict
1079 1770598 : myDict.emplace_hint(it, id, ptr);
1080 3541232 : while (ptr->getNumericalID() >= (int)myEdges.size()) {
1081 1770634 : myEdges.push_back(nullptr);
1082 : }
1083 1770598 : myEdges[ptr->getNumericalID()] = ptr;
1084 1770598 : return true;
1085 : }
1086 : return false;
1087 : }
1088 :
1089 :
1090 : MSEdge*
1091 8150868 : MSEdge::dictionary(const std::string& id) {
1092 : const DictType::iterator it = myDict.find(id);
1093 8150868 : if (it == myDict.end()) {
1094 : return nullptr;
1095 : }
1096 6378366 : return it->second;
1097 : }
1098 :
1099 :
1100 : MSEdge*
1101 2643355 : 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 2643355 : if (myEdges[startIdx] != nullptr && myEdges[startIdx]->getID() == id) {
1104 : return myEdges[startIdx];
1105 : }
1106 1599432 : if (startIdx + 1 < (int)myEdges.size() && myEdges[startIdx + 1] != nullptr && myEdges[startIdx + 1]->getID() == id) {
1107 : return myEdges[startIdx + 1];
1108 : }
1109 516901 : return dictionary(id);
1110 : }
1111 :
1112 :
1113 : const MSEdgeVector&
1114 885770 : MSEdge::getAllEdges() {
1115 885770 : return myEdges;
1116 : }
1117 :
1118 :
1119 : void
1120 41084 : MSEdge::clear() {
1121 1796767 : for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
1122 1755683 : delete (*i).second;
1123 : }
1124 : myDict.clear();
1125 : myEdges.clear();
1126 41084 : }
1127 :
1128 :
1129 : void
1130 309 : MSEdge::insertIDs(std::vector<std::string>& into) {
1131 16328 : for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
1132 16019 : into.push_back((*i).first);
1133 : }
1134 309 : }
1135 :
1136 :
1137 : void
1138 409531 : MSEdge::parseEdgesList(const std::string& desc, ConstMSEdgeVector& into,
1139 : const std::string& rid) {
1140 409531 : StringTokenizer st(desc);
1141 409531 : parseEdgesList(st.getVector(), into, rid);
1142 409531 : }
1143 :
1144 :
1145 : void
1146 409805 : MSEdge::parseEdgesList(const std::vector<std::string>& desc, ConstMSEdgeVector& into,
1147 : const std::string& rid) {
1148 1553660 : for (std::vector<std::string>::const_iterator i = desc.begin(); i != desc.end(); ++i) {
1149 1143906 : const MSEdge* edge = MSEdge::dictionary(*i);
1150 : // check whether the edge exists
1151 1143906 : if (edge == nullptr) {
1152 51 : throw ProcessError("The edge '" + *i + "' within the route " + rid + " is not known."
1153 153 : + "\n The route can not be build.");
1154 : }
1155 1143855 : into.push_back(edge);
1156 : }
1157 409754 : }
1158 :
1159 :
1160 : double
1161 2133690 : MSEdge::getDistanceTo(const MSEdge* other, const bool doBoundaryEstimate) const {
1162 : assert(this != other);
1163 2133690 : if (doBoundaryEstimate) {
1164 19288 : return myBoundary.distanceTo2D(other->myBoundary);
1165 : }
1166 2114402 : if (isTazConnector()) {
1167 562 : if (other->isTazConnector()) {
1168 446 : return myBoundary.distanceTo2D(other->myBoundary);
1169 : }
1170 116 : return myBoundary.distanceTo2D(other->getLanes()[0]->getShape()[0]);
1171 : }
1172 2113840 : if (other->isTazConnector()) {
1173 5279 : return other->myBoundary.distanceTo2D(getLanes()[0]->getShape()[-1]);
1174 : }
1175 2108561 : return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
1176 : }
1177 :
1178 :
1179 : const Position
1180 2429 : MSEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
1181 2429 : return MSLane::dictionary(stop.lane)->geometryPositionAtOffset((stop.endPos + stop.startPos) / 2.);
1182 : }
1183 :
1184 :
1185 : double
1186 88900808 : MSEdge::getSpeedLimit() const {
1187 : // @note lanes might have different maximum speeds in theory
1188 88900808 : return myLanes->empty() ? 1 : getLanes()[0]->getSpeedLimit();
1189 : }
1190 :
1191 :
1192 : double
1193 1874326 : MSEdge::getLengthGeometryFactor() const {
1194 1874326 : return myLanes->empty() ? 1 : getLanes()[0]->getLengthGeometryFactor();
1195 : }
1196 :
1197 : double
1198 520176508 : MSEdge::getVehicleMaxSpeed(const SUMOTrafficObject* const veh) const {
1199 : // @note lanes might have different maximum speeds in theory
1200 520176508 : return myLanes->empty() ? 1 : getLanes()[0]->getVehicleMaxSpeed(veh);
1201 : }
1202 :
1203 :
1204 : void
1205 205 : MSEdge::setMaxSpeed(const double val, const bool modified, const double jamThreshold) {
1206 : assert(val >= 0);
1207 205 : if (myLanes != nullptr) {
1208 564 : for (MSLane* const lane : *myLanes) {
1209 359 : lane->setMaxSpeed(val, modified, jamThreshold);
1210 : }
1211 : }
1212 205 : }
1213 :
1214 :
1215 : void
1216 1329900 : MSEdge::addTransportable(MSTransportable* t) const {
1217 1329900 : if (t->isPerson()) {
1218 : myPersons.insert(t);
1219 : } else {
1220 : myContainers.insert(t);
1221 : }
1222 1329900 : }
1223 :
1224 : void
1225 6731348 : MSEdge::removeTransportable(MSTransportable* t) const {
1226 6731348 : std::set<MSTransportable*, ComparatorNumericalIdLess>& tc = t->isPerson() ? myPersons : myContainers;
1227 : auto it = tc.find(t);
1228 6731348 : if (it != tc.end()) {
1229 : tc.erase(it);
1230 : }
1231 6731348 : }
1232 :
1233 : std::vector<MSTransportable*>
1234 7389809 : MSEdge::getSortedPersons(SUMOTime timestep, bool includeRiding) const {
1235 7389809 : std::vector<MSTransportable*> result(myPersons.begin(), myPersons.end());
1236 7389809 : if (includeRiding) {
1237 2354951 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
1238 1662531 : const MSLane::VehCont& vehs = (*i)->getVehiclesSecure();
1239 2886910 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
1240 1224379 : const std::vector<MSTransportable*>& persons = (*j)->getPersons();
1241 1224379 : result.insert(result.end(), persons.begin(), persons.end());
1242 : }
1243 1662531 : (*i)->releaseVehicles();
1244 : }
1245 : }
1246 7389809 : sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
1247 7389809 : return result;
1248 0 : }
1249 :
1250 :
1251 : std::vector<MSTransportable*>
1252 64739656 : MSEdge::getSortedContainers(SUMOTime timestep, bool /* includeRiding */) const {
1253 64739656 : std::vector<MSTransportable*> result(myContainers.begin(), myContainers.end());
1254 64739656 : sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
1255 64739656 : return result;
1256 0 : }
1257 :
1258 :
1259 : int
1260 5267089 : MSEdge::transportable_by_position_sorter::operator()(const MSTransportable* const c1, const MSTransportable* const c2) const {
1261 5267089 : const double pos1 = c1->getCurrentStage()->getEdgePos(myTime);
1262 5267089 : const double pos2 = c2->getCurrentStage()->getEdgePos(myTime);
1263 5267089 : if (pos1 != pos2) {
1264 5109301 : return pos1 < pos2;
1265 : }
1266 157788 : return c1->getID() < c2->getID();
1267 : }
1268 :
1269 :
1270 : void
1271 124009 : MSEdge::addSuccessor(MSEdge* edge, const MSEdge* via) {
1272 124009 : mySuccessors.push_back(edge);
1273 124009 : myViaSuccessors.push_back(std::make_pair(edge, via));
1274 124009 : if (isTazConnector() && edge->getFromJunction() != nullptr) {
1275 62001 : myBoundary.add(edge->getFromJunction()->getPosition());
1276 : }
1277 :
1278 124009 : edge->myPredecessors.push_back(this);
1279 124009 : if (edge->isTazConnector() && getToJunction() != nullptr) {
1280 62008 : edge->myBoundary.add(getToJunction()->getPosition());
1281 : }
1282 124009 : }
1283 :
1284 :
1285 : const MSEdgeVector&
1286 9043198 : MSEdge::getSuccessors(SUMOVehicleClass vClass) const {
1287 9043198 : if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
1288 9026214 : return mySuccessors;
1289 : }
1290 : #ifdef HAVE_FOX
1291 16984 : ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
1292 : #endif
1293 : std::map<SUMOVehicleClass, MSEdgeVector>::iterator i = myClassesSuccessorMap.find(vClass);
1294 16984 : if (i == myClassesSuccessorMap.end()) {
1295 : // instantiate vector
1296 1933 : myClassesSuccessorMap[vClass];
1297 : i = myClassesSuccessorMap.find(vClass);
1298 : // this vClass is requested for the first time. rebuild all successors
1299 9220 : for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
1300 7287 : if ((*it)->isTazConnector()) {
1301 239 : i->second.push_back(*it);
1302 : } else {
1303 7048 : const std::vector<MSLane*>* allowed = allowedLanes(**it, vClass);
1304 7048 : if (allowed != nullptr && allowed->size() > 0) {
1305 5831 : i->second.push_back(*it);
1306 : }
1307 : }
1308 : }
1309 : }
1310 : // can use cached value
1311 16984 : return i->second;
1312 : }
1313 :
1314 :
1315 : const MSConstEdgePairVector&
1316 162936655 : MSEdge::getViaSuccessors(SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
1317 162936655 : if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
1318 156556966 : return myViaSuccessors;
1319 : }
1320 : #ifdef HAVE_FOX
1321 6379689 : ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
1322 : #endif
1323 6379689 : auto& viaMap = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigClassesViaSuccessorMap : myClassesViaSuccessorMap;
1324 : auto i = viaMap.find(vClass);
1325 6379689 : if (i != viaMap.end()) {
1326 : // can use cached value
1327 6328171 : return i->second;
1328 : }
1329 : // instantiate vector
1330 51518 : MSConstEdgePairVector& result = viaMap[vClass];
1331 : // this vClass is requested for the first time. rebuild all successors
1332 208552 : for (const auto& viaPair : myViaSuccessors) {
1333 157034 : if (viaPair.first->isTazConnector()) {
1334 6322 : result.push_back(viaPair);
1335 : } else {
1336 150712 : const std::vector<MSLane*>* allowed = allowedLanes(*viaPair.first, vClass, ignoreTransientPermissions);
1337 150712 : if (allowed != nullptr && allowed->size() > 0) {
1338 120297 : result.push_back(viaPair);
1339 : }
1340 : }
1341 : }
1342 : return result;
1343 : }
1344 :
1345 :
1346 : void
1347 1709163 : MSEdge::setJunctions(MSJunction* from, MSJunction* to) {
1348 1709163 : myFromJunction = from;
1349 1709163 : myToJunction = to;
1350 1709163 : if (!isTazConnector()) {
1351 1709163 : myBoundary.add(from->getPosition());
1352 1709163 : myBoundary.add(to->getPosition());
1353 : }
1354 1709163 : }
1355 :
1356 :
1357 : bool
1358 2835550 : MSEdge::canChangeToOpposite() const {
1359 2835550 : return (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr &&
1360 : // do not change on curved internal lanes
1361 : (!isInternal()
1362 5453 : || (MSGlobals::gUsingInternalLanes
1363 5449 : && myLanes->back()->getIncomingLanes()[0].viaLink->getDirection() == LinkDirection::STRAIGHT)));
1364 : }
1365 :
1366 :
1367 : const MSEdge*
1368 22099783 : MSEdge::getOppositeEdge() const {
1369 22099783 : if (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr) {
1370 2991788 : return &(myLanes->back()->getOpposite()->getEdge());
1371 : } else {
1372 19107995 : return nullptr;
1373 : }
1374 : }
1375 :
1376 :
1377 : bool
1378 178 : MSEdge::hasMinorLink() const {
1379 370 : for (const MSLane* const l : *myLanes) {
1380 290 : for (const MSLink* const link : l->getLinkCont()) {
1381 98 : if (!link->havePriority()) {
1382 : return true;
1383 : }
1384 : }
1385 : }
1386 : return false;
1387 : }
1388 :
1389 : bool
1390 209206 : MSEdge::hasChangeProhibitions(SUMOVehicleClass svc, int index) const {
1391 209206 : if (myLanes->size() == 1) {
1392 : return false;
1393 : }
1394 284788 : for (const MSLane* const l : *myLanes) {
1395 193397 : if (l->getIndex() <= index && !l->allowsChangingRight(svc) && l->getIndex() > 0) {
1396 : return true;
1397 193353 : } 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 893814 : MSEdge::checkAndRegisterBiDirEdge(const std::string& bidiID) {
1406 893814 : if (bidiID != "") {
1407 28992 : myBidiEdge = dictionary(bidiID);
1408 28992 : if (myBidiEdge == nullptr) {
1409 0 : WRITE_ERRORF(TL("Bidi-edge '%' does not exist"), bidiID);
1410 : }
1411 28992 : setBidiLanes();
1412 511895 : return;
1413 : }
1414 864822 : if (getFunction() != SumoXMLEdgeFunc::NORMAL) {
1415 : return;
1416 : }
1417 : // legacy networks (no bidi attribute)
1418 381919 : ConstMSEdgeVector candidates = myToJunction->getOutgoing();
1419 3031172 : for (ConstMSEdgeVector::const_iterator it = candidates.begin(); it != candidates.end(); it++) {
1420 2649253 : if ((*it)->getToJunction() == myFromJunction) { //reverse edge
1421 306304 : if (myBidiEdge != nullptr && isSuperposable(*it)) {
1422 0 : WRITE_WARNINGF(TL("Ambiguous superposable edges between junction '%' and '%'."), myToJunction->getID(), myFromJunction->getID());
1423 0 : break;
1424 : }
1425 306304 : if (isSuperposable(*it)) {
1426 26 : myBidiEdge = *it;
1427 26 : setBidiLanes();
1428 : }
1429 : }
1430 : }
1431 381919 : }
1432 :
1433 :
1434 : void
1435 29018 : MSEdge::setBidiLanes() {
1436 : assert(myBidiEdge != nullptr);
1437 29018 : if (getNumLanes() == 1 && myBidiEdge->getNumLanes() == 1) {
1438 : // the other way round is set when this method runs for the bidiEdge
1439 28480 : getLanes()[0]->setBidiLane(myBidiEdge->getLanes()[0]);
1440 : } else {
1441 : // find lanes with matching reversed shapes
1442 : int numBidiLanes = 0;
1443 1680 : for (MSLane* l1 : *myLanes) {
1444 3630 : for (MSLane* l2 : *myBidiEdge->myLanes) {
1445 2488 : if (l1->getShape().reverse().almostSame(l2->getShape(), POSITION_EPS * 2)) {
1446 592 : l1->setBidiLane(l2);
1447 592 : numBidiLanes++;
1448 : }
1449 : }
1450 : }
1451 : // warn only once for each pair
1452 538 : if (numBidiLanes == 0 && getNumericalID() < myBidiEdge->getNumericalID()) {
1453 15 : WRITE_WARNINGF(TL("Edge '%' and bidi edge '%' have no matching bidi lanes"), getID(), myBidiEdge->getID());
1454 : }
1455 : }
1456 29018 : }
1457 :
1458 :
1459 : bool
1460 306304 : MSEdge::isSuperposable(const MSEdge* other) {
1461 306304 : 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 301722 : if ((*it1)->getShape().reverse() != (*it2)->getShape()) {
1468 : return false;
1469 : }
1470 : it1++;
1471 : it2++;
1472 26 : } while (it1 != myLanes->end());
1473 :
1474 : return true;
1475 : }
1476 :
1477 :
1478 : void
1479 71242 : MSEdge::addWaiting(SUMOVehicle* vehicle) const {
1480 : #ifdef HAVE_FOX
1481 71242 : ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1482 : #endif
1483 71242 : myWaiting.push_back(vehicle);
1484 71242 : }
1485 :
1486 :
1487 : void
1488 62954 : MSEdge::removeWaiting(const SUMOVehicle* vehicle) const {
1489 : #ifdef HAVE_FOX
1490 62954 : ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1491 : #endif
1492 62954 : std::vector<SUMOVehicle*>::iterator it = std::find(myWaiting.begin(), myWaiting.end(), vehicle);
1493 62954 : if (it != myWaiting.end()) {
1494 62628 : myWaiting.erase(it);
1495 : }
1496 62954 : }
1497 :
1498 :
1499 : SUMOVehicle*
1500 77169 : MSEdge::getWaitingVehicle(MSTransportable* transportable, const double position) const {
1501 : #ifdef HAVE_FOX
1502 77169 : ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1503 : #endif
1504 77473 : for (SUMOVehicle* const vehicle : myWaiting) {
1505 5189 : if (transportable->isWaitingFor(vehicle)) {
1506 7360 : if (vehicle->isStoppedInRange(position, MSGlobals::gStopTolerance) ||
1507 2265 : (!vehicle->hasDeparted() &&
1508 2059 : (vehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED ||
1509 83 : vehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED))) {
1510 : return vehicle;
1511 : }
1512 210 : if (!vehicle->isLineStop(position) && vehicle->allowsBoarding(transportable)) {
1513 228 : 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 144685 : MSEdge::getVehicles() const {
1524 : std::vector<const SUMOVehicle*> result;
1525 144685 : if (MSGlobals::gUseMesoSim) {
1526 164 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1527 88 : std::vector<const MEVehicle*> segmentVehs = segment->getVehicles();
1528 88 : result.insert(result.end(), segmentVehs.begin(), segmentVehs.end());
1529 88 : }
1530 : } else {
1531 387771 : for (MSLane* lane : getLanes()) {
1532 831951 : for (auto veh : lane->getVehiclesSecure()) {
1533 588827 : result.push_back(veh);
1534 : }
1535 243124 : lane->releaseVehicles();
1536 : }
1537 : }
1538 144685 : return result;
1539 0 : }
1540 :
1541 : int
1542 622083 : MSEdge::getNumDrivingLanes() const {
1543 : int result = 0;
1544 622083 : SVCPermissions filter = SVCAll;
1545 622083 : if ((myCombinedPermissions & ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
1546 : filter = ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR);
1547 2048 : } else if ((myCombinedPermissions & (SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
1548 : // filter out green verge
1549 : filter = (SVC_PEDESTRIAN | SVC_WHEELCHAIR);
1550 : }
1551 1401485 : for (const MSLane* const l : *myLanes) {
1552 779402 : if ((l->getPermissions() & filter) != 0) {
1553 690014 : result++;
1554 : }
1555 : }
1556 622083 : return result;
1557 : }
1558 :
1559 : int
1560 661 : MSEdge::getVehicleNumber() const {
1561 661 : return (int)getVehicles().size();
1562 : }
1563 :
1564 :
1565 : bool
1566 0 : MSEdge::isEmpty() const {
1567 : /// more efficient than retrieving vehicle number
1568 0 : if (MSGlobals::gUseMesoSim) {
1569 0 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1570 0 : if (segment->getCarNumber() > 0) {
1571 : return false;
1572 : }
1573 : }
1574 : } else {
1575 0 : for (MSLane* lane : getLanes()) {
1576 0 : if (lane->getVehicleNumber() > 0) {
1577 : return false;
1578 : }
1579 : }
1580 : }
1581 : return true;
1582 : }
1583 :
1584 :
1585 : double
1586 14 : MSEdge::getWaitingSeconds() const {
1587 : double wtime = 0;
1588 14 : if (MSGlobals::gUseMesoSim) {
1589 4 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1590 3 : wtime += segment->getWaitingSeconds();
1591 : }
1592 : } else {
1593 42 : for (MSLane* lane : getLanes()) {
1594 29 : wtime += lane->getWaitingSeconds();
1595 : }
1596 : }
1597 14 : return wtime;
1598 : }
1599 :
1600 :
1601 : double
1602 22 : MSEdge::getOccupancy() const {
1603 22 : if (myLanes->size() == 0) {
1604 : return 0;
1605 : }
1606 22 : if (MSGlobals::gUseMesoSim) {
1607 : /// @note MESegment only tracks brutto occupancy so we compute this from sratch
1608 : double sum = 0;
1609 4 : for (const SUMOVehicle* veh : getVehicles()) {
1610 2 : sum += dynamic_cast<const MEVehicle*>(veh)->getVehicleType().getLength();
1611 2 : }
1612 2 : return sum / (myLength * (double)myLanes->size());
1613 : } else {
1614 : double sum = 0;
1615 56 : for (auto lane : getLanes()) {
1616 36 : sum += lane->getNettoOccupancy();
1617 : }
1618 20 : return sum / (double)myLanes->size();
1619 : }
1620 : }
1621 :
1622 :
1623 : double
1624 0 : MSEdge::getFlow() const {
1625 0 : if (myLanes->size() == 0) {
1626 : return 0;
1627 : }
1628 : double flow = 0;
1629 0 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1630 0 : flow += (double) segment->getCarNumber() * segment->getMeanSpeed();
1631 : }
1632 0 : return 3600 * flow / (*myLanes)[0]->getLength();
1633 : }
1634 :
1635 :
1636 : double
1637 0 : MSEdge::getBruttoOccupancy() const {
1638 0 : if (myLanes->size() == 0) {
1639 : return 0;
1640 : }
1641 : double occ = 0;
1642 0 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1643 0 : occ += segment->getBruttoOccupancy();
1644 : }
1645 0 : return occ / (*myLanes)[0]->getLength() / (double)(myLanes->size());
1646 : }
1647 :
1648 : double
1649 4240 : MSEdge::getTravelTimeAggregated(const MSEdge* const edge, const SUMOVehicle* const veh, double /*time*/) {
1650 4240 : return edge->getLength() / MIN2(MSRoutingEngine::getAssumedSpeed(edge, veh), veh->getMaxSpeed());
1651 : }
1652 :
1653 :
1654 : void
1655 2098 : MSEdge::inferEdgeType() {
1656 : // @note must be called after closeBuilding() to ensure successors and
1657 : // predecessors are set
1658 2098 : if (isInternal() && myEdgeType == "") {
1659 1274 : const std::string typeBefore = getNormalBefore()->getEdgeType();
1660 1274 : if (typeBefore != "") {
1661 622 : const std::string typeAfter = getNormalSuccessor()->getEdgeType();
1662 622 : if (typeBefore == typeAfter) {
1663 : myEdgeType = typeBefore;
1664 244 : } else if (typeAfter != "") {
1665 60 : MSNet* net = MSNet::getInstance();
1666 60 : auto resBefore = net->getRestrictions(typeBefore);
1667 60 : auto resAfter = net->getRestrictions(typeAfter);
1668 60 : if (resBefore != nullptr && resAfter != nullptr) {
1669 : // create new restrictions for this type-combination
1670 80 : myEdgeType = typeBefore + "|" + typeAfter;
1671 40 : if (net->getRestrictions(myEdgeType) == nullptr) {
1672 40 : for (const auto& item : *resBefore) {
1673 20 : const SUMOVehicleClass svc = item.first;
1674 20 : const double speed = item.second;
1675 : const auto it = (*resAfter).find(svc);
1676 20 : if (it != (*resAfter).end()) {
1677 20 : const double speed2 = it->second;
1678 20 : const double newSpeed = (MSNet::getInstance()->hasJunctionHigherSpeeds()
1679 20 : ? MAX2(speed, speed2) : (speed + speed2) / 2);
1680 20 : net->addRestriction(myEdgeType, svc, newSpeed);
1681 : }
1682 : }
1683 : }
1684 : }
1685 : }
1686 : }
1687 : }
1688 2098 : }
1689 :
1690 :
1691 : double
1692 2178 : MSEdge::getDistanceAt(double pos) const {
1693 : // negative values of myDistances indicate descending kilometrage
1694 2178 : return fabs(myDistance + pos);
1695 : }
1696 :
1697 :
1698 : bool
1699 1081 : MSEdge::hasTransientPermissions() const {
1700 1081 : return myHaveTransientPermissions;
1701 : }
1702 :
1703 :
1704 : std::pair<double, SUMOTime>
1705 591608192 : MSEdge::getLastBlocked(int index) const {
1706 591608192 : if (myLaneChanger != nullptr) {
1707 591608192 : return myLaneChanger->getLastBlocked(index);
1708 : }
1709 0 : return std::make_pair(-1, -1);
1710 : }
1711 :
1712 :
1713 : double
1714 1631 : MSEdge::getPreference(const SUMOVTypeParameter& pars) const {
1715 3262 : return MSNet::getInstance()->getPreference(getRoutingType(), pars);
1716 : }
1717 :
1718 : void
1719 8157 : MSEdge::clearState() {
1720 : myPersons.clear();
1721 : myContainers.clear();
1722 : myWaiting.clear();
1723 8157 : }
1724 :
1725 : /****************************************************************************/
|