Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/guisim/GUITrafficLightLogicWrapper.cpp
169666 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 GUITrafficLightLogicWrapper.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Laura Bieker
19
/// @date Oct/Nov 2003
20
///
21
// A wrapper for tl-logics to allow their visualisation and interaction
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <cassert>
26
#include <utils/common/MsgHandler.h>
27
#include <utils/geom/GeomHelper.h>
28
#include <utils/gui/globjects/GUIGlObject.h>
29
#include <utils/gui/div/GLObjectValuePassConnector.h>
30
#include <utils/gui/windows/GUIAppEnum.h>
31
#include <utils/gui/images/GUIIconSubSys.h>
32
#include <utils/gui/div/GLHelper.h>
33
#include <utils/gui/div/GUIParameterTableWindow.h>
34
#include <utils/gui/globjects/GUIGLObjectPopupMenu.h>
35
#include <utils/gui/div/GUIGlobalSelection.h>
36
#include <microsim/MSLane.h>
37
#include <microsim/traffic_lights/MSTrafficLightLogic.h>
38
#include <microsim/traffic_lights/MSTLLogicControl.h>
39
#include <microsim/traffic_lights/MSOffTrafficLightLogic.h>
40
#include <microsim/traffic_lights/MSActuatedTrafficLightLogic.h>
41
#include <microsim/traffic_lights/MSDelayBasedTrafficLightLogic.h>
42
#include <microsim/traffic_lights/NEMAController.h>
43
#include <microsim/traffic_lights/MSRailSignal.h>
44
#include <microsim/logging/FunctionBinding.h>
45
#include <microsim/logging/FuncBinding_StringParam.h>
46
#include <gui/GUIApplicationWindow.h>
47
#include <gui/GUITLLogicPhasesTrackerWindow.h>
48
#include <gui/GUIGlobals.h>
49
#include <utils/gui/globjects/GLIncludes.h>
50
#include <utils/gui/div/GUIDesigns.h>
51
52
#include "GUITrafficLightLogicWrapper.h"
53
#include "GUINet.h"
54
55
// ===========================================================================
56
// FOX callback mapping
57
// ===========================================================================
58
FXDEFMAP(GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu)
59
GUITrafficLightLogicWrapperPopupMenuMap[] = {
60
FXMAPFUNC(SEL_COMMAND, MID_SHOWPHASES, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowPhases),
61
FXMAPFUNC(SEL_COMMAND, MID_TRACKPHASES, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdBegin2TrackPhases),
62
FXMAPFUNC(SEL_COMMAND, MID_SHOW_DETECTORS, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowDetectors),
63
FXMAPFUNC(SEL_COMMAND, MID_SWITCH_OFF, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLS2Off),
64
FXMAPFUNCS(SEL_COMMAND, MID_SWITCH, MID_SWITCH + 20, GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLSLogic),
65
};
66
67
// Object implementation
68
FXIMPLEMENT(GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu, GUIGLObjectPopupMenu, GUITrafficLightLogicWrapperPopupMenuMap, ARRAYNUMBER(GUITrafficLightLogicWrapperPopupMenuMap))
69
70
71
// ===========================================================================
72
// method definitions
73
// ===========================================================================
74
/* -------------------------------------------------------------------------
75
* GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu - methods
76
* ----------------------------------------------------------------------- */
77
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::GUITrafficLightLogicWrapperPopupMenu(
78
GUIMainWindow& app, GUISUMOAbstractView& parent, GUIGlObject* o) :
79
GUIGLObjectPopupMenu(app, parent, o) {}
80
81
82
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::~GUITrafficLightLogicWrapperPopupMenu() {}
83
84
85
86
long
87
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdBegin2TrackPhases(
88
FXObject*, FXSelector, void*) {
89
assert(myObject->getType() == GLO_TLLOGIC);
90
static_cast<GUITrafficLightLogicWrapper*>(myObject)->begin2TrackPhases();
91
return 1;
92
}
93
94
95
long
96
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowPhases(
97
FXObject*, FXSelector, void*) {
98
assert(myObject->getType() == GLO_TLLOGIC);
99
static_cast<GUITrafficLightLogicWrapper*>(myObject)->showPhases();
100
return 1;
101
}
102
103
long
104
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdShowDetectors(
105
FXObject*, FXSelector, void*) {
106
assert(myObject->getType() == GLO_TLLOGIC);
107
GUITrafficLightLogicWrapper* w = static_cast<GUITrafficLightLogicWrapper*>(myObject);
108
MSActuatedTrafficLightLogic* act = dynamic_cast<MSActuatedTrafficLightLogic*>(&w->getTLLogic());
109
if (act != nullptr) {
110
act->setShowDetectors(!act->showDetectors());
111
} else {
112
MSDelayBasedTrafficLightLogic* db = dynamic_cast<MSDelayBasedTrafficLightLogic*>(&w->getTLLogic());
113
if (db != nullptr) {
114
db->setShowDetectors(!db->showDetectors());
115
} else {
116
NEMALogic* nema = dynamic_cast<NEMALogic*>(&w->getTLLogic());
117
if (nema != nullptr) {
118
nema->setShowDetectors(!nema->showDetectors());
119
}
120
}
121
}
122
myParent->update();
123
return 1;
124
}
125
126
long
127
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLS2Off(
128
FXObject*, FXSelector /*sel*/, void*) {
129
assert(myObject->getType() == GLO_TLLOGIC);
130
static_cast<GUITrafficLightLogicWrapper*>(myObject)->switchTLSLogic(-1);
131
myParent->update();
132
return 1;
133
}
134
135
136
long
137
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapperPopupMenu::onCmdSwitchTLSLogic(
138
FXObject*, FXSelector sel, void*) {
139
assert(myObject->getType() == GLO_TLLOGIC);
140
static_cast<GUITrafficLightLogicWrapper*>(myObject)->switchTLSLogic(FXSELID(sel) - MID_SWITCH);
141
myParent->update();
142
return 1;
143
}
144
145
146
147
/* -------------------------------------------------------------------------
148
* GUITrafficLightLogicWrapper - methods
149
* ----------------------------------------------------------------------- */
150
GUITrafficLightLogicWrapper::GUITrafficLightLogicWrapper(MSTLLogicControl& control, MSTrafficLightLogic& tll) :
151
GUIGlObject(GLO_TLLOGIC, tll.getID(), GUIIconSubSys::getIcon(GUIIcon::LOCATETLS)),
152
myTLLogicControl(control), myTLLogic(tll) {
153
}
154
155
156
GUITrafficLightLogicWrapper::~GUITrafficLightLogicWrapper() {}
157
158
159
GUIGLObjectPopupMenu*
160
GUITrafficLightLogicWrapper::getPopUpMenu(GUIMainWindow& app, GUISUMOAbstractView& parent) {
161
myApp = &app;
162
GUIGLObjectPopupMenu* ret = new GUITrafficLightLogicWrapperPopupMenu(app, parent, this);
163
buildPopupHeader(ret, app);
164
buildCenterPopupEntry(ret);
165
const MSTLLogicControl::TLSLogicVariants& vars = myTLLogicControl.get(myTLLogic.getID());
166
std::vector<MSTrafficLightLogic*> logics = vars.getAllLogics();
167
if (logics.size() > 1) {
168
std::vector<MSTrafficLightLogic*>::const_iterator i;
169
int index = 0;
170
for (i = logics.begin(); i != logics.end(); ++i, ++index) {
171
if (!vars.isActive(*i) && dynamic_cast<MSOffTrafficLightLogic*>(*i) == nullptr) {
172
GUIDesigns::buildFXMenuCommand(ret, TLF("Switch to '%'", (*i)->getProgramID()),
173
GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), ret, (FXSelector)(MID_SWITCH + index));
174
}
175
}
176
new FXMenuSeparator(ret);
177
}
178
MSOffTrafficLightLogic* offLogic = dynamic_cast<MSOffTrafficLightLogic*>(vars.getActive());
179
if (offLogic == nullptr) {
180
GUIDesigns::buildFXMenuCommand(ret, TL("Switch off"), GUIIconSubSys::getIcon(GUIIcon::FLAG_MINUS), ret, MID_SWITCH_OFF);
181
}
182
GUIDesigns::buildFXMenuCommand(ret, TL("Track Phases"), nullptr, ret, MID_TRACKPHASES);
183
GUIDesigns::buildFXMenuCommand(ret, TL("Show Phases"), nullptr, ret, MID_SHOWPHASES);
184
MSActuatedTrafficLightLogic* act = dynamic_cast<MSActuatedTrafficLightLogic*>(&myTLLogic);
185
if (act != nullptr) {
186
GUIDesigns::buildFXMenuCommand(ret, act->showDetectors() ? TL("Hide Detectors") : TL("Show Detectors"), nullptr, ret, MID_SHOW_DETECTORS);
187
}
188
MSDelayBasedTrafficLightLogic* db = dynamic_cast<MSDelayBasedTrafficLightLogic*>(&myTLLogic);
189
if (db != nullptr) {
190
GUIDesigns::buildFXMenuCommand(ret, db->showDetectors() ? TL("Hide Detectors") : TL("Show Detectors"), nullptr, ret, MID_SHOW_DETECTORS);
191
}
192
NEMALogic* nema = dynamic_cast<NEMALogic*>(&myTLLogic);
193
if (nema != nullptr) {
194
GUIDesigns::buildFXMenuCommand(ret, nema->showDetectors() ? TL("Hide Detectors") : TL("Show Detectors"), nullptr, ret, MID_SHOW_DETECTORS);
195
}
196
new FXMenuSeparator(ret);
197
MSTrafficLightLogic* tll = getActiveTLLogic();
198
buildNameCopyPopupEntry(ret);
199
buildSelectionPopupEntry(ret);
200
GUIDesigns::buildFXMenuCommand(ret, TLF("Phase: %", toString(tll->getCurrentPhaseIndex())), nullptr, nullptr, 0);
201
const std::string& name = tll->getCurrentPhaseDef().getName();
202
if (name != "") {
203
GUIDesigns::buildFXMenuCommand(ret, TLF("Phase name: %", name), nullptr, nullptr, 0);
204
}
205
new FXMenuSeparator(ret);
206
buildShowParamsPopupEntry(ret, false);
207
buildPositionCopyEntry(ret, app);
208
return ret;
209
}
210
211
212
void
213
GUITrafficLightLogicWrapper::begin2TrackPhases() {
214
GUITLLogicPhasesTrackerWindow* window =
215
new GUITLLogicPhasesTrackerWindow(*myApp, myTLLogic, *this,
216
new FuncBinding_StringParam<MSTLLogicControl, std::pair<SUMOTime, MSPhaseDefinition> >
217
(&MSNet::getInstance()->getTLSControl(), &MSTLLogicControl::getPhaseDef, myTLLogic.getID()));
218
window->create();
219
window->show();
220
}
221
222
223
void
224
GUITrafficLightLogicWrapper::showPhases() {
225
GUITLLogicPhasesTrackerWindow* window =
226
new GUITLLogicPhasesTrackerWindow(*myApp, myTLLogic, *this,
227
static_cast<MSSimpleTrafficLightLogic&>(myTLLogic).getPhases());
228
window->setBeginTime(0);
229
window->create();
230
window->show();
231
}
232
233
234
GUIParameterTableWindow*
235
GUITrafficLightLogicWrapper::getParameterWindow(GUIMainWindow& app,
236
GUISUMOAbstractView&) {
237
GUIParameterTableWindow* ret = new GUIParameterTableWindow(app, *this);
238
ret->mkItem(TL("tlLogic [id]"), false, myTLLogic.getID());
239
ret->mkItem(TL("type"), false, toString(myTLLogic.getLogicType()));
240
ret->mkItem(TL("program"), false, myTLLogic.getProgramID());
241
ret->mkItem(TL("phase"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentPhase));
242
ret->mkItem(TL("phase name"), true, new FunctionBindingString<GUITrafficLightLogicWrapper>(this, &GUITrafficLightLogicWrapper::getCurrentPhaseName));
243
ret->mkItem(TL("duration"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentDurationSeconds));
244
ret->mkItem(TL("minDur"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentMinDurSeconds));
245
ret->mkItem(TL("maxDur"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentMaxDurSeconds));
246
ret->mkItem(TL("running duration"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getRunningDurationSeconds));
247
ret->mkItem(TL("earliestEnd"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentEarliestEndSeconds));
248
ret->mkItem(TL("latestEnd"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentLatestEndSeconds));
249
ret->mkItem(TL("time in cycle"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getCurrentTimeInCycleSeconds));
250
ret->mkItem(TL("cycle time"), true, new FunctionBinding<GUITrafficLightLogicWrapper, int>(this, &GUITrafficLightLogicWrapper::getDefaultCycleTimeSeconds));
251
MSRailSignal* rs = dynamic_cast<MSRailSignal*>(&myTLLogic);
252
if (rs != nullptr) {
253
ret->mkItem(TL("req driveway"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getRequestedDriveWay));
254
ret->mkItem(TL("blocking"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getBlockingVehicleIDs));
255
ret->mkItem(TL("blocking driveways"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getBlockingDriveWayIDs));
256
ret->mkItem(TL("rival"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getRivalVehicleIDs));
257
ret->mkItem(TL("priority"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getPriorityVehicleIDs));
258
ret->mkItem(TL("constraint"), true, new FunctionBindingString<MSRailSignal>(rs, &MSRailSignal::getConstraintInfo));
259
}
260
// close building
261
ret->closeBuilding(&myTLLogic);
262
return ret;
263
}
264
265
266
Boundary
267
GUITrafficLightLogicWrapper::getCenteringBoundary() const {
268
Boundary ret;
269
const MSTrafficLightLogic::LaneVectorVector& lanes = myTLLogic.getLaneVectors();
270
for (MSTrafficLightLogic::LaneVectorVector::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
271
const MSTrafficLightLogic::LaneVector& lanes2 = (*i);
272
for (MSTrafficLightLogic::LaneVector::const_iterator j = lanes2.begin(); j != lanes2.end(); ++j) {
273
ret.add((*j)->getShape()[-1]);
274
}
275
}
276
ret.grow(20);
277
return ret;
278
}
279
280
const std::string
281
GUITrafficLightLogicWrapper::getOptionalName() const {
282
return myTLLogic.getParameter("name", "");
283
}
284
285
286
void
287
GUITrafficLightLogicWrapper::switchTLSLogic(int to) {
288
if (to == -1) {
289
myTLLogicControl.switchTo(myTLLogic.getID(), "off");
290
GUINet::getGUIInstance()->createTLWrapper(getActiveTLLogic());
291
} else {
292
const MSTLLogicControl::TLSLogicVariants& vars = myTLLogicControl.get(myTLLogic.getID());
293
std::vector<MSTrafficLightLogic*> logics = vars.getAllLogics();
294
myTLLogicControl.switchTo(myTLLogic.getID(), logics[to]->getProgramID());
295
}
296
}
297
298
299
int
300
GUITrafficLightLogicWrapper::getLinkIndex(const MSLink* const link) const {
301
return myTLLogic.getLinkIndex(link);
302
}
303
304
305
void
306
GUITrafficLightLogicWrapper::drawGL(const GUIVisualizationSettings& s) const {
307
if (s.gaming) {
308
if (!MSNet::getInstance()->getTLSControl().isActive(&myTLLogic) || myTLLogic.getPhases().size() == 0) {
309
return;
310
}
311
const std::string& curState = myTLLogic.getCurrentPhaseDef().getState();
312
if (curState.find_first_of("gG") == std::string::npos) {
313
// no link is 'green' at the moment. find those that turn green next
314
const MSTrafficLightLogic::Phases& phases = myTLLogic.getPhases();
315
int curPhaseIdx = myTLLogic.getCurrentPhaseIndex();
316
int phaseIdx = (curPhaseIdx + 1) % phases.size();
317
std::vector<int> nextGreen;
318
while (phaseIdx != curPhaseIdx) {
319
const std::string& state = phases[phaseIdx]->getState();
320
for (int linkIdx = 0; linkIdx < (int)state.size(); linkIdx++) {
321
if ((LinkState)state[linkIdx] == LINKSTATE_TL_GREEN_MINOR ||
322
(LinkState)state[linkIdx] == LINKSTATE_TL_GREEN_MAJOR) {
323
nextGreen.push_back(linkIdx);
324
}
325
}
326
if (nextGreen.size() > 0) {
327
break;
328
}
329
phaseIdx = (phaseIdx + 1) % phases.size();
330
}
331
// highlight nextGreen links
332
for (const int idx : nextGreen) {
333
for (const MSLane* const lane : myTLLogic.getLanesAt(idx)) {
334
GLHelper::pushMatrix();
335
// split circle in red and yellow
336
const Position& pos = lane->getShape().back();
337
glTranslated(pos.x(), pos.y(), GLO_MAX);
338
double rot = RAD2DEG(lane->getShape().angleAt2D((int)lane->getShape().size() - 2)) - 90;
339
glRotated(rot, 0, 0, 1);
340
GLHelper::setColor(s.getLinkColor(LINKSTATE_TL_RED));
341
GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, -90, 90);
342
if (!isRailway(lane->getPermissions())) {
343
// no yellow half-cirlce in railway game
344
GLHelper::setColor(s.getLinkColor(LINKSTATE_TL_YELLOW_MAJOR));
345
GLHelper::drawFilledCircle(lane->getWidth() / 2., 8, 90, 270);
346
}
347
GLHelper::popMatrix();
348
}
349
}
350
}
351
}
352
}
353
354
MSTrafficLightLogic*
355
GUITrafficLightLogicWrapper::getActiveTLLogic() const {
356
return myTLLogicControl.getActive(myTLLogic.getID());
357
}
358
359
int
360
GUITrafficLightLogicWrapper::getCurrentPhase() const {
361
return getActiveTLLogic()->getCurrentPhaseIndex();
362
}
363
364
std::string
365
GUITrafficLightLogicWrapper::getCurrentPhaseName() const {
366
return getActiveTLLogic()->getCurrentPhaseDef().getName();
367
}
368
369
int
370
GUITrafficLightLogicWrapper::getCurrentDurationSeconds() const {
371
return (int)STEPS2TIME(getActiveTLLogic()->getCurrentPhaseDef().duration);
372
}
373
374
int
375
GUITrafficLightLogicWrapper::getCurrentMinDurSeconds() const {
376
return (int)STEPS2TIME(getActiveTLLogic()->getMinDur());
377
}
378
379
int
380
GUITrafficLightLogicWrapper::getCurrentMaxDurSeconds() const {
381
return (int)STEPS2TIME(getActiveTLLogic()->getMaxDur());
382
}
383
384
int
385
GUITrafficLightLogicWrapper::getCurrentEarliestEndSeconds() const {
386
const SUMOTime earliestEnd = getActiveTLLogic()->getEarliestEnd();
387
return earliestEnd == MSPhaseDefinition::UNSPECIFIED_DURATION ? -1 : (int)STEPS2TIME(earliestEnd);
388
}
389
390
int
391
GUITrafficLightLogicWrapper::getCurrentLatestEndSeconds() const {
392
const SUMOTime latestEnd = getActiveTLLogic()->getLatestEnd();
393
return latestEnd == MSPhaseDefinition::UNSPECIFIED_DURATION ? -1 : (int)STEPS2TIME(latestEnd);
394
}
395
396
int
397
GUITrafficLightLogicWrapper::getDefaultCycleTimeSeconds() const {
398
return (int)STEPS2TIME(getActiveTLLogic()->getDefaultCycleTime());
399
}
400
401
int
402
GUITrafficLightLogicWrapper::getCurrentTimeInCycleSeconds() const {
403
return (int)STEPS2TIME(getActiveTLLogic()->getTimeInCycle());
404
}
405
406
int
407
GUITrafficLightLogicWrapper::getRunningDurationSeconds() const {
408
return (int)STEPS2TIME(getActiveTLLogic()->getSpentDuration());
409
}
410
411
412
/****************************************************************************/
413
414