Eclipse SUMO - Simulation of Urban MObility
GUITLLogicPhasesTrackerWindow.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2020 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>
27 #include <utils/gui/div/GLHelper.h>
30 #include <microsim/MSLink.h>
31 #include <utils/common/ToString.h>
40 
41 
42 // ===========================================================================
43 // member method definitions
44 // ===========================================================================
45 /* -------------------------------------------------------------------------
46  * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-callbacks
47  * ----------------------------------------------------------------------- */
51 
52 };
53 
54 // Macro for the GLTestApp class hierarchy implementation
55 FXIMPLEMENT(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel, FXGLCanvas, GUITLLogicPhasesTrackerPanelMap, ARRAYNUMBER(GUITLLogicPhasesTrackerPanelMap))
56 
57 
58 
59 /* -------------------------------------------------------------------------
60  * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-methods
61  * ----------------------------------------------------------------------- */
63  FXComposite* c, GUIMainWindow& app,
65  : FXGLCanvas(c, app.getGLVisual(), app.getBuildGLCanvas(), (FXObject*) nullptr, (FXSelector) 0, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y/*, 0, 0, 300, 200*/),
66  myParent(&parent) {}
67 
68 
70 
71 
72 long
74  FXObject*, FXSelector, void*) {
75  if (makeCurrent()) {
76  int widthInPixels = getWidth();
77  int heightInPixels = getHeight();
78  if (widthInPixels != 0 && heightInPixels != 0) {
79  glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
80  glClearColor(0, 0, 0, 1);
81  glDisable(GL_DEPTH_TEST);
82  glDisable(GL_LIGHTING);
83  glDisable(GL_LINE_SMOOTH);
84  glEnable(GL_BLEND);
85  glEnable(GL_ALPHA_TEST);
86  glDisable(GL_COLOR_MATERIAL);
87  glLineWidth(1);
88  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
89  }
90  }
91  return 1;
92 }
93 
94 
95 long
97  FXObject*, FXSelector, void*) {
98  if (!isEnabled()) {
99  return 1;
100  }
101  if (makeCurrent()) {
102  int widthInPixels = getWidth();
103  int heightInPixels = getHeight();
104  if (widthInPixels != 0 && heightInPixels != 0) {
105  glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
106  glClearColor(0, 0, 0, 1);
107  glDisable(GL_DEPTH_TEST);
108  glDisable(GL_LIGHTING);
109  glDisable(GL_LINE_SMOOTH);
110  glEnable(GL_BLEND);
111  glEnable(GL_ALPHA_TEST);
112  glDisable(GL_COLOR_MATERIAL);
113  glLineWidth(1);
114  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
115  // draw
116  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
117  myParent->drawValues(*this);
118  swapBuffers();
119  }
120  makeNonCurrent();
121  }
122  return 1;
123 }
124 
125 
126 
127 /* -------------------------------------------------------------------------
128  * GUITLLogicPhasesTrackerWindow - FOX callback mapping
129  * ----------------------------------------------------------------------- */
130 FXDEFMAP(GUITLLogicPhasesTrackerWindow) GUITLLogicPhasesTrackerWindowMap[] = {
131  FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::onConfigure),
132  FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::onPaint),
133  FXMAPFUNC(SEL_COMMAND, MID_SIMSTEP, GUITLLogicPhasesTrackerWindow::onSimStep),
134 
135 };
136 
137 FXIMPLEMENT(GUITLLogicPhasesTrackerWindow, FXMainWindow, GUITLLogicPhasesTrackerWindowMap, ARRAYNUMBER(GUITLLogicPhasesTrackerWindowMap))
138 
139 
140 /* -------------------------------------------------------------------------
141  * GUITLLogicPhasesTrackerWindow-methods
142  * ----------------------------------------------------------------------- */
144  GUIMainWindow& app,
146  ValueSource<std::pair<SUMOTime, MSPhaseDefinition> >* src)
147  : FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL,
148  20, 20, 300, 200),
149  myApplication(&app), myTLLogic(&logic), myAmInTrackingMode(true) {
150  // build the toolbar
151  myToolBarDrag = new FXToolBarShell(this, GUIDesignToolBar);
152  myToolBar = new FXToolBar(this, myToolBarDrag, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | FRAME_RAISED);
153  new FXToolBarGrip(myToolBar, myToolBar, FXToolBar::ID_TOOLBARGRIP, GUIDesignToolBarGrip);
154  // interval manipulation
155  myBeginOffset = new FXRealSpinner(myToolBar, 10, this, MID_SIMSTEP, LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK);
156  //myBeginOffset->setFormatString("%.0f");
157  //myBeginOffset->setIncrements(1, 10, 100);
158  myBeginOffset->setIncrement(10);
159  myBeginOffset->setRange(60, 3600);
160  myBeginOffset->setValue(240);
161  new FXLabel(myToolBar, "(s)", nullptr, LAYOUT_CENTER_Y);
162  //
164  app.addChild(this);
165  for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
166  myLinkNames.push_back(toString<int>(i));
167  }
168  FXVerticalFrame* glcanvasFrame =
169  new FXVerticalFrame(this,
170  FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
171  0, 0, 0, 0, 0, 0, 0, 0);
172  myPanel = new
173  GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
174  setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str());
176  setHeight((FXint)(myTLLogic->getLinks().size() * 20 + 30 + 8 + 30));
177  setWidth(700);
178 }
179 
180 
182  GUIMainWindow& app,
184  const MSSimpleTrafficLightLogic::Phases& /*phases*/)
185  : FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL,
186  20, 20, 300, 200),
187  myApplication(&app), myTLLogic(&logic), myAmInTrackingMode(false),
188  myToolBarDrag(nullptr), myBeginOffset(nullptr) {
189  myConnector = nullptr;
190  setTitle("TLS-Tracker");
191  app.addChild(this);
192  for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
193  myLinkNames.push_back(toString<int>(i));
194  }
195  FXVerticalFrame* glcanvasFrame =
196  new FXVerticalFrame(this,
197  FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
198  0, 0, 0, 0, 0, 0, 0, 0);
199  myPanel = new
200  GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
201  setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str());
203  setHeight((FXint)(myTLLogic->getLinks().size() * 20 + 30 + 8));
204  setWidth(700);
205 }
206 
207 
209  myApplication->removeChild(this);
210  delete myConnector;
211  // just to quit cleanly on a failure
212  if (myLock.locked()) {
213  myLock.unlock();
214  }
215  delete myToolBarDrag;
216 }
217 
218 
219 void
221  FXMainWindow::create();
222  if (myToolBarDrag != nullptr) {
223  myToolBarDrag->create();
224  }
225 }
226 
227 
228 void
230  // compute what shall be shown (what is visible)
231  myFirstPhase2Show = 0;
232  myFirstPhaseOffset = 0;
233  SUMOTime leftOffset = 0;
234  myFirstTime2Show = 0;
235  if (!myAmInTrackingMode) {
236  myPhases.clear();
237  myDurations.clear();
238  // insert phases
239  MSSimpleTrafficLightLogic* simpleTLLogic = dynamic_cast<MSSimpleTrafficLightLogic*>(myTLLogic);
240  if (simpleTLLogic == nullptr) {
241  return;
242  }
243  const MSSimpleTrafficLightLogic::Phases& phases = simpleTLLogic->getPhases();
244  MSSimpleTrafficLightLogic::Phases::const_iterator j;
245  myLastTime = 0;
246  myBeginTime = 0;
247  for (j = phases.begin(); j != phases.end(); ++j) {
248  myPhases.push_back(*(*j));
249  myDurations.push_back((*j)->duration);
250  myLastTime += (*j)->duration;
251  }
252  if (myLastTime <= myBeginTime) {
253  WRITE_ERROR("Overflow in time computation occurred.");
254  return;
255  }
256  } else {
257  SUMOTime beginOffset = TIME2STEPS(myBeginOffset->getValue());
258  myBeginTime = myLastTime - beginOffset;
260  // check whether no phases are known at all
261  if (myDurations.size() != 0) {
262  SUMOTime durs = 0;
263  int phaseOffset = (int)myDurations.size() - 1;
264  DurationsVector::reverse_iterator i = myDurations.rbegin();
265  while (i != myDurations.rend()) {
266  if (durs + (*i) > beginOffset) {
267  myFirstPhase2Show = phaseOffset;
268  myFirstPhaseOffset = (durs + (*i)) - beginOffset;
269  break;
270  }
271  durs += (*i);
272  phaseOffset--;
273  ++i;
274  }
275  if (i == myDurations.rend()) {
276  // there are too few information stored;
277  myFirstPhase2Show = 0;
278  myFirstPhaseOffset = 0;
279  leftOffset = beginOffset - durs;
280  }
281  }
282  }
283  // begin drawing
284  glMatrixMode(GL_PROJECTION);
285  glLoadIdentity();
286  glMatrixMode(GL_MODELVIEW);
287  glLoadIdentity();
288  glTranslated(-1, -1, 0);
289  glScaled(2, 2, 1);
290  glDisable(GL_TEXTURE_2D);
291  // draw the horizontal lines dividing the signal groups
292  glColor3d(1, 1, 1);
293  // compute some values needed more than once
294  const double height = (double) caller.getHeight();
295  const double width = (double) caller.getWidth();
296  const double barWidth = MAX2(1.0, width - 31);
297  const double fontHeight = 0.08 * 300. / height;
298  const double fontWidth = 0.08 * 300. / width;
299  const double h9 = ((double) 9 / height);
300  const double h10 = ((double) 10 / height);
301  const double h11 = ((double) 11 / height);
302  const double h16 = ((double) 16 / height);
303  const double h20 = ((double) 20 / height);
304  // draw the link names and the lines dividing them
305  double h = (double)(1.0 - h10);
306  double h2 = 12;
307  for (int i = 0; i < (int)myTLLogic->getLinks().size() + 1; ++i) {
308  // draw the bar
309  glBegin(GL_LINES);
310  glVertex2d(0, h);
311  glVertex2d((double)(30. / width), h);
312  glEnd();
313  // draw the name
314  if (i < (int)myTLLogic->getLinks().size()) {
315  glTranslated(0, h - h20, 0);
316  GLHelper::drawText(myLinkNames[i], Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
317  glTranslated(0, -h + h20, 0);
318  h2 += 20;
319  }
320  h -= h20;
321  }
322  glBegin(GL_LINES);
323  glVertex2d(0, h + h20);
324  glVertex2d(1.0, h + h20);
325  glEnd();
326 
327  // draw the names closure (vertical line)
328  h += (double) 20 / height;
329  glColor3d(1, 1, 1);
330  glBegin(GL_LINES);
331  glVertex2d((double) 30 / width, 1.0);
332  glVertex2d((double) 30 / width, h);
333  glEnd();
334 
335 
336  // draw the phases
337  // disable value addition while drawing
338  myLock.lock();
339  // determine the initial offset
340  double x = ((double) 31. / width);
341  double ta = (double) leftOffset / width;
342  ta *= (double)((barWidth / ((double)(myLastTime - myBeginTime))));
343  x += ta;
344 
345  // and the initial phase information
346  PhasesVector::iterator pi = myPhases.begin() + myFirstPhase2Show;
347 
349 
350  // start drawing
351  for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
352  SUMOTime i = 30;
353  // the first phase may be drawn incompletely
354  SUMOTime duration = *pd - fpo;
355  // compute the heigh and the width of the phase
356  h = (double)(1.0 - h10);
357  double a = (double) duration / width;
358  a *= (double)((barWidth / ((double)(myLastTime - myBeginTime))));
359  const double x2 = x + a;
360 
361  // go through the links
362  for (int j = 0; j < (int) myTLLogic->getLinks().size(); ++j) {
363  // determine the current link's color
364  LinkState state = pi->getSignalState(j);
365  // draw the bar (red is drawn as a line)
367  switch (state) {
368  case LINKSTATE_TL_RED:
370  // draw a thin line
371  glBegin(GL_QUADS);
372  glVertex2d(x, h - h11);
373  glVertex2d(x, h - h9);
374  glVertex2d(x2, h - h9);
375  glVertex2d(x2, h - h11);
376  glEnd();
377  break;
378  default:
379  // draw a thick block
380  glBegin(GL_QUADS);
381  glVertex2d(x, h - h16);
382  glVertex2d(x, h);
383  glVertex2d(x2, h);
384  glVertex2d(x2, h - h16);
385  glEnd();
386  break;
387  }
388  // proceed to next link
389  h -= h20;
390  }
391  // proceed to next phase
392  i += duration;
393  ++pi;
394  x = x2;
395  // all further phases are drawn in full
396  fpo = 0;
397  }
398  // allow value addition
399  myLock.unlock();
400 
401  glColor3d(1, 1, 1);
402  if (myPhases.size() != 0) {
403  SUMOTime tickDist = TIME2STEPS(10);
404  // patch distances - hack
405  double t = myBeginOffset != nullptr ? (double) myBeginOffset->getValue() : STEPS2TIME(myLastTime - myBeginTime);
406  while (t > barWidth / 4.) {
407  tickDist += TIME2STEPS(10);
408  t -= (double)(barWidth / 4.);
409  }
410  // draw time information
411  //h = (double)(myTLLogic->getLinks().size() * 20 + 12);
412  double glh = (double)(1.0 - myTLLogic->getLinks().size() * h20 - h10);
413  // current begin time
414  // time ticks
415  SUMOTime currTime = myFirstTime2Show;
416  int pos = 31;// + /*!!!currTime*/ - myFirstTime2Show;
417  double glpos = (double) pos / width;
418  const double ticSize = 4 / height;
419  while (pos < width + 50) {
420  const std::string timeStr = (gHumanReadableTime
421  ? time2string(currTime % 3600000).substr(3) // only write mn:ss
422  : toString((int)STEPS2TIME(currTime)));
423  const double w = 50 / width;
424  glTranslated(glpos - w / 2., glh - h20, 0);
425  GLHelper::drawText(timeStr, Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
426  glTranslated(-glpos + w / 2., -glh + h20, 0);
427 
428  glBegin(GL_LINES);
429  glVertex2d(glpos, glh);
430  glVertex2d(glpos, glh - ticSize);
431  glEnd();
432 
433  const double a = STEPS2TIME(tickDist) * barWidth / STEPS2TIME(myLastTime - myBeginTime);
434  pos += (int) a;
435  glpos += a / width;
436  currTime += tickDist;
437  }
438  }
439 }
440 
441 
442 void
443 GUITLLogicPhasesTrackerWindow::addValue(std::pair<SUMOTime, MSPhaseDefinition> def) {
444  // do not draw while adding
445  myLock.lock();
446  // set the first time if not set before
447  if (myPhases.size() == 0) {
448  myBeginTime = def.first;
449  }
450  // append or set the phase
451  if (myPhases.size() == 0 || *(myPhases.end() - 1) != def.second) {
452  myPhases.push_back(def.second);
453  myDurations.push_back(DELTA_T);
454  } else {
455  *(myDurations.end() - 1) += DELTA_T;
456  }
457  // set the last time a phase was added at
458  myLastTime = def.first;
459  // allow drawing
460  myLock.unlock();
461 }
462 
463 
464 long
465 GUITLLogicPhasesTrackerWindow::onConfigure(FXObject* sender, FXSelector sel, void* ptr) {
466  myPanel->onConfigure(sender, sel, ptr);
467  return FXMainWindow::onConfigure(sender, sel, ptr);
468 }
469 
470 
471 long
472 GUITLLogicPhasesTrackerWindow::onPaint(FXObject* sender, FXSelector sel, void* ptr) {
473  myPanel->onPaint(sender, sel, ptr);
474  return FXMainWindow::onPaint(sender, sel, ptr);
475 }
476 
477 
478 long
479 GUITLLogicPhasesTrackerWindow::onSimStep(FXObject*, FXSelector, void*) {
480  update();
481  return 1;
482 }
483 
484 
485 void
487  myBeginTime = time;
488 }
489 
490 
491 /****************************************************************************/
@ MID_SIMSTEP
A Simulation step was performed.
Definition: GUIAppEnum.h:481
#define GUIDesignToolBarGrip
design for toolbar grip (used to change the position of toolbar with mouse)
Definition: GUIDesigns.h:348
#define GUIDesignToolBar
design for default toolbar
Definition: GUIDesigns.h:336
@ APP_TLSTRACKER
FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[]
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:31
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_RED
The link has red light (must brake)
bool gHumanReadableTime
Definition: StdDefs.cpp:27
T MAX2(T a, T b)
Definition: StdDefs.h:79
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition: GLHelper.cpp:446
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:498
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 removeChild(FXMainWindow *child)
removes the given child window from the list (FXMainWindow)
void addChild(FXMainWindow *child)
Adds a further child window to the list (FXMainWindow)
long onConfigure(FXObject *, FXSelector, void *)
called on size change
long onPaint(FXObject *, FXSelector, void *)
called if the widget shall be repainted
This window displays a phase diagram for a chosen tl-logic.
GUITLLogicPhasesTrackerWindow()
protected constructor for FOX
FXMutex myLock
A lock to avoid addition of new values while drawing.
SUMOTime myBeginTime
The first time a phase was added at.
std::vector< std::string > myLinkNames
The names of links.
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.
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)
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.
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
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.
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)
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
Returns the phases of this tls program.
The parent class for traffic light logics.
const LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
const std::string & getProgramID() const
Returns this tl-logic's id.
const std::string & getID() const
Returns the id.
Definition: Named.h:73
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:36
static const RGBColor WHITE
Definition: RGBColor.h:187
@ FONS_ALIGN_MIDDLE
Definition: fontstash.h:47
@ FONS_ALIGN_LEFT
Definition: fontstash.h:42
@ FONS_ALIGN_BOTTOM
Definition: fontstash.h:48