EventViewer.cpp
Go to the documentation of this file.
00001 /*
00002         Aseba - an event-based framework for distributed robot control
00003         Copyright (C) 2007--2012:
00004                 Stephane Magnenat <stephane at magnenat dot net>
00005                 (http://stephane.magnenat.net)
00006                 and other contributors, see authors.txt for details
00007         
00008         This program is free software: you can redistribute it and/or modify
00009         it under the terms of the GNU Lesser General Public License as published
00010         by the Free Software Foundation, version 3 of the License.
00011         
00012         This program is distributed in the hope that it will be useful,
00013         but WITHOUT ANY WARRANTY; without even the implied warranty of
00014         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015         GNU Lesser General Public License for more details.
00016         
00017         You should have received a copy of the GNU Lesser General Public License
00018         along with this program. If not, see <http://www.gnu.org/licenses/>.
00019 */
00020 
00021 #ifdef HAVE_QWT
00022 
00023 #include "EventViewer.h"
00024 #include <QVBoxLayout>
00025 #include <QHBoxLayout>
00026 #include <QCheckBox>
00027 #include <QPushButton>
00028 #include <QDoubleSpinBox>
00029 #include <QFile>
00030 #include <QFileDialog>
00031 #include <QSettings>
00032 #include <QtDebug>
00033 
00034 #include <qwt_plot.h>
00035 #include <qwt_plot_curve.h>
00036 #include <qwt_legend.h>
00037 
00038 #if QWT_VERSION >= 0x060000
00039         #include <qwt_series_data.h>
00040 #else
00041         #include <qwt_data.h>
00042 #endif
00043 
00044 #include <EventViewer.moc>
00045 
00046 namespace Aseba
00047 {
00050         
00051         #if QWT_VERSION >= 0x060000
00052         class EventDataWrapper : public QwtSeriesData<QPointF>
00053         {
00054         private:
00055                 std::deque<double>& _x;
00056                 std::deque<sint16>& _y;
00057                 
00058         public:
00059                 EventDataWrapper(std::deque<double>& _x, std::deque<sint16>& _y) :
00060                         _x(_x),
00061                         _y(_y)
00062                 { }
00063                 virtual QRectF boundingRect () const { return qwtBoundingRect(*this); }
00064                 virtual QPointF sample (size_t i) const { return QPointF(_x[i], double(_y[i])); }
00065                 virtual size_t size () const { return _x.size(); }
00066         };
00067         #else
00068         class EventDataWrapper : public QwtData
00069         {
00070         private:
00071                 std::deque<double>& _x;
00072                 std::deque<sint16>& _y;
00073                 
00074         public:
00075                 EventDataWrapper(std::deque<double>& _x, std::deque<sint16>& _y) :
00076                         _x(_x),
00077                         _y(_y)
00078                 { }
00079                 virtual QwtData *   copy () const { return new EventDataWrapper(*this); }
00080                 virtual size_t   size () const { return _x.size(); }
00081                 virtual double x (size_t i) const { return _x[i]; }
00082                 virtual double y (size_t i) const { return (double)_y[i]; }
00083         };
00084         #endif
00085         
00086         EventViewer::EventViewer(unsigned eventId, const QString& eventName, unsigned eventVariablesCount, MainWindow::EventViewers* eventsViewers) :
00087                 eventId(eventId),
00088                 eventsViewers(eventsViewers),
00089                 values(eventVariablesCount),
00090                 startingTime(QTime::currentTime())
00091         {
00092                 // create plot
00093                 plot = new QwtPlot;
00094                 plot->setCanvasBackground(Qt::white);
00095                 plot->setAxisTitle(plot->xBottom, tr("Time (seconds)"));
00096                 plot->setAxisTitle(plot->yLeft, tr("Values"));
00097                 
00098                 QwtLegend *legend = new QwtLegend;
00099                 //legend->setItemMode(QwtLegend::CheckableItem);
00100                 plot->insertLegend(legend, QwtPlot::BottomLegend);
00101                 
00102                 for (size_t i = 0; i < values.size(); i++)
00103                 {
00104                         QwtPlotCurve *curve = new QwtPlotCurve(QString("%0").arg(i));
00105                         #if QWT_VERSION >= 0x060000
00106                         curve->setData(new EventDataWrapper(timeStamps, values[i]));
00107                         #else
00108                         curve->setData(EventDataWrapper(timeStamps, values[i]));
00109                         #endif
00110                         curve->attach(plot);
00111                         curve->setPen(QPen(QColor::fromHsv((i * 360) / values.size(), 255, 100), 2));
00112                 }
00113                 
00114                 QVBoxLayout *layout = new QVBoxLayout(this);
00115                 layout->addWidget(plot);
00116                 
00117                 // add control
00118                 QHBoxLayout *controlLayout = new QHBoxLayout;
00119                 
00120                 status = new QLabel(tr("Recording..."));
00121                 controlLayout->addWidget(status);
00122                 
00123                 pauseRunButton = new QPushButton(QPixmap(QString(":/images/pause.png")), tr("&Pause"));
00124                 connect(pauseRunButton, SIGNAL(clicked()), SLOT(pauseRunCapture()));
00125                 controlLayout->addWidget(pauseRunButton);
00126                 
00127                 QPushButton *clearButton = new QPushButton(QPixmap(QString(":/images/reset.png")), tr("&Clear"));
00128                 connect(clearButton, SIGNAL(clicked()), SLOT(clearPlot()));
00129                 controlLayout->addWidget(clearButton);
00130                 
00131                 timeWindowCheckBox = new QCheckBox(tr("time &window:"));
00132                 controlLayout->addWidget(timeWindowCheckBox);
00133                 
00134                 timeWindowLength = new QDoubleSpinBox;
00135                 timeWindowLength->setSuffix("s");
00136                 connect(timeWindowCheckBox, SIGNAL(toggled(bool)), timeWindowLength, SLOT(setEnabled(bool))); 
00137                 timeWindowLength->setValue(10);
00138                 timeWindowLength->setEnabled(false);
00139                 controlLayout->addWidget(timeWindowLength);
00140                 controlLayout->addStretch();
00141                 
00142                 QPushButton *saveToFileButton = new QPushButton(QPixmap(QString(":/images/filesaveas.png")), tr("Save &As..."));
00143                 connect(saveToFileButton, SIGNAL(clicked()), SLOT(saveToFile()));
00144                 controlLayout->addWidget(saveToFileButton);
00145                 
00146                 layout->addLayout(controlLayout);
00147                 
00148                 // receive events
00149                 eventsViewers->insert(eventId, this);
00150                 isCapturing = true;
00151         }
00152         
00153         EventViewer::~EventViewer()
00154         {
00155                 if (eventsViewers && isCapturing)
00156                         eventsViewers->remove(eventId, this);
00157         }
00158         
00159         void EventViewer::addData(const VariablesDataVector& data)
00160         {
00161                 const double elapsedTime = (double)startingTime.msecsTo(QTime::currentTime()) / 1000.;
00162                 if (timeWindowCheckBox->isChecked())
00163                 {
00164                         // remove old data
00165                         while (
00166                                 (!timeStamps.empty()) &&
00167                                 (elapsedTime - timeStamps[0] > timeWindowLength->value())
00168                         )
00169                         {
00170                                 timeStamps.pop_front();
00171                                 for (size_t i = 0; i < values.size(); i++)
00172                                         values[i].pop_front();
00173                         }
00174                 }
00175                         
00176                         
00177                 timeStamps.push_back(elapsedTime);
00178                 for (size_t i = 0; i < values.size(); i++)
00179                 {
00180                         if (i < data.size())
00181                         {
00182                                 values[i].push_back(data[i]);
00183                         }
00184                         else
00185                         {
00186                                 values[i].push_back(0);
00187                         }
00188                 }
00189                 plot->replot();
00190         }
00191         
00192         void EventViewer::pauseRunCapture()
00193         {
00194                 if (isCapturing)
00195                 {
00196                         if (eventsViewers)
00197                                 eventsViewers->remove(eventId, this);
00198                         isCapturing = false;
00199                         status->setText(tr("Paused..."));
00200                         pauseRunButton->setIcon(QPixmap(QString(":/images/mix_record.png")));
00201                         pauseRunButton->setText(tr("&Record"));
00202                 }
00203                 else
00204                 {
00205                         if (eventsViewers)
00206                                 eventsViewers->insert(eventId, this);
00207                         isCapturing = true;
00208                         status->setText(tr("Recording..."));
00209                         pauseRunButton->setIcon(QPixmap(QString(":/images/pause.png")));
00210                         pauseRunButton->setText(tr("&Pause"));
00211                 }
00212         }
00213         
00214         void EventViewer::clearPlot()
00215         {
00216                 for (size_t i = 0; i < values.size(); i++)
00217                         values[i].clear();
00218                 timeStamps.clear();
00219                 plot->replot();
00220         }
00221         
00222         void EventViewer::saveToFile()
00223         {
00224                 QSettings settings;
00225                 QString lastFileName(settings.value("EventViewer/exportFileName", "").toString());
00226                 QString fileName = QFileDialog::getSaveFileName(this, tr("Save plot data to file"), lastFileName, "All Files (*);;CSV files (*.csv);;Text files (*.txt)");
00227                 
00228                 QFile file(fileName);
00229                 if (!file.open(QFile::WriteOnly | QFile::Truncate))
00230                         return;
00231                 
00232                 settings.setValue("EventViewer/exportFileName", fileName);
00233                 
00234                 QTextStream out(&file);
00235                 for (size_t i = 0; i < timeStamps.size(); ++i)
00236                 {
00237                         out << timeStamps[i] << " ";
00238                         for (size_t j = 0; j < values.size(); ++j)
00239                         {
00240                                 out << values[j][i];
00241                                 if (j + 1 < values.size())
00242                                         out << " ";
00243                         }
00244                         out << "\n";
00245                 }
00246         }
00247         
00249 }; // Aseba
00250 
00251 #endif // HAVE_QWT


aseba
Author(s): Stéphane Magnenat
autogenerated on Thu Jan 2 2014 11:17:16