Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/gui/GUITLLogicPhasesTrackerWindow.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 GUITLLogicPhasesTrackerWindow.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @date Oct/Nov 2003
19
///
20
// A window displaying the phase diagram of a tl-logic
21
/****************************************************************************/
22
#include <config.h>
23
24
#include <vector>
25
#include <iostream>
26
#include <utils/gui/windows/GUIMainWindow.h>
27
#include <utils/gui/div/GLHelper.h>
28
#include "GUITLLogicPhasesTrackerWindow.h"
29
#include <microsim/traffic_lights/MSTrafficLightLogic.h>
30
#include <microsim/output/MSInductLoop.h>
31
#include <microsim/MSLink.h>
32
#include <utils/common/ToString.h>
33
#include <utils/common/MsgHandler.h>
34
#include <guisim/GUITrafficLightLogicWrapper.h>
35
#include <utils/gui/windows/GUIAppEnum.h>
36
#include <utils/gui/images/GUIIconSubSys.h>
37
#include <utils/gui/settings/GUIVisualizationSettings.h>
38
#include <utils/gui/div/GUIDesigns.h>
39
#include <foreign/fontstash/fontstash.h>
40
#include <utils/gui/globjects/GLIncludes.h>
41
42
43
// ===========================================================================
44
// static member initialisation
45
// ===========================================================================
46
int GUITLLogicPhasesTrackerWindow::myLastY(-1);
47
48
// ===========================================================================
49
// member method definitions
50
// ===========================================================================
51
/* -------------------------------------------------------------------------
52
* GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-callbacks
53
* ----------------------------------------------------------------------- */
54
FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[] = {
55
FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure),
56
FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint),
57
FXMAPFUNC(SEL_MOTION, 0, GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onMouseMove),
58
59
};
60
61
// Macro for the GLTestApp class hierarchy implementation
62
FXIMPLEMENT(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel, FXGLCanvas, GUITLLogicPhasesTrackerPanelMap, ARRAYNUMBER(GUITLLogicPhasesTrackerPanelMap))
63
64
65
66
/* -------------------------------------------------------------------------
67
* GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-methods
68
* ----------------------------------------------------------------------- */
69
GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::GUITLLogicPhasesTrackerPanel(
70
FXComposite* c, GUIMainWindow& app,
71
GUITLLogicPhasesTrackerWindow& parent) :
72
FXGLCanvas(c, app.getGLVisual(), app.getBuildGLCanvas(), (FXObject*) nullptr, (FXSelector) 0, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y/*, 0, 0, 300, 200*/),
73
myParent(&parent)
74
{}
75
76
77
GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::~GUITLLogicPhasesTrackerPanel() {}
78
79
80
long
81
GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onConfigure(FXObject*, FXSelector, void*) {
82
if (makeCurrent()) {
83
int widthInPixels = getWidth();
84
int heightInPixels = getHeight();
85
if (widthInPixels != 0 && heightInPixels != 0) {
86
glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
87
glClearColor(0, 0, 0, 1);
88
glDisable(GL_DEPTH_TEST);
89
glDisable(GL_LIGHTING);
90
glDisable(GL_LINE_SMOOTH);
91
glEnable(GL_BLEND);
92
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
93
glEnable(GL_ALPHA_TEST);
94
glDisable(GL_COLOR_MATERIAL);
95
glLineWidth(1);
96
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
97
}
98
}
99
return 1;
100
}
101
102
103
long
104
GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onPaint(
105
FXObject*, FXSelector, void*) {
106
if (!isEnabled()) {
107
return 1;
108
}
109
if (makeCurrent()) {
110
int widthInPixels = getWidth();
111
int heightInPixels = getHeight();
112
if (widthInPixels != 0 && heightInPixels != 0) {
113
glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
114
glClearColor(0, 0, 0, 1);
115
glDisable(GL_DEPTH_TEST);
116
glDisable(GL_LIGHTING);
117
glDisable(GL_LINE_SMOOTH);
118
glEnable(GL_BLEND);
119
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
120
glEnable(GL_ALPHA_TEST);
121
glDisable(GL_COLOR_MATERIAL);
122
glLineWidth(1);
123
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
124
// draw
125
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
126
myParent->drawValues(*this);
127
swapBuffers();
128
}
129
makeNonCurrent();
130
}
131
return 1;
132
}
133
134
135
long
136
GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel::onMouseMove(FXObject*, FXSelector, void* ptr) {
137
FXEvent* event = (FXEvent*) ptr;
138
myMousePos.setx(event->win_x);
139
myMousePos.sety(event->win_y);
140
onPaint(nullptr, 0, nullptr);
141
return 1;
142
}
143
144
/* -------------------------------------------------------------------------
145
* GUITLLogicPhasesTrackerWindow - FOX callback mapping
146
* ----------------------------------------------------------------------- */
147
FXDEFMAP(GUITLLogicPhasesTrackerWindow) GUITLLogicPhasesTrackerWindowMap[] = {
148
FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::onConfigure),
149
FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::onPaint),
150
FXMAPFUNC(SEL_COMMAND, MID_SIMSTEP, GUITLLogicPhasesTrackerWindow::onSimStep),
151
152
};
153
154
FXIMPLEMENT(GUITLLogicPhasesTrackerWindow, FXMainWindow, GUITLLogicPhasesTrackerWindowMap, ARRAYNUMBER(GUITLLogicPhasesTrackerWindowMap))
155
156
157
/* -------------------------------------------------------------------------
158
* GUITLLogicPhasesTrackerWindow-methods
159
* ----------------------------------------------------------------------- */
160
GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow(
161
GUIMainWindow& app,
162
MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& wrapper,
163
ValueSource<std::pair<SUMOTime, MSPhaseDefinition> >* src) :
164
FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL, 20, 20, 300, 200),
165
myApplication(&app),
166
myTLLogic(&logic),
167
myAmInTrackingMode(true) {
168
initToolBar();
169
myConnector = new GLObjectValuePassConnector<std::pair<SUMOTime, MSPhaseDefinition> >(wrapper, src, this);
170
app.addChild(this);
171
for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
172
myLinkNames.push_back(toString<int>(i));
173
}
174
for (auto item : myTLLogic->getDetectorStates()) {
175
std::string detID = item.first;
176
if (detID.size() > 4) {
177
detID = detID.substr(detID.size() - 4);
178
}
179
myDetectorNames.push_back(detID);
180
}
181
for (auto item : myTLLogic->getConditions()) {
182
myConditionNames.push_back(item.first);
183
}
184
loadSettings();
185
const int newHeight = computeHeight();
186
FXScrollWindow* scrollWindow = new FXScrollWindow(this, LAYOUT_FILL_X | LAYOUT_FILL_Y | HSCROLLER_NEVER | FRAME_NONE);
187
FXHorizontalFrame* spacerFrame = new FXHorizontalFrame(scrollWindow, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_NONE);
188
new FXScrollWindow(spacerFrame, LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT | FRAME_NONE, 0, 0, 0, newHeight - 40);
189
FXVerticalFrame* glcanvasFrame =
190
new FXVerticalFrame(spacerFrame,
191
FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
192
0, 0, 0, 0, 0, 0, 0, 0);
193
myPanel = new GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
194
setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str());
195
setIcon(GUIIconSubSys::getIcon(GUIIcon::APP_TLSTRACKER));
196
setHeight(newHeight);
197
}
198
199
200
GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerWindow(
201
GUIMainWindow& app,
202
MSTrafficLightLogic& logic, GUITrafficLightLogicWrapper& /*wrapper*/,
203
const MSSimpleTrafficLightLogic::Phases& /*phases*/) :
204
FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL, 20, 20, 300, 200),
205
myApplication(&app),
206
myTLLogic(&logic),
207
myAmInTrackingMode(false),
208
myToolBarDrag(nullptr),
209
myBeginOffset(nullptr) {
210
myConnector = nullptr;
211
initToolBar();
212
app.addChild(this);
213
for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
214
myLinkNames.push_back(toString<int>(i));
215
}
216
int newHeight = computeHeight();
217
FXScrollWindow* scrollWindow = new FXScrollWindow(this, LAYOUT_FILL_X | LAYOUT_FILL_Y | HSCROLLER_NEVER | FRAME_NONE);
218
FXHorizontalFrame* spacerFrame = new FXHorizontalFrame(scrollWindow, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y | FRAME_NONE);
219
new FXScrollWindow(spacerFrame, LAYOUT_FIX_WIDTH | LAYOUT_FIX_HEIGHT | FRAME_NONE, 0, 0, 0, newHeight - 40);
220
FXVerticalFrame* glcanvasFrame =
221
new FXVerticalFrame(spacerFrame,
222
FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
223
0, 0, 0, 0, 0, 0, 0, 0);
224
myPanel = new GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
225
setTitle((logic.getID() + " - " + logic.getProgramID() + " - phases").c_str());
226
setIcon(GUIIconSubSys::getIcon(GUIIcon::APP_TLSTRACKER));
227
setHeight(newHeight);
228
setWidth(700);
229
}
230
231
232
GUITLLogicPhasesTrackerWindow::~GUITLLogicPhasesTrackerWindow() {
233
if (myAmInTrackingMode) {
234
saveSettings();
235
myLastY = -1;
236
}
237
myApplication->removeChild(this);
238
delete myConnector;
239
// just to quit cleanly on a failure
240
if (myLock.locked()) {
241
myLock.unlock();
242
}
243
delete myToolBarDrag;
244
}
245
246
void
247
GUITLLogicPhasesTrackerWindow::initToolBar() {
248
myToolBarDrag = new FXToolBarShell(this, GUIDesignToolBar);
249
myToolBar = new FXToolBar(this, myToolBarDrag, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | FRAME_RAISED);
250
new FXToolBarGrip(myToolBar, myToolBar, FXToolBar::ID_TOOLBARGRIP, GUIDesignToolBarGrip);
251
252
if (myAmInTrackingMode) {
253
// interval manipulation
254
new FXLabel(myToolBar, "range (s):", nullptr, LAYOUT_CENTER_Y);
255
myBeginOffset = new FXRealSpinner(myToolBar, 4, this, MID_SIMSTEP, LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK);
256
//myBeginOffset->setFormatString("%.0f");
257
//myBeginOffset->setIncrements(1, 10, 100);
258
myBeginOffset->setIncrement(10);
259
myBeginOffset->setRange(60, 3600);
260
myBeginOffset->setValue(240);
261
}
262
263
new FXLabel(myToolBar, "time style:", nullptr, LAYOUT_CENTER_Y);
264
myTimeMode = new MFXComboBoxIcon(myToolBar, nullptr, false, GUIDesignComboBoxVisibleItems,
265
this, MID_SIMSTEP, GUIDesignViewSettingsComboBox1);
266
myTimeMode->appendIconItem("seconds");
267
myTimeMode->appendIconItem("MM:SS");
268
myTimeMode->appendIconItem("time in cycle");
269
270
new FXLabel(myToolBar, "green time", nullptr, LAYOUT_CENTER_Y);
271
myGreenMode = new MFXComboBoxIcon(myToolBar, nullptr, false, GUIDesignComboBoxVisibleItems,
272
this, MID_SIMSTEP, GUIDesignViewSettingsComboBox1);
273
myGreenMode->appendIconItem("off");
274
myGreenMode->appendIconItem("phase");
275
myGreenMode->appendIconItem("running");
276
277
myIndexMode = new FXCheckButton(myToolBar, TL("phase names"), this, MID_SIMSTEP);
278
279
if (myAmInTrackingMode) {
280
myDetectorMode = new FXCheckButton(myToolBar, TL("detectors"), this, MID_SIMSTEP);
281
myConditionMode = new FXCheckButton(myToolBar, TL("conditions"), this, MID_SIMSTEP);
282
} else {
283
myDetectorMode = nullptr;
284
myConditionMode = nullptr;
285
}
286
}
287
288
289
void
290
GUITLLogicPhasesTrackerWindow::create() {
291
FXMainWindow::create();
292
if (myToolBarDrag != nullptr) {
293
myToolBarDrag->create();
294
}
295
}
296
297
int
298
GUITLLogicPhasesTrackerWindow::computeHeight() {
299
int newHeight = (int)myTLLogic->getLinks().size() * 20 + 30 + 8 + 30 + 60;
300
if (myAmInTrackingMode) {
301
newHeight += 20; // time bar
302
newHeight += 10; // something extra caused by the scroll frames
303
if (myDetectorMode->getCheck()) {
304
newHeight += (int)myTLLogic->getDetectorStates().size() * 20 + 5;
305
}
306
if (myConditionMode->getCheck()) {
307
newHeight += (int)myTLLogic->getConditions().size() * 20 + 5;
308
}
309
}
310
return newHeight;
311
}
312
313
void
314
GUITLLogicPhasesTrackerWindow::drawValues(GUITLLogicPhasesTrackerPanel& caller) {
315
// compute what shall be shown (what is visible)
316
myFirstPhase2Show = 0;
317
myFirstPhaseOffset = 0;
318
SUMOTime leftOffset = 0;
319
myFirstDet2Show = 0;
320
myFirstDetOffset = 0;
321
myFirstCond2Show = 0;
322
myFirstCondOffset = 0;
323
myFirstTime2Show = 0;
324
if (!myAmInTrackingMode) {
325
myPhases.clear();
326
myDurations.clear();
327
myTimeInCycle.clear();
328
myPhaseIndex.clear();
329
// insert phases
330
MSSimpleTrafficLightLogic* simpleTLLogic = dynamic_cast<MSSimpleTrafficLightLogic*>(myTLLogic);
331
if (simpleTLLogic == nullptr) {
332
return;
333
}
334
myLastTime = 0;
335
myBeginTime = 0;
336
int idx = 0;
337
for (MSPhaseDefinition* const phase : simpleTLLogic->getPhases()) {
338
myPhases.push_back(*phase);
339
myDurations.push_back(phase->duration);
340
myTimeInCycle.push_back(myLastTime);
341
myPhaseIndex.push_back(idx++);
342
myLastTime += phase->duration;
343
}
344
if (myLastTime <= myBeginTime) {
345
WRITE_ERROR(TL("Overflow in time computation occurred."));
346
return;
347
}
348
} else {
349
SUMOTime beginOffset = TIME2STEPS(myBeginOffset->getValue());
350
myBeginTime = myLastTime - beginOffset;
351
myFirstTime2Show = myBeginTime;
352
// check whether no phases are known at all
353
if (myDurations.size() != 0) {
354
SUMOTime durs = 0;
355
int phaseOffset = (int)myDurations.size() - 1;
356
DurationsVector::reverse_iterator i = myDurations.rbegin();
357
while (i != myDurations.rend()) {
358
if (durs + (*i) > beginOffset) {
359
myFirstPhase2Show = phaseOffset;
360
myFirstPhaseOffset = (durs + (*i)) - beginOffset;
361
break;
362
}
363
durs += (*i);
364
phaseOffset--;
365
++i;
366
}
367
if (i == myDurations.rend()) {
368
// there are too few information stored;
369
myFirstPhase2Show = 0;
370
myFirstPhaseOffset = 0;
371
leftOffset = beginOffset - durs;
372
}
373
}
374
if (myDetectorDurations.size() != 0) {
375
SUMOTime durs = 0;
376
int phaseOffset = (int)myDetectorDurations.size() - 1;
377
DurationsVector::reverse_iterator i = myDetectorDurations.rbegin();
378
while (i != myDetectorDurations.rend()) {
379
if (durs + (*i) > beginOffset) {
380
myFirstDet2Show = phaseOffset;
381
myFirstDetOffset = (durs + (*i)) - beginOffset;
382
break;
383
}
384
durs += (*i);
385
phaseOffset--;
386
++i;
387
}
388
if (i == myDetectorDurations.rend()) {
389
// there are too few information stored;
390
myFirstDet2Show = 0;
391
myFirstDetOffset = 0;
392
}
393
}
394
if (myConditionDurations.size() != 0) {
395
SUMOTime durs = 0;
396
int phaseOffset = (int)myConditionDurations.size() - 1;
397
DurationsVector::reverse_iterator i = myConditionDurations.rbegin();
398
while (i != myConditionDurations.rend()) {
399
if (durs + (*i) > beginOffset) {
400
myFirstCond2Show = phaseOffset;
401
myFirstCondOffset = (durs + (*i)) - beginOffset;
402
break;
403
}
404
durs += (*i);
405
phaseOffset--;
406
++i;
407
}
408
if (i == myConditionDurations.rend()) {
409
// there are too few information stored;
410
myFirstCond2Show = 0;
411
myFirstCondOffset = 0;
412
}
413
}
414
}
415
// begin drawing
416
glMatrixMode(GL_PROJECTION);
417
glLoadIdentity();
418
glMatrixMode(GL_MODELVIEW);
419
glLoadIdentity();
420
glTranslated(-1, -1, 0);
421
glScaled(2, 2, 1);
422
glDisable(GL_TEXTURE_2D);
423
// draw the horizontal lines dividing the signal groups
424
glColor3d(1, 1, 1);
425
// compute some values needed more than once
426
const double panelHeight = (double) caller.getHeight();
427
const double panelWidth = (double) caller.getWidth();
428
const double barWidth = MAX2(1.0, panelWidth - 31);
429
const double fontHeight = 0.06 * 300. / panelHeight;
430
const double fontWidth = 0.06 * 300. / panelWidth;
431
const double h9 = 9. / panelHeight;
432
const double hTop = 20. / panelHeight;
433
const double h11 = 11. / panelHeight;
434
const double stateHeight = 16. / panelHeight;
435
const double h20 = 20. / panelHeight;
436
const double h30 = 15. / panelHeight;
437
const double h35 = 34. / panelHeight;
438
const double h60 = 70. / panelHeight;
439
const double h75 = 73. / panelHeight;
440
const double h80 = 90. / panelHeight;
441
const double w30 = 30 / panelWidth;
442
double h = 1. - hTop;
443
// draw the line below indices
444
glColor3d(1, 1, 1);
445
glBegin(GL_LINES);
446
glVertex2d(0, h);
447
glVertex2d(1, h);
448
glEnd();
449
// draw the link names and the lines dividing them
450
drawNames(myLinkNames, fontHeight, fontWidth, h20, w30, h, 0);
451
glBegin(GL_LINES);
452
glVertex2d(0, h + h20);
453
glVertex2d(1.0, h + h20);
454
glEnd();
455
456
// draw the names closure (vertical line)
457
h += h20;
458
glColor3d(1, 1, 1);
459
glBegin(GL_LINES);
460
glVertex2d(w30, 1.);
461
glVertex2d(w30, h);
462
glEnd();
463
464
if (myAmInTrackingMode) {
465
// optionally draw detector names
466
h -= h60;
467
if (myDetectorMode->getCheck()) {
468
const double top = h;
469
glBegin(GL_LINES);
470
glVertex2d(0, h);
471
glVertex2d(1.0, h);
472
glEnd();
473
drawNames(myDetectorNames, fontHeight * 0.7, fontWidth * 0.7, h20, w30, h, 3);
474
glBegin(GL_LINES);
475
glVertex2d(0, h + h20);
476
glVertex2d(1.0, h + h20);
477
glEnd();
478
// draw the names closure (vertical line)
479
glColor3d(1, 1, 1);
480
glBegin(GL_LINES);
481
glVertex2d(30. / panelWidth, top);
482
glVertex2d(30. / panelWidth, h + h20);
483
glEnd();
484
h -= h30;
485
}
486
// optionally draw condition names
487
if (myConditionMode->getCheck()) {
488
const double top = h;
489
glBegin(GL_LINES);
490
glVertex2d(0, h);
491
glVertex2d(1.0, h);
492
glEnd();
493
drawNames(myConditionNames, fontHeight * 0.7, fontWidth * 0.7, h20, w30, h, 3);
494
glBegin(GL_LINES);
495
glVertex2d(0, h + h20);
496
glVertex2d(1.0, h + h20);
497
glEnd();
498
// draw the names closure (vertical line)
499
glColor3d(1, 1, 1);
500
glBegin(GL_LINES);
501
glVertex2d(30. / panelWidth, top);
502
glVertex2d(30. / panelWidth, h + h20);
503
glEnd();
504
}
505
}
506
507
// draw the phases
508
// disable value addition while drawing
509
myLock.lock();
510
// determine the initial offset
511
double x = 31. / panelWidth;
512
double ta = (double) leftOffset / panelWidth;
513
ta *= barWidth / ((double)(myLastTime - myBeginTime));
514
x += ta;
515
516
// and the initial phase information
517
PhasesVector::iterator pi = myPhases.begin() + myFirstPhase2Show;
518
IndexVector::iterator ii = myPhaseIndex.begin() + myFirstPhase2Show;
519
520
SUMOTime fpo = myFirstPhaseOffset;
521
const bool phaseNames = myIndexMode->getCheck() == TRUE;
522
std::string lastName = "";
523
double spaceForName = 0;
524
525
// start drawing
526
std::vector<SUMOTime> runningGreen(myTLLogic->getLinks().size(), 0);
527
for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
528
// the first phase may be drawn incompletely
529
SUMOTime duration = *pd - fpo;
530
// compute the height and the width of the phase
531
h = 1. - hTop;
532
double a = (double) duration / panelWidth;
533
a *= barWidth / ((double)(myLastTime - myBeginTime));
534
const double x2 = x + a;
535
536
// go through the links
537
for (int j = 0; j < (int) myTLLogic->getLinks().size(); ++j) {
538
// determine the current link's color
539
LinkState state = pi->getSignalState(j);
540
// draw the bar (red is drawn as a line)
541
GLHelper::setColor(GUIVisualizationSettings::getLinkColor(state));
542
switch (state) {
543
case LINKSTATE_TL_RED:
544
case LINKSTATE_TL_REDYELLOW:
545
// draw a thin line
546
glBegin(GL_QUADS);
547
glVertex2d(x, h - h11);
548
glVertex2d(x, h - h9);
549
glVertex2d(x2, h - h9);
550
glVertex2d(x2, h - h11);
551
glEnd();
552
break;
553
default:
554
// draw a thick block
555
glBegin(GL_QUADS);
556
glVertex2d(x, h - stateHeight);
557
glVertex2d(x, h);
558
glVertex2d(x2, h);
559
glVertex2d(x2, h - stateHeight);
560
glEnd();
561
break;
562
}
563
if (myGreenMode->getCurrentItem() != 0) {
564
SUMOTime drawnDuration = 0;
565
double xOffset = 0;
566
if (state == LINKSTATE_TL_GREEN_MINOR || state == LINKSTATE_TL_GREEN_MAJOR) {
567
if (myGreenMode->getCurrentItem() == 1) {
568
drawnDuration = *pd;
569
} else {
570
runningGreen[j] += *pd;
571
if (pd + 1 == myDurations.end()) {
572
drawnDuration = runningGreen[j];
573
xOffset = -(double)(drawnDuration - *pd) / panelWidth * (barWidth / ((double)(myLastTime - myBeginTime)));
574
}
575
}
576
} else {
577
if (runningGreen[j] > 0) {
578
drawnDuration = runningGreen[j];
579
xOffset = -(double)drawnDuration / panelWidth * (barWidth / ((double)(myLastTime - myBeginTime)));
580
}
581
runningGreen[j] = 0;
582
}
583
if (drawnDuration > 0) {
584
GLHelper::drawText(toString((int)STEPS2TIME(drawnDuration)),
585
Position(x + xOffset, h - h9),
586
0, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
587
}
588
}
589
// proceed to next link
590
h -= h20;
591
}
592
593
// draw phase index / name (no names for intermediate)
594
std::string name = phaseNames ? pi->getName() : toString(*ii);
595
if (name != lastName) {
596
const double lastNameWidth = GLHelper::getTextWidth(lastName, fontWidth);
597
if (spaceForName < lastNameWidth) {
598
// clear space to avoid overdrawn text
599
glColor3d(0, 0, 0);
600
glBegin(GL_QUADS);
601
glVertex2d(x, 1 - fontHeight);
602
glVertex2d(x, 1);
603
glVertex2d(1, 1);
604
glVertex2d(1, 1 - fontHeight);
605
glEnd();
606
}
607
spaceForName = a;
608
GLHelper::drawText(name, Position(x, 1 - hTop), 0, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
609
} else {
610
spaceForName += a;
611
}
612
lastName = name;
613
// proceed to next phase
614
++pi;
615
++ii;
616
x = x2;
617
// all further phases are drawn in full
618
fpo = 0;
619
}
620
621
if (myAmInTrackingMode) {
622
h -= h75;
623
if (myDetectorMode->getCheck()) {
624
glColor3d(0.7, 0.7, 1.0);
625
drawAdditionalStates(caller, myDetectorStates, myDetectorDurations, myFirstDetOffset, myFirstDet2Show, h,
626
panelWidth, (double)leftOffset, barWidth, stateHeight, h20, h);
627
h -= h35;
628
}
629
if (myConditionMode->getCheck()) {
630
glColor3d(0.9, 0.6, 0.9);
631
drawAdditionalStates(caller, myConditionStates, myConditionDurations, myFirstCondOffset, myFirstCond2Show, h,
632
panelWidth, (double)leftOffset, barWidth, stateHeight, h20, h);
633
}
634
}
635
// allow value addition
636
myLock.unlock();
637
638
if (myPhases.size() != 0) {
639
const double timeRange = STEPS2TIME(myLastTime - myBeginTime);
640
SUMOTime tickDist = TIME2STEPS(10);
641
// patch distances - hack
642
double t = myBeginOffset != nullptr ? myBeginOffset->getValue() : timeRange;
643
while (t > barWidth / 4.) {
644
tickDist += TIME2STEPS(10);
645
t -= barWidth / 4.;
646
}
647
// draw time information
648
//h = (double)(myTLLogic->getLinks().size() * 20 + 12);
649
double glh = 1. - (double)myTLLogic->getLinks().size() * h20 - hTop;
650
// current begin time
651
// time ticks
652
SUMOTime currTime = myFirstTime2Show;
653
double glpos = 31. / panelWidth;
654
const double ticSize = 4. / panelHeight;
655
if (leftOffset > 0) {
656
const double a = STEPS2TIME(leftOffset) * barWidth / timeRange;
657
glpos += a / panelWidth;
658
currTime += leftOffset;
659
} else if (myFirstPhaseOffset > 0) {
660
const double a = STEPS2TIME(-myFirstPhaseOffset) * barWidth / timeRange;
661
glpos += a / panelWidth;
662
currTime -= myFirstPhaseOffset;
663
}
664
int ticShift = myFirstPhase2Show;
665
const bool mmSS = myTimeMode->getCurrentItem() == 1;
666
const bool cycleTime = myTimeMode->getCurrentItem() == 2;
667
SUMOTime lastTimeInCycle = -1;
668
lastName = "";
669
pi = myPhases.begin() + myFirstPhase2Show;
670
for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
671
const SUMOTime timeInCycle = myTimeInCycle[pd - myDurations.begin()];
672
// draw times at different heights
673
ticShift = (ticShift % 3) + 1;
674
const std::string timeStr = (mmSS
675
? StringUtils::padFront(toString((currTime % 3600000) / 60000), 2, '0') + ":"
676
+ StringUtils::padFront(toString((currTime % 60000) / 1000), 2, '0')
677
: toString((int)STEPS2TIME(cycleTime ? timeInCycle : currTime)));
678
const double w = 10 * (double)timeStr.size() / panelWidth;
679
glTranslated(glpos - w / 2., glh - h20 * ticShift, 0);
680
GLHelper::drawText(timeStr, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
681
glTranslated(-glpos + w / 2., -glh + h20 * ticShift, 0);
682
683
// draw tic
684
glColor3d(1, 1, 1);
685
glBegin(GL_LINES);
686
glVertex2d(glpos, glh);
687
glVertex2d(glpos, glh - ticSize * ticShift);
688
glEnd();
689
690
// draw vertical lines for names, detectors and conditions on each phase switch
691
if (myAmInTrackingMode) {
692
double hStart = 1;
693
if (!phaseNames || (pi->getName() != lastName)) {
694
glColor3d(0.4, 0.4, 0.4);
695
glBegin(GL_LINES);
696
glVertex2d(glpos, hStart);
697
hStart -= h20;
698
glVertex2d(glpos, hStart);
699
glEnd();
700
}
701
lastName = pi->getName();
702
703
hStart = glh - h60;
704
if (myDetectorMode->getCheck() && glpos >= w30) {
705
glColor3d(0.4, 0.4, 0.4);
706
glBegin(GL_LINES);
707
glVertex2d(glpos, hStart);
708
hStart -= (double)myDetectorNames.size() * h20;
709
glVertex2d(glpos, hStart);
710
glEnd();
711
hStart -= h35;
712
}
713
if (myConditionMode->getCheck() && glpos >= w30) {
714
glColor3d(0.4, 0.4, 0.4);
715
glBegin(GL_LINES);
716
glVertex2d(glpos, hStart);
717
glVertex2d(glpos, hStart - (double)myConditionNames.size() * h20);
718
glEnd();
719
}
720
}
721
722
// draw vertical line for cycle reset
723
if (timeInCycle == 0 || timeInCycle < lastTimeInCycle) {
724
const double cycle0pos = glpos - STEPS2TIME(timeInCycle) * barWidth / timeRange / panelWidth;
725
if (cycle0pos >= 31 / panelWidth) {
726
glColor3d(0.6, 0.6, 0.6);
727
glBegin(GL_LINES);
728
glVertex2d(cycle0pos, 1);
729
glVertex2d(cycle0pos, glh);
730
glEnd();
731
glColor3d(1, 1, 1);
732
}
733
}
734
735
lastTimeInCycle = timeInCycle;
736
tickDist = *pd;
737
const double a = STEPS2TIME(tickDist) * barWidth / timeRange;
738
glpos += a / panelWidth;
739
currTime += tickDist;
740
++pi;
741
}
742
743
// draw bottom time bar with fixed spacing
744
if (myAmInTrackingMode && (myDetectorMode->getCheck() || myConditionMode->getCheck()) && glpos >= w30) {
745
glColor3d(1, 1, 1);
746
tickDist = TIME2STEPS(10);
747
// patch distances - hack
748
t = myBeginOffset != nullptr ? myBeginOffset->getValue() : STEPS2TIME(myLastTime - myBeginTime);
749
while (t > barWidth / 4.) {
750
tickDist += TIME2STEPS(10);
751
t -= barWidth / 4.;
752
}
753
glh = 1. - (double)myLinkNames.size() * h20 - h80;
754
glh -= h20 * (double)(myDetectorMode->getCheck() ? myDetectorNames.size() : myConditionNames.size());
755
currTime = myFirstTime2Show;
756
int pos = 31;
757
glpos = (double) pos / panelWidth;
758
if (leftOffset > 0) {
759
const double a = STEPS2TIME(leftOffset) * barWidth / timeRange;
760
pos += (int)a;
761
glpos += a / panelWidth;
762
currTime += leftOffset;
763
} else if (myFirstPhaseOffset > 0) {
764
const double a = -STEPS2TIME(myBeginTime % tickDist) * barWidth / timeRange;
765
pos += (int)a;
766
glpos += a / panelWidth;
767
currTime = myBeginTime - (myBeginTime % tickDist);
768
}
769
while (pos < panelWidth + 50.) {
770
const std::string timeStr = (mmSS
771
? StringUtils::padFront(toString((currTime % 3600000) / 60000), 2, '0') + ":"
772
+ StringUtils::padFront(toString((currTime % 60000) / 1000), 2, '0')
773
: toString((int)STEPS2TIME(cycleTime ? findTimeInCycle(currTime) : currTime)));
774
const double w = 10. * (double)timeStr.size() / panelWidth;
775
glTranslated(glpos - w / 2., glh - h20, 0);
776
GLHelper::drawText(timeStr, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
777
glTranslated(-glpos + w / 2., -glh + h20, 0);
778
779
glBegin(GL_LINES);
780
glVertex2d(glpos, glh);
781
glVertex2d(glpos, glh - ticSize);
782
glEnd();
783
784
const double a = STEPS2TIME(tickDist) * barWidth / STEPS2TIME(myLastTime - myBeginTime);
785
pos += (int) a;
786
glpos += a / panelWidth;
787
currTime += tickDist;
788
}
789
}
790
}
791
}
792
793
794
void
795
GUITLLogicPhasesTrackerWindow::drawNames(const std::vector<std::string>& names, double fontHeight, double fontWidth, double divHeight, double divWidth, double& h, int extraLines) {
796
int i = 0;
797
for (const std::string& name : names) {
798
// draw the bar
799
glBegin(GL_LINES);
800
glVertex2d(0, h);
801
glVertex2d(divWidth, h);
802
glEnd();
803
// draw the name
804
glTranslated(0, h - divHeight, 0);
805
GLHelper::drawText(name, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
806
glTranslated(0, -h + divHeight, 0);
807
808
if (extraLines > 0 && i > 0 && i % extraLines == 0) {
809
glColor3d(0.4, 0.4, 0.4);
810
glBegin(GL_LINES);
811
glVertex2d(divWidth, h);
812
glVertex2d(1.0, h);
813
glEnd();
814
glColor3d(1, 1, 1);
815
}
816
h -= divHeight;
817
i++;
818
}
819
h -= divHeight;
820
}
821
822
823
void
824
GUITLLogicPhasesTrackerWindow::drawAdditionalStates(GUITLLogicPhasesTrackerPanel& caller,
825
const AdditionalStatesVector& states,
826
const DurationsVector& durations, SUMOTime firstOffset, int first2Show, double hStart,
827
double panelWidth, double leftOffset, double barWidth, double stateHeight, double h20, double& h) {
828
double x = 31. / panelWidth;
829
double ta = leftOffset / panelWidth;
830
ta *= barWidth / ((double)(myLastTime - myBeginTime));
831
x += ta;
832
auto di = states.begin() + first2Show;
833
SUMOTime fpo = firstOffset;
834
835
double mx = caller.getMousePos().x() / caller.getWidth();
836
double my = 1 - caller.getMousePos().y() / caller.getHeight();
837
std::string tooltip = "";
838
// start drawing
839
for (auto pd = durations.begin() + first2Show; pd != durations.end(); ++pd) {
840
// the first phase may be drawn incompletely
841
SUMOTime duration = *pd - fpo;
842
// compute the height and the width of the phase
843
h = hStart;
844
double a = (double) duration / panelWidth;
845
a *= barWidth / ((double)(myLastTime - myBeginTime));
846
const double x2 = x + a;
847
const bool tooltipX = x < mx && mx < x2;
848
//std::cout << SIMTIME << " detStates=" << toString(*di) << "\n";
849
// go through the detectors
850
for (double j : *di) {
851
if (j != 0) {
852
// draw a thick block
853
glBegin(GL_QUADS);
854
glVertex2d(x, h - stateHeight);
855
glVertex2d(x, h);
856
glVertex2d(x2, h);
857
glVertex2d(x2, h - stateHeight);
858
glEnd();
859
if (tooltipX) {
860
const bool tooltipY = (h - stateHeight) < my && my < h;
861
if (tooltipY) {
862
tooltip = toString((int)j);
863
}
864
}
865
}
866
// proceed to next link
867
h -= h20;
868
}
869
// proceed to next phase
870
++di;
871
x = x2;
872
// all further phases are drawn in full
873
fpo = 0;
874
}
875
if (tooltip != "") {
876
// delay tool tip drawing until all bars are drawn to prevent overwriting
877
GLHelper::drawText(tooltip, Position(mx, my), 0, h20, RGBColor::YELLOW, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, 20 / caller.getWidth());
878
}
879
}
880
881
SUMOTime
882
GUITLLogicPhasesTrackerWindow::findTimeInCycle(SUMOTime t) {
883
// find latest cycle reset before t
884
int i = (int)myPhases.size() - 1;
885
SUMOTime lookBack = myLastTime - t - myDurations.back();
886
//std::cout << SIMTIME << " findTimeInCycle t=" << STEPS2TIME(t)
887
// << " last=" << STEPS2TIME(myLastTime)
888
// << " lastDur=" << STEPS2TIME(myDurations.back())
889
// << " lookBack=" << STEPS2TIME(lookBack)
890
// << " i0=" << i;
891
// look backwards through the phases until to the first cycle crossing before t
892
while (lookBack > 0 && i > 1) {
893
i--;
894
lookBack -= myDurations[i];
895
}
896
SUMOTime timeInCycle = myTimeInCycle[i < 0 ? 0 : i];
897
//std::cout << " iF=" << i << " lookBack2=" << STEPS2TIME(lookBack) << " tic=" << STEPS2TIME(timeInCycle) << "\n";
898
if (lookBack <= 0) {
899
return timeInCycle - lookBack;
900
}
901
return myTLLogic->mapTimeInCycle(t);
902
}
903
904
void
905
GUITLLogicPhasesTrackerWindow::addValue(std::pair<SUMOTime, MSPhaseDefinition> def) {
906
// do not draw while adding
907
myLock.lock();
908
// set the first time if not set before
909
if (myPhases.size() == 0) {
910
myBeginTime = def.first;
911
}
912
// append or set the phase
913
if (myPhases.size() == 0 || myPhases.back() != def.second) {
914
myPhases.push_back(def.second);
915
myDurations.push_back(DELTA_T);
916
myTimeInCycle.push_back(myTLLogic->mapTimeInCycle(def.first - DELTA_T));
917
myPhaseIndex.push_back(myTLLogic->getCurrentPhaseIndex());
918
} else {
919
myDurations.back() += DELTA_T;
920
}
921
// updated detector states
922
std::vector<double> detectorStates;
923
for (auto item : myTLLogic->getDetectorStates()) {
924
detectorStates.push_back(item.second);
925
}
926
if (myDetectorStates.size() == 0 || myDetectorStates.back() != detectorStates) {
927
myDetectorStates.push_back(detectorStates);
928
myDetectorDurations.push_back(DELTA_T);
929
} else {
930
myDetectorDurations.back() += DELTA_T;
931
}
932
// updated condition states
933
std::vector<double> conditionStates;
934
for (auto item : myTLLogic->getConditions()) {
935
conditionStates.push_back(item.second);
936
}
937
if (myConditionStates.size() == 0 || myConditionStates.back() != conditionStates) {
938
myConditionStates.push_back(conditionStates);
939
myConditionDurations.push_back(DELTA_T);
940
} else {
941
myConditionDurations.back() += DELTA_T;
942
}
943
// set the last time a phase was added at
944
myLastTime = def.first;
945
// allow drawing
946
myLock.unlock();
947
}
948
949
950
long
951
GUITLLogicPhasesTrackerWindow::onConfigure(FXObject* sender, FXSelector sel, void* ptr) {
952
myPanel->onConfigure(sender, sel, ptr);
953
return FXMainWindow::onConfigure(sender, sel, ptr);
954
}
955
956
957
long
958
GUITLLogicPhasesTrackerWindow::onPaint(FXObject* sender, FXSelector sel, void* ptr) {
959
myPanel->onPaint(sender, sel, ptr);
960
return FXMainWindow::onPaint(sender, sel, ptr);
961
}
962
963
964
long
965
GUITLLogicPhasesTrackerWindow::onSimStep(FXObject* sender, FXSelector, void*) {
966
if (sender == myDetectorMode || sender == myConditionMode) {
967
resize(getWidth(), computeHeight());
968
}
969
update();
970
return 1;
971
}
972
973
974
void
975
GUITLLogicPhasesTrackerWindow::setBeginTime(SUMOTime time) {
976
myBeginTime = time;
977
}
978
979
980
void
981
GUITLLogicPhasesTrackerWindow::saveSettings() {
982
getApp()->reg().writeIntEntry("TL_TRACKER", "x", getX());
983
getApp()->reg().writeIntEntry("TL_TRACKER", "y", getY());
984
getApp()->reg().writeIntEntry("TL_TRACKER", "width", getWidth());
985
getApp()->reg().writeIntEntry("TL_TRACKER", "timeRange", (int)myBeginOffset->getValue());
986
getApp()->reg().writeIntEntry("TL_TRACKER", "timeMode", myTimeMode->getCurrentItem());
987
getApp()->reg().writeIntEntry("TL_TRACKER", "greenMode", (myGreenMode->getCurrentItem()));
988
getApp()->reg().writeIntEntry("TL_TRACKER", "indexMode", (int)(myIndexMode->getCheck()));
989
getApp()->reg().writeIntEntry("TL_TRACKER", "detectorMode", (int)(myDetectorMode->getCheck()));
990
getApp()->reg().writeIntEntry("TL_TRACKER", "conditionMode", (int)(myConditionMode->getCheck()));
991
}
992
993
994
void
995
GUITLLogicPhasesTrackerWindow::loadSettings() {
996
// ensure window is visible after switching screen resolutions
997
const FXint minSize = 400;
998
const FXint minTitlebarHeight = 20;
999
setX(MAX2(0, MIN2(getApp()->reg().readIntEntry("TL_TRACKER", "x", 150),
1000
getApp()->getRootWindow()->getWidth() - minSize)));
1001
if (myLastY == -1) {
1002
myLastY = MAX2(minTitlebarHeight,
1003
MIN2(getApp()->reg().readIntEntry("TL_TRACKER", "y", 150),
1004
getApp()->getRootWindow()->getHeight() - minSize));
1005
} else {
1006
myLastY += getHeight() + 20;
1007
}
1008
setY(myLastY);
1009
setWidth(MAX2(getApp()->reg().readIntEntry("TL_TRACKER", "width", 700), minSize));
1010
myBeginOffset->setValue(getApp()->reg().readIntEntry("TL_TRACKER", "timeRange", (int)myBeginOffset->getValue()));
1011
myTimeMode->setCurrentItem(getApp()->reg().readIntEntry("TL_TRACKER", "timeMode", myTimeMode->getCurrentItem()));
1012
myGreenMode->setCurrentItem(getApp()->reg().readIntEntry("TL_TRACKER", "greenMode", myGreenMode->getCurrentItem()));
1013
myIndexMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "indexMode", (int)(myIndexMode->getCheck())));
1014
myDetectorMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "detectorMode", (int)(myDetectorMode->getCheck())));
1015
myConditionMode->setCheck((FXbool)getApp()->reg().readIntEntry("TL_TRACKER", "conditionMode", (int)(myConditionMode->getCheck())));
1016
}
1017
1018
/****************************************************************************/
1019
1020