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 546916 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority, const std::string& type) :
58 : Named(id),
59 546916 : myFromJunction(from),
60 546916 : myToJunction(to),
61 546916 : myIndex(index),
62 546916 : myPriority(priority),
63 546916 : myType(type),
64 546916 : mySpeed(-1),
65 546916 : myLength(0),
66 546916 : myAmSink(false),
67 546916 : myAmSource(false),
68 546916 : myUsingTTTimeLine(false),
69 546916 : myUsingETimeLine(false),
70 546916 : myRestrictions(nullptr),
71 546916 : myCombinedPermissions(0),
72 546916 : myOtherTazConnector(nullptr),
73 1093832 : myTimePenalty(0) {
74 1093832 : while ((int)myEdges.size() <= index) {
75 546916 : myEdges.push_back(0);
76 : }
77 546916 : myEdges[index] = this;
78 546916 : if (from == nullptr && to == nullptr) {
79 : // TAZ edge, no lanes
80 28004 : myCombinedPermissions = SVCAll;
81 : } else {
82 : // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
83 518912 : myBoundary.add(from->getPosition());
84 518912 : myBoundary.add(to->getPosition());
85 : }
86 546916 : }
87 :
88 :
89 13 : ROEdge::ROEdge(const std::string& id, const RONode* from, const RONode* to, SVCPermissions p) :
90 : Named(id),
91 13 : myFromJunction(const_cast<RONode*>(from)),
92 13 : myToJunction(const_cast<RONode*>(to)),
93 13 : myIndex(-1),
94 13 : myPriority(0),
95 26 : myType(""),
96 13 : mySpeed(std::numeric_limits<double>::max()),
97 13 : myLength(0),
98 13 : myAmSink(false),
99 13 : myAmSource(false),
100 13 : myUsingTTTimeLine(false),
101 13 : myUsingETimeLine(false),
102 13 : myCombinedPermissions(p),
103 13 : myOtherTazConnector(nullptr),
104 13 : myTimePenalty(0)
105 13 : { }
106 :
107 :
108 1621631 : ROEdge::~ROEdge() {
109 1218030 : for (ROLane* const lane : myLanes) {
110 673774 : delete lane;
111 : }
112 544256 : delete myReversedRoutingEdge;
113 544256 : delete myFlippedRoutingEdge;
114 544256 : delete myRailwayRoutingEdge;
115 2165887 : }
116 :
117 :
118 : void
119 677264 : ROEdge::addLane(ROLane* lane) {
120 677264 : const double speed = lane->getSpeed();
121 677264 : if (speed > mySpeed) {
122 519466 : mySpeed = speed;
123 519466 : myLength = lane->getLength();
124 : }
125 677264 : mySpeed = speed > mySpeed ? speed : mySpeed;
126 677264 : myLanes.push_back(lane);
127 :
128 : // integrate new allowed classes
129 677264 : myCombinedPermissions |= lane->getPermissions();
130 677264 : }
131 :
132 :
133 : void
134 1222042 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
135 1222042 : if (isInternal()) {
136 : // for internal edges after an internal junction,
137 : // this is called twice and only the second call counts
138 : myFollowingEdges.clear();
139 : myFollowingViaEdges.clear();
140 : }
141 1222042 : if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
142 1160487 : myFollowingEdges.push_back(s);
143 1160487 : myFollowingViaEdges.push_back(std::make_pair(s, via));
144 1160487 : if (isTazConnector() && s->getFromJunction() != nullptr) {
145 22014 : myBoundary.add(s->getFromJunction()->getPosition());
146 : }
147 1160487 : if (!isInternal()) {
148 435156 : s->myApproachingEdges.push_back(this);
149 435156 : if (s->isTazConnector() && getToJunction() != nullptr) {
150 22015 : s->myBoundary.add(getToJunction()->getPosition());
151 : }
152 : }
153 1160487 : if (via != nullptr) {
154 301622 : if (via->myApproachingEdges.size() == 0) {
155 301325 : via->myApproachingEdges.push_back(this);
156 : }
157 : }
158 : }
159 1222042 : }
160 :
161 :
162 : void
163 189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
164 189 : myEfforts.add(timeBegin, timeEnd, value);
165 189 : myUsingETimeLine = true;
166 189 : }
167 :
168 :
169 : void
170 247462 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
171 247462 : myTravelTimes.add(timeBegin, timeEnd, value);
172 247462 : myUsingTTTimeLine = true;
173 247462 : }
174 :
175 :
176 : double
177 0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
178 0 : double ret = 0;
179 0 : if (!getStoredEffort(time, ret)) {
180 0 : return myLength / MIN2(veh->getMaxSpeed(), getVClassMaxSpeed(veh->getVClass())) + myTimePenalty;
181 : }
182 0 : return ret;
183 : }
184 :
185 :
186 : double
187 44459 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
188 : assert(this != other);
189 44459 : if (doBoundaryEstimate) {
190 10099 : return myBoundary.distanceTo2D(other->myBoundary);
191 : }
192 34360 : if (isTazConnector()) {
193 207 : if (other->isTazConnector()) {
194 196 : return myBoundary.distanceTo2D(other->myBoundary);
195 : }
196 11 : return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
197 : }
198 34153 : if (other->isTazConnector()) {
199 817 : return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
200 : }
201 33336 : return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
202 : //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
203 : }
204 :
205 :
206 : bool
207 26723 : ROEdge::hasLoadedTravelTime(double time) const {
208 26723 : return myUsingTTTimeLine && myTravelTimes.describesTime(time);
209 : }
210 :
211 :
212 : double
213 12167555 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
214 12167555 : if (myUsingTTTimeLine) {
215 4315441 : if (myTravelTimes.describesTime(time)) {
216 4306383 : double lineTT = myTravelTimes.getValue(time);
217 4306383 : if (myInterpolate) {
218 : const double inTT = lineTT;
219 68 : const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
220 68 : if (split >= 0) {
221 18 : lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
222 : }
223 : }
224 4306383 : return MAX2(getMinimumTravelTime(veh), lineTT);
225 : } else {
226 9058 : if (!myHaveTTWarned) {
227 3 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
228 1 : myHaveTTWarned = true;
229 : }
230 : }
231 : }
232 15722232 : const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter()[0] * getVClassMaxSpeed(veh->getVClass())) : mySpeed;
233 7861172 : return myLength / speed + myTimePenalty;
234 : }
235 :
236 :
237 : double
238 0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
239 0 : double ret = 0;
240 0 : if (!edge->getStoredEffort(time, ret)) {
241 0 : const double v = MIN2(veh->getMaxSpeed(), edge->getVClassMaxSpeed(veh->getVClass()));
242 0 : ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 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 16656 : ROEdge::getNumSuccessors() const {
275 16656 : if (myAmSink) {
276 : return 0;
277 : }
278 16656 : return (int) myFollowingEdges.size();
279 : }
280 :
281 :
282 : int
283 12534 : ROEdge::getNumPredecessors() const {
284 12534 : if (myAmSource) {
285 : return 0;
286 : }
287 12534 : 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 5115 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
316 5115 : 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 5115 : if (myUsingTTTimeLine) {
343 3571 : myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
344 : }
345 5115 : }
346 :
347 :
348 : void
349 296 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
350 592 : for (const std::string& key : restrictionKeys) {
351 296 : const std::string value = getParameter(key, "1e40");
352 296 : myParamRestrictions.push_back(StringUtils::toDouble(value));
353 : }
354 296 : }
355 :
356 :
357 : double
358 122809 : ROEdge::getLengthGeometryFactor() const {
359 122809 : 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 655262 : if (!(*i)->prohibits(vehicle)) {
367 : return false;
368 : }
369 : }
370 : return true;
371 : }
372 :
373 :
374 : const ROEdgeVector&
375 13532 : ROEdge::getAllEdges() {
376 13532 : return myEdges;
377 : }
378 :
379 :
380 : const Position
381 1403 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
382 1403 : const double middle = (stop.endPos + stop.startPos) / 2.;
383 4209 : const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
384 1403 : return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
385 : }
386 :
387 :
388 : const ROEdgeVector&
389 1266968 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
390 1266968 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
391 1243622 : return myFollowingEdges;
392 : }
393 : #ifdef HAVE_FOX
394 23346 : FXMutexLock locker(myLock);
395 : #endif
396 : std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
397 23346 : if (i != myClassesSuccessorMap.end()) {
398 : // can use cached value
399 20145 : return i->second;
400 : }
401 : // this vClass is requested for the first time. rebuild all successors
402 : std::set<ROEdge*> followers;
403 8947 : for (const ROLane* const lane : myLanes) {
404 5746 : if ((lane->getPermissions() & vClass) != 0) {
405 12070 : for (const auto& next : lane->getOutgoingViaLanes()) {
406 7192 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
407 6689 : followers.insert(&next.first->getEdge());
408 : }
409 : }
410 : }
411 : }
412 : // also add district edges (they are not connected at the lane level
413 10309 : for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
414 7108 : if ((*it)->isTazConnector()) {
415 : followers.insert(*it);
416 : }
417 : }
418 3201 : myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
419 : followers.begin(), followers.end());
420 3201 : return myClassesSuccessorMap[vClass];
421 : }
422 :
423 :
424 : const ROConstEdgePairVector&
425 9578208 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
426 9578208 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
427 8786632 : return myFollowingViaEdges;
428 : }
429 : #ifdef HAVE_FOX
430 791576 : FXMutexLock locker(myLock);
431 : #endif
432 : std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
433 791576 : if (i != myClassesViaSuccessorMap.end()) {
434 : // can use cached value
435 771897 : 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 53333 : for (const ROLane* const lane : myLanes) {
440 33654 : if ((lane->getPermissions() & vClass) != 0) {
441 66471 : for (const auto& next : lane->getOutgoingViaLanes()) {
442 42153 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
443 37161 : 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 66342 : for (const ROEdge* e : myFollowingEdges) {
450 46663 : if (e->isTazConnector()) {
451 372 : followers.insert(std::make_pair(e, e));
452 : }
453 : }
454 19679 : myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
455 : followers.begin(), followers.end());
456 19679 : return myClassesViaSuccessorMap[vClass];
457 : }
458 :
459 :
460 : bool
461 174737 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass) const {
462 174737 : const ROEdgeVector& followers = getSuccessors(vClass);
463 174737 : return std::find(followers.begin(), followers.end(), &e) != followers.end();
464 : }
465 :
466 : bool
467 3 : ROEdge::initPriorityFactor(double priorityFactor) {
468 3 : myPriorityFactor = priorityFactor;
469 : double maxEdgePriority = -std::numeric_limits<double>::max();
470 57 : for (ROEdge* edge : myEdges) {
471 54 : maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
472 97 : myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
473 : }
474 3 : myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
475 3 : if (myEdgePriorityRange == 0) {
476 1 : WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
477 1 : myPriorityFactor = 0;
478 1 : return false;
479 : }
480 : return true;
481 : }
482 :
483 :
484 : /****************************************************************************/
|