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 473818 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority) :
58 : Named(id),
59 473818 : myFromJunction(from),
60 473818 : myToJunction(to),
61 473818 : myIndex(index),
62 473818 : myPriority(priority),
63 473818 : mySpeed(-1),
64 473818 : myLength(0),
65 473818 : myAmSink(false),
66 473818 : myAmSource(false),
67 473818 : myUsingTTTimeLine(false),
68 473818 : myUsingETimeLine(false),
69 473818 : myCombinedPermissions(0),
70 473818 : myOtherTazConnector(nullptr),
71 473818 : myTimePenalty(0) {
72 947636 : while ((int)myEdges.size() <= index) {
73 473818 : myEdges.push_back(0);
74 : }
75 473818 : myEdges[index] = this;
76 473818 : if (from == nullptr && to == nullptr) {
77 : // TAZ edge, no lanes
78 27648 : myCombinedPermissions = SVCAll;
79 : } else {
80 : // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
81 446170 : myBoundary.add(from->getPosition());
82 446170 : myBoundary.add(to->getPosition());
83 : }
84 473818 : }
85 :
86 :
87 931595 : ROEdge::~ROEdge() {
88 1063143 : for (ROLane* const lane : myLanes) {
89 591985 : delete lane;
90 : }
91 471158 : delete myReversedRoutingEdge;
92 471158 : delete myFlippedRoutingEdge;
93 471158 : delete myRailwayRoutingEdge;
94 1873911 : }
95 :
96 :
97 : void
98 595475 : ROEdge::addLane(ROLane* lane) {
99 595475 : const double speed = lane->getSpeed();
100 595475 : if (speed > mySpeed) {
101 446484 : mySpeed = speed;
102 446484 : myLength = lane->getLength();
103 : }
104 595475 : mySpeed = speed > mySpeed ? speed : mySpeed;
105 595475 : myLanes.push_back(lane);
106 :
107 : // integrate new allowed classes
108 595475 : myCombinedPermissions |= lane->getPermissions();
109 595475 : }
110 :
111 :
112 : void
113 1073936 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
114 1073936 : if (isInternal()) {
115 : // for internal edges after an internal junction,
116 : // this is called twice and only the second call counts
117 : myFollowingEdges.clear();
118 : myFollowingViaEdges.clear();
119 : }
120 1073936 : if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
121 1015403 : myFollowingEdges.push_back(s);
122 1015403 : myFollowingViaEdges.push_back(std::make_pair(s, via));
123 1015403 : if (isTazConnector() && s->getFromJunction() != nullptr) {
124 21765 : myBoundary.add(s->getFromJunction()->getPosition());
125 : }
126 1015403 : if (!isInternal()) {
127 368893 : s->myApproachingEdges.push_back(this);
128 368893 : if (s->isTazConnector() && getToJunction() != nullptr) {
129 21766 : s->myBoundary.add(getToJunction()->getPosition());
130 : }
131 : }
132 1015403 : if (via != nullptr) {
133 265335 : if (via->myApproachingEdges.size() == 0) {
134 265174 : via->myApproachingEdges.push_back(this);
135 : }
136 : }
137 : }
138 1073936 : }
139 :
140 :
141 : void
142 189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
143 189 : myEfforts.add(timeBegin, timeEnd, value);
144 189 : myUsingETimeLine = true;
145 189 : }
146 :
147 :
148 : void
149 246660 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
150 246660 : myTravelTimes.add(timeBegin, timeEnd, value);
151 246660 : myUsingTTTimeLine = true;
152 246660 : }
153 :
154 :
155 : double
156 0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
157 0 : double ret = 0;
158 0 : if (!getStoredEffort(time, ret)) {
159 0 : return myLength / MIN2(veh->getMaxSpeed(), mySpeed) + myTimePenalty;
160 : }
161 0 : return ret;
162 : }
163 :
164 :
165 : double
166 43280 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
167 : assert(this != other);
168 43280 : if (doBoundaryEstimate) {
169 10040 : return myBoundary.distanceTo2D(other->myBoundary);
170 : }
171 : if (isTazConnector()) {
172 94 : if (other->isTazConnector()) {
173 84 : return myBoundary.distanceTo2D(other->myBoundary);
174 : }
175 10 : return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
176 : }
177 33146 : if (other->isTazConnector()) {
178 619 : return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
179 : }
180 32527 : return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
181 : //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
182 : }
183 :
184 :
185 : bool
186 26618 : ROEdge::hasLoadedTravelTime(double time) const {
187 26618 : return myUsingTTTimeLine && myTravelTimes.describesTime(time);
188 : }
189 :
190 :
191 : double
192 11031303 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
193 11031303 : if (myUsingTTTimeLine) {
194 4294448 : if (myTravelTimes.describesTime(time)) {
195 4285690 : double lineTT = myTravelTimes.getValue(time);
196 4285690 : if (myInterpolate) {
197 : const double inTT = lineTT;
198 68 : const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
199 68 : if (split >= 0) {
200 18 : lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
201 : }
202 : }
203 4285690 : return MAX2(getMinimumTravelTime(veh), lineTT);
204 : } else {
205 8758 : if (!myHaveTTWarned) {
206 0 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
207 0 : myHaveTTWarned = true;
208 : }
209 : }
210 : }
211 6745613 : const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter()[0] * mySpeed) : mySpeed;
212 6745613 : return myLength / speed + myTimePenalty;
213 : }
214 :
215 :
216 : double
217 0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
218 0 : double ret = 0;
219 0 : if (!edge->getStoredEffort(time, ret)) {
220 0 : const double v = MIN2(veh->getMaxSpeed(), edge->mySpeed);
221 0 : ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 0);
222 : }
223 0 : return ret;
224 : }
225 :
226 :
227 : bool
228 1656 : ROEdge::getStoredEffort(double time, double& ret) const {
229 1656 : if (myUsingETimeLine) {
230 190 : if (!myEfforts.describesTime(time)) {
231 0 : if (!myHaveEWarned) {
232 0 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
233 0 : myHaveEWarned = true;
234 : }
235 0 : return false;
236 : }
237 190 : if (myInterpolate) {
238 0 : const double inTT = myTravelTimes.getValue(time);
239 0 : const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
240 0 : if (ratio >= 0.) {
241 0 : ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
242 0 : return true;
243 : }
244 : }
245 190 : ret = myEfforts.getValue(time);
246 190 : return true;
247 : }
248 : return false;
249 : }
250 :
251 :
252 : int
253 16474 : ROEdge::getNumSuccessors() const {
254 16474 : if (myAmSink) {
255 : return 0;
256 : }
257 16474 : return (int) myFollowingEdges.size();
258 : }
259 :
260 :
261 : int
262 12352 : ROEdge::getNumPredecessors() const {
263 12352 : if (myAmSource) {
264 : return 0;
265 : }
266 12352 : return (int) myApproachingEdges.size();
267 : }
268 :
269 :
270 : const ROEdge*
271 16 : ROEdge::getNormalBefore() const {
272 : const ROEdge* result = this;
273 40 : while (result->isInternal()) {
274 : assert(myApproachingEdges.size() == 1);
275 24 : result = result->myApproachingEdges.front();
276 : }
277 16 : return result;
278 : }
279 :
280 :
281 :
282 : const ROEdge*
283 8 : ROEdge::getNormalAfter() const {
284 : const ROEdge* result = this;
285 16 : while (result->isInternal()) {
286 : assert(myFollowingEdges.size() == 1);
287 8 : result = result->myFollowingEdges.front();
288 : }
289 8 : return result;
290 : }
291 :
292 :
293 : void
294 4892 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
295 4892 : if (myUsingETimeLine) {
296 147 : double value = myLength / mySpeed;
297 147 : const SUMOEmissionClass c = PollutantsInterface::getClassByName("unknown");
298 147 : if (measure == "CO") {
299 26 : value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
300 : }
301 147 : if (measure == "CO2") {
302 19 : value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
303 : }
304 147 : if (measure == "HC") {
305 26 : value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
306 : }
307 147 : if (measure == "PMx") {
308 19 : value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
309 : }
310 147 : if (measure == "NOx") {
311 19 : value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
312 : }
313 147 : if (measure == "fuel") {
314 19 : value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
315 : }
316 147 : if (measure == "electricity") {
317 0 : value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
318 : }
319 147 : myEfforts.fillGaps(value, boundariesOverride);
320 : }
321 4892 : if (myUsingTTTimeLine) {
322 3519 : myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
323 : }
324 4892 : }
325 :
326 :
327 : void
328 224 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
329 448 : for (const std::string& key : restrictionKeys) {
330 224 : const std::string value = getParameter(key, "1e40");
331 224 : myParamRestrictions.push_back(StringUtils::toDouble(value));
332 : }
333 224 : }
334 :
335 :
336 : double
337 111808 : ROEdge::getLengthGeometryFactor() const {
338 111808 : return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
339 : }
340 :
341 :
342 : bool
343 326880 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
344 326880 : for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
345 653760 : if (!(*i)->prohibits(vehicle)) {
346 : return false;
347 : }
348 : }
349 : return true;
350 : }
351 :
352 :
353 : const ROEdgeVector&
354 13211 : ROEdge::getAllEdges() {
355 13211 : return myEdges;
356 : }
357 :
358 :
359 : const Position
360 1371 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
361 1371 : const double middle = (stop.endPos + stop.startPos) / 2.;
362 4113 : const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
363 1371 : return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
364 : }
365 :
366 :
367 : const ROEdgeVector&
368 1260012 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
369 1260012 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
370 1240502 : return myFollowingEdges;
371 : }
372 : #ifdef HAVE_FOX
373 19510 : FXMutexLock locker(myLock);
374 : #endif
375 : std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
376 19510 : if (i != myClassesSuccessorMap.end()) {
377 : // can use cached value
378 17296 : return i->second;
379 : }
380 : // this vClass is requested for the first time. rebuild all successors
381 : std::set<ROEdge*> followers;
382 6240 : for (const ROLane* const lane : myLanes) {
383 4026 : if ((lane->getPermissions() & vClass) != 0) {
384 8267 : for (const auto& next : lane->getOutgoingViaLanes()) {
385 4776 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
386 4459 : followers.insert(&next.first->getEdge());
387 : }
388 : }
389 : }
390 : }
391 : // also add district edges (they are not connected at the lane level
392 6965 : for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
393 4751 : if ((*it)->isTazConnector()) {
394 : followers.insert(*it);
395 : }
396 : }
397 2214 : myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
398 : followers.begin(), followers.end());
399 2214 : return myClassesSuccessorMap[vClass];
400 : }
401 :
402 :
403 : const ROConstEdgePairVector&
404 8453140 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
405 8453140 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
406 8009097 : return myFollowingViaEdges;
407 : }
408 : #ifdef HAVE_FOX
409 444043 : FXMutexLock locker(myLock);
410 : #endif
411 : std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
412 444043 : if (i != myClassesViaSuccessorMap.end()) {
413 : // can use cached value
414 431141 : return i->second;
415 : }
416 : // this vClass is requested for the first time. rebuild all successors
417 : std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
418 34173 : for (const ROLane* const lane : myLanes) {
419 21271 : if ((lane->getPermissions() & vClass) != 0) {
420 41581 : for (const auto& next : lane->getOutgoingViaLanes()) {
421 25235 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
422 22524 : followers.insert(std::make_pair(&next.first->getEdge(), next.second));
423 : }
424 : }
425 : }
426 : }
427 : // also add district edges (they are not connected at the lane level
428 40123 : for (const ROEdge* e : myFollowingEdges) {
429 27221 : if (e->isTazConnector()) {
430 220 : followers.insert(std::make_pair(e, e));
431 : }
432 : }
433 12902 : myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
434 : followers.begin(), followers.end());
435 12902 : return myClassesViaSuccessorMap[vClass];
436 : }
437 :
438 :
439 : bool
440 170607 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass) const {
441 170607 : const ROEdgeVector& followers = getSuccessors(vClass);
442 170607 : return std::find(followers.begin(), followers.end(), &e) != followers.end();
443 : }
444 :
445 : bool
446 3 : ROEdge::initPriorityFactor(double priorityFactor) {
447 3 : myPriorityFactor = priorityFactor;
448 : double maxEdgePriority = -std::numeric_limits<double>::max();
449 57 : for (ROEdge* edge : myEdges) {
450 54 : maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
451 97 : myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
452 : }
453 3 : myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
454 3 : if (myEdgePriorityRange == 0) {
455 1 : WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
456 1 : myPriorityFactor = 0;
457 1 : return false;
458 : }
459 : return true;
460 : }
461 :
462 :
463 : /****************************************************************************/
|