Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netbuild/NBLoadedTLDef.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-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 NBLoadedTLDef.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Sascha Krieg
18
/// @author Michael Behrisch
19
/// @date Tue, 29.05.2005
20
///
21
// A loaded (complete) traffic light logic
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <vector>
26
#include <set>
27
#include <cassert>
28
#include <iterator>
29
#include <utils/common/MsgHandler.h>
30
#include <utils/common/ToString.h>
31
#include <utils/options/OptionsCont.h>
32
#include "NBTrafficLightLogic.h"
33
#include "NBTrafficLightDefinition.h"
34
#include "NBLoadedTLDef.h"
35
#include "NBNode.h"
36
37
38
// ===========================================================================
39
// method definitions
40
// ===========================================================================
41
/* -------------------------------------------------------------------------
42
* NBLoadedTLDef::SignalGroup-methods
43
* ----------------------------------------------------------------------- */
44
NBLoadedTLDef::SignalGroup::SignalGroup(const std::string& id)
45
: Named(id) {}
46
47
NBLoadedTLDef::SignalGroup::~SignalGroup() {}
48
49
void
50
NBLoadedTLDef::SignalGroup::addConnection(const NBConnection& c) {
51
assert(c.getFromLane() < 0 || c.getFrom()->getNumLanes() > c.getFromLane());
52
myConnections.push_back(c);
53
}
54
55
56
void
57
NBLoadedTLDef::SignalGroup::addPhaseBegin(SUMOTime time, TLColor color) {
58
myPhases.push_back(PhaseDef(time, color));
59
}
60
61
62
void
63
NBLoadedTLDef::SignalGroup::setYellowTimes(SUMOTime tRedYellow, SUMOTime tYellow) {
64
myTRedYellow = tRedYellow;
65
myTYellow = tYellow;
66
}
67
68
69
void
70
NBLoadedTLDef::SignalGroup::sortPhases() {
71
std::sort(myPhases.begin(), myPhases.end(), [](const PhaseDef & p1, const PhaseDef & p2) {
72
return p1.myTime < p2.myTime;
73
});
74
}
75
76
77
void
78
NBLoadedTLDef::SignalGroup::patchTYellow(SUMOTime tyellow, bool forced) {
79
if (myTYellow < 0) {
80
// was not set before (was not loaded)
81
myTYellow = tyellow;
82
} else if (forced && myTYellow < tyellow) {
83
WRITE_WARNINGF(TL("TYellow of signal group '%' was less than the computed one; patched (was:%, is:%)"), getID(), toString(myTYellow), time2string(tyellow));
84
myTYellow = tyellow;
85
}
86
}
87
88
89
std::vector<SUMOTime>
90
NBLoadedTLDef::SignalGroup::getTimes(SUMOTime cycleDuration) const {
91
// within the phase container, we should have the green and red phases add their times
92
std::vector<SUMOTime> ret;
93
for (const PhaseDef& p : myPhases) {
94
ret.push_back(p.myTime);
95
}
96
// further, we possibly should set the yellow phases
97
if (myTYellow > 0) {
98
for (const PhaseDef& p : myPhases) {
99
if (p.myColor == TLCOLOR_RED) {
100
ret.push_back((p.myTime + myTYellow) % cycleDuration);
101
}
102
}
103
}
104
return ret;
105
}
106
107
108
int
109
NBLoadedTLDef::SignalGroup::getLinkNo() const {
110
return (int) myConnections.size();
111
}
112
113
114
bool
115
NBLoadedTLDef::SignalGroup::mayDrive(SUMOTime time) const {
116
assert(myPhases.size() != 0);
117
for (std::vector<PhaseDef>::const_reverse_iterator i = myPhases.rbegin(); i != myPhases.rend(); i++) {
118
SUMOTime nextTime = (*i).myTime;
119
if (time >= nextTime) {
120
return (*i).myColor == TLCOLOR_GREEN;
121
}
122
}
123
return (*(myPhases.end() - 1)).myColor == TLCOLOR_GREEN;
124
}
125
126
127
bool
128
NBLoadedTLDef::SignalGroup::hasYellow(SUMOTime time) const {
129
bool has_red_now = !mayDrive(time);
130
bool had_green = mayDrive(time - myTYellow);
131
return has_red_now && had_green;
132
}
133
134
135
const NBConnection&
136
NBLoadedTLDef::SignalGroup::getConnection(int pos) const {
137
assert(pos < (int)myConnections.size());
138
return myConnections[pos];
139
}
140
141
142
bool
143
NBLoadedTLDef::SignalGroup::containsIncoming(NBEdge* from) const {
144
for (NBConnectionVector::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
145
if ((*i).getFrom() == from) {
146
return true;
147
}
148
}
149
return false;
150
}
151
152
153
void
154
NBLoadedTLDef::SignalGroup::remapIncoming(NBEdge* which, const EdgeVector& by) {
155
NBConnectionVector newConns;
156
for (NBConnectionVector::iterator i = myConnections.begin(); i != myConnections.end();) {
157
if ((*i).getFrom() == which) {
158
NBConnection conn((*i).getFrom(), (*i).getTo());
159
i = myConnections.erase(i);
160
for (EdgeVector::const_iterator j = by.begin(); j != by.end(); j++) {
161
NBConnection curr(conn);
162
if (!curr.replaceFrom(which, *j)) {
163
throw ProcessError("Could not replace edge '" + which->getID() + "' by '" + (*j)->getID() + "'.\nUndefined...");
164
}
165
newConns.push_back(curr);
166
}
167
} else {
168
i++;
169
}
170
}
171
copy(newConns.begin(), newConns.end(),
172
back_inserter(myConnections));
173
}
174
175
176
bool
177
NBLoadedTLDef::SignalGroup::containsOutgoing(NBEdge* to) const {
178
for (NBConnectionVector::const_iterator i = myConnections.begin(); i != myConnections.end(); i++) {
179
if ((*i).getTo() == to) {
180
return true;
181
}
182
}
183
return false;
184
}
185
186
187
void
188
NBLoadedTLDef::SignalGroup::remapOutgoing(NBEdge* which, const EdgeVector& by) {
189
NBConnectionVector newConns;
190
for (NBConnectionVector::iterator i = myConnections.begin(); i != myConnections.end();) {
191
if ((*i).getTo() == which) {
192
NBConnection conn((*i).getFrom(), (*i).getTo());
193
i = myConnections.erase(i);
194
for (EdgeVector::const_iterator j = by.begin(); j != by.end(); j++) {
195
NBConnection curr(conn);
196
if (!curr.replaceTo(which, *j)) {
197
throw ProcessError("Could not replace edge '" + which->getID() + "' by '" + (*j)->getID() + "'.\nUndefined...");
198
}
199
newConns.push_back(curr);
200
}
201
} else {
202
i++;
203
}
204
}
205
copy(newConns.begin(), newConns.end(),
206
back_inserter(myConnections));
207
}
208
209
210
void
211
NBLoadedTLDef::SignalGroup::remap(NBEdge* removed, int removedLane,
212
NBEdge* by, int byLane) {
213
for (NBConnectionVector::iterator i = myConnections.begin(); i != myConnections.end(); i++) {
214
if ((*i).getTo() == removed
215
&&
216
((*i).getToLane() == removedLane
217
||
218
(*i).getToLane() == -1)) {
219
(*i).replaceTo(removed, removedLane, by, byLane);
220
221
} else if ((*i).getTo() == removed && removedLane == -1) {
222
(*i).replaceTo(removed, by);
223
}
224
225
if ((*i).getFrom() == removed
226
&&
227
((*i).getFromLane() == removedLane
228
||
229
(*i).getFromLane() == -1)) {
230
(*i).replaceFrom(removed, removedLane, by, byLane);
231
232
} else if ((*i).getFrom() == removed && removedLane == -1) {
233
(*i).replaceFrom(removed, by);
234
}
235
}
236
}
237
238
239
/* -------------------------------------------------------------------------
240
* NBLoadedTLDef::Phase-methods
241
* ----------------------------------------------------------------------- */
242
NBLoadedTLDef::NBLoadedTLDef(const NBEdgeCont& ec, const std::string& id,
243
const std::vector<NBNode*>& junctions, SUMOTime offset, TrafficLightType type) :
244
NBTrafficLightDefinition(id, junctions, DefaultProgramID, offset, type),
245
myEdgeCont(&ec) {
246
}
247
248
249
NBLoadedTLDef::NBLoadedTLDef(const NBEdgeCont& ec, const std::string& id, NBNode* junction, SUMOTime offset, TrafficLightType type) :
250
NBTrafficLightDefinition(id, junction, DefaultProgramID, offset, type),
251
myEdgeCont(&ec) {
252
}
253
254
255
NBLoadedTLDef::NBLoadedTLDef(const NBEdgeCont& ec, const std::string& id, SUMOTime offset, TrafficLightType type) :
256
NBTrafficLightDefinition(id, DefaultProgramID, offset, type),
257
myEdgeCont(&ec) {
258
}
259
260
261
NBLoadedTLDef::~NBLoadedTLDef() {
262
for (SignalGroupCont::iterator i = mySignalGroups.begin(); i != mySignalGroups.end(); ++i) {
263
delete (*i).second;
264
}
265
}
266
267
268
NBTrafficLightLogic*
269
NBLoadedTLDef::myCompute(int brakingTimeSeconds) {
270
MsgHandler::getWarningInstance()->clear(); // !!!
271
// compute the switching times and count the signals
272
std::set<SUMOTime> switchTimes;
273
int numSignals = 0;
274
for (const auto& i : mySignalGroups) {
275
NBLoadedTLDef::SignalGroup* const group = i.second;
276
// needed later
277
group->sortPhases();
278
// patch the yellow time for this group
279
group->patchTYellow(TIME2STEPS(brakingTimeSeconds), OptionsCont::getOptions().getBool("tls.yellow.patch-small"));
280
// copy the now valid times into the container
281
// both the given red and green phases are added and also the
282
// yellow times
283
const std::vector<SUMOTime> gtimes = group->getTimes(myCycleDuration);
284
switchTimes.insert(gtimes.begin(), gtimes.end());
285
numSignals += group->getLinkNo();
286
}
287
288
// build the phases
289
NBTrafficLightLogic* logic = new NBTrafficLightLogic(getID(), getProgramID(), numSignals, myOffset, myType);
290
SUMOTime prev = -1;
291
for (const SUMOTime l : switchTimes) {
292
if (prev != -1) {
293
logic->addStep(l - prev, buildPhaseState(prev));
294
}
295
prev = l;
296
}
297
logic->addStep(myCycleDuration + (*switchTimes.begin()) - prev, buildPhaseState(prev));
298
// check whether any warnings were printed
299
if (MsgHandler::getWarningInstance()->wasInformed()) {
300
WRITE_WARNINGF(TL("During computation of traffic light '%'."), getID());
301
}
302
logic->closeBuilding();
303
304
// initialize myNeedsContRelation
305
myNeedsContRelation.clear();
306
const bool controlledWithin = !OptionsCont::getOptions().getBool("tls.uncontrolled-within");
307
const std::vector<NBTrafficLightLogic::PhaseDefinition> phases = logic->getPhases();
308
for (std::vector<NBTrafficLightLogic::PhaseDefinition>::const_iterator it = phases.begin(); it != phases.end(); it++) {
309
const std::string state = (*it).state;
310
for (NBConnectionVector::const_iterator it1 = myControlledLinks.begin(); it1 != myControlledLinks.end(); it1++) {
311
const NBConnection& c1 = *it1;
312
const int i1 = c1.getTLIndex();
313
if (i1 == NBConnection::InvalidTlIndex || state[i1] != 'g' || c1.getFrom() == nullptr || c1.getTo() == nullptr) {
314
continue;
315
}
316
for (NBConnectionVector::const_iterator it2 = myControlledLinks.begin(); it2 != myControlledLinks.end(); it2++) {
317
const NBConnection& c2 = *it2;
318
const int i2 = c2.getTLIndex();
319
if (i2 != NBConnection::InvalidTlIndex
320
&& i2 != i1
321
&& (state[i2] == 'G' || state[i2] == 'g')
322
&& c2.getFrom() != nullptr && c2.getTo() != nullptr) {
323
const bool rightTurnConflict = NBNode::rightTurnConflict(
324
c1.getFrom(), c1.getTo(), c1.getFromLane(), c2.getFrom(), c2.getTo(), c2.getFromLane());
325
if (forbids(c2.getFrom(), c2.getTo(), c1.getFrom(), c1.getTo(), true, controlledWithin) || rightTurnConflict) {
326
myNeedsContRelation.insert(StreamPair(c1.getFrom(), c1.getTo(), c2.getFrom(), c2.getTo()));
327
}
328
}
329
}
330
}
331
}
332
myNeedsContRelationReady = true;
333
334
return logic;
335
}
336
337
338
void
339
NBLoadedTLDef::setTLControllingInformation() const {
340
// assign the tl-indices to the edge connections
341
for (NBConnectionVector::const_iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
342
const NBConnection& c = *it;
343
if (c.getTLIndex() != NBConnection::InvalidTlIndex) {
344
c.getFrom()->setControllingTLInformation(c, getID());
345
}
346
}
347
}
348
349
350
std::string
351
NBLoadedTLDef::buildPhaseState(const SUMOTime time) const {
352
int pos = 0;
353
std::string state;
354
// set the green and yellow information first;
355
// the information whether other have to break needs those masks
356
// completely filled
357
for (SignalGroupCont::const_iterator i = mySignalGroups.begin(); i != mySignalGroups.end(); i++) {
358
SignalGroup* group = (*i).second;
359
int linkNo = group->getLinkNo();
360
bool mayDrive = group->mayDrive(time);
361
bool hasYellow = group->hasYellow(time);
362
char c = 'r';
363
if (mayDrive) {
364
c = 'g';
365
}
366
if (hasYellow) {
367
c = 'y';
368
}
369
for (int j = 0; j < linkNo; j++) {
370
const NBConnection& conn = group->getConnection(j);
371
NBConnection assConn(conn);
372
// assert that the connection really exists
373
if (assConn.check(*myEdgeCont)) {
374
state = state + c;
375
++pos;
376
}
377
}
378
}
379
// set the braking mask
380
pos = 0;
381
for (SignalGroupCont::const_iterator i = mySignalGroups.begin(); i != mySignalGroups.end(); i++) {
382
SignalGroup* group = (*i).second;
383
int linkNo = group->getLinkNo();
384
for (int j = 0; j < linkNo; j++) {
385
const NBConnection& conn = group->getConnection(j);
386
NBConnection assConn(conn);
387
if (assConn.check(*myEdgeCont)) {
388
if (!mustBrake(assConn, state, pos)) {
389
if (state[pos] == 'g') {
390
state[pos] = 'G';
391
}
392
if (state[pos] == 'y') {
393
state[pos] = 'Y';
394
}
395
}
396
pos++;
397
}
398
}
399
}
400
return state;
401
}
402
403
404
bool
405
NBLoadedTLDef::mustBrake(const NBConnection& possProhibited,
406
const std::string& state,
407
int strmpos) const {
408
// check whether the stream has red
409
if (state[strmpos] != 'g' && state[strmpos] != 'G') {
410
return true;
411
}
412
413
// check whether another stream which has green is a higher
414
// priorised foe to the given
415
int pos = 0;
416
for (SignalGroupCont::const_iterator i = mySignalGroups.begin(); i != mySignalGroups.end(); i++) {
417
SignalGroup* group = (*i).second;
418
// get other links that have green
419
int linkNo = group->getLinkNo();
420
for (int j = 0; j < linkNo; j++) {
421
// get the current connection (possible foe)
422
const NBConnection& other = group->getConnection(j);
423
NBConnection possProhibitor(other);
424
// if the connection ist still valid ...
425
if (possProhibitor.check(*myEdgeCont)) {
426
// ... do nothing if it starts at the same edge
427
if (possProhibited.getFrom() == possProhibitor.getFrom()) {
428
pos++;
429
continue;
430
}
431
if (state[pos] == 'g' || state[pos] == 'G') {
432
if (NBTrafficLightDefinition::mustBrake(possProhibited, possProhibitor, true)) {
433
return true;
434
}
435
}
436
pos++;
437
}
438
}
439
}
440
return false;
441
}
442
443
444
void
445
NBLoadedTLDef::setParticipantsInformation() {
446
// assign participating nodes to the request
447
collectNodes();
448
// collect the information about participating edges and links
449
collectEdges();
450
collectLinks();
451
}
452
453
void
454
NBLoadedTLDef::collectNodes() {
455
myControlledNodes.clear();
456
SignalGroupCont::const_iterator m;
457
for (m = mySignalGroups.begin(); m != mySignalGroups.end(); m++) {
458
SignalGroup* group = (*m).second;
459
int linkNo = group->getLinkNo();
460
for (int j = 0; j < linkNo; j++) {
461
const NBConnection& conn = group->getConnection(j);
462
NBEdge* edge = conn.getFrom();
463
NBNode* node = edge->getToNode();
464
myControlledNodes.push_back(node);
465
}
466
}
467
std::sort(myControlledNodes.begin(), myControlledNodes.end(), NBNode::nodes_by_id_sorter());
468
}
469
470
471
void
472
NBLoadedTLDef::collectLinks() {
473
myControlledLinks.clear();
474
// build the list of links which are controlled by the traffic light
475
for (EdgeVector::iterator i = myIncomingEdges.begin(); i != myIncomingEdges.end(); i++) {
476
NBEdge* incoming = *i;
477
int noLanes = incoming->getNumLanes();
478
for (int j = 0; j < noLanes; j++) {
479
std::vector<NBEdge::Connection> elv = incoming->getConnectionsFromLane(j);
480
for (std::vector<NBEdge::Connection>::iterator k = elv.begin(); k != elv.end(); k++) {
481
NBEdge::Connection el = *k;
482
if (el.toEdge != nullptr) {
483
myControlledLinks.push_back(NBConnection(incoming, j, el.toEdge, el.toLane));
484
}
485
}
486
}
487
}
488
489
// assign tl-indices to myControlledLinks
490
int pos = 0;
491
for (SignalGroupCont::const_iterator m = mySignalGroups.begin(); m != mySignalGroups.end(); m++) {
492
SignalGroup* group = (*m).second;
493
int linkNo = group->getLinkNo();
494
for (int j = 0; j < linkNo; j++) {
495
const NBConnection& conn = group->getConnection(j);
496
assert(conn.getFromLane() < 0 || (int) conn.getFrom()->getNumLanes() > conn.getFromLane());
497
NBConnection tst(conn);
498
tst.setTLIndex(pos);
499
if (tst.check(*myEdgeCont)) {
500
if (tst.getFrom()->mayBeTLSControlled(tst.getFromLane(), tst.getTo(), tst.getToLane())) {
501
for (NBConnectionVector::iterator it = myControlledLinks.begin(); it != myControlledLinks.end(); it++) {
502
NBConnection& c = *it;
503
if (c.getTLIndex() == NBConnection::InvalidTlIndex
504
&& tst.getFrom() == c.getFrom() && tst.getTo() == c.getTo()
505
&& (tst.getFromLane() < 0 || tst.getFromLane() == c.getFromLane())
506
&& (tst.getToLane() < 0 || tst.getToLane() == c.getToLane())) {
507
c.setTLIndex(pos);
508
}
509
}
510
//std::cout << getID() << " group=" << (*m).first << " tst=" << tst << "\n";
511
pos++;
512
}
513
} else {
514
WRITE_WARNINGF(TL("Could not set signal on connection (signal: %, group: %)"), getID(), group->getID());
515
}
516
}
517
}
518
}
519
520
521
bool
522
NBLoadedTLDef::addToSignalGroup(const std::string& groupid,
523
const NBConnection& connection) {
524
if (mySignalGroups.find(groupid) == mySignalGroups.end()) {
525
return false;
526
}
527
mySignalGroups[groupid]->addConnection(connection);
528
NBNode* n1 = connection.getFrom()->getToNode();
529
if (n1 != nullptr) {
530
addNode(n1);
531
n1->addTrafficLight(this);
532
}
533
NBNode* n2 = connection.getTo()->getFromNode();
534
if (n2 != nullptr) {
535
addNode(n2);
536
n2->addTrafficLight(this);
537
}
538
return true;
539
}
540
541
542
bool
543
NBLoadedTLDef::addToSignalGroup(const std::string& groupid,
544
const NBConnectionVector& connections) {
545
bool ok = true;
546
for (NBConnectionVector::const_iterator i = connections.begin(); i != connections.end(); i++) {
547
ok &= addToSignalGroup(groupid, *i);
548
}
549
return ok;
550
}
551
552
553
void
554
NBLoadedTLDef::addSignalGroup(const std::string& id) {
555
assert(mySignalGroups.find(id) == mySignalGroups.end());
556
mySignalGroups[id] = new SignalGroup(id);
557
}
558
559
560
void
561
NBLoadedTLDef::addSignalGroupPhaseBegin(const std::string& groupid, SUMOTime time,
562
TLColor color) {
563
assert(mySignalGroups.find(groupid) != mySignalGroups.end());
564
mySignalGroups[groupid]->addPhaseBegin(time, color);
565
}
566
567
void
568
NBLoadedTLDef::setSignalYellowTimes(const std::string& groupid,
569
SUMOTime myTRedYellow, SUMOTime myTYellow) {
570
assert(mySignalGroups.find(groupid) != mySignalGroups.end());
571
mySignalGroups[groupid]->setYellowTimes(myTRedYellow, myTYellow);
572
}
573
574
575
void
576
NBLoadedTLDef::setCycleDuration(SUMOTime cycleDur) {
577
myCycleDuration = cycleDur;
578
}
579
580
581
void
582
NBLoadedTLDef::remapRemoved(NBEdge* removed,
583
const EdgeVector& incoming,
584
const EdgeVector& outgoing) {
585
for (SignalGroupCont::const_iterator i = mySignalGroups.begin(); i != mySignalGroups.end(); i++) {
586
SignalGroup* group = (*i).second;
587
if (group->containsIncoming(removed)) {
588
group->remapIncoming(removed, incoming);
589
}
590
if (group->containsOutgoing(removed)) {
591
group->remapOutgoing(removed, outgoing);
592
}
593
}
594
}
595
596
597
void
598
NBLoadedTLDef::replaceRemoved(NBEdge* removed, int removedLane,
599
NBEdge* by, int byLane, bool incoming) {
600
for (SignalGroupCont::const_iterator i = mySignalGroups.begin(); i != mySignalGroups.end(); i++) {
601
SignalGroup* group = (*i).second;
602
if ((incoming && group->containsIncoming(removed)) || (!incoming && group->containsOutgoing(removed))) {
603
group->remap(removed, removedLane, by, byLane);
604
}
605
}
606
}
607
608
609
void
610
NBLoadedTLDef::initNeedsContRelation() const {
611
if (!myNeedsContRelationReady) {
612
throw ProcessError(TL("myNeedsContRelation was not properly initialized\n"));
613
}
614
}
615
616
617
int
618
NBLoadedTLDef::getMaxIndex() {
619
setParticipantsInformation();
620
NBTrafficLightLogic* logic = compute(OptionsCont::getOptions());
621
if (logic != nullptr) {
622
return logic->getNumLinks() - 1;
623
} else {
624
return -1;
625
}
626
}
627
628
629
/****************************************************************************/
630
631