Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file 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 478868 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority) :
58 : Named(id),
59 478868 : myFromJunction(from),
60 478868 : myToJunction(to),
61 478868 : myIndex(index),
62 478868 : myPriority(priority),
63 478868 : mySpeed(-1),
64 478868 : myLength(0),
65 478868 : myAmSink(false),
66 478868 : myAmSource(false),
67 478868 : myUsingTTTimeLine(false),
68 478868 : myUsingETimeLine(false),
69 478868 : myCombinedPermissions(0),
70 478868 : myOtherTazConnector(nullptr),
71 478868 : myTimePenalty(0) {
72 957736 : while ((int)myEdges.size() <= index) {
73 478868 : myEdges.push_back(0);
74 : }
75 478868 : myEdges[index] = this;
76 478868 : if (from == nullptr && to == nullptr) {
77 : // TAZ edge, no lanes
78 27714 : myCombinedPermissions = SVCAll;
79 : } else {
80 : // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
81 451154 : myBoundary.add(from->getPosition());
82 451154 : myBoundary.add(to->getPosition());
83 : }
84 478868 : }
85 :
86 :
87 13 : ROEdge::ROEdge(const std::string& id, const RONode* from, const RONode* to, SVCPermissions p) :
88 : Named(id),
89 13 : myFromJunction(const_cast<RONode*>(from)),
90 13 : myToJunction(const_cast<RONode*>(to)),
91 13 : myIndex(-1),
92 13 : myPriority(0),
93 13 : mySpeed(std::numeric_limits<double>::max()),
94 13 : myLength(0),
95 13 : myAmSink(false),
96 13 : myAmSource(false),
97 13 : myUsingTTTimeLine(false),
98 13 : myUsingETimeLine(false),
99 13 : myCombinedPermissions(p),
100 13 : myOtherTazConnector(nullptr),
101 13 : myTimePenalty(0)
102 13 : { }
103 :
104 :
105 941654 : ROEdge::~ROEdge() {
106 1074094 : for (ROLane* const lane : myLanes) {
107 597886 : delete lane;
108 : }
109 476208 : delete myReversedRoutingEdge;
110 476208 : delete myFlippedRoutingEdge;
111 476208 : delete myRailwayRoutingEdge;
112 1894070 : }
113 :
114 :
115 : void
116 601376 : ROEdge::addLane(ROLane* lane) {
117 601376 : const double speed = lane->getSpeed();
118 601376 : if (speed > mySpeed) {
119 451480 : mySpeed = speed;
120 451480 : myLength = lane->getLength();
121 : }
122 601376 : mySpeed = speed > mySpeed ? speed : mySpeed;
123 601376 : myLanes.push_back(lane);
124 :
125 : // integrate new allowed classes
126 601376 : myCombinedPermissions |= lane->getPermissions();
127 601376 : }
128 :
129 :
130 : void
131 1084485 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
132 1084485 : if (isInternal()) {
133 : // for internal edges after an internal junction,
134 : // this is called twice and only the second call counts
135 : myFollowingEdges.clear();
136 : myFollowingViaEdges.clear();
137 : }
138 1084485 : if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
139 1025553 : myFollowingEdges.push_back(s);
140 1025553 : myFollowingViaEdges.push_back(std::make_pair(s, via));
141 1025553 : if (isTazConnector() && s->getFromJunction() != nullptr) {
142 21842 : myBoundary.add(s->getFromJunction()->getPosition());
143 : }
144 1025553 : if (!isInternal()) {
145 373405 : s->myApproachingEdges.push_back(this);
146 373405 : if (s->isTazConnector() && getToJunction() != nullptr) {
147 21843 : s->myBoundary.add(getToJunction()->getPosition());
148 : }
149 : }
150 1025553 : if (via != nullptr) {
151 267680 : if (via->myApproachingEdges.size() == 0) {
152 267491 : via->myApproachingEdges.push_back(this);
153 : }
154 : }
155 : }
156 1084485 : }
157 :
158 :
159 : void
160 189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
161 189 : myEfforts.add(timeBegin, timeEnd, value);
162 189 : myUsingETimeLine = true;
163 189 : }
164 :
165 :
166 : void
167 246881 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
168 246881 : myTravelTimes.add(timeBegin, timeEnd, value);
169 246881 : myUsingTTTimeLine = true;
170 246881 : }
171 :
172 :
173 : double
174 0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
175 0 : double ret = 0;
176 0 : if (!getStoredEffort(time, ret)) {
177 0 : return myLength / MIN2(veh->getMaxSpeed(), mySpeed) + myTimePenalty;
178 : }
179 0 : return ret;
180 : }
181 :
182 :
183 : double
184 43896 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
185 : assert(this != other);
186 43896 : if (doBoundaryEstimate) {
187 10057 : return myBoundary.distanceTo2D(other->myBoundary);
188 : }
189 33839 : if (isTazConnector()) {
190 116 : if (other->isTazConnector()) {
191 106 : return myBoundary.distanceTo2D(other->myBoundary);
192 : }
193 10 : return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
194 : }
195 33723 : if (other->isTazConnector()) {
196 647 : return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
197 : }
198 33076 : return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
199 : //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
200 : }
201 :
202 :
203 : bool
204 26659 : ROEdge::hasLoadedTravelTime(double time) const {
205 26659 : return myUsingTTTimeLine && myTravelTimes.describesTime(time);
206 : }
207 :
208 :
209 : double
210 11119965 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
211 11119965 : if (myUsingTTTimeLine) {
212 4311129 : if (myTravelTimes.describesTime(time)) {
213 4302071 : double lineTT = myTravelTimes.getValue(time);
214 4302071 : if (myInterpolate) {
215 : const double inTT = lineTT;
216 68 : const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
217 68 : if (split >= 0) {
218 18 : lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
219 : }
220 : }
221 4302071 : return MAX2(getMinimumTravelTime(veh), lineTT);
222 : } else {
223 9058 : if (!myHaveTTWarned) {
224 3 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
225 1 : myHaveTTWarned = true;
226 : }
227 : }
228 : }
229 6817894 : const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter()[0] * mySpeed) : mySpeed;
230 6817894 : return myLength / speed + myTimePenalty;
231 : }
232 :
233 :
234 : double
235 0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
236 0 : double ret = 0;
237 0 : if (!edge->getStoredEffort(time, ret)) {
238 0 : const double v = MIN2(veh->getMaxSpeed(), edge->mySpeed);
239 0 : ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 0);
240 : }
241 0 : return ret;
242 : }
243 :
244 :
245 : bool
246 1656 : ROEdge::getStoredEffort(double time, double& ret) const {
247 1656 : if (myUsingETimeLine) {
248 190 : if (!myEfforts.describesTime(time)) {
249 0 : if (!myHaveEWarned) {
250 0 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
251 0 : myHaveEWarned = true;
252 : }
253 0 : return false;
254 : }
255 190 : if (myInterpolate) {
256 0 : const double inTT = myTravelTimes.getValue(time);
257 0 : const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
258 0 : if (ratio >= 0.) {
259 0 : ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
260 0 : return true;
261 : }
262 : }
263 190 : ret = myEfforts.getValue(time);
264 190 : return true;
265 : }
266 : return false;
267 : }
268 :
269 :
270 : int
271 16484 : ROEdge::getNumSuccessors() const {
272 16484 : if (myAmSink) {
273 : return 0;
274 : }
275 16484 : return (int) myFollowingEdges.size();
276 : }
277 :
278 :
279 : int
280 12362 : ROEdge::getNumPredecessors() const {
281 12362 : if (myAmSource) {
282 : return 0;
283 : }
284 12362 : return (int) myApproachingEdges.size();
285 : }
286 :
287 :
288 : const ROEdge*
289 16 : ROEdge::getNormalBefore() const {
290 : const ROEdge* result = this;
291 40 : while (result->isInternal()) {
292 : assert(myApproachingEdges.size() == 1);
293 24 : result = result->myApproachingEdges.front();
294 : }
295 16 : return result;
296 : }
297 :
298 :
299 :
300 : const ROEdge*
301 8 : ROEdge::getNormalAfter() const {
302 : const ROEdge* result = this;
303 16 : while (result->isInternal()) {
304 : assert(myFollowingEdges.size() == 1);
305 8 : result = result->myFollowingEdges.front();
306 : }
307 8 : return result;
308 : }
309 :
310 :
311 : void
312 4927 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
313 4927 : if (myUsingETimeLine) {
314 147 : double value = myLength / mySpeed;
315 147 : const SUMOEmissionClass c = PollutantsInterface::getClassByName("unknown");
316 147 : if (measure == "CO") {
317 26 : value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
318 : }
319 147 : if (measure == "CO2") {
320 19 : value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
321 : }
322 147 : if (measure == "HC") {
323 26 : value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
324 : }
325 147 : if (measure == "PMx") {
326 19 : value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
327 : }
328 147 : if (measure == "NOx") {
329 19 : value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
330 : }
331 147 : if (measure == "fuel") {
332 19 : value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
333 : }
334 147 : if (measure == "electricity") {
335 0 : value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
336 : }
337 147 : myEfforts.fillGaps(value, boundariesOverride);
338 : }
339 4927 : if (myUsingTTTimeLine) {
340 3542 : myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
341 : }
342 4927 : }
343 :
344 :
345 : void
346 224 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
347 448 : for (const std::string& key : restrictionKeys) {
348 224 : const std::string value = getParameter(key, "1e40");
349 224 : myParamRestrictions.push_back(StringUtils::toDouble(value));
350 : }
351 224 : }
352 :
353 :
354 : double
355 118409 : ROEdge::getLengthGeometryFactor() const {
356 118409 : return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
357 : }
358 :
359 :
360 : bool
361 326880 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
362 326880 : for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
363 653760 : if (!(*i)->prohibits(vehicle)) {
364 : return false;
365 : }
366 : }
367 : return true;
368 : }
369 :
370 :
371 : const ROEdgeVector&
372 13355 : ROEdge::getAllEdges() {
373 13355 : return myEdges;
374 : }
375 :
376 :
377 : const Position
378 1371 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
379 1371 : const double middle = (stop.endPos + stop.startPos) / 2.;
380 4113 : const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
381 1371 : return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
382 : }
383 :
384 :
385 : const ROEdgeVector&
386 1265154 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
387 1265154 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
388 1242654 : return myFollowingEdges;
389 : }
390 : #ifdef HAVE_FOX
391 22500 : FXMutexLock locker(myLock);
392 : #endif
393 : std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
394 22500 : if (i != myClassesSuccessorMap.end()) {
395 : // can use cached value
396 19764 : return i->second;
397 : }
398 : // this vClass is requested for the first time. rebuild all successors
399 : std::set<ROEdge*> followers;
400 7516 : for (const ROLane* const lane : myLanes) {
401 4780 : if ((lane->getPermissions() & vClass) != 0) {
402 10291 : for (const auto& next : lane->getOutgoingViaLanes()) {
403 6060 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
404 5703 : followers.insert(&next.first->getEdge());
405 : }
406 : }
407 : }
408 : }
409 : // also add district edges (they are not connected at the lane level
410 8603 : for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
411 5867 : if ((*it)->isTazConnector()) {
412 : followers.insert(*it);
413 : }
414 : }
415 2736 : myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
416 : followers.begin(), followers.end());
417 2736 : return myClassesSuccessorMap[vClass];
418 : }
419 :
420 :
421 : const ROConstEdgePairVector&
422 8520976 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
423 8520976 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
424 8024822 : return myFollowingViaEdges;
425 : }
426 : #ifdef HAVE_FOX
427 496154 : FXMutexLock locker(myLock);
428 : #endif
429 : std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
430 496154 : if (i != myClassesViaSuccessorMap.end()) {
431 : // can use cached value
432 482376 : return i->second;
433 : }
434 : // this vClass is requested for the first time. rebuild all successors
435 : std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
436 36024 : for (const ROLane* const lane : myLanes) {
437 22246 : if ((lane->getPermissions() & vClass) != 0) {
438 44165 : for (const auto& next : lane->getOutgoingViaLanes()) {
439 26906 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
440 24126 : followers.insert(std::make_pair(&next.first->getEdge(), next.second));
441 : }
442 : }
443 : }
444 : }
445 : // also add district edges (they are not connected at the lane level
446 42841 : for (const ROEdge* e : myFollowingEdges) {
447 29063 : if (e->isTazConnector()) {
448 288 : followers.insert(std::make_pair(e, e));
449 : }
450 : }
451 13778 : myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
452 : followers.begin(), followers.end());
453 13778 : return myClassesViaSuccessorMap[vClass];
454 : }
455 :
456 :
457 : bool
458 173693 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass) const {
459 173693 : const ROEdgeVector& followers = getSuccessors(vClass);
460 173693 : return std::find(followers.begin(), followers.end(), &e) != followers.end();
461 : }
462 :
463 : bool
464 3 : ROEdge::initPriorityFactor(double priorityFactor) {
465 3 : myPriorityFactor = priorityFactor;
466 : double maxEdgePriority = -std::numeric_limits<double>::max();
467 57 : for (ROEdge* edge : myEdges) {
468 54 : maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
469 97 : myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
470 : }
471 3 : myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
472 3 : if (myEdgePriorityRange == 0) {
473 1 : WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
474 1 : myPriorityFactor = 0;
475 1 : return false;
476 : }
477 : return true;
478 : }
479 :
480 :
481 : /****************************************************************************/
|