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