publisher_csv.cpp
Go to the documentation of this file.
1 #include <QTextStream>
2 #include <QFile>
3 #include <QMessageBox>
4 #include <thread>
5 #include <QGuiApplication>
6 #include <QClipboard>
7 #include <sstream>
8 #include <QFileDialog>
9 #include <QMessageBox>
10 #include <QSettings>
11 #include <QByteArray>
12 #include "publisher_csv.h"
13 
15 {
16 }
17 
19 {
20 }
21 
23 {
24  _enabled = enabled;
25 
26  if (_enabled)
27  {
28  _dialog = new QDialog();
29  _notification_timer = new QTimer(_dialog);
30  _notification_timer->setSingleShot(true);
31 
32  _ui = new Ui::PublisherCSV_DIalog();
33  _ui->setupUi(_dialog);
34  _dialog->setAttribute(Qt::WA_DeleteOnClose);
35 
36  _start_time = std::numeric_limits<double>::quiet_NaN();
37  _end_time = std::numeric_limits<double>::quiet_NaN();
38  _ui->lineEditStart->setText("");
39  _ui->lineEditEnd->setText("");
40 
42 
43  //--------------------
44  connect(_notification_timer, &QTimer::timeout, this,
45  [this]() { _ui->labelNotification->setText(""); });
46  //--------------------
47  connect(_dialog, &QDialog::finished, this, &StatePublisherCSV::onWindowClosed);
48 
49  //--------------------
50  connect(_ui->buttonGetStart, &QPushButton::clicked, this, [this]() {
51  _start_time = _previous_time;
52  _ui->checkBoxFirst->setChecked(false);
53  _ui->lineEditStart->setEnabled(true);
54  _ui->lineEditStart->setText(QString::number(_previous_time, 'f', 3));
55  updateButtonsState();
56  });
57  //--------------------
58  connect(_ui->buttonGetEnd, &QPushButton::clicked, this, [this]() {
59  _end_time = _previous_time;
60  _ui->checkBoxLast->setChecked(false);
61  _ui->lineEditEnd->setEnabled(true);
62  _ui->lineEditEnd->setText(QString::number(_previous_time, 'f', 3));
63  updateButtonsState();
64  });
65  //--------------------
66  connect(_ui->checkBoxFirst, &QCheckBox::toggled, this, [this](bool checked) {
67  _ui->lineEditStart->setEnabled(!checked);
68  _start_time = (checked) ? std::numeric_limits<double>::lowest() : _previous_time;
69  updateButtonsState();
70  });
71  //--------------------
72  connect(_ui->checkBoxLast, &QCheckBox::toggled, this, [this](bool checked) {
73  _ui->lineEditEnd->setEnabled(!checked);
74  _end_time = (checked) ? std::numeric_limits<double>::max() : _previous_time;
75 
76  updateButtonsState();
77  });
78  //--------------------
79  connect(_ui->buttonStatisticsClip, &QPushButton::clicked, this, [this]() {
80  auto csv_string = generateStatisticsCSV(_start_time, _end_time);
81  QClipboard* clipboard = QGuiApplication::clipboard();
82  clipboard->setText(csv_string);
83  _ui->labelNotification->setText("Statistics copied to Clipboard");
84  _notification_timer->start(2000);
85  });
86 
87  //--------------------
88  connect(_ui->buttonRangeClip, &QPushButton::clicked, this, [this]() {
89  auto csv_string = generateRangeCSV(_start_time, _end_time);
90  QClipboard* clipboard = QGuiApplication::clipboard();
91  clipboard->setText(csv_string);
92  _ui->labelNotification->setText("Range data copied to Clipboard");
93  _notification_timer->start(2000);
94  });
95 
96  //--------------------
97  connect(_ui->buttonStatisticsFile, &QPushButton::clicked, this, [this]() {
98  auto csv_string = generateStatisticsCSV(_start_time, _end_time);
99  this->saveFile(csv_string);
100  });
101 
102  //--------------------
103  connect(_ui->buttonRangeFile, &QPushButton::clicked, this, [this]() {
104  auto csv_string = generateRangeCSV(_start_time, _end_time);
105  this->saveFile(csv_string);
106  });
107 
108  //--------------------
109  _dialog->setWindowFlag(Qt::WindowStaysOnTopHint);
110  _dialog->show();
111  }
112  else
113  {
114  if (_dialog)
115  {
116  _dialog->done(0);
117  }
118  }
119 }
120 
122 {
123  _enabled = false;
124  emit closed();
125 }
126 
127 QString StatePublisherCSV::generateStatisticsCSV(double time_start, double time_end)
128 {
129  std::map<std::string, const PJ::PlotData*> ordered_map;
130  for (const auto& it : _datamap->numeric)
131  {
132  ordered_map.insert({ it.first, &it.second });
133  }
134 
135  std::stringstream out;
136  out << "Series,Current,Min,Max,Average\n";
137  out << "Start Time," << time_start << "\n";
138  out << "End Time," << time_end << "\n";
139  out << "Current Time," << _previous_time << "\n";
140 
141  for (const auto& it : ordered_map)
142  {
143  const auto& name = it.first;
144  const auto& plot = *(it.second);
145  int index = plot.getIndexFromX(time_start);
146  if (index < 0)
147  {
148  continue; // skip this
149  }
150 
151  auto current_value = plot.getYfromX(_previous_time);
152 
153  auto point = plot.at(index);
154 
155  if (point.x > time_end) // out of range
156  {
157  continue;
158  }
159  if (index + 1 == plot.size()) // out of range
160  {
161  continue;
162  }
163 
164  double min_value = point.y;
165  double max_value = point.y;
166  double total = point.y;
167  int count = 1;
168  index++;
169 
170  while (index < plot.size())
171  {
172  point = plot.at(index);
173  if (point.x > time_end)
174  {
175  break;
176  }
177  double value = point.y;
178  max_value = std::max(max_value, value);
179  min_value = std::min(min_value, value);
180  total += value;
181  count++;
182  index++;
183  }
184  out << name << ',';
185  out << ((current_value) ? std::to_string(current_value.value()) : "");
186  out << ',';
187  out << std::to_string(min_value) << ',';
188  out << std::to_string(max_value) << ',';
189  out << std::to_string(total / double(count)) << '\n';
190  }
191  return QString::fromStdString(out.str());
192 }
193 
194 bool StatePublisherCSV::getTimeRanges(double* first, double* last)
195 {
196  bool ok;
197  *first = _ui->lineEditStart->text().toDouble(&ok);
198  if (!ok)
199  {
200  return false;
201  }
202  *last = _ui->lineEditEnd->text().toDouble(&ok);
203  if (!ok)
204  {
205  return false;
206  }
207  return true;
208 }
209 
211 {
212  bool enable = (_start_time <= _end_time);
213  _ui->buttonRangeClip->setEnabled(enable);
214  _ui->buttonRangeFile->setEnabled(enable);
215  _ui->buttonStatisticsClip->setEnabled(enable);
216  _ui->buttonStatisticsFile->setEnabled(enable);
217 }
218 
219 void StatePublisherCSV::saveFile(QString text)
220 {
221  // QFileDialog::getSaveFileName(nullptr, "Save as CSV file", );
222 
223  QSettings settings;
224  QString directory_path =
225  settings.value("StatePublisherCSV.saveDirectory", QDir::currentPath()).toString();
226 
227  QString fileName = QFileDialog::getSaveFileName(
228  nullptr, tr("Save as CSV file"), directory_path, tr("CSV files (*.csv)"));
229 
230  if (fileName.isEmpty())
231  {
232  return;
233  }
234  if (!fileName.endsWith(".csv"))
235  {
236  fileName.append(".csv");
237  }
238 
239  QFile file(fileName);
240  if (!file.open(QIODevice::WriteOnly))
241  {
242  QMessageBox::warning(nullptr, "Error",
243  QString("Failed to open the file [%1]").arg(fileName));
244  return;
245  }
246 
247  file.write(text.toUtf8());
248  file.close();
249 
250  directory_path = QFileInfo(fileName).absolutePath();
251  settings.setValue("StatePublisherCSV.saveDirectory", directory_path);
252 }
253 
254 QString StatePublisherCSV::generateRangeCSV(double time_start, double time_end)
255 {
256  using PlotPair = std::pair<std::string, const PJ::PlotData*>;
257 
258  std::vector<PlotPair> ordered_plotdata;
259 
260  for (const auto& it : _datamap->numeric)
261  {
262  if (it.second.size() == 0 || it.second.front().x > time_end ||
263  it.second.back().x < time_start)
264  {
265  continue;
266  }
267  ordered_plotdata.push_back({ it.first, &it.second });
268  }
269  const size_t plot_count = ordered_plotdata.size();
270 
271  std::sort(ordered_plotdata.begin(), ordered_plotdata.end(),
272  [](const PlotPair& a, const PlotPair& b) { return a.first < b.first; });
273 
274  // current index per plordata
275  std::vector<size_t> indices(plot_count, 0);
276 
277  const auto NaN = std::numeric_limits<double>::quiet_NaN();
278  std::vector<double> row_values(plot_count, NaN);
279 
280  QString labels;
281  labels += "__time,";
282  for (size_t i = 0; i < plot_count; i++)
283  {
284  labels += QString::fromStdString(ordered_plotdata[i].first);
285  labels += (i + 1 < plot_count) ? "," : "\n";
286 
287  const PJ::PlotData* plotdata = (ordered_plotdata[i].second);
288  int index = plotdata->getIndexFromX(time_start);
289  if (index < 0)
290  {
291  index = plotdata->size();
292  }
293  indices[i] = index + 1;
294  }
295 
296  bool done = false;
297  QStringList rows = { labels };
298 
299  while (!done)
300  {
301  // done will become false if at least one plotdata is not completed
302  done = true;
303  double min_time = std::numeric_limits<double>::max();
304 
305  for (size_t i = 0; i < plot_count; i++)
306  {
307  size_t index = indices[i];
308  const PJ::PlotData* plotdata = (ordered_plotdata[i].second);
309  row_values[i] = NaN;
310 
311  if (index >= plotdata->size())
312  {
313  continue;
314  }
315  const auto& point = plotdata->at(index);
316  if (point.x > time_end)
317  {
318  continue;
319  }
320 
321  done = false;
322 
323  if (min_time > point.x)
324  {
325  min_time = point.x; // new min_time
326  // reset previous flags
327  std::fill(row_values.begin(), row_values.begin() + i, NaN);
328  row_values[i] = point.y;
329  }
330  else if (std::abs(min_time - point.x) < std::numeric_limits<double>::epsilon())
331  {
332  row_values[i] = point.y;
333  }
334  }
335 
336  if (min_time > time_end || done)
337  {
338  break;
339  }
340 
341  // the row to append to the CSV file
342  QString row_str = QString::number(min_time, 'f', 6) + ",";
343 
344  for (size_t i = 0; i < plot_count; i++)
345  {
346  if (!std::isnan(row_values[i]))
347  {
348  row_str += QString::number(row_values[i], 'f', 9);
349  // value used, move to the nex index
350  indices[i]++;
351  }
352  row_str += (i + 1 < plot_count) ? "," : "\n";
353  }
354  rows.push_back(row_str);
355  }
356  return rows.join("");
357 }
detail::first
auto first(const T &value, const Tail &...) -> const T &
Definition: compile.h:60
StatePublisherCSV::~StatePublisherCSV
virtual ~StatePublisherCSV() override
Definition: publisher_csv.cpp:18
StatePublisherCSV::_dialog
QDialog * _dialog
Definition: publisher_csv.h:57
PJ::TimeseriesBase
Definition: timeseries.h:16
StatePublisherCSV::saveFile
void saveFile(QString text)
Definition: publisher_csv.cpp:219
StatePublisherCSV::name
virtual const char * name() const override
Name of the plugin type, NOT the particular instance.
Definition: publisher_csv.h:22
arg
auto arg(const Char *name, const T &arg) -> detail::named_arg< Char, T >
Definition: core.h:1875
StatePublisherCSV::enabled
virtual bool enabled() const override
True if started.
Definition: publisher_csv.h:29
detail::max_value
constexpr auto max_value() -> T
Definition: format.h:449
StatePublisherCSV::getTimeRanges
bool getTimeRanges(double *first, double *last)
Definition: publisher_csv.cpp:194
PJ::StatePublisher::closed
void closed()
signal to be emitted when the plugin disable itself.
StatePublisherCSV::_start_time
double _start_time
Definition: publisher_csv.h:54
StatePublisherCSV::_ui
Ui::PublisherCSV_DIalog * _ui
Definition: publisher_csv.h:58
ok
ROSCPP_DECL bool ok()
PJ::PlotDataMapRef::numeric
TimeseriesMap numeric
Numerical timeseries.
Definition: plotdata.h:39
detail::fill
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t< Char > &fill) -> OutputIt
Definition: format.h:1715
detail::count
constexpr auto count() -> size_t
Definition: core.h:1222
StatePublisherCSV::_end_time
double _end_time
Definition: publisher_csv.h:55
StatePublisherCSV::generateStatisticsCSV
QString generateStatisticsCSV(double time_start, double time_end)
Definition: publisher_csv.cpp:127
StatePublisherCSV::_enabled
bool _enabled
Definition: publisher_csv.h:52
StatePublisherCSV::generateRangeCSV
QString generateRangeCSV(double time_start, double time_end)
Definition: publisher_csv.cpp:254
StatePublisherCSV::setEnabled
virtual void setEnabled(bool enabled) override
Definition: publisher_csv.cpp:22
sol::meta::enable
std::enable_if_t< all< Args... >::value, enable_t > enable
Definition: sol.hpp:2244
sort
static int sort(lua_State *L)
Definition: ltablib.c:398
PJ::TimeseriesBase::getIndexFromX
int getIndexFromX(double x) const
Definition: timeseries.h:106
PJ::PlotDataBase::size
virtual size_t size() const
Definition: plotdatabase.h:183
StatePublisherCSV::_notification_timer
QTimer * _notification_timer
Definition: publisher_csv.h:60
PJ::PlotDataBase::at
const Point & at(size_t index) const
Definition: plotdatabase.h:193
StatePublisherCSV::updateButtonsState
void updateButtonsState()
Definition: publisher_csv.cpp:210
StatePublisherCSV::StatePublisherCSV
StatePublisherCSV()
Definition: publisher_csv.cpp:14
StatePublisherCSV::_previous_time
double _previous_time
Definition: publisher_csv.h:53
publisher_csv.h
StatePublisherCSV::onWindowClosed
void onWindowClosed()
Definition: publisher_csv.cpp:121
detail::isnan
constexpr auto isnan(T value) -> bool
Definition: format.h:2734
PJ::StatePublisher::_datamap
const PlotDataMapRef * _datamap
Definition: statepublisher_base.h:52


plotjuggler
Author(s): Davide Faconti
autogenerated on Mon Nov 11 2024 03:23:45