Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
GUITLLogicPhasesTrackerWindow.cpp
Go to the documentation of this file.
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/****************************************************************************/
20// A window displaying the phase diagram of a tl-logic
21/****************************************************************************/
22#include <config.h>
23
24#include <vector>
25#include <iostream>
31#include <microsim/MSLink.h>
41
42
43// ===========================================================================
44// static member initialisation
45// ===========================================================================
47
48// ===========================================================================
49// member method definitions
50// ===========================================================================
51/* -------------------------------------------------------------------------
52 * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-callbacks
53 * ----------------------------------------------------------------------- */
60
61// Macro for the GLTestApp class hierarchy implementation
62FXIMPLEMENT(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel, FXGLCanvas, GUITLLogicPhasesTrackerPanelMap, ARRAYNUMBER(GUITLLogicPhasesTrackerPanelMap))
63
64
65
66/* -------------------------------------------------------------------------
67 * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-methods
68 * ----------------------------------------------------------------------- */
70 FXComposite* c, GUIMainWindow& app,
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
78
79
80long
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
103long
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
135long
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 * ----------------------------------------------------------------------- */
147FXDEFMAP(GUITLLogicPhasesTrackerWindow) GUITLLogicPhasesTrackerWindowMap[] = {
148 FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::onConfigure),
149 FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::onPaint),
151
152};
153
154FXIMPLEMENT(GUITLLogicPhasesTrackerWindow, FXMainWindow, GUITLLogicPhasesTrackerWindowMap, ARRAYNUMBER(GUITLLogicPhasesTrackerWindowMap))
155
156
157/* -------------------------------------------------------------------------
158 * GUITLLogicPhasesTrackerWindow-methods
159 * ----------------------------------------------------------------------- */
161 GUIMainWindow& app,
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();
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());
196 setHeight(newHeight);
197}
198
199
201 GUIMainWindow& app,
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());
227 setHeight(newHeight);
228 setWidth(700);
229}
230
231
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
246void
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);
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);
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
289void
291 FXMainWindow::create();
292 if (myToolBarDrag != nullptr) {
293 myToolBarDrag->create();
294 }
295}
296
297int
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
313void
315 // compute what shall be shown (what is visible)
318 SUMOTime leftOffset = 0;
319 myFirstDet2Show = 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;
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;
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;
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;
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
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)
542 switch (state) {
543 case LINKSTATE_TL_RED:
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);
626 panelWidth, (double)leftOffset, barWidth, stateHeight, h20, h);
627 h -= h35;
628 }
629 if (myConditionMode->getCheck()) {
630 glColor3d(0.9, 0.6, 0.9);
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
794void
795GUITLLogicPhasesTrackerWindow::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
823void
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
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
904void
905GUITLLogicPhasesTrackerWindow::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 {
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 {
942 }
943 // set the last time a phase was added at
944 myLastTime = def.first;
945 // allow drawing
946 myLock.unlock();
947}
948
949
950long
951GUITLLogicPhasesTrackerWindow::onConfigure(FXObject* sender, FXSelector sel, void* ptr) {
952 myPanel->onConfigure(sender, sel, ptr);
953 return FXMainWindow::onConfigure(sender, sel, ptr);
954}
955
956
957long
958GUITLLogicPhasesTrackerWindow::onPaint(FXObject* sender, FXSelector sel, void* ptr) {
959 myPanel->onPaint(sender, sel, ptr);
960 return FXMainWindow::onPaint(sender, sel, ptr);
961}
962
963
964long
965GUITLLogicPhasesTrackerWindow::onSimStep(FXObject* sender, FXSelector, void*) {
966 if (sender == myDetectorMode || sender == myConditionMode) {
967 resize(getWidth(), computeHeight());
968 }
969 update();
970 return 1;
971}
972
973
974void
978
979
980void
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
994void
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/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
@ MID_SIMSTEP
A Simulation step was performed.
Definition GUIAppEnum.h:543
#define GUIDesignViewSettingsComboBox1
Combo boxes.
Definition GUIDesigns.h:580
#define GUIDesignToolBarGrip
design for toolbar grip (used to change the position of toolbar with mouse)
Definition GUIDesigns.h:480
#define GUIDesignToolBar
design for default toolbar
Definition GUIDesigns.h:465
#define GUIDesignComboBoxVisibleItems
Definition GUIDesigns.h:64
FXDEFMAP(GUIDialog_AppSettings) GUIDialog_AppSettingsMap[]
@ APP_TLSTRACKER
Definition GUIIcons.h:201
FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[]
#define WRITE_ERROR(msg)
Definition MsgHandler.h:295
#define TL(string)
Definition MsgHandler.h:304
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define TIME2STEPS(x)
Definition SUMOTime.h:57
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_REDYELLOW
The link has red light (must brake) but indicates upcoming green.
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_RED
The link has red light (must brake).
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition GLHelper.cpp:653
static double getTextWidth(const std::string &text, double size)
get required width of text
Definition GLHelper.cpp:741
static void drawText(const std::string &text, const Position &pos, const double layer, const double size, const RGBColor &col=RGBColor::BLACK, const double angle=0, const int align=0, double width=-1)
Definition GLHelper.cpp:747
Class passing values from a GUIGlObject to another object.
static FXIcon * getIcon(const GUIIcon which)
returns a icon previously defined in the enum GUIIcon
void addChild(FXMainWindow *child)
Adds a further child window to the list (FXMainWindow).
long onConfigure(FXObject *, FXSelector, void *)
called on size change
GUITLLogicPhasesTrackerPanel(FXComposite *c, GUIMainWindow &app, GUITLLogicPhasesTrackerWindow &parent)
Constructor.
long onPaint(FXObject *, FXSelector, void *)
called if the widget shall be repainted
long onMouseMove(FXObject *, FXSelector, void *)
called on mouse movement (for updating tooltip)
This window displays a phase diagram for a chosen tl-logic.
GUITLLogicPhasesTrackerWindow()
protected constructor for FOX
AdditionalStatesVector myDetectorStates
The state of all used detectors of the current phase.
FXMutex myLock
A lock to avoid addition of new values while drawing.
SUMOTime myBeginTime
The first time a phase was added at.
MFXComboBoxIcon * myGreenMode
Whether green durations are printed.
static int myLastY
y-Position of previously opened window
DurationsVector myTimeInCycle
The time within the cycle for the current phase.
std::vector< std::string > myLinkNames
The names of links.
DurationsVector myDetectorDurations
The list of detector state durations.
FXCheckButton * myDetectorMode
Whether detector states are drawn.
FXRealSpinner * myBeginOffset
The offset changer (tracking mode).
long onSimStep(FXObject *sender, FXSelector sel, void *ptr)
called on a simulation step
GUITLLogicPhasesTrackerPanel * myPanel
The panel to draw on.
GUITLLogicPhasesTrackerWindow(GUIMainWindow &app, MSTrafficLightLogic &logic, GUITrafficLightLogicWrapper &wrapper, ValueSource< std::pair< SUMOTime, MSPhaseDefinition > > *src)
Constructor to track current phases.
int computeHeight()
compute required windowHeight
void setBeginTime(SUMOTime time)
Sets the time the display shall be shown as beginning at.
FXToolBarShell * myToolBarDrag
The tool bar drag (tracking mode).
FXToolBar * myToolBar
The tool bar (tracking mode).
PhasesVector myPhases
The list of phases.
SUMOTime myFirstPhaseOffset
The offset to draw the first phase (left offset).
IndexVector myPhaseIndex
The index of the current phase.
void addValue(std::pair< SUMOTime, MSPhaseDefinition > def)
Adds a further phase definition.
GLObjectValuePassConnector< std::pair< SUMOTime, MSPhaseDefinition > > * myConnector
The connector for retrieval of further phases.
MFXComboBoxIcon * myTimeMode
The time mode.
int myFirstPhase2Show
The index of the first phase that fits into the window.
long onPaint(FXObject *sender, FXSelector sel, void *ptr)
called if the widget shall be repainted
SUMOTime findTimeInCycle(SUMOTime t)
find time in cycle based on myTimeInCycle
FXCheckButton * myConditionMode
Whether detector states are drawn.
long onConfigure(FXObject *sender, FXSelector sel, void *ptr)
called on size change
SUMOTime myLastTime
The last time a phase was added at.
void create()
Creates the window (FOX-Toolkit).
MSTrafficLightLogic * myTLLogic
The logic to display.
std::vector< std::vector< double > > AdditionalStatesVector
Definition of a storage for detector and condition states.
void drawNames(const std::vector< std::string > &names, double fontHeight, double fontWidth, double divHeight, double divWidth, double &h, int extraLines)
draw row title
FXCheckButton * myIndexMode
Whether phase names shall be printed instead of indices.
std::vector< SUMOTime > DurationsVector
Definition of a storage for durations.
void drawAdditionalStates(GUITLLogicPhasesTrackerPanel &caller, const AdditionalStatesVector &states, const DurationsVector &durations, SUMOTime firstOffset, int first2Show, double hStart, double panelWidth, double leftOffset, double barWidth, double stateHeight, double h20, double &h)
draw detector and condition states
SUMOTime myFirstTime2Show
The time the diagram begins at.
GUIMainWindow * myApplication
The main application.
bool myAmInTrackingMode
Information whether the tracking mode is on.
void drawValues(GUITLLogicPhasesTrackerPanel &caller)
Draws all values.
DurationsVector myDurations
The list of phase durations.
static const RGBColor & getLinkColor(const LinkState &ls, bool realistic=false)
map from LinkState to color constants
The definition of a single phase of a tls logic.
A fixed traffic light logic.
const Phases & getPhases() const override
Returns the phases of this tls program.
The parent class for traffic light logics.
const std::string & getProgramID() const
Returns this tl-logic's id.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
const std::string & getID() const
Returns the id.
Definition Named.h:74
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
double x() const
Returns the x-position.
Definition Position.h:52
double y() const
Returns the y-position.
Definition Position.h:57
static const RGBColor WHITE
Definition RGBColor.h:195
static const RGBColor YELLOW
Definition RGBColor.h:191
static const RGBColor BLACK
Definition RGBColor.h:196
static std::string padFront(const std::string &str, int length, char padding)
@ FONS_ALIGN_MIDDLE
Definition fontstash.h:47
@ FONS_ALIGN_LEFT
Definition fontstash.h:42
@ FONS_ALIGN_BOTTOM
Definition fontstash.h:48
Definition json.hpp:4471