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 2001596 : 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 2001596 : double distance) :
75 2001596 : Named(id), myNumericalID(numericalID), myLanes(nullptr),
76 2001596 : myLaneChanger(nullptr), myFunction(function), myVaporizationRequests(0),
77 2001596 : myLastFailedInsertionTime(-1),
78 2001596 : myFromJunction(nullptr), myToJunction(nullptr),
79 2001596 : myHaveTransientPermissions(false),
80 2001596 : myOtherTazConnector(nullptr),
81 2001596 : myStreetName(streetName),
82 2001596 : myEdgeType(edgeType),
83 2001596 : myRoutingType(routingType),
84 2001596 : myPriority(priority),
85 2001596 : myDistance(distance),
86 2001596 : myWidth(0.),
87 2001596 : myLength(0.),
88 2001596 : myEmptyTraveltime(0.),
89 2001596 : myTimePenalty(0.),
90 2001596 : myAmDelayed(false),
91 2001596 : myAmRoundabout(false),
92 2001596 : myAmFringe(true),
93 4003192 : myBidiEdge(nullptr)
94 2001596 : { }
95 :
96 :
97 3446805 : MSEdge::~MSEdge() {
98 1986627 : delete myLaneChanger;
99 1986627 : delete myReversedRoutingEdge;
100 1986627 : delete myRailwayRoutingEdge;
101 13379940 : }
102 :
103 :
104 : void
105 1864491 : MSEdge::initialize(const std::vector<MSLane*>* lanes) {
106 : assert(lanes != 0);
107 1864491 : myLanes = std::shared_ptr<const std::vector<MSLane*> >(lanes);
108 1864491 : if (myFunction == SumoXMLEdgeFunc::CONNECTOR) {
109 70008 : myCombinedPermissions = SVCAll;
110 : }
111 4022839 : for (MSLane* const lane : *lanes) {
112 2158348 : lane->setRightSideOnEdge(myWidth, (int)mySublaneSides.size());
113 2158348 : MSLeaderInfo ahead(lane->getWidth());
114 5036687 : for (int j = 0; j < ahead.numSublanes(); ++j) {
115 2878339 : mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
116 : }
117 2158348 : myWidth += lane->getWidth();
118 2158348 : }
119 1864491 : }
120 :
121 :
122 1914870 : void MSEdge::recalcCache() {
123 1914870 : if (myLanes->empty()) {
124 : return;
125 : }
126 1914870 : myLength = myLanes->front()->getLength();
127 3829740 : myEmptyTraveltime = myLength / MAX2(getSpeedLimit(), NUMERICAL_EPS);
128 1914870 : if (isNormal() && (MSGlobals::gUseMesoSim || MSGlobals::gTLSPenalty > 0)) {
129 : SUMOTime minorPenalty = 0;
130 196392 : bool haveTLSPenalty = MSGlobals::gTLSPenalty > 0;
131 196392 : if (MSGlobals::gUseMesoSim) {
132 196277 : const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(getEdgeType());
133 196277 : minorPenalty = edgeType.minorPenalty;
134 196277 : haveTLSPenalty = edgeType.tlsPenalty > 0;
135 : }
136 196392 : 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 1718478 : } else if (isCrossing() && MSGlobals::gTLSPenalty > 0) {
158 : // penalties are recorded for the entering link
159 112 : for (const auto& ili : myLanes->front()->getIncomingLanes()) {
160 56 : double penalty = STEPS2TIME(ili.viaLink->getMesoTLSPenalty());
161 56 : if (!ili.viaLink->haveOffPriority()) {
162 0 : penalty = MAX2(penalty, MSGlobals::gMinorPenalty);
163 : }
164 56 : if (penalty > 0) {
165 20 : myEmptyTraveltime += penalty;
166 20 : myTimePenalty = penalty;
167 : }
168 : }
169 1718422 : } else if (isInternal() && MSGlobals::gUsingInternalLanes) {
170 1012940 : const MSLink* link = myLanes->front()->getIncomingLanes()[0].viaLink;
171 1012940 : if (!link->isTLSControlled() && !link->havePriority()) {
172 497838 : if (link->isTurnaround()) {
173 189818 : myEmptyTraveltime += MSGlobals::gTurnaroundPenalty;
174 189818 : myTimePenalty = MSGlobals::gTurnaroundPenalty;
175 : } else {
176 308020 : myEmptyTraveltime += MSGlobals::gMinorPenalty;
177 308020 : 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 1791953 : MSEdge::closeBuilding() {
209 3947348 : for (MSLane* const lane : *myLanes) {
210 5118540 : for (MSLink* const link : lane->getLinkCont()) {
211 2963145 : link->initParallelLinks();
212 : MSLane* const toL = link->getLane();
213 : MSLane* const viaL = link->getViaLane();
214 2963145 : if (toL != nullptr) {
215 : MSEdge& to = toL->getEdge();
216 2963145 : if (std::find(mySuccessors.begin(), mySuccessors.end(), &to) == mySuccessors.end()) {
217 2761483 : mySuccessors.push_back(&to);
218 5522966 : myViaSuccessors.push_back(std::make_pair(&to, (viaL == nullptr ? nullptr : &viaL->getEdge())));
219 : }
220 2963145 : if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
221 2761483 : to.myPredecessors.push_back(this);
222 : }
223 2963145 : if (link->getDirection() != LinkDirection::TURN) {
224 2310227 : myAmFringe = false;
225 : }
226 : }
227 2963145 : if (viaL != nullptr) {
228 : MSEdge& to = viaL->getEdge();
229 1037255 : if (std::find(to.myPredecessors.begin(), to.myPredecessors.end(), this) == to.myPredecessors.end()) {
230 955959 : to.myPredecessors.push_back(this);
231 : }
232 : }
233 : }
234 2155395 : lane->checkBufferType();
235 : }
236 1791953 : std::sort(mySuccessors.begin(), mySuccessors.end(), by_id_sorter());
237 1791953 : rebuildAllowedLanes(true);
238 1791953 : recalcCache();
239 :
240 : // extend lookup table for sublane model after all edges are read
241 1791953 : if (myLanes->back()->getOpposite() != nullptr) {
242 8356 : MSLane* opposite = myLanes->back()->getOpposite();
243 8356 : MSLeaderInfo ahead(opposite->getWidth());
244 22778 : for (int j = 0; j < ahead.numSublanes(); ++j) {
245 14422 : mySublaneSides.push_back(myWidth + j * MSGlobals::gLateralResolution);
246 : }
247 8356 : }
248 1791953 : }
249 :
250 :
251 : void
252 1791945 : MSEdge::postLoadInitLaneChanger() {
253 1791945 : if (myLaneChanger != nullptr) {
254 446146 : myLaneChanger->postloadInitLC();
255 : }
256 1791945 : }
257 :
258 : void
259 1791953 : MSEdge::buildLaneChanger() {
260 1791953 : if (!myLanes->empty()) {
261 1791953 : const bool allowChanging = allowsLaneChanging();
262 1791953 : if (MSGlobals::gLateralResolution > 0) {
263 : // may always initiate sublane-change
264 185222 : if (!isInternal() || MSGlobals::gUsingInternalLanes) {
265 185031 : myLaneChanger = new MSLaneChangerSublane(myLanes.get(), allowChanging);
266 : }
267 : } else {
268 1606731 : if (MSGlobals::gLaneChangeDuration > 0) {
269 4981 : myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
270 1601750 : } else if (myLanes->size() > 1 || canChangeToOpposite()) {
271 256142 : myLaneChanger = new MSLaneChanger(myLanes.get(), allowChanging);
272 : }
273 : }
274 : }
275 1791953 : }
276 :
277 :
278 : bool
279 1791953 : MSEdge::allowsLaneChanging() const {
280 1791953 : 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 1509583 : for (const MSLane* const lane : *myLanes) {
284 1033802 : const MSLink* const link = lane->getLogicalPredecessorLane()->getLinkTo(lane);
285 : assert(link != nullptr);
286 : const LinkState state = link->getState();
287 469489 : if ((state == LINKSTATE_MINOR && lane->getBidiLane() == nullptr)
288 564739 : || state == LINKSTATE_EQUAL
289 564739 : || state == LINKSTATE_STOP
290 : || state == LINKSTATE_ALLWAY_STOP
291 1033802 : || state == LINKSTATE_DEADEND) {
292 : return false;
293 : }
294 : }
295 : }
296 : return true;
297 : }
298 :
299 :
300 : void
301 18988261 : MSEdge::addToAllowed(const SVCPermissions permissions, std::shared_ptr<const std::vector<MSLane*> > allowedLanes, AllowedLanesCont& laneCont) const {
302 18988261 : if (!allowedLanes->empty()) {
303 : // recheck whether we had this list to save memory
304 18709977 : for (auto& allowed : laneCont) {
305 17664137 : if (*allowed.second == *allowedLanes) {
306 13306068 : allowed.first |= permissions;
307 : return;
308 : }
309 : }
310 1045840 : laneCont.push_back(std::make_pair(permissions, allowedLanes));
311 : }
312 : }
313 :
314 :
315 : SVCPermissions
316 3011303 : MSEdge::getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored) {
317 3011303 : SVCPermissions ignored = myMesoIgnoredVClasses & ~ignoreIgnored;
318 3011303 : return (p | ignored) == ignored ? 0 : p;
319 : }
320 :
321 :
322 : void
323 1793578 : MSEdge::rebuildAllowedLanes(const bool onInit, bool updateVehicles) {
324 : // rebuild myMinimumPermissions and myCombinedPermissions
325 1793578 : myMinimumPermissions = SVCAll;
326 1793578 : myCombinedPermissions = 0;
327 : bool lanesChangedPermission = false;
328 3951110 : 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 2157532 : SVCPermissions allow = getMesoPermissions(lane->getPermissions(), SVC_PEDESTRIAN);
333 2157532 : myMinimumPermissions &= allow;
334 2157532 : myCombinedPermissions |= allow;
335 2157532 : lanesChangedPermission |= lane->hadPermissionChanges();
336 : }
337 1793578 : if (!onInit && !myHaveTransientPermissions && lanesChangedPermission) {
338 1149 : myHaveTransientPermissions = true;
339 : // backup original structures when first needed
340 1149 : myOrigAllowed = myAllowed;
341 : myOrigAllowedTargets = myAllowedTargets;
342 : myOrigClassesViaSuccessorMap = myClassesViaSuccessorMap;
343 : }
344 : // rebuild myAllowed
345 : myAllowed.clear();
346 1793578 : if (myCombinedPermissions != myMinimumPermissions) {
347 170299 : myAllowed.push_back(std::make_pair(SVC_IGNORING, myLanes));
348 5790166 : for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
349 5619867 : if ((myCombinedPermissions & vclass) == vclass) {
350 : std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
351 11934734 : for (MSLane* const lane : *myLanes) {
352 8079797 : if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
353 4077328 : allowedLanes->push_back(lane);
354 : }
355 : }
356 7709874 : addToAllowed(vclass, allowedLanes, myAllowed);
357 : }
358 : }
359 : }
360 1793578 : if (onInit) {
361 1791953 : myOriginalMinimumPermissions = myMinimumPermissions;
362 1791953 : myOriginalCombinedPermissions = myCombinedPermissions;
363 : } else {
364 1625 : rebuildAllowedTargets(updateVehicles);
365 4125 : for (MSEdge* pred : myPredecessors) {
366 2500 : if (myHaveTransientPermissions && !pred->myHaveTransientPermissions) {
367 1593 : pred->myOrigAllowed = pred->myAllowed;
368 : pred->myOrigAllowedTargets = pred->myAllowedTargets;
369 : pred->myOrigClassesViaSuccessorMap = pred->myClassesViaSuccessorMap;
370 1593 : pred->myHaveTransientPermissions = true;
371 : }
372 2500 : pred->rebuildAllowedTargets(updateVehicles);
373 : }
374 1625 : if (MSGlobals::gUseMesoSim) {
375 2897 : for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*this); s != nullptr; s = s->getNextSegment()) {
376 2467 : s->updatePermissions();
377 : }
378 : }
379 : }
380 1793578 : }
381 :
382 :
383 : void
384 1797216 : MSEdge::rebuildAllowedTargets(const bool updateVehicles) {
385 : myAllowedTargets.clear();
386 4566635 : 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 6313691 : for (MSLane* const lane : *myLanes) {
391 : SVCPermissions combinedTargetPermissions = 0;
392 10065559 : for (const MSLink* const link : lane->getLinkCont()) {
393 6521287 : if (&link->getLane()->getEdge() == target) {
394 2972132 : allLanes->push_back(lane);
395 2972132 : combinedTargetPermissions |= link->getLane()->getPermissions();
396 2972132 : if (link->getViaLane() != nullptr &&
397 1039888 : ((lane->getPermissions() & link->getLane()->getPermissions()) != link->getViaLane()->getPermissions())) {
398 : // custom connection permissions
399 : universalMap = false;
400 : }
401 : }
402 : }
403 3544272 : if (combinedTargetPermissions == 0 || (lane->getPermissions() & combinedTargetPermissions) != lane->getPermissions()) {
404 : universalMap = false;
405 : }
406 : }
407 2769419 : if (universalMap) {
408 2251939 : if (myAllowed.empty()) {
409 : // we have no lane specific permissions
410 4435470 : myAllowedTargets[target].push_back(std::make_pair(myMinimumPermissions, myLanes));
411 : } else {
412 134573 : for (const auto& i : myAllowed) {
413 301107 : addToAllowed(i.first, i.second, myAllowedTargets[target]);
414 : }
415 : }
416 : } else {
417 1034960 : addToAllowed(SVC_IGNORING, allLanes, myAllowedTargets[target]);
418 : // compute the vclass specific mapping
419 17594320 : for (SVCPermissions vclass = SVC_PRIVATE; vclass <= SUMOVehicleClass_MAX; vclass *= 2) {
420 17076840 : if ((myCombinedPermissions & vclass) == vclass) {
421 : std::shared_ptr<std::vector<MSLane*> > allowedLanes = std::make_shared<std::vector<MSLane*> >();
422 45121419 : for (MSLane* const lane : *myLanes) {
423 30605944 : if (lane->allowsVehicleClass((SUMOVehicleClass)vclass)) {
424 58670659 : for (const MSLink* const link : lane->getLinkCont()) {
425 38383821 : if (link->getLane()->allowsVehicleClass((SUMOVehicleClass)vclass) && &link->getLane()->getEdge() == target && (link->getViaLane() == nullptr || link->getViaLane()->allowsVehicleClass((SUMOVehicleClass)vclass))) {
426 10240257 : allowedLanes->push_back(lane);
427 : }
428 : }
429 : }
430 : }
431 43546425 : addToAllowed(vclass, allowedLanes, myAllowedTargets[target]);
432 : }
433 : }
434 : }
435 : }
436 1797216 : if (updateVehicles) {
437 3241 : for (const MSLane* const lane : *myLanes) {
438 1872 : const MSLane::VehCont& vehs = lane->getVehiclesSecure();
439 4181 : for (MSVehicle* veh : vehs) {
440 2309 : veh->updateBestLanes(true);
441 : }
442 1872 : lane->releaseVehicles();
443 : }
444 : }
445 : myClassesSuccessorMap.clear();
446 1797216 : }
447 :
448 :
449 : // ------------ Access to the edge's lanes
450 : MSLane*
451 774 : MSEdge::leftLane(const MSLane* const lane) const {
452 774 : return parallelLane(lane, 1);
453 : }
454 :
455 :
456 : MSLane*
457 400 : MSEdge::rightLane(const MSLane* const lane) const {
458 400 : return parallelLane(lane, -1);
459 : }
460 :
461 :
462 : MSLane*
463 84934303 : MSEdge::parallelLane(const MSLane* const lane, int offset, bool includeOpposite) const {
464 84934303 : const int resultIndex = lane->getIndex() + offset;
465 84934303 : if (resultIndex >= getNumLanes() && includeOpposite) {
466 20654050 : const MSEdge* opposite = getOppositeEdge();
467 20654050 : if (opposite != nullptr && resultIndex < getNumLanes() + opposite->getNumLanes()) {
468 1386369 : return opposite->getLanes()[opposite->getNumLanes() + getNumLanes() - resultIndex - 1];
469 : }
470 : return nullptr;
471 64280253 : } else if (resultIndex >= (int)myLanes->size() || resultIndex < 0) {
472 : return nullptr;
473 : } else {
474 39130840 : return (*myLanes)[resultIndex];
475 : }
476 : }
477 :
478 :
479 : const std::vector<MSLane*>*
480 77269215 : MSEdge::allowedLanes(const MSEdge& destination, SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
481 77269215 : const auto& targets = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigAllowedTargets : myAllowedTargets;
482 : AllowedLanesByTarget::const_iterator i = targets.find(&destination);
483 77269215 : if (i != targets.end()) {
484 77247419 : for (const auto& allowed : i->second) {
485 77121876 : 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 274628880 : MSEdge::allowedLanes(SUMOVehicleClass vclass) const {
496 274628880 : if ((myMinimumPermissions & vclass) == vclass) {
497 43678734 : return myLanes.get();
498 : } else {
499 230950146 : if ((myCombinedPermissions & vclass) == vclass) {
500 461896801 : for (const auto& allowed : myAllowed) {
501 461896801 : if ((allowed.first & vclass) == vclass) {
502 : return allowed.second.get();
503 : }
504 : }
505 : }
506 2007 : return nullptr;
507 : }
508 : }
509 :
510 :
511 : const std::vector<MSLane*>*
512 2177044461 : MSEdge::allowedLanes(SUMOVehicleClass vclass, bool ignoreTransientPermissions) const {
513 2177044461 : const SVCPermissions& minP = ignoreTransientPermissions ? myOriginalMinimumPermissions : myMinimumPermissions;
514 2177044461 : if ((minP & vclass) == vclass) {
515 639867267 : return myLanes.get();
516 : } else {
517 1537177194 : const SVCPermissions comP = ignoreTransientPermissions ? myOriginalCombinedPermissions : myCombinedPermissions;
518 1537177194 : if ((comP & vclass) == vclass) {
519 1537177122 : const AllowedLanesCont& allowedCont = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigAllowed : myAllowed;
520 3080052621 : for (const auto& allowed : allowedCont) {
521 3080052621 : if ((allowed.first & vclass) == vclass) {
522 : return allowed.second.get();
523 : }
524 : }
525 : }
526 72 : 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 279 : MSEdge::decVaporization(SUMOTime) {
541 279 : --myVaporizationRequests;
542 279 : return 0;
543 : }
544 :
545 :
546 : MSLane*
547 217727575 : MSEdge::getFreeLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos) const {
548 217727575 : if (allowed == nullptr) {
549 184076002 : allowed = allowedLanes(vclass);
550 : }
551 : MSLane* res = nullptr;
552 184076002 : if (allowed != nullptr) {
553 : double largestGap = 0;
554 : MSLane* resByGap = nullptr;
555 : double leastOccupancy = std::numeric_limits<double>::max();
556 460028240 : for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i) {
557 242302664 : const double occupancy = (*i)->getBruttoOccupancy();
558 242302664 : if (occupancy < leastOccupancy) {
559 225718126 : res = (*i);
560 : leastOccupancy = occupancy;
561 : }
562 242302664 : const MSVehicle* last = (*i)->getLastFullVehicle();
563 242302664 : const double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
564 242302664 : if (lastGap > largestGap) {
565 : largestGap = lastGap;
566 58040405 : resByGap = (*i);
567 : }
568 : }
569 217725576 : 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 217727575 : return res;
575 : }
576 :
577 :
578 : MSLane*
579 839407690 : MSEdge::getProbableLane(const std::vector<MSLane*>* allowed, const SUMOVehicleClass vclass, double departPos, double maxSpeed) const {
580 839407690 : 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 1684875903 : for (std::vector<MSLane*>::const_iterator i = allowed->begin(); i != allowed->end(); ++i, aIndex++) {
591 845468213 : const double occupancy = (*i)->getBruttoOccupancy();
592 845468213 : if (occupancy < leastOccupancy) {
593 844743178 : res = (*i);
594 : leastOccupancy = occupancy;
595 : }
596 845468213 : const MSVehicle* last = (*i)->getLastFullVehicle();
597 845468213 : double lastGap = (last != nullptr ? last->getPositionOnLane() : myLength) - departPos;
598 : // never insert to the left of a vehicle with a larger speedFactor
599 845468213 : if (lastGap > largestGap && maxSpeed >= largestSpeed) {
600 : largestGap = lastGap;
601 800263327 : resByGap = (*i);
602 : }
603 845468213 : if (last != nullptr) {
604 843223108 : largestSpeed = MAX2(largestSpeed, getVehicleMaxSpeed(last));
605 : }
606 : }
607 839407690 : 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 839407690 : return res;
613 : }
614 :
615 :
616 : double
617 1058246604 : MSEdge::getDepartPosBound(const MSVehicle& veh, bool upper) const {
618 1058246604 : const SUMOVehicleParameter& pars = veh.getParameter();
619 : double pos = getLength();
620 : // determine the position
621 1058246604 : switch (pars.departPosProcedure) {
622 10036637 : case DepartPosDefinition::GIVEN:
623 10036637 : pos = pars.departPos;
624 10036637 : if (pos < 0.) {
625 2860457 : 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 11726366 : case DepartPosDefinition::LAST:
639 11726366 : if (upper) {
640 468012 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
641 317802 : MSVehicle* last = (*i)->getLastFullVehicle();
642 317802 : if (last != nullptr) {
643 276006 : pos = MIN2(pos, last->getPositionOnLane());
644 : }
645 : }
646 : } else {
647 : pos = 0;
648 : }
649 : break;
650 831175700 : case DepartPosDefinition::BASE:
651 : case DepartPosDefinition::DEFAULT:
652 831175700 : if (!upper) {
653 : pos = 0;
654 : }
655 : break;
656 28 : default:
657 28 : pos = MIN2(pos, veh.getVehicleType().getLength());
658 : break;
659 : }
660 1058246604 : return pos;
661 : }
662 :
663 :
664 : MSLane*
665 46 : MSEdge::getDepartLaneMeso(SUMOVehicle& veh) const {
666 46 : if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN) {
667 3 : if ((int) myLanes->size() <= veh.getParameter().departLane || !(*myLanes)[veh.getParameter().departLane]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
668 0 : return nullptr;
669 : }
670 3 : return (*myLanes)[veh.getParameter().departLane];
671 : }
672 43 : return (*myLanes)[0];
673 : }
674 :
675 :
676 : MSLane*
677 1761631050 : MSEdge::getDepartLane(MSVehicle& veh) const {
678 1761631050 : DepartLaneDefinition dld = veh.getParameter().departLaneProcedure;
679 1761631050 : int departLane = veh.getParameter().departLane;
680 1761631050 : if (dld == DepartLaneDefinition::DEFAULT) {
681 1324506773 : dld = myDefaultDepartLaneDefinition;
682 1324506773 : departLane = myDefaultDepartLane;
683 : }
684 1761631050 : switch (dld) {
685 121736733 : case DepartLaneDefinition::GIVEN:
686 121736733 : if ((int) myLanes->size() <= departLane || !(*myLanes)[departLane]->allowsVehicleClass(veh.getVClass())) {
687 66 : return nullptr;
688 : }
689 121736667 : return (*myLanes)[departLane];
690 90524451 : case DepartLaneDefinition::RANDOM:
691 181048902 : return RandHelper::getRandomFrom(*allowedLanes(veh.getVehicleType().getVehicleClass()));
692 183973381 : case DepartLaneDefinition::FREE:
693 183973381 : return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
694 4971244 : case DepartLaneDefinition::ALLOWED_FREE:
695 4971244 : if (veh.getRoute().size() == 1) {
696 5960 : return getFreeLane(nullptr, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
697 : } else {
698 4965284 : return getFreeLane(allowedLanes(**(veh.getRoute().begin() + 1), veh.getVehicleType().getVehicleClass()), veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
699 : }
700 867890083 : case DepartLaneDefinition::BEST_FREE:
701 : case DepartLaneDefinition::BEST_PROB: {
702 867890083 : veh.updateBestLanes(false, myLanes->front());
703 867890083 : const std::vector<MSVehicle::LaneQ>& bl = veh.getBestLanes();
704 : double bestLength = -1;
705 2562444456 : for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
706 1694554373 : if ((*i).length > bestLength) {
707 : bestLength = (*i).length;
708 : }
709 : }
710 : // beyond a certain length, all lanes are suitable
711 : // however, we still need to check departPos to avoid unsuitable insertion
712 : // (this is only possible in some cases)
713 : double departPos = 0;
714 867890083 : if (bestLength > BEST_LANE_LOOKAHEAD) {
715 1411896 : departPos = getDepartPosBound(veh);
716 1411896 : bestLength = MIN2(bestLength - departPos, BEST_LANE_LOOKAHEAD);
717 : }
718 867890083 : std::vector<MSLane*>* bestLanes = new std::vector<MSLane*>();
719 2562444456 : for (std::vector<MSVehicle::LaneQ>::const_iterator i = bl.begin(); i != bl.end(); ++i) {
720 1694554373 : if (((*i).length - departPos) >= bestLength) {
721 876700063 : if (isInternal()) {
722 32 : for (MSLane* lane : *myLanes) {
723 20 : if (lane->getNormalSuccessorLane() == (*i).lane && lane->allowsVehicleClass(veh.getVClass()) ) {
724 12 : bestLanes->push_back(lane);
725 : }
726 : }
727 876700051 : } else if ((*i).lane->allowsVehicleClass(veh.getVClass())) {
728 876268101 : bestLanes->push_back((*i).lane);
729 : }
730 : }
731 : }
732 : MSLane* ret = nullptr;
733 867890083 : if (veh.getParameter().departLaneProcedure == DepartLaneDefinition::BEST_FREE) {
734 28482393 : ret = getFreeLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false));
735 : } else {
736 839407690 : ret = getProbableLane(bestLanes, veh.getVehicleType().getVehicleClass(), getDepartPosBound(veh, false), getVehicleMaxSpeed(&veh));
737 : }
738 867890083 : delete bestLanes;
739 867890083 : return ret;
740 : }
741 492535158 : case DepartLaneDefinition::DEFAULT:
742 : case DepartLaneDefinition::FIRST_ALLOWED:
743 492535158 : return getFirstAllowed(veh.getVehicleType().getVehicleClass());
744 : default:
745 : break;
746 : }
747 0 : if (!(*myLanes)[0]->allowsVehicleClass(veh.getVehicleType().getVehicleClass())) {
748 : return nullptr;
749 : }
750 0 : return (*myLanes)[0];
751 : }
752 :
753 :
754 : MSLane*
755 493508995 : MSEdge::getFirstAllowed(SUMOVehicleClass vClass, bool defaultFirst, int routingMode) const {
756 500741001 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
757 499872101 : if ((*i)->allowsVehicleClass(vClass, routingMode)) {
758 492640095 : return *i;
759 : }
760 : }
761 868900 : return defaultFirst && !myLanes->empty() ? myLanes->front() : nullptr;
762 : }
763 :
764 :
765 : bool
766 2837057275 : MSEdge::validateDepartSpeed(SUMOVehicle& v) const {
767 2837057275 : const SUMOVehicleParameter& pars = v.getParameter();
768 2837057275 : const MSVehicleType& type = v.getVehicleType();
769 2837057275 : if (pars.departSpeedProcedure == DepartSpeedDefinition::GIVEN) {
770 : // departSpeed could have been rounded down in the output
771 150720415 : double vMax = getVehicleMaxSpeed(&v) + SPEED_EPS;
772 150720415 : if (pars.departSpeed > vMax) {
773 : // check departLane (getVehicleMaxSpeed checks lane 0)
774 19610 : MSLane* departLane = MSGlobals::gMesoNet ? getDepartLaneMeso(v) : getDepartLane(dynamic_cast<MSVehicle&>(v));
775 19610 : if (departLane != nullptr) {
776 19610 : vMax = departLane->getVehicleMaxSpeed(&v);
777 19610 : if (pars.wasSet(VEHPARS_SPEEDFACTOR_SET)) {
778 : // speedFactor could have been rounded down in the output
779 7 : vMax *= (1 + SPEED_EPS);
780 : }
781 : // additive term must come after multiplication!
782 19610 : vMax += SPEED_EPS;
783 19610 : if (pars.departSpeed > vMax) {
784 19596 : if (type.getSpeedFactor().getParameter(1) > 0.) {
785 39154 : v.setChosenSpeedFactor(type.computeChosenSpeedDeviation(pars.speedFactor, nullptr, pars.departSpeed / MIN2(getSpeedLimit(), type.getDesiredMaxSpeed() - SPEED_EPS)));
786 19577 : if (v.getChosenSpeedFactor() > type.getSpeedFactor().getParameter(0) + 2 * type.getSpeedFactor().getParameter(1)) {
787 : // only warn for significant deviation
788 33536 : WRITE_WARNINGF(TL("Choosing new speed factor % for vehicle '%' to match departure speed % (max %)."),
789 : toString(v.getChosenSpeedFactor()), pars.id, pars.departSpeed, vMax);
790 : }
791 : } else {
792 : return false;
793 : }
794 : }
795 : }
796 : }
797 : }
798 : return true;
799 : }
800 :
801 :
802 : bool
803 2837518659 : MSEdge::insertVehicle(SUMOVehicle& v, SUMOTime time, const bool checkOnly, const bool forceCheck) const {
804 : // when vaporizing, no vehicles are inserted, but checking needs to be successful to trigger removal
805 2837499873 : if (isVaporizing() || isTazConnector()
806 5674553233 : || v.getRouteValidity(true, checkOnly) != MSBaseVehicle::ROUTE_VALID) {
807 484152 : return checkOnly;
808 : }
809 2837034329 : const SUMOVehicleParameter& pars = v.getParameter();
810 2837034329 : if (!validateDepartSpeed(v)) {
811 14 : if (MSGlobals::gCheckRoutes) {
812 21 : throw ProcessError(TLF("Departure speed for vehicle '%' is too high for the departure edge '%', time=%.",
813 21 : pars.id, getID(), time2string(time)));
814 : } else {
815 21 : WRITE_WARNINGF(TL("Departure speed for vehicle '%' is too high for the departure edge '%', time=%."),
816 : pars.id, getID(), time2string(time));
817 : }
818 : }
819 2837034322 : if (MSGlobals::gUseMesoSim) {
820 600470037 : if (!forceCheck && myLastFailedInsertionTime == time) {
821 : return false;
822 : }
823 : double pos = 0.0;
824 103399040 : switch (pars.departPosProcedure) {
825 596116 : case DepartPosDefinition::GIVEN:
826 596116 : if (pars.departPos >= 0.) {
827 : pos = pars.departPos;
828 : } else {
829 8397 : pos = pars.departPos + getLength();
830 : }
831 596116 : if (pos < 0 || pos > getLength()) {
832 6 : WRITE_WARNINGF(TL("Invalid departPos % given for vehicle '%', time=%. Inserting at lane end instead."),
833 : pos, v.getID(), time2string(time));
834 : pos = getLength();
835 : }
836 : break;
837 : case DepartPosDefinition::RANDOM:
838 : case DepartPosDefinition::RANDOM_FREE:
839 : pos = RandHelper::rand(getLength());
840 44186 : break;
841 : default:
842 : break;
843 : }
844 : bool result = false;
845 103399040 : MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this, pos);
846 : MEVehicle* veh = static_cast<MEVehicle*>(&v);
847 : int qIdx;
848 103399040 : if (pars.departPosProcedure == DepartPosDefinition::FREE) {
849 486502 : while (segment != nullptr && !result) {
850 447954 : if (checkOnly) {
851 6 : result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
852 : } else {
853 447948 : result = segment->initialise(veh, time);
854 : }
855 : segment = segment->getNextSegment();
856 : }
857 : } else {
858 103360492 : if (checkOnly) {
859 93006973 : result = segment->hasSpaceFor(veh, time, qIdx, true) == time;
860 : } else {
861 10353519 : result = segment->initialise(veh, time);
862 : }
863 : }
864 103399038 : return result;
865 : }
866 2236564285 : if (checkOnly) {
867 616019653 : DepartLaneDefinition dld = v.getParameter().departLaneProcedure;
868 616019653 : if (dld == DepartLaneDefinition::DEFAULT) {
869 561258175 : dld = myDefaultDepartLaneDefinition;
870 : }
871 616019653 : switch (dld) {
872 80186848 : case DepartLaneDefinition::GIVEN:
873 : case DepartLaneDefinition::DEFAULT:
874 : case DepartLaneDefinition::FIRST_ALLOWED: {
875 80186848 : MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
876 80186848 : if (insertionLane == nullptr) {
877 1295850 : WRITE_WARNINGF(TL("Could not insert vehicle '%' on any lane of edge '%', time=%."),
878 : v.getID(), getID(), time2string(time));
879 431950 : return false;
880 : }
881 79754898 : const double occupancy = insertionLane->getBruttoOccupancy();
882 79754898 : return (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
883 6031808 : v.getParameter().departProcedure == DepartDefinition::SPLIT);
884 : }
885 535832805 : default:
886 553324860 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
887 545161575 : const double occupancy = (*i)->getBruttoOccupancy();
888 545161575 : if (occupancy == 0 || occupancy * myLength + v.getVehicleType().getLengthWithGap() <= myLength ||
889 17492055 : v.getParameter().departProcedure == DepartDefinition::SPLIT) {
890 : return true;
891 : }
892 : }
893 : }
894 : return false;
895 : }
896 1620544632 : MSLane* insertionLane = getDepartLane(static_cast<MSVehicle&>(v));
897 1620544632 : if (insertionLane == nullptr) {
898 : return false;
899 : }
900 :
901 1619675732 : if (!forceCheck) {
902 1619675555 : if (myLastFailedInsertionTime == time) {
903 : if (myFailedInsertionMemory.count(insertionLane->getIndex())) {
904 : // A vehicle was already rejected for the proposed insertionLane in this timestep
905 : return false;
906 : }
907 : } else {
908 : // last rejection occurred in a previous timestep, clear cache
909 : myFailedInsertionMemory.clear();
910 : }
911 : }
912 :
913 13574432 : bool success = insertionLane->insertVehicle(static_cast<MSVehicle&>(v));
914 :
915 13574431 : if (!success) {
916 : // constraints may enforce explicit re-ordering so we need to try other vehicles after failure
917 20188910 : if (!insertionLane->hasParameter("insertionOrder" + v.getID())) {
918 10094308 : myFailedInsertionMemory.insert(insertionLane->getIndex());
919 : }
920 : }
921 : return success;
922 : }
923 :
924 :
925 : void
926 42738562 : MSEdge::changeLanes(SUMOTime t) const {
927 42738562 : if (myLaneChanger != nullptr) {
928 42738562 : myLaneChanger->laneChange(t);
929 : }
930 42738562 : }
931 :
932 :
933 : const MSEdge*
934 5805451 : MSEdge::getInternalFollowingEdge(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
935 : //@todo to be optimized
936 6625039 : for (const MSLane* const l : *myLanes) {
937 9699790 : for (const MSLink* const link : l->getLinkCont()) {
938 8880202 : if (&link->getLane()->getEdge() == followerAfterInternal) {
939 5541078 : if (link->getViaLane() != nullptr) {
940 4510547 : if (link->getViaLane()->allowsVehicleClass(vClass)) {
941 4470216 : return &link->getViaLane()->getEdge();
942 : } else {
943 40331 : continue;
944 : }
945 : } else {
946 : return nullptr; // network without internal links
947 : }
948 : }
949 : }
950 : }
951 : return nullptr;
952 : }
953 :
954 :
955 : double
956 1243717 : MSEdge::getInternalFollowingLengthTo(const MSEdge* followerAfterInternal, SUMOVehicleClass vClass) const {
957 : assert(followerAfterInternal != 0);
958 : assert(!followerAfterInternal->isInternal());
959 : double dist = 0.;
960 1243717 : const MSEdge* edge = getInternalFollowingEdge(followerAfterInternal, vClass);
961 : // Take into account non-internal lengths until next non-internal edge
962 2296146 : while (edge != nullptr && edge->isInternal()) {
963 1052429 : dist += edge->getLength();
964 1052429 : edge = edge->getInternalFollowingEdge(followerAfterInternal, vClass);
965 : }
966 1243717 : return dist;
967 : }
968 :
969 :
970 : const MSEdge*
971 150497 : MSEdge::getNormalBefore() const {
972 : const MSEdge* result = this;
973 159624 : while (result->isInternal() && MSGlobals::gUsingInternalLanes) {
974 : assert(result->getPredecessors().size() == 1);
975 9127 : result = result->getPredecessors().front();
976 : }
977 150497 : return result;
978 : }
979 :
980 : const MSEdge*
981 6177536 : MSEdge::getNormalSuccessor() const {
982 : const MSEdge* result = this;
983 11577594 : while (result->isInternal()) {
984 : assert(result->getSuccessors().size() == 1);
985 5400058 : result = result->getSuccessors().front();
986 : }
987 6177536 : return result;
988 : }
989 :
990 : double
991 192789453 : MSEdge::getMeanSpeed() const {
992 : double v = 0;
993 : double totalNumVehs = 0;
994 192789453 : if (MSGlobals::gUseMesoSim) {
995 255624914 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
996 : const int numVehs = segment->getCarNumber();
997 187138331 : if (numVehs > 0) {
998 25317240 : v += numVehs * segment->getMeanSpeed();
999 25317240 : totalNumVehs += numVehs;
1000 : }
1001 : }
1002 68486583 : if (totalNumVehs == 0) {
1003 59277262 : return getLength() / myEmptyTraveltime; // may include tls-penalty
1004 : }
1005 : } else {
1006 285916115 : for (const MSLane* const lane : *myLanes) {
1007 : int numVehs = lane->getVehicleNumber();
1008 161613245 : if (numVehs == 0) {
1009 : // take speed limit but with lowest possible weight
1010 : numVehs = 1;
1011 : }
1012 161613245 : v += numVehs * lane->getMeanSpeed();
1013 161613245 : totalNumVehs += numVehs;
1014 : }
1015 124302870 : if (myBidiEdge != nullptr) {
1016 8791088 : for (const MSLane* const lane : myBidiEdge->getLanes()) {
1017 4554078 : if (lane->getVehicleNumber() > 0) {
1018 : // do not route across edges which are already occupied in reverse direction
1019 : return 0;
1020 : }
1021 : }
1022 : }
1023 123986798 : if (totalNumVehs == 0) {
1024 0 : return getSpeedLimit();
1025 : }
1026 : }
1027 133196119 : return v / totalNumVehs;
1028 : }
1029 :
1030 :
1031 : double
1032 8 : MSEdge::getMeanFriction() const {
1033 : double f = 0.;
1034 32 : for (const MSLane* const lane : *myLanes) {
1035 24 : f += lane->getFrictionCoefficient();
1036 : }
1037 8 : if (!myLanes->empty()) {
1038 8 : return f / (double)myLanes->size();
1039 : }
1040 : return 1.;
1041 : }
1042 :
1043 :
1044 : double
1045 1272 : MSEdge::getMeanSpeedBike() const {
1046 1272 : if (MSGlobals::gUseMesoSim) {
1047 : // no separate bicycle speeds in meso
1048 362 : return getMeanSpeed();
1049 : }
1050 : double v = 0;
1051 : double totalNumVehs = 0;
1052 3005 : for (const MSLane* const lane : *myLanes) {
1053 : const int numVehs = lane->getVehicleNumber();
1054 2095 : v += numVehs * lane->getMeanSpeedBike();
1055 2095 : totalNumVehs += numVehs;
1056 : }
1057 910 : if (totalNumVehs == 0) {
1058 455 : return getSpeedLimit();
1059 : }
1060 455 : return v / totalNumVehs;
1061 : }
1062 :
1063 :
1064 : double
1065 64380 : MSEdge::getCurrentTravelTime(double minSpeed) const {
1066 : assert(minSpeed > 0);
1067 64380 : if (!myAmDelayed) {
1068 44802 : return myEmptyTraveltime;
1069 : }
1070 39156 : return getLength() / MAX2(minSpeed, getMeanSpeed());
1071 : }
1072 :
1073 :
1074 : double
1075 0 : MSEdge::getRoutingSpeed() const {
1076 0 : return MSRoutingEngine::getAssumedSpeed(this, nullptr);
1077 : }
1078 :
1079 :
1080 : bool
1081 1864489 : MSEdge::dictionary(const std::string& id, MSEdge* ptr) {
1082 : const DictType::iterator it = myDict.lower_bound(id);
1083 1864489 : if (it == myDict.end() || it->first != id) {
1084 : // id not in myDict
1085 1864489 : myDict.emplace_hint(it, id, ptr);
1086 3729018 : while (ptr->getNumericalID() >= (int)myEdges.size()) {
1087 1864529 : myEdges.push_back(nullptr);
1088 : }
1089 1864489 : myEdges[ptr->getNumericalID()] = ptr;
1090 1864489 : return true;
1091 : }
1092 : return false;
1093 : }
1094 :
1095 :
1096 : MSEdge*
1097 8785021 : MSEdge::dictionary(const std::string& id) {
1098 : const DictType::iterator it = myDict.find(id);
1099 8785021 : if (it == myDict.end()) {
1100 : return nullptr;
1101 : }
1102 6917864 : return it->second;
1103 : }
1104 :
1105 :
1106 : MSEdge*
1107 2969651 : MSEdge::dictionaryHint(const std::string& id, const int startIdx) {
1108 : // this method is mainly useful when parsing connections from the net.xml which are sorted by "from" id
1109 2969651 : if (myEdges[startIdx] != nullptr && myEdges[startIdx]->getID() == id) {
1110 : return myEdges[startIdx];
1111 : }
1112 1875878 : if (startIdx + 1 < (int)myEdges.size() && myEdges[startIdx + 1] != nullptr && myEdges[startIdx + 1]->getID() == id) {
1113 : return myEdges[startIdx + 1];
1114 : }
1115 618467 : return dictionary(id);
1116 : }
1117 :
1118 :
1119 : const MSEdgeVector&
1120 911828 : MSEdge::getAllEdges() {
1121 911828 : return myEdges;
1122 : }
1123 :
1124 :
1125 : void
1126 42718 : MSEdge::clear() {
1127 1892240 : for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
1128 1849522 : delete (*i).second;
1129 : }
1130 : myDict.clear();
1131 : myEdges.clear();
1132 42718 : }
1133 :
1134 :
1135 : void
1136 285 : MSEdge::insertIDs(std::vector<std::string>& into) {
1137 16016 : for (DictType::iterator i = myDict.begin(); i != myDict.end(); ++i) {
1138 15731 : into.push_back((*i).first);
1139 : }
1140 285 : }
1141 :
1142 :
1143 : void
1144 416267 : MSEdge::parseEdgesList(const std::string& desc, ConstMSEdgeVector& into,
1145 : const std::string& rid) {
1146 416267 : StringTokenizer st(desc);
1147 416267 : parseEdgesList(st.getVector(), into, rid);
1148 416267 : }
1149 :
1150 :
1151 : void
1152 416548 : MSEdge::parseEdgesList(const std::vector<std::string>& desc, ConstMSEdgeVector& into,
1153 : const std::string& rid) {
1154 1573378 : for (std::vector<std::string>::const_iterator i = desc.begin(); i != desc.end(); ++i) {
1155 1156879 : const MSEdge* edge = MSEdge::dictionary(*i);
1156 : // check whether the edge exists
1157 1156879 : if (edge == nullptr) {
1158 49 : throw ProcessError("The edge '" + *i + "' within the route " + rid + " is not known."
1159 147 : + "\n The route can not be build.");
1160 : }
1161 1156830 : into.push_back(edge);
1162 : }
1163 416499 : }
1164 :
1165 :
1166 : double
1167 1834662 : MSEdge::getDistanceTo(const MSEdge* other, const bool doBoundaryEstimate) const {
1168 : assert(this != other);
1169 1834662 : if (doBoundaryEstimate) {
1170 19288 : return myBoundary.distanceTo2D(other->myBoundary);
1171 : }
1172 1815374 : if (isTazConnector()) {
1173 564 : if (other->isTazConnector()) {
1174 448 : return myBoundary.distanceTo2D(other->myBoundary);
1175 : }
1176 116 : return myBoundary.distanceTo2D(other->getLanes()[0]->getShape()[0]);
1177 : }
1178 1814810 : if (other->isTazConnector()) {
1179 5405 : return other->myBoundary.distanceTo2D(getLanes()[0]->getShape()[-1]);
1180 : }
1181 1809405 : return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
1182 : }
1183 :
1184 :
1185 : const Position
1186 2453 : MSEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
1187 2453 : return MSLane::dictionary(stop.lane)->geometryPositionAtOffset((stop.endPos + stop.startPos) / 2.);
1188 : }
1189 :
1190 :
1191 : double
1192 94086841 : MSEdge::getSpeedLimit() const {
1193 : // @note lanes might have different maximum speeds in theory
1194 94086841 : return myLanes->empty() ? 1 : getLanes()[0]->getSpeedLimit();
1195 : }
1196 :
1197 :
1198 : double
1199 848 : MSEdge::getSpeedLimit(SUMOVehicleClass svc) const {
1200 : // @note lanes might have different maximum speeds in theory
1201 848 : return myLanes->empty() ? 1 : getLanes()[0]->getSpeedLimit(svc);
1202 : }
1203 :
1204 :
1205 : double
1206 1944183 : MSEdge::getLengthGeometryFactor() const {
1207 1944183 : return myLanes->empty() ? 1 : getLanes()[0]->getLengthGeometryFactor();
1208 : }
1209 :
1210 : double
1211 2071421637 : MSEdge::getVehicleMaxSpeed(const SUMOTrafficObject* const veh) const {
1212 : // @note lanes might have different maximum speeds in theory
1213 2071421637 : return myLanes->empty() ? 1 : getLanes()[0]->getVehicleMaxSpeed(veh);
1214 : }
1215 :
1216 :
1217 : void
1218 205 : MSEdge::setMaxSpeed(const double val, const bool modified, const double jamThreshold) {
1219 : assert(val >= 0);
1220 205 : if (myLanes != nullptr) {
1221 564 : for (MSLane* const lane : *myLanes) {
1222 359 : lane->setMaxSpeed(val, modified, jamThreshold);
1223 : }
1224 : }
1225 205 : }
1226 :
1227 :
1228 : void
1229 3222447 : MSEdge::addTransportable(MSTransportable* t) const {
1230 3222447 : if (t->isPerson()) {
1231 : myPersons.insert(t);
1232 : } else {
1233 : myContainers.insert(t);
1234 : }
1235 3222447 : }
1236 :
1237 : void
1238 8008713 : MSEdge::removeTransportable(MSTransportable* t) const {
1239 8008713 : std::set<MSTransportable*, ComparatorNumericalIdLess>& tc = t->isPerson() ? myPersons : myContainers;
1240 : auto it = tc.find(t);
1241 8008713 : if (it != tc.end()) {
1242 : tc.erase(it);
1243 : }
1244 8008713 : }
1245 :
1246 : std::vector<MSTransportable*>
1247 110506699 : MSEdge::getSortedPersons(SUMOTime timestep, bool includeRiding) const {
1248 110506699 : std::vector<MSTransportable*> result(myPersons.begin(), myPersons.end());
1249 110506699 : if (includeRiding) {
1250 2896155 : for (std::vector<MSLane*>::const_iterator i = myLanes->begin(); i != myLanes->end(); ++i) {
1251 2042878 : const MSLane::VehCont& vehs = (*i)->getVehiclesSecure();
1252 3266518 : for (MSLane::VehCont::const_iterator j = vehs.begin(); j != vehs.end(); ++j) {
1253 1223640 : const std::vector<MSTransportable*>& persons = (*j)->getPersons();
1254 1223640 : result.insert(result.end(), persons.begin(), persons.end());
1255 : }
1256 2042878 : (*i)->releaseVehicles();
1257 : }
1258 : }
1259 110506699 : sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
1260 110506699 : return result;
1261 0 : }
1262 :
1263 :
1264 : std::vector<MSTransportable*>
1265 52272966 : MSEdge::getSortedContainers(SUMOTime timestep, bool /* includeRiding */) const {
1266 52272966 : std::vector<MSTransportable*> result(myContainers.begin(), myContainers.end());
1267 52272966 : sort(result.begin(), result.end(), transportable_by_position_sorter(timestep));
1268 52272966 : return result;
1269 0 : }
1270 :
1271 :
1272 : int
1273 5268076 : MSEdge::transportable_by_position_sorter::operator()(const MSTransportable* const c1, const MSTransportable* const c2) const {
1274 5268076 : const double pos1 = c1->getCurrentStage()->getEdgePos(myTime);
1275 5268076 : const double pos2 = c2->getCurrentStage()->getEdgePos(myTime);
1276 5268076 : if (pos1 != pos2) {
1277 5110288 : return pos1 < pos2;
1278 : }
1279 157788 : return c1->getID() < c2->getID();
1280 : }
1281 :
1282 :
1283 : void
1284 125245 : MSEdge::addSuccessor(MSEdge* edge, const MSEdge* via) {
1285 125245 : mySuccessors.push_back(edge);
1286 125245 : myViaSuccessors.push_back(std::make_pair(edge, via));
1287 125245 : if (isTazConnector() && edge->getFromJunction() != nullptr) {
1288 62619 : myBoundary.add(edge->getFromJunction()->getPosition());
1289 : }
1290 :
1291 125245 : edge->myPredecessors.push_back(this);
1292 125245 : if (edge->isTazConnector() && getToJunction() != nullptr) {
1293 62626 : edge->myBoundary.add(getToJunction()->getPosition());
1294 : }
1295 125245 : }
1296 :
1297 :
1298 : const MSEdgeVector&
1299 78719003 : MSEdge::getSuccessors(SUMOVehicleClass vClass) const {
1300 78719003 : if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
1301 78701795 : return mySuccessors;
1302 : }
1303 : #ifdef HAVE_FOX
1304 17208 : ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
1305 : #endif
1306 : std::map<SUMOVehicleClass, MSEdgeVector>::iterator i = myClassesSuccessorMap.find(vClass);
1307 17208 : if (i == myClassesSuccessorMap.end()) {
1308 : // instantiate vector
1309 2232 : myClassesSuccessorMap[vClass];
1310 : i = myClassesSuccessorMap.find(vClass);
1311 : // this vClass is requested for the first time. rebuild all successors
1312 11486 : for (MSEdgeVector::const_iterator it = mySuccessors.begin(); it != mySuccessors.end(); ++it) {
1313 9254 : if ((*it)->isTazConnector()) {
1314 289 : i->second.push_back(*it);
1315 : } else {
1316 8965 : const std::vector<MSLane*>* allowed = allowedLanes(**it, vClass);
1317 8965 : if (allowed != nullptr && allowed->size() > 0) {
1318 6737 : i->second.push_back(*it);
1319 : }
1320 : }
1321 : }
1322 : }
1323 : // can use cached value
1324 17208 : return i->second;
1325 : }
1326 :
1327 :
1328 : const MSConstEdgePairVector&
1329 198952987 : MSEdge::getViaSuccessors(SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
1330 198952987 : if (vClass == SVC_IGNORING || !MSNet::getInstance()->hasPermissions() || myFunction == SumoXMLEdgeFunc::CONNECTOR) {
1331 193087846 : return myViaSuccessors;
1332 : }
1333 : #ifdef HAVE_FOX
1334 5865141 : ScopedLocker<> lock(mySuccessorMutex, MSGlobals::gNumThreads > 1);
1335 : #endif
1336 5865141 : auto& viaMap = ignoreTransientPermissions && myHaveTransientPermissions ? myOrigClassesViaSuccessorMap : myClassesViaSuccessorMap;
1337 : auto i = viaMap.find(vClass);
1338 5865141 : if (i != viaMap.end()) {
1339 : // can use cached value
1340 5809471 : return i->second;
1341 : }
1342 : // instantiate vector
1343 55670 : MSConstEdgePairVector& result = viaMap[vClass];
1344 : // this vClass is requested for the first time. rebuild all successors
1345 237232 : for (const auto& viaPair : myViaSuccessors) {
1346 181562 : if (viaPair.first->isTazConnector()) {
1347 6321 : result.push_back(viaPair);
1348 : } else {
1349 175241 : const std::vector<MSLane*>* allowed = allowedLanes(*viaPair.first, vClass, ignoreTransientPermissions);
1350 175241 : if (allowed != nullptr && allowed->size() > 0) {
1351 131691 : result.push_back(viaPair);
1352 : }
1353 : }
1354 : }
1355 : return result;
1356 : }
1357 :
1358 :
1359 : void
1360 1794260 : MSEdge::setJunctions(MSJunction* from, MSJunction* to) {
1361 1794260 : myFromJunction = from;
1362 1794260 : myToJunction = to;
1363 1794260 : if (!isTazConnector()) {
1364 1794260 : myBoundary.add(from->getPosition());
1365 1794260 : myBoundary.add(to->getPosition());
1366 : }
1367 1794260 : }
1368 :
1369 :
1370 : bool
1371 2959841 : MSEdge::canChangeToOpposite() const {
1372 2959841 : return (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr &&
1373 : // do not change on curved internal lanes
1374 : (!isInternal()
1375 5944 : || (MSGlobals::gUsingInternalLanes
1376 5944 : && myLanes->back()->getIncomingLanes()[0].viaLink->getDirection() == LinkDirection::STRAIGHT)));
1377 : }
1378 :
1379 :
1380 : const MSEdge*
1381 22416807 : MSEdge::getOppositeEdge() const {
1382 22416807 : if (!myLanes->empty() && myLanes->back()->getOpposite() != nullptr) {
1383 2997510 : return &(myLanes->back()->getOpposite()->getEdge());
1384 : } else {
1385 19419297 : return nullptr;
1386 : }
1387 : }
1388 :
1389 :
1390 : bool
1391 178 : MSEdge::hasMinorLink() const {
1392 354 : for (const MSLane* const l : *myLanes) {
1393 386 : for (const MSLink* const link : l->getLinkCont()) {
1394 210 : if (!link->havePriority()) {
1395 : return true;
1396 : }
1397 : }
1398 : }
1399 : return false;
1400 : }
1401 :
1402 : bool
1403 211169 : MSEdge::hasChangeProhibitions(SUMOVehicleClass svc, int index) const {
1404 211169 : if (myLanes->size() == 1) {
1405 : return false;
1406 : }
1407 293114 : for (const MSLane* const l : *myLanes) {
1408 198945 : if (l->getIndex() <= index && !l->allowsChangingRight(svc) && l->getIndex() > 0) {
1409 : return true;
1410 198901 : } else if (l->getIndex() >= index && !l->allowsChangingLeft(svc) && l->getIndex() < (int)(myLanes->size() - 1)) {
1411 : return true;
1412 : }
1413 : }
1414 : return false;
1415 : }
1416 :
1417 : void
1418 924878 : MSEdge::checkAndRegisterBiDirEdge(const std::string& bidiID) {
1419 924878 : if (bidiID != "") {
1420 32980 : myBidiEdge = dictionary(bidiID);
1421 32980 : if (myBidiEdge == nullptr) {
1422 0 : WRITE_ERRORF(TL("Bidi-edge '%' does not exist"), bidiID);
1423 : }
1424 32980 : setBidiLanes();
1425 529876 : return;
1426 : }
1427 891898 : if (getFunction() != SumoXMLEdgeFunc::NORMAL) {
1428 : return;
1429 : }
1430 : // legacy networks (no bidi attribute)
1431 395002 : ConstMSEdgeVector candidates = myToJunction->getOutgoing();
1432 3119648 : for (ConstMSEdgeVector::const_iterator it = candidates.begin(); it != candidates.end(); it++) {
1433 2724646 : if ((*it)->getToJunction() == myFromJunction) { //reverse edge
1434 312612 : if (myBidiEdge != nullptr && isSuperposable(*it)) {
1435 0 : WRITE_WARNINGF(TL("Ambiguous superposable edges between junction '%' and '%'."), myToJunction->getID(), myFromJunction->getID());
1436 0 : break;
1437 : }
1438 312612 : if (isSuperposable(*it)) {
1439 26 : myBidiEdge = *it;
1440 26 : setBidiLanes();
1441 : }
1442 : }
1443 : }
1444 395002 : }
1445 :
1446 :
1447 : void
1448 33006 : MSEdge::setBidiLanes() {
1449 : assert(myBidiEdge != nullptr);
1450 33006 : if (getNumLanes() == 1 && myBidiEdge->getNumLanes() == 1) {
1451 : // the other way round is set when this method runs for the bidiEdge
1452 31274 : getLanes()[0]->setBidiLane(myBidiEdge->getLanes()[0]);
1453 : } else {
1454 : // find lanes with matching reversed shapes
1455 : int numBidiLanes = 0;
1456 5262 : for (MSLane* l1 : *myLanes) {
1457 10794 : for (MSLane* l2 : *myBidiEdge->myLanes) {
1458 7264 : if (l1->getShape().reverse().almostSame(l2->getShape(), POSITION_EPS * 2)) {
1459 1786 : l1->setBidiLane(l2);
1460 1786 : numBidiLanes++;
1461 : }
1462 : }
1463 : }
1464 : // warn only once for each pair
1465 1732 : if (numBidiLanes == 0 && getNumericalID() < myBidiEdge->getNumericalID()) {
1466 15 : WRITE_WARNINGF(TL("Edge '%' and bidi edge '%' have no matching bidi lanes"), getID(), myBidiEdge->getID());
1467 : }
1468 : }
1469 33006 : }
1470 :
1471 :
1472 : bool
1473 312612 : MSEdge::isSuperposable(const MSEdge* other) {
1474 312612 : if (other == nullptr || other->getLanes().size() != myLanes->size()) {
1475 : return false;
1476 : }
1477 : std::vector<MSLane*>::const_iterator it1 = myLanes->begin();
1478 : std::vector<MSLane*>::const_reverse_iterator it2 = other->getLanes().rbegin();
1479 : do {
1480 307918 : if ((*it1)->getShape().reverse() != (*it2)->getShape()) {
1481 : return false;
1482 : }
1483 : it1++;
1484 : it2++;
1485 26 : } while (it1 != myLanes->end());
1486 :
1487 : return true;
1488 : }
1489 :
1490 :
1491 : void
1492 74267 : MSEdge::addWaiting(SUMOVehicle* vehicle) const {
1493 : #ifdef HAVE_FOX
1494 74267 : ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1495 : #endif
1496 74267 : myWaiting.push_back(vehicle);
1497 74267 : }
1498 :
1499 :
1500 : void
1501 65848 : MSEdge::removeWaiting(const SUMOVehicle* vehicle) const {
1502 : #ifdef HAVE_FOX
1503 65848 : ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1504 : #endif
1505 65848 : std::vector<SUMOVehicle*>::iterator it = std::find(myWaiting.begin(), myWaiting.end(), vehicle);
1506 65848 : if (it != myWaiting.end()) {
1507 65237 : myWaiting.erase(it);
1508 : }
1509 65848 : }
1510 :
1511 :
1512 : SUMOVehicle*
1513 136874 : MSEdge::getWaitingVehicle(MSTransportable* transportable, const double position) const {
1514 : #ifdef HAVE_FOX
1515 136874 : ScopedLocker<> lock(myWaitingMutex, MSGlobals::gNumSimThreads > 1);
1516 : #endif
1517 137174 : for (SUMOVehicle* const vehicle : myWaiting) {
1518 25736 : if (transportable->isWaitingFor(vehicle)) {
1519 28169 : if (vehicle->isStoppedInRange(position, MSGlobals::gStopTolerance) ||
1520 2524 : (!vehicle->hasDeparted() &&
1521 2318 : (vehicle->getParameter().departProcedure == DepartDefinition::TRIGGERED ||
1522 82 : vehicle->getParameter().departProcedure == DepartDefinition::CONTAINER_TRIGGERED))) {
1523 : return vehicle;
1524 : }
1525 209 : if (!vehicle->isLineStop(position) && vehicle->allowsBoarding(transportable)) {
1526 222 : WRITE_WARNING((transportable->isPerson() ? "Person '" : "Container '")
1527 : + transportable->getID() + "' at edge '" + getID() + "' position " + toString(position) + " cannot use waiting vehicle '"
1528 : + vehicle->getID() + "' at position " + toString(vehicle->getPositionOnLane()) + " because it is too far away.");
1529 : }
1530 : }
1531 : }
1532 : return nullptr;
1533 : }
1534 :
1535 : std::vector<const SUMOVehicle*>
1536 144414 : MSEdge::getVehicles() const {
1537 : std::vector<const SUMOVehicle*> result;
1538 144414 : if (MSGlobals::gUseMesoSim) {
1539 220 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1540 122 : std::vector<const MEVehicle*> segmentVehs = segment->getVehicles();
1541 122 : result.insert(result.end(), segmentVehs.begin(), segmentVehs.end());
1542 122 : }
1543 : } else {
1544 386581 : for (MSLane* lane : getLanes()) {
1545 830409 : for (auto veh : lane->getVehiclesSecure()) {
1546 588193 : result.push_back(veh);
1547 : }
1548 242216 : lane->releaseVehicles();
1549 : }
1550 : }
1551 144414 : return result;
1552 0 : }
1553 :
1554 : int
1555 628995 : MSEdge::getNumDrivingLanes() const {
1556 : int result = 0;
1557 628995 : SVCPermissions filter = SVCAll;
1558 628995 : if ((myCombinedPermissions & ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
1559 : filter = ~(SVC_PEDESTRIAN | SVC_WHEELCHAIR);
1560 3862 : } else if ((myCombinedPermissions & (SVC_PEDESTRIAN | SVC_WHEELCHAIR)) != 0) {
1561 : // filter out green verge
1562 : filter = (SVC_PEDESTRIAN | SVC_WHEELCHAIR);
1563 : }
1564 1416828 : for (const MSLane* const l : *myLanes) {
1565 787833 : if ((l->getPermissions() & filter) != 0) {
1566 697475 : result++;
1567 : }
1568 : }
1569 628995 : return result;
1570 : }
1571 :
1572 : int
1573 399 : MSEdge::getVehicleNumber() const {
1574 399 : return (int)getVehicles().size();
1575 : }
1576 :
1577 :
1578 : bool
1579 0 : MSEdge::isEmpty() const {
1580 : /// more efficient than retrieving vehicle number
1581 0 : if (MSGlobals::gUseMesoSim) {
1582 0 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1583 0 : if (segment->getCarNumber() > 0) {
1584 : return false;
1585 : }
1586 : }
1587 : } else {
1588 0 : for (MSLane* lane : getLanes()) {
1589 0 : if (lane->getVehicleNumber() > 0) {
1590 : return false;
1591 : }
1592 : }
1593 : }
1594 : return true;
1595 : }
1596 :
1597 :
1598 : double
1599 14 : MSEdge::getWaitingSeconds() const {
1600 : double wtime = 0;
1601 14 : if (MSGlobals::gUseMesoSim) {
1602 12 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1603 9 : wtime += segment->getWaitingSeconds();
1604 : }
1605 : } else {
1606 34 : for (MSLane* lane : getLanes()) {
1607 23 : wtime += lane->getWaitingSeconds();
1608 : }
1609 : }
1610 14 : return wtime;
1611 : }
1612 :
1613 :
1614 : double
1615 22 : MSEdge::getOccupancy() const {
1616 22 : if (myLanes->size() == 0) {
1617 : return 0;
1618 : }
1619 22 : if (MSGlobals::gUseMesoSim) {
1620 : /// @note MESegment only tracks brutto occupancy so we compute this from sratch
1621 : double sum = 0;
1622 8 : for (const SUMOVehicle* veh : getVehicles()) {
1623 4 : sum += dynamic_cast<const MEVehicle*>(veh)->getVehicleType().getLength();
1624 4 : }
1625 4 : return sum / (myLength * (double)myLanes->size());
1626 : } else {
1627 : double sum = 0;
1628 48 : for (auto lane : getLanes()) {
1629 30 : sum += lane->getNettoOccupancy();
1630 : }
1631 18 : return sum / (double)myLanes->size();
1632 : }
1633 : }
1634 :
1635 :
1636 : double
1637 0 : MSEdge::getFlow() const {
1638 0 : if (myLanes->size() == 0) {
1639 : return 0;
1640 : }
1641 : double flow = 0;
1642 0 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1643 0 : flow += (double) segment->getCarNumber() * segment->getMeanSpeed();
1644 : }
1645 0 : return 3600 * flow / (*myLanes)[0]->getLength();
1646 : }
1647 :
1648 :
1649 : double
1650 0 : MSEdge::getBruttoOccupancy() const {
1651 0 : if (myLanes->size() == 0) {
1652 : return 0;
1653 : }
1654 : double occ = 0;
1655 0 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this); segment != nullptr; segment = segment->getNextSegment()) {
1656 0 : occ += segment->getBruttoOccupancy();
1657 : }
1658 0 : return occ / (*myLanes)[0]->getLength() / (double)(myLanes->size());
1659 : }
1660 :
1661 : double
1662 4240 : MSEdge::getTravelTimeAggregated(const MSEdge* const edge, const SUMOVehicle* const veh, double /*time*/) {
1663 4240 : return edge->getLength() / MIN2(MSRoutingEngine::getAssumedSpeed(edge, veh), veh->getMaxSpeed());
1664 : }
1665 :
1666 :
1667 : void
1668 2098 : MSEdge::inferEdgeType() {
1669 : // @note must be called after closeBuilding() to ensure successors and
1670 : // predecessors are set
1671 2098 : if (isInternal() && myEdgeType == "") {
1672 1274 : const std::string typeBefore = getNormalBefore()->getEdgeType();
1673 1274 : if (typeBefore != "") {
1674 694 : const std::string typeAfter = getNormalSuccessor()->getEdgeType();
1675 694 : if (typeBefore == typeAfter) {
1676 : myEdgeType = typeBefore;
1677 314 : } else if (typeAfter != "") {
1678 68 : MSNet* net = MSNet::getInstance();
1679 68 : auto resBefore = net->getRestrictions(typeBefore);
1680 68 : auto resAfter = net->getRestrictions(typeAfter);
1681 68 : if (resBefore != nullptr && resAfter != nullptr) {
1682 : // create new restrictions for this type-combination
1683 96 : myEdgeType = typeBefore + "|" + typeAfter;
1684 48 : if (net->getRestrictions(myEdgeType) == nullptr) {
1685 48 : for (const auto& item : *resBefore) {
1686 24 : const SUMOVehicleClass svc = item.first;
1687 24 : const double speed = item.second;
1688 : const auto it = (*resAfter).find(svc);
1689 24 : if (it != (*resAfter).end()) {
1690 24 : const double speed2 = it->second;
1691 24 : const double newSpeed = (MSNet::getInstance()->hasJunctionHigherSpeeds()
1692 24 : ? MAX2(speed, speed2) : (speed + speed2) / 2);
1693 24 : net->addRestriction(myEdgeType, svc, newSpeed);
1694 : }
1695 : }
1696 : }
1697 : }
1698 : }
1699 : }
1700 : }
1701 2098 : }
1702 :
1703 :
1704 : double
1705 2178 : MSEdge::getDistanceAt(double pos) const {
1706 : // negative values of myDistances indicate descending kilometrage
1707 2178 : return fabs(myDistance + pos);
1708 : }
1709 :
1710 :
1711 : bool
1712 1350 : MSEdge::hasTransientPermissions() const {
1713 1350 : return myHaveTransientPermissions;
1714 : }
1715 :
1716 :
1717 : std::pair<double, SUMOTime>
1718 596399248 : MSEdge::getLastBlocked(int index) const {
1719 596399248 : if (myLaneChanger != nullptr) {
1720 596399248 : return myLaneChanger->getLastBlocked(index);
1721 : }
1722 0 : return std::make_pair(-1, -1);
1723 : }
1724 :
1725 :
1726 : double
1727 2855 : MSEdge::getPreference(const SUMOVTypeParameter& pars) const {
1728 5710 : return MSNet::getInstance()->getPreference(getRoutingType(), pars);
1729 : }
1730 :
1731 :
1732 : void
1733 7032 : MSEdge::clearState() {
1734 : myPersons.clear();
1735 : myContainers.clear();
1736 : myWaiting.clear();
1737 7032 : }
1738 :
1739 :
1740 : const std::map<const MEVehicle*, std::pair<double, int> >&
1741 1668959 : MSEdge::getMesoPositions() const {
1742 : assert(MSGlobals::gUseMesoSim);
1743 1668959 : if (myLastCacheUpdate < SIMSTEP) {
1744 1626137 : myLastCacheUpdate = SIMSTEP;
1745 : auto old = std::move(myCachedMesoPos);
1746 : myCachedMesoPos.clear(); // moved-from map is valid-but-unspecified; make it defined-empty
1747 : int laneIndex = 0;
1748 1626137 : const double now = SIMTIME;
1749 3811617 : for (std::vector<MSLane*>::const_iterator msl = myLanes->begin(); msl != myLanes->end(); ++msl, ++laneIndex) {
1750 : // go through the vehicles
1751 : double segmentOffset = 0; // offset at start of current segment
1752 2185480 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*this);
1753 4726914 : segment != nullptr; segment = segment->getNextSegment()) {
1754 : const double segLength = segment->getLength();
1755 2541434 : const double lanesCovered = segment->numQueues() == 1 ? std::round(segment->getCapacity() / segLength) : 1.;
1756 2541434 : if (laneIndex < segment->numQueues()) {
1757 : // make a copy so we don't have to worry about synchronization
1758 2011989 : std::vector<MEVehicle*> queue = segment->getQueue(laneIndex);
1759 2011989 : const int queueSize = (int)queue.size();
1760 : SUMOTime earliestExitTime = segment->getQueueBlockTime(laneIndex);
1761 : int overlap = 0;
1762 : double prevPos = std::numeric_limits<double>::max();
1763 5049214 : for (int i = 0; i < queueSize; ++i) {
1764 3037225 : const MEVehicle* const veh = queue[queueSize - i - 1];
1765 : earliestExitTime = MAX2(earliestExitTime, veh->getEventTime());
1766 3037225 : const double vehLength = veh->getVehicleType().getLengthWithGap();
1767 3037225 : double maxPos = segmentOffset + segLength;
1768 : auto it = old.find(veh);
1769 3037225 : const double oldPos = it != old.end() ? it->second.first : 0.; // store the old position to prevent backwards moving vehicles
1770 3037225 : if (i > 0) {
1771 2759608 : earliestExitTime += segment->getMinTauWithVehLength(vehLength, veh->getVehicleType().getCarFollowModel().getHeadwayTime());
1772 2759608 : maxPos = MIN2(maxPos, prevPos - vehLength / lanesCovered);
1773 : }
1774 3037225 : const double entry = veh->getLastEntryTimeSeconds();
1775 : assert(STEPS2TIME(earliestExitTime) > entry);
1776 3037225 : const double pos = MAX2(MIN2(segmentOffset + segLength * (now - entry) / (STEPS2TIME(earliestExitTime) - entry), maxPos), oldPos);
1777 : // check if we overlap with the previous vehicle such that the gui has the chance to add some lateral offset
1778 3037225 : if (overlap == 0 && prevPos - pos < vehLength) {
1779 893724 : overlap = lanesCovered > 1. ? -3 : -1;
1780 : } else {
1781 : overlap = 0;
1782 : }
1783 3037225 : myCachedMesoPos[veh] = std::make_pair(pos, overlap);
1784 : prevPos = pos;
1785 : }
1786 2011989 : }
1787 2541434 : segmentOffset += segLength;
1788 : }
1789 : }
1790 : }
1791 1668959 : return myCachedMesoPos;
1792 : }
1793 :
1794 :
1795 : double
1796 11314668 : MSEdge::getMinLength() const {
1797 : double result = std::numeric_limits<double>::max();
1798 32563933 : for (const MSLane* l : *myLanes) {
1799 : result = MIN2(result, l->getLength());
1800 : }
1801 11314668 : return result;
1802 : }
1803 :
1804 :
1805 : /****************************************************************************/
|