Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/router/ROEdge.cpp
193874 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2002-2026 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
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
myFromJunction(from),
60
myToJunction(to),
61
myIndex(index),
62
myPriority(priority),
63
myType(type),
64
myRoutingType(routingType),
65
mySpeed(-1),
66
myLength(0),
67
myAmSink(false),
68
myAmSource(false),
69
myUsingTTTimeLine(false),
70
myUsingETimeLine(false),
71
mySpeedRestrictions(nullptr),
72
myCombinedPermissions(0),
73
myOtherTazConnector(nullptr),
74
myTimePenalty(0) {
75
while ((int)myEdges.size() <= index) {
76
myEdges.push_back(0);
77
}
78
myEdges[index] = this;
79
if (from == nullptr && to == nullptr) {
80
// TAZ edge, no lanes
81
myCombinedPermissions = SVCAll;
82
} else {
83
// TODO we should not calculate the boundary here, the position for the nodes is not valid yet
84
myBoundary.add(from->getPosition());
85
myBoundary.add(to->getPosition());
86
}
87
}
88
89
90
ROEdge::ROEdge(const std::string& id, const RONode* from, const RONode* to, SVCPermissions p) :
91
Named(id),
92
myFromJunction(const_cast<RONode*>(from)),
93
myToJunction(const_cast<RONode*>(to)),
94
myIndex(-1),
95
myPriority(0),
96
myType(""),
97
mySpeed(std::numeric_limits<double>::max()),
98
myLength(0),
99
myAmSink(false),
100
myAmSource(false),
101
myUsingTTTimeLine(false),
102
myUsingETimeLine(false),
103
myCombinedPermissions(p),
104
myOtherTazConnector(nullptr),
105
myTimePenalty(0)
106
{ }
107
108
109
ROEdge::~ROEdge() {
110
for (ROLane* const lane : myLanes) {
111
delete lane;
112
}
113
delete myReversedRoutingEdge;
114
delete myFlippedRoutingEdge;
115
delete myRailwayRoutingEdge;
116
}
117
118
119
void
120
ROEdge::addLane(ROLane* lane) {
121
const double speed = lane->getSpeed();
122
if (speed > mySpeed) {
123
mySpeed = speed;
124
myLength = lane->getLength();
125
}
126
mySpeed = speed > mySpeed ? speed : mySpeed;
127
myLanes.push_back(lane);
128
129
// integrate new allowed classes
130
myCombinedPermissions |= lane->getPermissions();
131
}
132
133
134
void
135
ROEdge::addSuccessor(ROEdge* s, ROEdge* via, std::string) {
136
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
if (find(myFollowingEdges.begin(), myFollowingEdges.end(), s) == myFollowingEdges.end()) {
143
myFollowingEdges.push_back(s);
144
myFollowingViaEdges.push_back(std::make_pair(s, via));
145
if (isTazConnector() && s->getFromJunction() != nullptr) {
146
myBoundary.add(s->getFromJunction()->getPosition());
147
}
148
if (!isInternal()) {
149
s->myApproachingEdges.push_back(this);
150
if (s->isTazConnector() && getToJunction() != nullptr) {
151
s->myBoundary.add(getToJunction()->getPosition());
152
}
153
}
154
if (via != nullptr) {
155
if (via->myApproachingEdges.size() == 0) {
156
via->myApproachingEdges.push_back(this);
157
}
158
}
159
}
160
}
161
162
163
void
164
ROEdge::addEffort(double value, double timeBegin, double timeEnd) {
165
myEfforts.add(timeBegin, timeEnd, value);
166
myUsingETimeLine = true;
167
}
168
169
170
void
171
ROEdge::addTravelTime(double value, double timeBegin, double timeEnd) {
172
myTravelTimes.add(timeBegin, timeEnd, value);
173
myUsingTTTimeLine = true;
174
}
175
176
177
double
178
ROEdge::getEffort(const ROVehicle* const veh, double time) const {
179
double ret = 0;
180
if (!getStoredEffort(time, ret)) {
181
return myLength / getMaxSpeed(veh);
182
}
183
return ret;
184
}
185
186
187
double
188
ROEdge::getDistanceTo(const ROEdge* other, const bool doBoundaryEstimate) const {
189
assert(this != other);
190
if (doBoundaryEstimate) {
191
return myBoundary.distanceTo2D(other->myBoundary);
192
}
193
if (isTazConnector()) {
194
if (other->isTazConnector()) {
195
return myBoundary.distanceTo2D(other->myBoundary);
196
}
197
return myBoundary.distanceTo2D(other->getFromJunction()->getPosition());
198
}
199
if (other->isTazConnector()) {
200
return other->myBoundary.distanceTo2D(getToJunction()->getPosition());
201
}
202
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
ROEdge::hasLoadedTravelTime(double time) const {
209
return myUsingTTTimeLine && myTravelTimes.describesTime(time);
210
}
211
212
213
double
214
ROEdge::getTravelTime(const ROVehicle* const veh, double time) const {
215
if (myUsingTTTimeLine) {
216
if (myTravelTimes.describesTime(time)) {
217
double lineTT = myTravelTimes.getValue(time);
218
if (myInterpolate) {
219
const double inTT = lineTT;
220
const double split = (double)(myTravelTimes.getSplitTime(time, time + inTT) - time);
221
if (split >= 0) {
222
lineTT = myTravelTimes.getValue(time + inTT) * ((double)1. - split / inTT) + split;
223
}
224
}
225
return MAX2(getMinimumTravelTime(veh), lineTT);
226
} else {
227
if (!myHaveTTWarned) {
228
WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / max speed."), time, myID);
229
myHaveTTWarned = true;
230
}
231
}
232
}
233
const double speed = veh != nullptr ? getMaxSpeed(veh) : mySpeed;
234
return myLength / speed + myTimePenalty;
235
}
236
237
238
double
239
ROEdge::getNoiseEffort(const ROEdge* const edge, const ROVehicle* const veh, double time) {
240
double ret = 0;
241
if (!edge->getStoredEffort(time, ret)) {
242
ret = HelpersHarmonoise::computeNoise(veh->getType()->emissionClass, edge->getMaxSpeed(veh), 0);
243
}
244
return ret;
245
}
246
247
248
bool
249
ROEdge::getStoredEffort(double time, double& ret) const {
250
if (myUsingETimeLine) {
251
if (!myEfforts.describesTime(time)) {
252
if (!myHaveEWarned) {
253
WRITE_WARNINGF(TL("No interval matches passed time=% in edge '%'.\n Using edge's length / edge's speed."), time, myID);
254
myHaveEWarned = true;
255
}
256
return false;
257
}
258
if (myInterpolate) {
259
const double inTT = myTravelTimes.getValue(time);
260
const double ratio = (myEfforts.getSplitTime(time, time + inTT) - time) / inTT;
261
if (ratio >= 0.) {
262
ret = ratio * myEfforts.getValue(time) + (1. - ratio) * myEfforts.getValue(time + inTT);
263
return true;
264
}
265
}
266
ret = myEfforts.getValue(time);
267
return true;
268
}
269
return false;
270
}
271
272
273
int
274
ROEdge::getNumSuccessors() const {
275
if (myAmSink) {
276
return 0;
277
}
278
return (int) myFollowingEdges.size();
279
}
280
281
282
int
283
ROEdge::getNumPredecessors() const {
284
if (myAmSource) {
285
return 0;
286
}
287
return (int) myApproachingEdges.size();
288
}
289
290
291
const ROEdge*
292
ROEdge::getNormalBefore() const {
293
const ROEdge* result = this;
294
while (result->isInternal()) {
295
assert(myApproachingEdges.size() == 1);
296
result = result->myApproachingEdges.front();
297
}
298
return result;
299
}
300
301
302
303
const ROEdge*
304
ROEdge::getNormalAfter() const {
305
const ROEdge* result = this;
306
while (result->isInternal()) {
307
assert(myFollowingEdges.size() == 1);
308
result = result->myFollowingEdges.front();
309
}
310
return result;
311
}
312
313
314
void
315
ROEdge::buildTimeLines(const std::string& measure, const bool boundariesOverride) {
316
if (myUsingETimeLine) {
317
double value = myLength / mySpeed;
318
const SUMOEmissionClass c = PollutantsInterface::getClassByName("HBEFA4/default");
319
if (measure == "CO") {
320
value = PollutantsInterface::compute(c, PollutantsInterface::CO, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
321
}
322
if (measure == "CO2") {
323
value = PollutantsInterface::compute(c, PollutantsInterface::CO2, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
324
}
325
if (measure == "HC") {
326
value = PollutantsInterface::compute(c, PollutantsInterface::HC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
327
}
328
if (measure == "PMx") {
329
value = PollutantsInterface::compute(c, PollutantsInterface::PM_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
330
}
331
if (measure == "NOx") {
332
value = PollutantsInterface::compute(c, PollutantsInterface::NO_X, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
333
}
334
if (measure == "fuel") {
335
value = PollutantsInterface::compute(c, PollutantsInterface::FUEL, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
336
}
337
if (measure == "electricity") {
338
value = PollutantsInterface::compute(c, PollutantsInterface::ELEC, mySpeed, 0, 0, nullptr) * value; // @todo: give correct slope
339
}
340
myEfforts.fillGaps(value, boundariesOverride);
341
}
342
if (myUsingTTTimeLine) {
343
myTravelTimes.fillGaps(myLength / mySpeed + myTimePenalty, boundariesOverride);
344
}
345
}
346
347
348
void
349
ROEdge::cacheParamRestrictions(const std::vector<std::string>& restrictionKeys) {
350
for (const std::string& key : restrictionKeys) {
351
const std::string value = getParameter(key, "1e40");
352
myParamRestrictions.push_back(StringUtils::toDouble(value));
353
}
354
}
355
356
357
double
358
ROEdge::getLengthGeometryFactor() const {
359
return myLanes.empty() ? 1. : myLanes[0]->getShape().length() / myLanes[0]->getLength();
360
}
361
362
363
bool
364
ROEdge::allFollowersProhibit(const ROVehicle* const vehicle) const {
365
for (ROEdgeVector::const_iterator i = myFollowingEdges.begin(); i != myFollowingEdges.end(); ++i) {
366
if (!(*i)->prohibits(vehicle)) {
367
return false;
368
}
369
}
370
return true;
371
}
372
373
374
const ROEdgeVector&
375
ROEdge::getAllEdges() {
376
return myEdges;
377
}
378
379
380
const Position
381
ROEdge::getStopPosition(const SUMOVehicleParameter::Stop& stop) {
382
const double middle = (stop.endPos + stop.startPos) / 2.;
383
const ROEdge* const edge = RONet::getInstance()->getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
384
return (edge->getFromJunction()->getPosition() + edge->getToJunction()->getPosition()) * (middle / edge->getLength());
385
}
386
387
388
const ROEdgeVector&
389
ROEdge::getSuccessors(SUMOVehicleClass vClass) const {
390
if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
391
return myFollowingEdges;
392
}
393
#ifdef HAVE_FOX
394
FXMutexLock locker(myLock);
395
#endif
396
std::map<SUMOVehicleClass, ROEdgeVector>::const_iterator i = myClassesSuccessorMap.find(vClass);
397
if (i != myClassesSuccessorMap.end()) {
398
// can use cached value
399
return i->second;
400
}
401
// this vClass is requested for the first time. rebuild all successors
402
std::set<ROEdge*> followers;
403
for (const ROLane* const lane : myLanes) {
404
if ((lane->getPermissions() & vClass) != 0) {
405
for (const auto& next : lane->getOutgoingViaLanes()) {
406
if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
407
followers.insert(&next.first->getEdge());
408
}
409
}
410
}
411
}
412
// also add district edges (they are not connected at the lane level
413
for (ROEdgeVector::const_iterator it = myFollowingEdges.begin(); it != myFollowingEdges.end(); ++it) {
414
if ((*it)->isTazConnector()) {
415
followers.insert(*it);
416
}
417
}
418
myClassesSuccessorMap[vClass].insert(myClassesSuccessorMap[vClass].begin(),
419
followers.begin(), followers.end());
420
return myClassesSuccessorMap[vClass];
421
}
422
423
424
const ROConstEdgePairVector&
425
ROEdge::getViaSuccessors(SUMOVehicleClass vClass, bool /*ignoreTransientPermissions*/) const {
426
if (vClass == SVC_IGNORING || !RONet::getInstance()->hasPermissions() || isTazConnector()) {
427
return myFollowingViaEdges;
428
}
429
#ifdef HAVE_FOX
430
FXMutexLock locker(myLock);
431
#endif
432
std::map<SUMOVehicleClass, ROConstEdgePairVector>::const_iterator i = myClassesViaSuccessorMap.find(vClass);
433
if (i != myClassesViaSuccessorMap.end()) {
434
// can use cached value
435
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
for (const ROLane* const lane : myLanes) {
440
if ((lane->getPermissions() & vClass) != 0) {
441
for (const auto& next : lane->getOutgoingViaLanes()) {
442
if ((next.first->getPermissions() & vClass) != 0 && (next.second == nullptr || (next.second->getPermissions() & vClass) != 0)) {
443
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
for (const ROEdge* e : myFollowingEdges) {
450
if (e->isTazConnector()) {
451
followers.insert(std::make_pair(e, e));
452
}
453
}
454
myClassesViaSuccessorMap[vClass].insert(myClassesViaSuccessorMap[vClass].begin(),
455
followers.begin(), followers.end());
456
return myClassesViaSuccessorMap[vClass];
457
}
458
459
460
bool
461
ROEdge::isConnectedTo(const ROEdge& e, const SUMOVehicleClass vClass, bool ignoreTransientPermissions) const {
462
// @todo needs to be used with #12501
463
UNUSED_PARAMETER(ignoreTransientPermissions);
464
const ROEdgeVector& followers = getSuccessors(vClass);
465
return std::find(followers.begin(), followers.end(), &e) != followers.end();
466
}
467
468
bool
469
ROEdge::initPriorityFactor(double priorityFactor) {
470
myPriorityFactor = priorityFactor;
471
double maxEdgePriority = -std::numeric_limits<double>::max();
472
for (ROEdge* edge : myEdges) {
473
maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
474
myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
475
}
476
myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
477
if (myEdgePriorityRange == 0) {
478
WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority."));
479
myPriorityFactor = 0;
480
return false;
481
}
482
return true;
483
}
484
485
486
/****************************************************************************/
487
488