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 : /// @date Sept 2002
22 : ///
23 : // A basic edge for routing applications
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/ToString.h>
29 : #include <algorithm>
30 : #include <cassert>
31 : #include <iostream>
32 : #include <utils/vehicle/SUMOVTypeParameter.h>
33 : #include <utils/emissions/PollutantsInterface.h>
34 : #include <utils/emissions/HelpersHarmonoise.h>
35 : #include "ROLane.h"
36 : #include "RONet.h"
37 : #include "ROVehicle.h"
38 : #include "ROEdge.h"
39 :
40 :
41 : // ===========================================================================
42 : // static member definitions
43 : // ===========================================================================
44 : bool ROEdge::myInterpolate = false;
45 : bool ROEdge::myHaveTTWarned = false;
46 : bool ROEdge::myHaveEWarned = false;
47 : ROEdgeVector ROEdge::myEdges;
48 : double ROEdge::myPriorityFactor(0);
49 : double ROEdge::myMinEdgePriority(std::numeric_limits<double>::max());
50 : double ROEdge::myEdgePriorityRange(0);
51 :
52 :
53 : // ===========================================================================
54 : // method definitions
55 : // ===========================================================================
56 311257 : ROEdge::ROEdge(const std::string& id, RONode* from, RONode* to, int index, const int priority) :
57 : Named(id),
58 311257 : myFromJunction(from),
59 311257 : myToJunction(to),
60 311257 : myIndex(index),
61 311257 : myPriority(priority),
62 311257 : mySpeed(-1),
63 311257 : myLength(0),
64 311257 : myAmSink(false),
65 311257 : myAmSource(false),
66 311257 : myUsingTTTimeLine(false),
67 311257 : myUsingETimeLine(false),
68 311257 : myCombinedPermissions(0),
69 311257 : myOtherTazConnector(nullptr),
70 311257 : myTimePenalty(0) {
71 622514 : while ((int)myEdges.size() <= index) {
72 311257 : myEdges.push_back(0);
73 : }
74 311257 : myEdges[index] = this;
75 311257 : if (from == nullptr && to == nullptr) {
76 : // TAZ edge, no lanes
77 2410 : myCombinedPermissions = SVCAll;
78 : } else {
79 : // TODO we should not calculate the boundary here, the position for the nodes is not valid yet
80 308847 : myBoundary.add(from->getPosition());
81 308847 : myBoundary.add(to->getPosition());
82 : }
83 311257 : }
84 :
85 :
86 602730 : ROEdge::~ROEdge() {
87 657033 : for (ROLane* const lane : myLanes) {
88 348436 : delete lane;
89 : }
90 308597 : delete myReversedRoutingEdge;
91 308597 : delete myRailwayRoutingEdge;
92 1219924 : }
93 :
94 :
95 : void
96 351926 : ROEdge::addLane(ROLane* lane) {
97 351926 : const double speed = lane->getSpeed();
98 351926 : if (speed > mySpeed) {
99 309349 : mySpeed = speed;
100 309349 : myLength = lane->getLength();
101 : }
102 351926 : mySpeed = speed > mySpeed ? speed : mySpeed;
103 351926 : myLanes.push_back(lane);
104 :
105 : // integrate new allowed classes
106 351926 : myCombinedPermissions |= lane->getPermissions();
107 351926 : }
108 :
109 :
110 : void
111 605308 : ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
112 605308 : if (isInternal()) {
113 : // for internal edges after an internal junction,
114 : // this is called twice and only the second call counts
115 : myFollowingEdges.clear();
116 : myFollowingViaEdges.clear();
117 : }
118 605308 : if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
119 590225 : myFollowingEdges.push_back(s);
120 590225 : myFollowingViaEdges.push_back(std::make_pair(s, via));
121 590225 : if (isTazConnector() && s->getFromJunction() != nullptr) {
122 2607 : myBoundary.add(s->getFromJunction()->getPosition());
123 : }
124 590225 : if (!isInternal()) {
125 283743 : s->myApproachingEdges.push_back(this);
126 283743 : if (s->isTazConnector() && getToJunction() != nullptr) {
127 2608 : s->myBoundary.add(getToJunction()->getPosition());
128 : }
129 : }
130 590225 : if (via != nullptr) {
131 138242 : if (via->myApproachingEdges.size() == 0) {
132 138242 : via->myApproachingEdges.push_back(this);
133 : }
134 : }
135 : }
136 605308 : }
137 :
138 :
139 : void
140 189 : ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
141 189 : myEfforts.add(timeBegin, timeEnd, value);
142 189 : myUsingETimeLine = true;
143 189 : }
144 :
145 :
146 : void
147 250836 : ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
148 250836 : myTravelTimes.add(timeBegin, timeEnd, value);
149 250836 : myUsingTTTimeLine = true;
150 250836 : }
151 :
152 :
153 : double
154 0 : ROEdge::getEffort(const ROVehicle* const veh, double time) const {
155 0 : double ret = 0;
156 0 : if (!getStoredEffort(time, ret)) {
157 0 : return myLength / MIN2(veh->getMaxSpeed(), mySpeed) + myTimePenalty;
158 : }
159 0 : return ret;
160 : }
161 :
162 :
163 : double
164 42845 : ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
165 : assert(this != other);
166 42845 : if (doBoundaryEstimate) {
167 9377 : return myBoundary.distanceTo2D(other->myBoundary);
168 : }
169 : if (isTazConnector()) {
170 88 : if (other->isTazConnector()) {
171 79 : return myBoundary.distanceTo2D(other->myBoundary);
172 : }
173 9 : return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
174 : }
175 33380 : if (other->isTazConnector()) {
176 615 : return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
177 : }
178 32765 : return getLanes()[0]->getShape()[-1].distanceTo2D(other->getLanes()[0]->getShape()[0]);
179 : //return getToJunction()->getPosition().distanceTo2D(other->getFromJunction()->getPosition());
180 : }
181 :
182 :
183 : bool
184 26607 : ROEdge::hasLoadedTravelTime(double time) const {
185 26607 : return myUsingTTTimeLine && myTravelTimes.describesTime(time);
186 : }
187 :
188 :
189 : double
190 18062910 : ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
191 18062910 : if (myUsingTTTimeLine) {
192 8147245 : if (myTravelTimes.describesTime(time)) {
193 8136459 : double lineTT = myTravelTimes.getValue(time);
194 8136459 : if (myInterpolate) {
195 : const double inTT = lineTT;
196 68 : const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
197 68 : if (split >= 0) {
198 18 : lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
199 : }
200 : }
201 8136459 : return MAX2(getMinimumTravelTime(veh), lineTT);
202 : } else {
203 10786 : if (!myHaveTTWarned) {
204 6 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
205 2 : myHaveTTWarned = true;
206 : }
207 : }
208 : }
209 9926451 : const double speed = veh != nullptr ? MIN2(veh->getMaxSpeed(), veh->getType()->speedFactor.getParameter()[0] * mySpeed) : mySpeed;
210 9926451 : return myLength / speed + myTimePenalty;
211 : }
212 :
213 :
214 : double
215 0 : ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
216 0 : double ret = 0;
217 0 : if (!edge->getStoredEffort(time, ret)) {
218 0 : const double v = MIN2(veh->getMaxSpeed(), edge->mySpeed);
219 0 : ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, v, 0);
220 : }
221 0 : return ret;
222 : }
223 :
224 :
225 : bool
226 1736 : ROEdge::getStoredEffort(double time, double& ret) const {
227 1736 : if (myUsingETimeLine) {
228 190 : if (!myEfforts.describesTime(time)) {
229 0 : if (!myHaveEWarned) {
230 0 : WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
231 0 : myHaveEWarned = true;
232 : }
233 0 : return false;
234 : }
235 190 : if (myInterpolate) {
236 0 : const double inTT = myTravelTimes.getValue(time);
237 0 : const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
238 0 : if (ratio >= 0.) {
239 0 : ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
240 0 : return true;
241 : }
242 : }
243 190 : ret = myEfforts.getValue(time);
244 190 : return true;
245 : }
246 : return false;
247 : }
248 :
249 :
250 : int
251 26040 : ROEdge::getNumSuccessors() const {
252 26040 : if (myAmSink) {
253 : return 0;
254 : }
255 26040 : return (int) myFollowingEdges.size();
256 : }
257 :
258 :
259 : int
260 21918 : ROEdge::getNumPredecessors() const {
261 21918 : if (myAmSource) {
262 : return 0;
263 : }
264 21918 : return (int) myApproachingEdges.size();
265 : }
266 :
267 :
268 : const ROEdge*
269 16 : ROEdge::getNormalBefore() const {
270 : const ROEdge* result = this;
271 40 : while (result->isInternal()) {
272 : assert(myApproachingEdges.size() == 1);
273 24 : result = result->myApproachingEdges.front();
274 : }
275 16 : return result;
276 : }
277 :
278 :
279 :
280 : const ROEdge*
281 8 : ROEdge::getNormalAfter() const {
282 : const ROEdge* result = this;
283 16 : while (result->isInternal()) {
284 : assert(myFollowingEdges.size() == 1);
285 8 : result = result->myFollowingEdges.front();
286 : }
287 8 : return result;
288 : }
289 :
290 :
291 : void
292 9023 : ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
293 9023 : if (myUsingETimeLine) {
294 147 : double value = myLength / mySpeed;
295 294 : const SUMOEmissionClass c = PollutantsInterface::getClassByName("unknown");
296 147 : if (measure == "CO") {
297 26 : value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
298 : }
299 147 : if (measure == "CO2") {
300 19 : value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
301 : }
302 147 : if (measure == "HC") {
303 26 : value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
304 : }
305 147 : if (measure == "PMx") {
306 19 : value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
307 : }
308 147 : if (measure == "NOx") {
309 19 : value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
310 : }
311 147 : if (measure == "fuel") {
312 19 : value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
313 : }
314 147 : if (measure == "electricity") {
315 0 : value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
316 : }
317 147 : myEfforts.fillGaps(value, boundariesOverride);
318 : }
319 9023 : if (myUsingTTTimeLine) {
320 6410 : myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
321 : }
322 9023 : }
323 :
324 :
325 : void
326 224 : ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
327 448 : for (const std::string& key : restrictionKeys) {
328 224 : const std::string value = getParameter(key, "1e40");
329 224 : myParamRestrictions.push_back(StringUtils::toDouble(value));
330 : }
331 224 : }
332 :
333 :
334 : double
335 114812 : ROEdge::getLengthGeometryFactor() const {
336 114812 : return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
337 : }
338 :
339 :
340 : bool
341 644099 : ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
342 644099 : for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
343 1288198 : if (!(*i)->prohibits(vehicle)) {
344 : return false;
345 : }
346 : }
347 : return true;
348 : }
349 :
350 :
351 : const ROEdgeVector&
352 6714 : ROEdge::getAllEdges() {
353 6714 : return myEdges;
354 : }
355 :
356 :
357 : const Position
358 1702 : ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
359 1702 : const double middle = (stop.endPos + stop.startPos) / 2.;
360 5106 : const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
361 1702 : return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
362 : }
363 :
364 :
365 : const ROEdgeVector&
366 2355163 : ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
367 2355163 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
368 2325279 : return myFollowingEdges;
369 : }
370 : #ifdef HAVE_FOX
371 29884 : FXMutexLock locker(myLock);
372 : #endif
373 : std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
374 29884 : if (i != myClassesSuccessorMap.end()) {
375 : // can use cached value
376 26843 : return i->second;
377 : }
378 : // this vClass is requested for the first time. rebuild all successors
379 : std::set<ROEdge*> followers;
380 8848 : for (const ROLane* const lane : myLanes) {
381 5807 : if ((lane->getPermissions() & vClass) != 0) {
382 11824 : for (const auto& next : lane->getOutgoingViaLanes()) {
383 7075 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
384 6556 : followers.insert(&next.first->getEdge());
385 : }
386 : }
387 : }
388 : }
389 : // also add district edges (they are not connected at the lane level
390 10097 : for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
391 7056 : if ((*it)->isTazConnector()) {
392 : followers.insert(*it);
393 : }
394 : }
395 3041 : myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
396 : followers.begin(), followers.end());
397 3041 : return myClassesSuccessorMap[vClass];
398 : }
399 :
400 :
401 : const ROConstEdgePairVector&
402 12980590 : ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
403 12980590 : if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
404 12117931 : return myFollowingViaEdges;
405 : }
406 : #ifdef HAVE_FOX
407 862659 : FXMutexLock locker(myLock);
408 : #endif
409 : std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
410 862659 : if (i != myClassesViaSuccessorMap.end()) {
411 : // can use cached value
412 843651 : return i->second;
413 : }
414 : // this vClass is requested for the first time. rebuild all successors
415 : std::set<std::pair<const ROEdge*, const ROEdge*> > followers;
416 52130 : for (const ROLane* const lane : myLanes) {
417 33122 : if ((lane->getPermissions() & vClass) != 0) {
418 64740 : for (const auto& next : lane->getOutgoingViaLanes()) {
419 41181 : if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
420 36174 : followers.insert(std::make_pair(&next.first->getEdge(), next.second));
421 : }
422 : }
423 : }
424 : }
425 : // also add district edges (they are not connected at the lane level
426 64632 : for (const ROEdge* e : myFollowingEdges) {
427 45624 : if (e->isTazConnector()) {
428 192 : followers.insert(std::make_pair(e, e));
429 : }
430 : }
431 19008 : myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
432 : followers.begin(), followers.end());
433 19008 : return myClassesViaSuccessorMap[vClass];
434 : }
435 :
436 :
437 : bool
438 305391 : ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass) const {
439 305391 : const ROEdgeVector& followers = getSuccessors(vClass);
440 305391 : return std::find(followers.begin(), followers.end(), &e) != followers.end();
441 : }
442 :
443 : bool
444 3 : ROEdge::initPriorityFactor(double priorityFactor) {
445 3 : myPriorityFactor = priorityFactor;
446 : double maxEdgePriority = -std::numeric_limits<double>::max();
447 57 : for (ROEdge* edge : myEdges) {
448 54 : maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
449 97 : myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
450 : }
451 3 : myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
452 3 : if (myEdgePriorityRange == 0) {
453 1 : WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
454 1 : myPriorityFactor = 0;
455 1 : return false;
456 : }
457 : return true;
458 : }
459 :
460 :
461 : /****************************************************************************/
|