Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-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 ROEdge.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Christian Roessel
18 : /// @author Michael Behrisch
19 : /// @author Melanie Knocke
20 : /// @author Yun-Pang Floetteroed
21 : /// @author Ruediger Ebendt
22 : /// @date Sept 2002
23 : ///
24 : // A basic edge for routing applications
25 : /****************************************************************************/
26 : #include <config.h>
27 :
28 : #include <utils/common/MsgHandler.h>
29 : #include <utils/common/ToString.h>
30 : #include <algorithm>
31 : #include <cassert>
32 : #include <iostream>
33 : #include <utils/vehicle/SUMOVTypeParameter.h>
34 : #include <utils/emissions/PollutantsInterface.h>
35 : #include <utils/emissions/HelpersHarmonoise.h>
36 : #include "ROLane.h"
37 : #include "RONet.h"
38 : #include "ROVehicle.h"
39 : #include "ROEdge.h"
40 :
41 :
42 : // ===========================================================================
43 : // static member definitions
44 : // ===========================================================================
45 : bool ROEdge::myInterpolate = false;
46 : bool ROEdge::myHaveTTWarned = false;
47 : bool ROEdge::myHaveEWarned = false;
48 : ROEdgeVector ROEdge::myEdges;
49 : double ROEdge::myPriorityFactor(0);
50 : double ROEdge::myMinEdgePriority(std::numeric_limits<double>::max());
51 : double ROEdge::myEdgePriorityRange(0);
52 :
53 :
54 : // ===========================================================================
55 : // method definitions
56 : // ===========================================================================
57 286937 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority, const std::string& type, const std::string& routingType) :
58 : Named(id),
59 286937 : myFromJunction(from),
60 286937 : myToJunction(to),
61 286937 : myIndex(index),
62 286937 : myPriority(priority),
63 286937 : myType(type),
64 286937 : myRoutingType(routingType),
65 286937 : mySpeed(-1),
66 286937 : myLength(0),
67 286937 : myAmSink(false),
68 286937 : myAmSource(false),
69 286937 : myUsingTTTimeLine(false),
70 286937 : myUsingETimeLine(false),
71 286937 : mySpeedRestrictions(nullptr),
72 286937 : myCombinedPermissions(0),
73 286937 : myOtherTazConnector(nullptr),
74 573874 : myTimePenalty(0) {
75 573874 : while ((int)myEdges.size() <= index) {
76 286937 : myEdges.push_back(0);
77 : }
78 286937 : myEdges[index] = this;
79 286937 : if (from == nullptr && to == nullptr) {
80 : // TAZ edge, no lanes
81 3632 : myCombinedPermissions = SVCAll;
82 : } else {
83 : // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
84 283305 : myBoundary.add(from->getPosition());
85 283305 : myBoundary.add(to->getPosition());
86 : }
87 286937 : }
88 :
89 :
90 13 : ROEdge::ROEdge(const std::string& id, const RONode* from, const RONode* to, SVCPermissions p) :
91 : Named(id),
92 13 : myFromJunction(const_cast<RONode*>(from)),
93 13 : myToJunction(const_cast<RONode*>(to)),
94 13 : myIndex(-1),
95 13 : myPriority(0),
96 13 : myType(""),
97 13 : mySpeed(std::numeric_limits<double>::max()),
98 13 : myLength(0),
99 13 : myAmSink(false),
100 13 : myAmSource(false),
101 13 : myUsingTTTimeLine(false),
102 13 : myUsingETimeLine(false),
103 13 : myCombinedPermissions(p),
104 13 : myOtherTazConnector(nullptr),
105 13 : myTimePenalty(0)
106 13 : { }
107 :
108 :
109 841697 : ROEdge::~ROEdge() {
110 600806 : for (ROLane* const lane : myLanes) {
111 316516 : delete lane;
112 : }
113 284290 : delete myReversedRoutingEdge;
114 284290 : delete myFlippedRoutingEdge;
115 284290 : delete myRailwayRoutingEdge;
116 1125987 : }
117 :
118 :
119 : void
120 320006 : ROEdge::addLane(ROLane* lane) {
121 320006 : const double speed = lane->getSpeed();
122 320006 : if (speed > mySpeed) {
123 283859 : mySpeed = speed;
124 283859 : myLength = lane->getLength();
125 : }
126 320006 : mySpeed = speed > mySpeed ? speed : mySpeed;
127 320006 : myLanes.push_back(lane);
128 :
129 : // integrate new allowed classes
130 320006 : myCombinedPermissions |= lane->getPermissions();
131 320006 : }
132 :
133 :
134 : void
135 566650 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
136 566650 : if (isInternal()) {
137 : // for internal edges after an internal junction,
138 : // this is called twice and only the second call counts
139 : myFollowingEdges.clear();
140 : myFollowingViaEdges.clear();
141 : }
142 566650 : if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
143 553378 : myFollowingEdges.push_back(s);
144 553378 : myFollowingViaEdges.push_back(std::make_pair(s, via));
145 553378 : if (isTazConnector() && s->getFromJunction() != nullptr) {
146 3834 : myBoundary.add(s->getFromJunction()->getPosition());
147 : }
148 553378 : if (!isInternal()) {
149 260509 : s->myApproachingEdges.push_back(this);
150 260509 : if (s->isTazConnector() && getToJunction() != nullptr) {
151 3835 : s->myBoundary.add(getToJunction()->getPosition());
152 : }
153 : }
154 553378 : if (via != nullptr) {
155 134419 : if (via->myApproachingEdges.size() == 0) {
156 134144 : via->myApproachingEdges.push_back(this);
157 : }
158 : }
159 : }
160 566650 : }
161 :
162 :
163 : void
164 189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
165 189 : myEfforts.add(timeBegin, timeEnd, value);
166 189 : myUsingETimeLine = true;
167 189 : }
168 :
169 :
170 : void
171 247817 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
172 247817 : myTravelTimes.add(timeBegin, timeEnd, value);
173 247817 : myUsingTTTimeLine = true;
174 247817 : }
175 :
176 :
177 : double
178 0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
179 0 : double ret = 0;
180 0 : if (!getStoredEffort(time, ret)) {
181 0 : return myLength / getMaxSpeed(veh);
182 : }
183 0 : return ret;
184 : }
185 :
186 :
187 : double
188 45925 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
189 : assert(this != other);
190 45925 : if (doBoundaryEstimate) {
191 11472 : return myBoundary.distanceTo2D(other->myBoundary);
192 : }
193 34453 : if (isTazConnector()) {
194 197 : if (other->isTazConnector()) {
195 186 : return myBoundary.distanceTo2D(other->myBoundary);
196 : }
197 11 : return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
198 : }
199 34256 : if (other->isTazConnector()) {
200 817 : return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
201 : }
202 33439 : return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
203 : //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
204 : }
205 :
206 :
207 : bool
208 26723 : ROEdge::hasLoadedTravelTime(double time) const {
209 26723 : return myUsingTTTimeLine && myTravelTimes.describesTime(time);
210 : }
211 :
212 :
213 : double
214 13344641 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
215 13344641 : if (myUsingTTTimeLine) {
216 4330552 : if (myTravelTimes.describesTime(time)) {
217 4321794 : double lineTT = myTravelTimes.getValue(time);
218 4321794 : if (myInterpolate) {
219 : const double inTT = lineTT;
220 68 : const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
221 68 : if (split >= 0) {
222 18 : lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
223 : }
224 : }
225 4321794 : return MAX2(getMinimumTravelTime(veh), lineTT);
226 : } else {
227 8758 : if (!myHaveTTWarned) {
228 0 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
229 0 : myHaveTTWarned = true;
230 : }
231 : }
232 : }
233 9022847 : const double speed = veh != nullptr ? getMaxSpeed(veh) : mySpeed;
234 9022847 : return myLength / speed + myTimePenalty;
235 : }
236 :
237 :
238 : double
239 0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
240 0 : double ret = 0;
241 0 : if (!edge->getStoredEffort(time, ret)) {
242 0 : ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, edge->getMaxSpeed(veh), 0);
243 : }
244 0 : return ret;
245 : }
246 :
247 :
248 : bool
249 1666 : ROEdge::getStoredEffort(double time, double& ret) const {
250 1666 : if (myUsingETimeLine) {
251 190 : if (!myEfforts.describesTime(time)) {
252 0 : if (!myHaveEWarned) {
253 0 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
254 0 : myHaveEWarned = true;
255 : }
256 0 : return false;
257 : }
258 190 : if (myInterpolate) {
259 0 : const double inTT = myTravelTimes.getValue(time);
260 0 : const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
261 0 : if (ratio >= 0.) {
262 0 : ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
263 0 : return true;
264 : }
265 : }
266 190 : ret = myEfforts.getValue(time);
267 190 : return true;
268 : }
269 : return false;
270 : }
271 :
272 :
273 : int
274 19236 : ROEdge::getNumSuccessors() const {
275 19236 : if (myAmSink) {
276 : return 0;
277 : }
278 19236 : return (int) myFollowingEdges.size();
279 : }
280 :
281 :
282 : int
283 15110 : ROEdge::getNumPredecessors() const {
284 15110 : if (myAmSource) {
285 : return 0;
286 : }
287 15110 : return (int) myApproachingEdges.size();
288 : }
289 :
290 :
291 : const ROEdge*
292 16 : ROEdge::getNormalBefore() const {
293 : const ROEdge* result = this;
294 40 : while (result->isInternal()) {
295 : assert(myApproachingEdges.size() == 1);
296 24 : result = result->myApproachingEdges.front();
297 : }
298 16 : return result;
299 : }
300 :
301 :
302 :
303 : const ROEdge*
304 8 : ROEdge::getNormalAfter() const {
305 : const ROEdge* result = this;
306 16 : while (result->isInternal()) {
307 : assert(myFollowingEdges.size() == 1);
308 8 : result = result->myFollowingEdges.front();
309 : }
310 8 : return result;
311 : }
312 :
313 :
314 : void
315 6228 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
316 6228 : if (myUsingETimeLine) {
317 147 : double value = myLength / mySpeed;
318 147 : const SUMOEmissionClass c = PollutantsInterface::getClassByName("HBEFA4/default");
319 147 : if (measure == "CO") {
320 26 : value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
321 : }
322 147 : if (measure == "CO2") {
323 19 : value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
324 : }
325 147 : if (measure == "HC") {
326 26 : value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
327 : }
328 147 : if (measure == "PMx") {
329 19 : value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
330 : }
331 147 : if (measure == "NOx") {
332 19 : value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
333 : }
334 147 : if (measure == "fuel") {
335 19 : value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
336 : }
337 147 : if (measure == "electricity") {
338 0 : value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
339 : }
340 147 : myEfforts.fillGaps(value, boundariesOverride);
341 : }
342 6228 : if (myUsingTTTimeLine) {
343 3924 : myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
344 : }
345 6228 : }
346 :
347 :
348 : void
349 408 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
350 816 : for (const std::string& key : restrictionKeys) {
351 408 : const std::string value = getParameter(key, "1e40");
352 408 : myParamRestrictions.push_back(StringUtils::toDouble(value));
353 : }
354 408 : }
355 :
356 :
357 : double
358 139696 : ROEdge::getLengthGeometryFactor() const {
359 139696 : return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
360 : }
361 :
362 :
363 : bool
364 327631 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
365 327631 : for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
366 327631 : if (!(*i)->prohibits(vehicle)) {
367 : return false;
368 : }
369 : }
370 : return true;
371 : }
372 :
373 :
374 : const ROEdgeVector&
375 7905 : ROEdge::getAllEdges() {
376 7905 : return myEdges;
377 : }
378 :
379 :
380 : const Position
381 1415 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
382 1415 : const double middle = (stop.endPos + stop.startPos) / 2.;
383 4245 : const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
384 1415 : return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
385 : }
386 :
387 :
388 : const ROEdgeVector&
389 1374240 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
390 1374240 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
391 1323492 : return myFollowingEdges;
392 : }
393 : #ifdef HAVE_FOX
394 50748 : FXMutexLock locker(myLock);
395 : #endif
396 : std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
397 50748 : if (i != myClassesSuccessorMap.end()) {
398 : // can use cached value
399 46956 : return i->second;
400 : }
401 : // this vClass is requested for the first time. rebuild all successors
402 : std::set<ROEdge*> followers;
403 10324 : for (const ROLane* const lane : myLanes) {
404 6532 : if ((lane->getPermissions() & vClass) != 0) {
405 13943 : for (const auto& next : lane->getOutgoingViaLanes()) {
406 8313 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
407 7722 : followers.insert(&next.first->getEdge());
408 : }
409 : }
410 : }
411 : }
412 : // also add district edges (they are not connected at the lane level
413 11943 : for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
414 8151 : if ((*it)->isTazConnector()) {
415 : followers.insert(*it);
416 : }
417 : }
418 3792 : myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
419 : followers.begin(), followers.end());
420 3792 : return myClassesSuccessorMap[vClass];
421 : }
422 :
423 :
424 : const ROConstEdgePairVector&
425 10615494 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
426 10615494 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
427 9661698 : return myFollowingViaEdges;
428 : }
429 : #ifdef HAVE_FOX
430 953796 : FXMutexLock locker(myLock);
431 : #endif
432 : std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
433 953796 : if (i != myClassesViaSuccessorMap.end()) {
434 : // can use cached value
435 932733 : return i->second;
436 : }
437 : // this vClass is requested for the first time. rebuild all successors
438 : std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
439 56476 : for (const ROLane* const lane : myLanes) {
440 35413 : if ((lane->getPermissions() & vClass) != 0) {
441 70523 : for (const auto& next : lane->getOutgoingViaLanes()) {
442 44569 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
443 39467 : followers.insert(std::make_pair(&next.first->getEdge(), next.second));
444 : }
445 : }
446 : }
447 : }
448 : // also add district edges (they are not connected at the lane level
449 70102 : for (const ROEdge* e : myFollowingEdges) {
450 49039 : if (e->isTazConnector()) {
451 372 : followers.insert(std::make_pair(e, e));
452 : }
453 : }
454 21063 : myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
455 : followers.begin(), followers.end());
456 21063 : return myClassesViaSuccessorMap[vClass];
457 : }
458 :
459 :
460 : bool
461 328927 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
462 : // @todo needs to be used with #12501
463 : UNUSED_PARAMETER(ignoreTransientPermissions);
464 328927 : const ROEdgeVector& followers = getSuccessors(vClass);
465 328927 : return std::find(followers.begin(), followers.end(), &e) != followers.end();
466 : }
467 :
468 : bool
469 3 : ROEdge::initPriorityFactor(double priorityFactor) {
470 3 : myPriorityFactor = priorityFactor;
471 : double maxEdgePriority = -std::numeric_limits<double>::max();
472 57 : for (ROEdge* edge : myEdges) {
473 54 : maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
474 97 : myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
475 : }
476 3 : myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
477 3 : if (myEdgePriorityRange == 0) {
478 1 : WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
479 1 : myPriorityFactor = 0;
480 1 : return false;
481 : }
482 : return true;
483 : }
484 :
485 :
486 : /****************************************************************************/
|