SUMO - Simulation of Urban MObility
GUIParameterTracker.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-2018 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 which displays the time line of one (or more) value(s)
18 /****************************************************************************/
19 
20 
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25 
26 #include <string>
27 #include <fstream>
30 #include <utils/common/ToString.h>
32 #include <utils/common/SUMOTime.h>
33 #include <utils/gui/div/GLHelper.h>
41 #include "GUIParameterTracker.h"
43 
44 
45 // ===========================================================================
46 // FOX callback mapping
47 // ===========================================================================
48 FXDEFMAP(GUIParameterTracker) GUIParameterTrackerMap[] = {
49  FXMAPFUNC(SEL_CONFIGURE, 0, GUIParameterTracker::onConfigure),
50  FXMAPFUNC(SEL_PAINT, 0, GUIParameterTracker::onPaint),
51  FXMAPFUNC(SEL_COMMAND, MID_SIMSTEP, GUIParameterTracker::onSimStep),
54 
55 };
56 
57 // Macro for the GLTestApp class hierarchy implementation
58 FXIMPLEMENT(GUIParameterTracker, FXMainWindow, GUIParameterTrackerMap, ARRAYNUMBER(GUIParameterTrackerMap))
59 
60 
61 // ===========================================================================
62 // method definitions
63 // ===========================================================================
65  const std::string& name)
66  : FXMainWindow(app.getApp(), "Tracker", nullptr, nullptr, DECOR_ALL, 20, 20, 300, 200),
67  myApplication(&app) {
68  buildToolBar();
69  app.addChild(this);
70  FXVerticalFrame* glcanvasFrame = new FXVerticalFrame(this, FRAME_SUNKEN | LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 0, 0, 0, 0, 0, 0);
71  myPanel = new GUIParameterTrackerPanel(glcanvasFrame, *myApplication, *this);
72  setTitle(name.c_str());
74 }
75 
76 
79  for (std::vector<TrackerValueDesc*>::iterator i1 = myTracked.begin(); i1 != myTracked.end(); i1++) {
80  delete(*i1);
81  }
82  // deleted by GUINet
83  for (std::vector<GLObjectValuePassConnector<double>*>::iterator i2 = myValuePassers.begin(); i2 != myValuePassers.end(); i2++) {
84  delete(*i2);
85  }
86  delete myToolBarDrag;
87  delete myToolBar;
88 }
89 
90 
91 void
93  FXMainWindow::create();
94  myToolBarDrag->create();
95 }
96 
97 
98 void
100  myToolBarDrag = new FXToolBarShell(this, GUIDesignToolBarShell3);
101  myToolBar = new FXToolBar(this, myToolBarDrag, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | FRAME_RAISED);
102  new FXToolBarGrip(myToolBar, myToolBar, FXToolBar::ID_TOOLBARGRIP, GUIDesignToolBarGrip);
103  // save button
104  new FXButton(myToolBar, "\t\tSave the data...",
106  // aggregation interval combo
108  new FXComboBox(myToolBar, 8, this, MID_AGGREGATIONINTERVAL,
110  myAggregationInterval->appendItem("1s");
111  myAggregationInterval->appendItem("1min");
112  myAggregationInterval->appendItem("5min");
113  myAggregationInterval->appendItem("15min");
114  myAggregationInterval->appendItem("30min");
115  myAggregationInterval->appendItem("60min");
116  myAggregationInterval->setNumVisible(6);
117 }
118 
119 
120 void
122  TrackerValueDesc* newTracked) {
123  myTracked.push_back(newTracked);
124  // build connection (is automatically set into an execution map)
125  myValuePassers.push_back(new GLObjectValuePassConnector<double>(o, src, newTracked));
126 }
127 
128 
129 long
130 GUIParameterTracker::onConfigure(FXObject* sender, FXSelector sel, void* data) {
131  myPanel->onConfigure(sender, sel, data);
132  return FXMainWindow::onConfigure(sender, sel, data);
133 }
134 
135 
136 long
137 GUIParameterTracker::onPaint(FXObject* sender, FXSelector sel, void* data) {
138  myPanel->onPaint(sender, sel, data);
139  return FXMainWindow::onPaint(sender, sel, data);
140 }
141 
142 
143 long
144 GUIParameterTracker::onSimStep(FXObject*, FXSelector, void*) {
145  update();
146  return 1;
147 }
148 
149 
150 long
151 GUIParameterTracker::onCmdChangeAggregation(FXObject*, FXSelector, void*) {
152  int index = myAggregationInterval->getCurrentItem();
153  int aggInt = 0;
154  switch (index) {
155  case 0:
156  aggInt = 1;
157  break;
158  case 1:
159  aggInt = 60;
160  break;
161  case 2:
162  aggInt = 60 * 5;
163  break;
164  case 3:
165  aggInt = 60 * 15;
166  break;
167  case 4:
168  aggInt = 60 * 30;
169  break;
170  case 5:
171  aggInt = 60 * 60;
172  break;
173  default:
174  throw 1;
175  break;
176  }
177  for (std::vector<TrackerValueDesc*>::iterator i1 = myTracked.begin(); i1 != myTracked.end(); i1++) {
178  (*i1)->setAggregationSpan(TIME2STEPS(aggInt));
179  }
180  return 1;
181 }
182 
183 
184 long
185 GUIParameterTracker::onCmdSave(FXObject*, FXSelector, void*) {
186  FXString file = MFXUtils::getFilename2Write(this, "Save Data", ".csv", GUIIconSubSys::getIcon(ICON_EMPTY), gCurrentFolder);
187  if (file == "") {
188  return 1;
189  }
190  try {
191  OutputDevice& dev = OutputDevice::getDevice(file.text());
192  // write header
193  std::vector<TrackerValueDesc*>::iterator i;
194  dev << "# ";
195  for (i = myTracked.begin(); i != myTracked.end(); ++i) {
196  if (i != myTracked.begin()) {
197  dev << ';';
198  }
199  TrackerValueDesc* tvd = *i;
200  dev << tvd->getName();
201  }
202  dev << '\n';
203  // count entries
204  int max = 0;
205  for (i = myTracked.begin(); i != myTracked.end(); ++i) {
206  TrackerValueDesc* tvd = *i;
207  int sizei = (int)tvd->getAggregatedValues().size();
208  if (max < sizei) {
209  max = sizei;
210  }
211  tvd->unlockValues();
212  }
213  // write entries
214  for (int j = 0; j < max; j++) {
215  for (i = myTracked.begin(); i != myTracked.end(); ++i) {
216  if (i != myTracked.begin()) {
217  dev << ';';
218  }
219  TrackerValueDesc* tvd = *i;
220  dev << tvd->getAggregatedValues()[j];
221  tvd->unlockValues();
222  }
223  dev << '\n';
224  }
225  dev.close();
226  } catch (IOError& e) {
227  FXMessageBox::error(this, MBOX_OK, "Storing failed!", "%s", e.what());
228  }
229  return 1;
230 }
231 
232 
233 /* -------------------------------------------------------------------------
234  * GUIParameterTracker::GUIParameterTrackerPanel-methods
235  * ----------------------------------------------------------------------- */
236 FXDEFMAP(GUIParameterTracker::GUIParameterTrackerPanel) GUIParameterTrackerPanelMap[] = {
239 
240 };
241 
242 // Macro for the GLTestApp class hierarchy implementation
243 FXIMPLEMENT(GUIParameterTracker::GUIParameterTrackerPanel, FXGLCanvas, GUIParameterTrackerPanelMap, ARRAYNUMBER(GUIParameterTrackerPanelMap))
244 
245 
246 
248  FXComposite* c, GUIMainWindow& app,
249  GUIParameterTracker& parent)
250  : FXGLCanvas(c, app.getGLVisual(), app.getBuildGLCanvas(), (FXObject*) nullptr, (FXSelector) 0, LAYOUT_SIDE_TOP | LAYOUT_FILL_X | LAYOUT_FILL_Y, 0, 0, 300, 200),
251  myParent(&parent), myApplication(&app) {}
252 
253 
255 
256 
257 void
259  glMatrixMode(GL_PROJECTION);
260  glLoadIdentity();
261  glMatrixMode(GL_MODELVIEW);
262  glLoadIdentity();
263  glDisable(GL_TEXTURE_2D);
264  int run = 0;
265  for (std::vector<TrackerValueDesc*>::iterator i = myParent->myTracked.begin(); i != myParent->myTracked.end(); i++) {
266  TrackerValueDesc* desc = *i;
267  drawValue(*desc,
268  (double) myWidthInPixels / (double) myParent->myTracked.size() * (double) run);
269  run++;
270  }
271 }
272 
273 
274 void
276  double /*namePos*/) {
277  const double fontWidth = 0.1 * 300. / myWidthInPixels;
278  const double fontHeight = 0.1 * 300. / myHeightInPixels;
279  //
280  // apply scaling
281  glPushMatrix();
282 
283  // apply the positiopn offset of the display
284  glScaled(0.8, 0.8, 1);
285  // apply value range scaling
286  double ys = (double) 2.0 / (double) desc.getRange();
287  glScaled(1.0, ys, 1.0);
288  glTranslated(-1.0, -desc.getYCenter(), 0);
289 
290  // set color
291  const unsigned char red = desc.getColor().red();
292  const unsigned char green = desc.getColor().green();
293  const unsigned char blue = desc.getColor().blue();
294  // draw value bounderies
295  // draw minimum boundary
296  glBegin(GL_LINES);
297  glVertex2d(0, desc.getMin());
298  glVertex2d(2.0, desc.getMin());
299  glEnd();
300  glBegin(GL_LINES);
301  glVertex2d(0, desc.getMax());
302  glVertex2d(2.0, desc.getMax());
303  glEnd();
304  glColor4ub(red, green, blue, 77);
305  for (int a = 1; a < 6; a++) {
306  double ypos = (desc.getRange()) / (double) 6.0 * (double) a + desc.getMin();
307  glBegin(GL_LINES);
308  glVertex2d(0, ypos);
309  glVertex2d(2.0, ypos);
310  glEnd();
311  }
312  const std::vector<double>& values = desc.getAggregatedValues();
313  double latest = 0;
314  if (values.size() < 2) {
315  glPopMatrix();
316  desc.unlockValues();
317  return;
318  } else {
319  latest = values.back();
320  // init values
321  double xStep = (double) 2.0 / (double) values.size();
322  std::vector<double>::const_iterator i = values.begin();
323  double yp = (*i);
324  double xp = 0;
325  i++;
326  glColor4ub(red, green, blue, 255);
327  for (; i != values.end(); i++) {
328  double yn = (*i);
329  double xn = xp + xStep;
330  glBegin(GL_LINES);
331  glVertex2d(xp, yp);
332  glVertex2d(xn, yn);
333  glEnd();
334  yp = yn;
335  xp = xn;
336  }
337  desc.unlockValues();
338  glPopMatrix();
339  }
340 
341  // draw value bounderies and descriptions
342  glColor3b(red, green, blue);
343 
344  // draw min time
345  SUMOTime beginStep = desc.getRecordingBegin();
346  std::string begStr = time2string(beginStep);
347  double w = 50 / myWidthInPixels;
348  glTranslated(-0.8 - w / 2., -0.88, 0);
349  GLHelper::drawText(begStr, Position(0, 0), 1, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
350  glTranslated(0.8 + w / 2., 0.88, 0);
351 
352  // draw max time
353  glTranslated(0.75, -0.88, 0);
354  GLHelper::drawText(time2string(beginStep + static_cast<SUMOTime>(values.size() * desc.getAggregationSpan())),
355  Position(0, 0), 1, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
356  glTranslated(-0.75, 0.88, 0);
357 
358  // draw min value
359  glTranslated(-0.98, -0.82, 0);
360  GLHelper::drawText(toString(desc.getMin()), Position(0, 0), 1, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
361  glTranslated(0.98, 0.82, 0);
362 
363  // draw max value
364  glTranslated(-0.98, 0.78, 0);
365  GLHelper::drawText(toString(desc.getMax()), Position(0, 0), 1, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
366  glTranslated(0.98, -0.78, 0);
367 
368  // draw current value
369  double p = (double) 0.8 -
370  ((double) 1.6 / (desc.getMax() - desc.getMin()) * (latest - desc.getMin()));
371  glTranslated(-0.98, -(p + .02), 0);
372  GLHelper::drawText(toString(latest), Position(0, 0), 1, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
373  glTranslated(0.98, p + .02, 0);
374 
375  // draw name
376  glTranslated(-0.98, .92, 0);
377  GLHelper::drawText(desc.getName(), Position(0, 0), 1, fontHeight, RGBColor::BLACK, 0, FONS_ALIGN_LEFT | FONS_ALIGN_MIDDLE, fontWidth);
378  glTranslated(0.98, -.92, 0);
379 }
380 
381 
382 long
384  FXSelector, void*) {
385  if (makeCurrent()) {
386  myWidthInPixels = myParent->getWidth();
387  myHeightInPixels = myParent->getHeight();
388  if (myWidthInPixels != 0 && myHeightInPixels != 0) {
389  glViewport(0, 0, myWidthInPixels - 1, myHeightInPixels - 1);
390  glClearColor(1.0, 1.0, 1.0, 1);
391  glDisable(GL_DEPTH_TEST);
392  glDisable(GL_LIGHTING);
393  glDisable(GL_LINE_SMOOTH);
394  glEnable(GL_BLEND);
395  glEnable(GL_ALPHA_TEST);
396  glDisable(GL_COLOR_MATERIAL);
397  glLineWidth(1);
398  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
399  }
400  makeNonCurrent();
401  }
402  return 1;
403 }
404 
405 
406 long
408  FXSelector, void*) {
409  if (!isEnabled()) {
410  return 1;
411  }
412  if (makeCurrent()) {
413  myWidthInPixels = getWidth();
414  myHeightInPixels = getHeight();
415  if (myWidthInPixels != 0 && myHeightInPixels != 0) {
416  glViewport(0, 0, myWidthInPixels - 1, myHeightInPixels - 1);
417  glClearColor(1.0, 1.0, 1.0, 1);
418  glDisable(GL_DEPTH_TEST);
419  glDisable(GL_LIGHTING);
420  glDisable(GL_LINE_SMOOTH);
421  glEnable(GL_BLEND);
422  glEnable(GL_ALPHA_TEST);
423  glDisable(GL_COLOR_MATERIAL);
424  glLineWidth(1);
425  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
426  // draw
427  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
428  drawValues();
429  swapBuffers();
430  }
431  makeNonCurrent();
432  }
433  return 1;
434 }
435 
436 
437 
438 /****************************************************************************/
439 
double getYCenter() const
Returns the center of the value.
void close()
Closes the device and removes it from the dictionary.
long long int SUMOTime
Definition: SUMOTime.h:36
void drawValue(TrackerValueDesc &desc, double namePos)
Draws a single value.
#define GUIDesignButtonToolbar
little button with icon placed in navigation toolbar
Definition: GUIDesigns.h:80
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:65
#define GUIDesignToolBarGrip
design for toolbar grip (used to change the position of toolbar with mouse)
Definition: GUIDesigns.h:283
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:611
void unlockValues()
Releases the locking after the values have been drawn.
SUMOTime getRecordingBegin() const
Returns the timestep the recording started.
Representation of a timeline of floats with their names and moments.
FXString gCurrentFolder
The folder used as last.
unsigned char blue() const
Returns the blue-amount of the color.
Definition: RGBColor.h:77
static const RGBColor BLACK
Definition: RGBColor.h:192
#define TIME2STEPS(x)
Definition: SUMOTime.h:60
long onCmdSave(FXObject *, FXSelector, void *)
Called when the data shall be saved.
GUIMainWindow * myApplication
The main application.
static FXString getFilename2Write(FXWindow *parent, const FXString &header, const FXString &extension, FXIcon *icon, FXString &currentFolder)
Returns the file name to write.
Definition: MFXUtils.cpp:84
long onPaint(FXObject *, FXSelector, void *)
Called if the window shall be repainted.
FXToolBar * myToolBar
The tracker tool bar.
SUMOTime getAggregationSpan() const
get the aggregation amount
A window which displays the time line of one (or more) value(s)
Save the current values.
FXToolBarShell * myToolBarDrag
for some menu detaching fun
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
void addTracked(GUIGlObject &o, ValueSource< double > *src, TrackerValueDesc *newTracked)
Adds a further time line to display.
FXComboBox * myAggregationInterval
A combo box to select an aggregation interval.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:39
void buildToolBar()
Builds the tool bar.
#define GUIDesignComboBoxStatic
Combo box static (not editable)
Definition: GUIDesigns.h:198
long onPaint(FXObject *, FXSelector, void *)
Called if the window shall be repainted.
const std::vector< double > & getAggregatedValues()
returns the vector of aggregated values The values will be locked - no further addition will be perfo...
long onSimStep(FXObject *, FXSelector, void *)
Called on a simulation step.
void create()
Creates the window.
~GUIParameterTracker()
Destructor.
void removeChild(FXMainWindow *child)
const std::string & getName() const
Returns the name of the value.
long onCmdChangeAggregation(FXObject *, FXSelector, void *)
Called when the aggregation interval (combo) has been changed.
static OutputDevice & getDevice(const std::string &name)
Returns the described OutputDevice.
unsigned char green() const
Returns the green-amount of the color.
Definition: RGBColor.h:70
double getMax() const
Returns the values maximum.
A Simulation step was performed.
Definition: GUIAppEnum.h:294
std::vector< TrackerValueDesc * > myTracked
The list of tracked values.
GUIParameterTrackerPanel * myPanel
The panel to display the values in.
unsigned char red() const
Returns the red-amount of the color.
Definition: RGBColor.h:63
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
const RGBColor & getColor() const
Returns the color to use to display the value.
double getMin() const
Returns the values minimum.
#define GUIDesignToolBarShell3
Definition: GUIDesigns.h:291
static FXIcon * getIcon(GUIIcon which)
returns a icon previously defined in the enum GUIIcon
std::vector< GLObjectValuePassConnector< double > * > myValuePassers
The value sources.
long onConfigure(FXObject *, FXSelector, void *)
Called on window resizing.
double getRange() const
returns the maximum value range
FXDEFMAP(GUIParameterTracker) GUIParameterTrackerMap[]
Class passing values from a GUIGlObject to another object.
long onConfigure(FXObject *, FXSelector, void *)
Called on window resizing.