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