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-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
17 // A window displaying the phase diagram of a tl-logic
18 /****************************************************************************/
19 
20 
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25 
26 #include <vector>
27 #include <iostream>
29 #include <utils/gui/div/GLHelper.h>
32 #include <microsim/MSLink.h>
33 #include <utils/common/ToString.h>
42 
43 
44 // ===========================================================================
45 // member method definitions
46 // ===========================================================================
47 /* -------------------------------------------------------------------------
48  * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-callbacks
49  * ----------------------------------------------------------------------- */
50 FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[] = {
53 
54 };
55 
56 // Macro for the GLTestApp class hierarchy implementation
57 FXIMPLEMENT(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel, FXGLCanvas, GUITLLogicPhasesTrackerPanelMap, ARRAYNUMBER(GUITLLogicPhasesTrackerPanelMap))
58 
59 
60 
61 /* -------------------------------------------------------------------------
62  * GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel-methods
63  * ----------------------------------------------------------------------- */
65  FXComposite* c, GUIMainWindow& app,
67  : FXGLCanvas(c, app.getGLVisual(), app.getBuildGLCanvas(), (FXObject*) nullptr, (FXSelector) 0, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y/*, 0, 0, 300, 200*/),
68  myParent(&parent) {}
69 
70 
72 
73 
74 long
76  FXObject*, FXSelector, void*) {
77  if (makeCurrent()) {
78  int widthInPixels = getWidth();
79  int heightInPixels = getHeight();
80  if (widthInPixels != 0 && heightInPixels != 0) {
81  glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
82  glClearColor(0, 0, 0, 1);
83  glDisable(GL_DEPTH_TEST);
84  glDisable(GL_LIGHTING);
85  glDisable(GL_LINE_SMOOTH);
86  glEnable(GL_BLEND);
87  glEnable(GL_ALPHA_TEST);
88  glDisable(GL_COLOR_MATERIAL);
89  glLineWidth(1);
90  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
91  }
92  }
93  return 1;
94 }
95 
96 
97 long
99  FXObject*, FXSelector, void*) {
100  if (!isEnabled()) {
101  return 1;
102  }
103  if (makeCurrent()) {
104  int widthInPixels = getWidth();
105  int heightInPixels = getHeight();
106  if (widthInPixels != 0 && heightInPixels != 0) {
107  glViewport(0, 0, widthInPixels - 1, heightInPixels - 1);
108  glClearColor(0, 0, 0, 1);
109  glDisable(GL_DEPTH_TEST);
110  glDisable(GL_LIGHTING);
111  glDisable(GL_LINE_SMOOTH);
112  glEnable(GL_BLEND);
113  glEnable(GL_ALPHA_TEST);
114  glDisable(GL_COLOR_MATERIAL);
115  glLineWidth(1);
116  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
117  // draw
118  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
119  myParent->drawValues(*this);
120  swapBuffers();
121  }
122  makeNonCurrent();
123  }
124  return 1;
125 }
126 
127 
128 
129 /* -------------------------------------------------------------------------
130  * GUITLLogicPhasesTrackerWindow - FOX callback mapping
131  * ----------------------------------------------------------------------- */
132 FXDEFMAP(GUITLLogicPhasesTrackerWindow) GUITLLogicPhasesTrackerWindowMap[] = {
133  FXMAPFUNC(SEL_CONFIGURE, 0, GUITLLogicPhasesTrackerWindow::onConfigure),
134  FXMAPFUNC(SEL_PAINT, 0, GUITLLogicPhasesTrackerWindow::onPaint),
135  FXMAPFUNC(SEL_COMMAND, MID_SIMSTEP, GUITLLogicPhasesTrackerWindow::onSimStep),
136 
137 };
138 
139 FXIMPLEMENT(GUITLLogicPhasesTrackerWindow, FXMainWindow, GUITLLogicPhasesTrackerWindowMap, ARRAYNUMBER(GUITLLogicPhasesTrackerWindowMap))
140 
141 
142 /* -------------------------------------------------------------------------
143  * GUITLLogicPhasesTrackerWindow-methods
144  * ----------------------------------------------------------------------- */
146  GUIMainWindow& app,
148  ValueSource<std::pair<SUMOTime, MSPhaseDefinition> >* src)
149  : FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL,
150  20, 20, 300, 200),
151  myApplication(&app), myTLLogic(&logic), myAmInTrackingMode(true) {
152  // build the toolbar
153  myToolBarDrag = new FXToolBarShell(this, GUIDesignToolBar);
154  myToolBar = new FXToolBar(this, myToolBarDrag, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | FRAME_RAISED);
155  new FXToolBarGrip(myToolBar, myToolBar, FXToolBar::ID_TOOLBARGRIP, GUIDesignToolBarGrip);
156  // interval manipulation
157  myBeginOffset = new FXRealSpinner(myToolBar, 10, this, MID_SIMSTEP, LAYOUT_TOP | FRAME_SUNKEN | FRAME_THICK);
158  //myBeginOffset->setFormatString("%.0f");
159  //myBeginOffset->setIncrements(1, 10, 100);
160  myBeginOffset->setIncrement(10);
161  myBeginOffset->setRange(60, 3600);
162  myBeginOffset->setValue(240);
163  new FXLabel(myToolBar, "(s)", nullptr, LAYOUT_CENTER_Y);
164  //
166  FXint height = (FXint)(myTLLogic->getLinks().size() * 20 + 30 + 8 + 30);
167  app.addChild(this);
168  for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
169  myLinkNames.push_back(toString<int>(i));
170  }
171  FXVerticalFrame* glcanvasFrame =
172  new FXVerticalFrame(this,
173  FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
174  0, 0, 0, 0, 0, 0, 0, 0);
175  myPanel = new
176  GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
177  setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str());
179  setHeight(height);
180 }
181 
182 
184  GUIMainWindow& app,
186  const MSSimpleTrafficLightLogic::Phases& /*phases*/)
187  : FXMainWindow(app.getApp(), "TLS-Tracker", nullptr, nullptr, DECOR_ALL,
188  20, 20, 300, 200),
189  myApplication(&app), myTLLogic(&logic), myAmInTrackingMode(false),
190  myToolBarDrag(nullptr), myBeginOffset(nullptr) {
191  myConnector = nullptr;
192  FXint height = (FXint)(myTLLogic->getLinks().size() * 20 + 30 + 8);
193  setTitle("TLS-Tracker");
194  app.addChild(this);
195  for (int i = 0; i < (int)myTLLogic->getLinks().size(); ++i) {
196  myLinkNames.push_back(toString<int>(i));
197  }
198  FXVerticalFrame* glcanvasFrame =
199  new FXVerticalFrame(this,
200  FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y,
201  0, 0, 0, 0, 0, 0, 0, 0);
202  myPanel = new
203  GUITLLogicPhasesTrackerPanel(glcanvasFrame, *myApplication, *this);
204  setTitle((logic.getID() + " - " + logic.getProgramID() + " - tracker").c_str());
206  setHeight(height);
207 }
208 
209 
211  myApplication->removeChild(this);
212  delete myConnector;
213  // just to quit cleanly on a failure
214  if (myLock.locked()) {
215  myLock.unlock();
216  }
217  delete myToolBarDrag;
218 }
219 
220 
221 void
223  FXMainWindow::create();
224  if (myToolBarDrag != nullptr) {
225  myToolBarDrag->create();
226  }
227 }
228 
229 
230 void
232  // compute what shall be shown (what is visible)
233  myFirstPhase2Show = 0;
234  myFirstPhaseOffset = 0;
235  SUMOTime leftOffset = 0;
236  myFirstTime2Show = 0;
237  if (!myAmInTrackingMode) {
238  myPhases.clear();
239  myDurations.clear();
240  // insert phases
241  MSSimpleTrafficLightLogic* simpleTLLogic = dynamic_cast<MSSimpleTrafficLightLogic*>(myTLLogic);
242  if (simpleTLLogic == nullptr) {
243  return;
244  }
245  const MSSimpleTrafficLightLogic::Phases& phases = simpleTLLogic->getPhases();
246  MSSimpleTrafficLightLogic::Phases::const_iterator j;
247  myLastTime = 0;
248  myBeginTime = 0;
249  for (j = phases.begin(); j != phases.end(); ++j) {
250  myPhases.push_back(*(*j));
251  myDurations.push_back((*j)->duration);
252  myLastTime += (*j)->duration;
253  }
254  if (myLastTime <= myBeginTime) {
255  WRITE_ERROR("Overflow in time computation occurred.");
256  return;
257  }
258  } else {
259  SUMOTime beginOffset = TIME2STEPS(myBeginOffset->getValue());
260  myBeginTime = myLastTime - beginOffset;
262  // check whether no phases are known at all
263  if (myDurations.size() != 0) {
264  SUMOTime durs = 0;
265  int phaseOffset = (int)myDurations.size() - 1;
266  DurationsVector::reverse_iterator i = myDurations.rbegin();
267  while (i != myDurations.rend()) {
268  if (durs + (*i) > beginOffset) {
269  myFirstPhase2Show = phaseOffset;
270  myFirstPhaseOffset = (durs + (*i)) - beginOffset;
271  break;
272  }
273  durs += (*i);
274  phaseOffset--;
275  ++i;
276  }
277  if (i == myDurations.rend()) {
278  // there are too few information stored;
279  myFirstPhase2Show = 0;
280  myFirstPhaseOffset = 0;
281  leftOffset = beginOffset - durs;
282  }
283  }
284  }
285  // begin drawing
286  glMatrixMode(GL_PROJECTION);
287  glLoadIdentity();
288  glMatrixMode(GL_MODELVIEW);
289  glLoadIdentity();
290  glTranslated(-1, -1, 0);
291  glScaled(2, 2, 1);
292  glDisable(GL_TEXTURE_2D);
293  // draw the horizontal lines dividing the signal groups
294  glColor3d(1, 1, 1);
295  // compute some values needed more than once
296  const double height = (double) caller.getHeight();
297  const double width = (double) caller.getWidth();
298  const double barWidth = MAX2(1.0, width - 31);
299  const double fontHeight = 0.08 * 300. / height;
300  const double fontWidth = 0.08 * 300. / width;
301  const double h9 = ((double) 9 / height);
302  const double h10 = ((double) 10 / height);
303  const double h11 = ((double) 11 / height);
304  const double h16 = ((double) 16 / height);
305  const double h20 = ((double) 20 / height);
306  // draw the link names and the lines dividing them
307  double h = (double)(1.0 - h10);
308  double h2 = 12;
309  for (int i = 0; i < (int)myTLLogic->getLinks().size() + 1; ++i) {
310  // draw the bar
311  glBegin(GL_LINES);
312  glVertex2d(0, h);
313  glVertex2d((double)(30. / width), h);
314  glEnd();
315  // draw the name
316  if (i < (int)myTLLogic->getLinks().size()) {
317  glTranslated(0, h - h20, 0);
318  GLHelper::drawText(myLinkNames[i], Position(0, 0), 1, fontHeight, RGBColor::WHITE, 0, FONS_ALIGN_LEFT | FONS_ALIGN_BOTTOM, fontWidth);
319  glTranslated(0, -h + h20, 0);
320  h2 += 20;
321  }
322  h -= h20;
323  }
324  glBegin(GL_LINES);
325  glVertex2d(0, h + h20);
326  glVertex2d(1.0, h + h20);
327  glEnd();
328 
329  // draw the names closure (vertical line)
330  h += (double) 20 / height;
331  glColor3d(1, 1, 1);
332  glBegin(GL_LINES);
333  glVertex2d((double) 30 / width, 1.0);
334  glVertex2d((double) 30 / width, h);
335  glEnd();
336 
337 
338  // draw the phases
339  // disable value addition while drawing
340  myLock.lock();
341  // determine the initial offset
342  double x = ((double) 31. / width);
343  double ta = (double) leftOffset / width;
344  ta *= (double)((barWidth / ((double)(myLastTime - myBeginTime))));
345  x += ta;
346 
347  // and the initial phase information
348  PhasesVector::iterator pi = myPhases.begin() + myFirstPhase2Show;
349 
351 
352  // start drawing
353  for (DurationsVector::iterator pd = myDurations.begin() + myFirstPhase2Show; pd != myDurations.end(); ++pd) {
354  SUMOTime i = 30;
355  // the first phase may be drawn incompletely
356  SUMOTime duration = *pd - fpo;
357  // compute the heigh and the width of the phase
358  h = (double)(1.0 - h10);
359  double a = (double) duration / width;
360  a *= (double)((barWidth / ((double)(myLastTime - myBeginTime))));
361  const double x2 = x + a;
362 
363  // go through the links
364  for (int j = 0; j < (int) myTLLogic->getLinks().size(); ++j) {
365  // determine the current link's color
366  LinkState state = pi->getSignalState(j);
367  // draw the bar (red is drawn as a line)
369  switch (state) {
370  case LINKSTATE_TL_RED:
372  // draw a thin line
373  glBegin(GL_QUADS);
374  glVertex2d(x, h - h11);
375  glVertex2d(x, h - h9);
376  glVertex2d(x2, h - h9);
377  glVertex2d(x2, h - h11);
378  glEnd();
379  break;
380  default:
381  // draw a thick block
382  glBegin(GL_QUADS);
383  glVertex2d(x, h - h16);
384  glVertex2d(x, h);
385  glVertex2d(x2, h);
386  glVertex2d(x2, h - h16);
387  glEnd();
388  break;
389  }
390  // proceed to next link
391  h -= h20;
392  }
393  // proceed to next phase
394  i += duration;
395  ++pi;
396  x = x2;
397  // all further phases are drawn in full
398  fpo = 0;
399  }
400  // allow value addition
401  myLock.unlock();
402 
403  glColor3d(1, 1, 1);
404  if (myPhases.size() != 0) {
405  SUMOTime tickDist = TIME2STEPS(10);
406  // patch distances - hack
407  double t = myBeginOffset != nullptr ? (double) myBeginOffset->getValue() : STEPS2TIME(myLastTime - myBeginTime);
408  while (t > barWidth / 4.) {
409  tickDist += TIME2STEPS(10);
410  t -= (double)(barWidth / 4.);
411  }
412  // draw time information
413  //h = (double)(myTLLogic->getLinks().size() * 20 + 12);
414  double glh = (double)(1.0 - myTLLogic->getLinks().size() * h20 - h10);
415  // current begin time
416  // time ticks
417  SUMOTime currTime = myFirstTime2Show;
418  int pos = 31;// + /*!!!currTime*/ - myFirstTime2Show;
419  double glpos = (double) pos / width;
420  const double ticSize = 4 / height;
421  while (pos < width + 50) {
422  const std::string timeStr = time2string(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
466  FXSelector sel, void* data) {
467  myPanel->onConfigure(sender, sel, data);
468  return FXMainWindow::onConfigure(sender, sel, data);
469 }
470 
471 
472 long
474  FXSelector sel, void* data) {
475  myPanel->onPaint(sender, sel, data);
476  return FXMainWindow::onPaint(sender, sel, data);
477 }
478 
479 
480 long
482  FXSelector, void*) {
483  update();
484  return 1;
485 }
486 
487 
488 void
490  myBeginTime = time;
491 }
492 
493 
494 /****************************************************************************/
495 
long long int SUMOTime
Definition: SUMOTime.h:35
bool myAmInTrackingMode
Information whether the tracking mode is on.
GUIMainWindow * myApplication
The main application.
static const RGBColor WHITE
Definition: RGBColor.h:197
long onSimStep(FXObject *sender, FXSelector sel, void *data)
called on a simulation step
void create()
Creates the window (FOX-Toolkit)
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:65
std::vector< std::string > myLinkNames
The names of links.
#define GUIDesignToolBarGrip
design for toolbar grip (used to change the position of toolbar with mouse)
Definition: GUIDesigns.h:323
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, int align=0, double width=-1)
Definition: GLHelper.cpp:668
int myFirstPhase2Show
The index of the first phase that fits into the window.
T MAX2(T a, T b)
Definition: StdDefs.h:80
SUMOTime DELTA_T
Definition: SUMOTime.cpp:35
PhasesVector myPhases
The list of phases.
#define GUIDesignToolBar
design for default toolbar
Definition: GUIDesigns.h:311
const std::string & getID() const
Returns the id.
Definition: Named.h:77
#define TIME2STEPS(x)
Definition: SUMOTime.h:59
DurationsVector myDurations
The list of phase durations.
const LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
long onConfigure(FXObject *sender, FXSelector sel, void *data)
called on size change
FXDEFMAP(GUITLLogicPhasesTrackerWindow::GUITLLogicPhasesTrackerPanel) GUITLLogicPhasesTrackerPanelMap[]
A fixed traffic light logic.
void drawValues(GUITLLogicPhasesTrackerPanel &caller)
Draws all values.
FXMutex myLock
A lock to avoid addition of new values while drawing.
SUMOTime myFirstTime2Show
The time the diagram begins at.
static void setColor(const RGBColor &c)
Sets the gl-color to this value.
Definition: GLHelper.cpp:616
const std::string & getProgramID() const
Returns this tl-logic&#39;s id.
long onConfigure(FXObject *, FXSelector, void *)
called on size change
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
#define STEPS2TIME(x)
Definition: SUMOTime.h:57
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic, in MSLink and GNEInternalLane.
FXToolBarShell * myToolBarDrag
The tool bar drag (tracking mode)
SUMOTime myLastTime
The last time a phase was added at.
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.
SUMOTime myFirstPhaseOffset
The offset to draw the first phase (left offset)
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:245
void removeChild(FXMainWindow *child)
A Simulation step was performed.
Definition: GUIAppEnum.h:441
The link has red light (must brake)
MSTrafficLightLogic * myTLLogic
The logic to display.
long onPaint(FXObject *sender, FXSelector sel, void *data)
called if the widget shall be repainted
GUITLLogicPhasesTrackerPanel * myPanel
The panel to draw on.
This window displays a phase diagram for a chosen tl-logic.
The parent class for traffic light logics.
FXToolBar * myToolBar
The tool bar (tracking mode)
void setBeginTime(SUMOTime time)
Sets the time the display shall be shown as beginning at.
GUITLLogicPhasesTrackerWindow()
protected constructor for FOX
void addChild(FXMainWindow *child)
const Phases & getPhases() const
Returns the phases of this tls program.
FXRealSpinner * myBeginOffset
The offset changer (tracking mode)
long onPaint(FXObject *, FXSelector, void *)
called if the widget shall be repainted
The definition of a single phase of a tls logic.
static const RGBColor & getLinkColor(const LinkState &ls)
map from LinkState to color constants
static FXIcon * getIcon(GUIIcon which)
returns a icon previously defined in the enum GUIIcon
The link has red light (must brake) but indicates upcoming green.
SUMOTime myBeginTime
The first time a phase was added at.
Class passing values from a GUIGlObject to another object.