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