Commit b135d321 authored by pixhawk's avatar pixhawk

Significantly improved plotting, now capturing data in linechart allows...

Significantly improved plotting, now capturing data in linechart allows limmediate processing / analysis of the whole flight
parent 96947527
price quantity
210 81
250 73
280 64
300 61
320 50
340 46
360 45
380 44
400 43
420 39
440 36
...@@ -36,6 +36,9 @@ This file is part of the QGROUNDCONTROL project ...@@ -36,6 +36,9 @@ This file is part of the QGROUNDCONTROL project
#include <QDebug> #include <QDebug>
/**
* It will only get active upon calling startCompression()
*/
LogCompressor::LogCompressor(QString logFileName, QString outFileName, int uasid) : LogCompressor::LogCompressor(QString logFileName, QString outFileName, int uasid) :
logFileName(logFileName), logFileName(logFileName),
outFileName(outFileName), outFileName(outFileName),
...@@ -44,7 +47,6 @@ LogCompressor::LogCompressor(QString logFileName, QString outFileName, int uasid ...@@ -44,7 +47,6 @@ LogCompressor::LogCompressor(QString logFileName, QString outFileName, int uasid
dataLines(1), dataLines(1),
uasid(uasid) uasid(uasid)
{ {
start();
} }
void LogCompressor::run() void LogCompressor::run()
...@@ -174,9 +176,15 @@ void LogCompressor::run() ...@@ -174,9 +176,15 @@ void LogCompressor::run()
dataLines = 1; dataLines = 1;
delete keys; delete keys;
qDebug() << "Done with logfile processing"; qDebug() << "Done with logfile processing";
emit finishedFile(outfile.fileName());
running = false; running = false;
} }
void LogCompressor::startCompression()
{
start();
}
bool LogCompressor::isFinished() bool LogCompressor::isFinished()
{ {
return !running; return !running;
......
...@@ -5,11 +5,15 @@ ...@@ -5,11 +5,15 @@
class LogCompressor : public QThread class LogCompressor : public QThread
{ {
Q_OBJECT
public: public:
/** @brief Create the log compressor. It will only get active upon calling startCompression() */
LogCompressor(QString logFileName, QString outFileName="", int uasid = 0); LogCompressor(QString logFileName, QString outFileName="", int uasid = 0);
void startCompression();
bool isFinished(); bool isFinished();
int getDataLines(); int getDataLines();
int getCurrentLine(); int getCurrentLine();
protected: protected:
void run(); void run();
QString logFileName; QString logFileName;
...@@ -18,6 +22,12 @@ protected: ...@@ -18,6 +22,12 @@ protected:
int currentDataLine; int currentDataLine;
int dataLines; int dataLines;
int uasid; int uasid;
signals:
/** @brief This signal is emitted once a logfile has been finished writing
* @param fileName The name out the output (CSV) file
*/
void finishedFile(QString fileName);
}; };
#endif // LOGCOMPRESSOR_H #endif // LOGCOMPRESSOR_H
...@@ -145,6 +145,7 @@ void MainWindow::connectWidgets() ...@@ -145,6 +145,7 @@ void MainWindow::connectWidgets()
{ {
connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), linechart, SLOT(addSystem(UASInterface*))); connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), linechart, SLOT(addSystem(UASInterface*)));
connect(UASManager::instance(), SIGNAL(activeUASSet(int)), linechart, SLOT(selectSystem(int))); connect(UASManager::instance(), SIGNAL(activeUASSet(int)), linechart, SLOT(selectSystem(int)));
connect(linechart, SIGNAL(logfileWritten(QString)), this, SLOT(loadDataView(QString)));
connect(mavlink, SIGNAL(receiveLossChanged(int, float)), info, SLOT(updateSendLoss(int, float))); connect(mavlink, SIGNAL(receiveLossChanged(int, float)), info, SLOT(updateSendLoss(int, float)));
} }
...@@ -544,6 +545,13 @@ void MainWindow::loadDataView() ...@@ -544,6 +545,13 @@ void MainWindow::loadDataView()
centerStack->setCurrentWidget(dataplot); centerStack->setCurrentWidget(dataplot);
} }
void MainWindow::loadDataView(QString fileName)
{
clearView();
centerStack->setCurrentWidget(dataplot);
dataplot->loadFile(fileName);
}
void MainWindow::loadPilotView() void MainWindow::loadPilotView()
{ {
clearView(); clearView();
......
...@@ -119,6 +119,8 @@ public slots: ...@@ -119,6 +119,8 @@ public slots:
void loadMAVLinkView(); void loadMAVLinkView();
/** @brief Load data view, allowing to plot flight data */ /** @brief Load data view, allowing to plot flight data */
void loadDataView(); void loadDataView();
/** @brief Load data view, allowing to plot flight data */
void loadDataView(QString fileName);
/** @brief Show the online help for users */ /** @brief Show the online help for users */
void showHelp(); void showHelp();
......
This diff is collapsed.
...@@ -16,11 +16,17 @@ public: ...@@ -16,11 +16,17 @@ public:
QGCDataPlot2D(QWidget *parent = 0); QGCDataPlot2D(QWidget *parent = 0);
~QGCDataPlot2D(); ~QGCDataPlot2D();
/** @brief Calculate and display regression function*/
bool calculateRegression(QString xName, QString yName, QString method="linear");
/** @brief Linear regression over data points */ /** @brief Linear regression over data points */
int linearRegression(double *x,double *y,int n,double *a,double *b,double *r); int linearRegression(double* x,double* y,int n,double* a,double* b,double* r);
public slots: public slots:
/** @brief Load previously selected file */
void loadFile(); void loadFile();
/** @brief Load file with this name */
void loadFile(QString file);
/** @brief Reload a file, with filtering enabled */ /** @brief Reload a file, with filtering enabled */
void reloadFile(); void reloadFile();
void selectFile(); void selectFile();
...@@ -29,10 +35,14 @@ public slots: ...@@ -29,10 +35,14 @@ public slots:
void saveCsvLog(); void saveCsvLog();
/** @brief Save plot to PDF or SVG */ /** @brief Save plot to PDF or SVG */
void savePlot(); void savePlot();
/** @brief Export PDF file */
void exportPDF(QString fileName);
/** @brief Export SVG file */ /** @brief Export SVG file */
void exportSVG(QString file); void exportSVG(QString file);
/** @brief Print or save PDF file (MacOS/Linux) */ /** @brief Print or save PDF file (MacOS/Linux) */
void print(); void print();
/** @brief Calculate and display regression function*/
bool calculateRegression();
protected: protected:
void changeEvent(QEvent *e); void changeEvent(QEvent *e);
...@@ -40,6 +50,7 @@ protected: ...@@ -40,6 +50,7 @@ protected:
LogCompressor* compressor; LogCompressor* compressor;
QFile* logFile; QFile* logFile;
QString fileName; QString fileName;
QStringList curveNames;
private: private:
Ui::QGCDataPlot2D *ui; Ui::QGCDataPlot2D *ui;
......
...@@ -6,22 +6,22 @@ ...@@ -6,22 +6,22 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>807</width> <width>1073</width>
<height>308</height> <height>308</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout" columnstretch="2,10,2,0,0,0,0,0,0,0,0,0,0"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2"> <item row="0" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>X</string> <string>X</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2"> <item row="0" column="1" colspan="2">
<widget class="QComboBox" name="xAxis"/> <widget class="QComboBox" name="xAxis"/>
</item> </item>
<item row="0" column="3"> <item row="0" column="3">
...@@ -53,7 +53,12 @@ ...@@ -53,7 +53,12 @@
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Only dots</string> <string>Only rectangles</string>
</property>
</item>
<item>
<property name="text">
<string>Only symbols</string>
</property> </property>
</item> </item>
<item> <item>
...@@ -68,7 +73,12 @@ ...@@ -68,7 +73,12 @@
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Lines and dots</string> <string>Lines and rects</string>
</property>
</item>
<item>
<property name="text">
<string>Lines and symbols</string>
</property> </property>
</item> </item>
<item> <item>
...@@ -83,7 +93,7 @@ ...@@ -83,7 +93,7 @@
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Dotted lines and dots</string> <string>Dotted lines and rects</string>
</property> </property>
</item> </item>
<item> <item>
...@@ -98,39 +108,91 @@ ...@@ -98,39 +108,91 @@
</item> </item>
<item> <item>
<property name="text"> <property name="text">
<string>Dashed lines and dots</string> <string>Dashed lines and rects</string>
</property> </property>
</item> </item>
</widget> </widget>
</item> </item>
<item row="0" column="9"> <item row="0" column="7" colspan="2">
<widget class="QPushButton" name="reloadButton"> <widget class="QPushButton" name="reloadButton">
<property name="text"> <property name="text">
<string>Reload</string> <string>Replot</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="10"> <item row="0" column="11">
<spacer name="horizontalSpacer_2"> <widget class="Line" name="line">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Vertical</enum>
</property> </property>
<property name="sizeHint" stdset="0"> </widget>
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item> </item>
<item row="0" column="11"> <item row="0" column="12" colspan="2">
<widget class="QPushButton" name="savePlotButton"> <widget class="QPushButton" name="savePlotButton">
<property name="text"> <property name="text">
<string>Save Plot</string> <string>Save Image</string>
</property>
</widget>
</item>
<item row="0" column="19">
<widget class="QPushButton" name="printButton">
<property name="text">
<string>Print</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Title</string>
</property>
</widget>
</item>
<item row="1" column="2" colspan="3">
<widget class="QLineEdit" name="plotTitle"/>
</item>
<item row="1" column="5">
<widget class="QLabel" name="label_5">
<property name="text">
<string>X label</string>
</property>
</widget>
</item>
<item row="1" column="6" colspan="2">
<widget class="QLineEdit" name="plotXAxisLabel"/>
</item>
<item row="1" column="8">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Y label</string>
</property>
</widget>
</item>
<item row="1" column="9" colspan="3">
<widget class="QLineEdit" name="plotYAxisLabel"/>
</item>
<item row="1" column="12" colspan="2">
<widget class="QCheckBox" name="symmetricCheckBox">
<property name="text">
<string>Symmetric</string>
</property>
</widget>
</item>
<item row="1" column="14" colspan="2">
<widget class="QCheckBox" name="legendCheckBox">
<property name="text">
<string>Legend</string>
</property>
</widget>
</item>
<item row="1" column="16">
<widget class="QCheckBox" name="gridCheckBox">
<property name="text">
<string>Grid</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="13"> <item row="2" column="0" colspan="20">
<widget class="QFrame" name="plotFrame"> <widget class="QFrame" name="plotFrame">
<property name="frameShape"> <property name="frameShape">
<enum>QFrame::StyledPanel</enum> <enum>QFrame::StyledPanel</enum>
...@@ -140,14 +202,14 @@ ...@@ -140,14 +202,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>File</string> <string>File</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1" colspan="2"> <item row="3" column="1" colspan="2">
<widget class="QComboBox" name="inputFileType"> <widget class="QComboBox" name="inputFileType">
<item> <item>
<property name="text"> <property name="text">
...@@ -166,14 +228,21 @@ ...@@ -166,14 +228,21 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="2" column="3" colspan="4"> <item row="3" column="3" colspan="4">
<widget class="QLabel" name="filenameLabel"> <widget class="QLabel" name="filenameLabel">
<property name="text"> <property name="text">
<string>Please select input file..</string> <string>Please select input file..</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="10"> <item row="3" column="8" colspan="2">
<widget class="QPushButton" name="selectFileButton">
<property name="text">
<string>Select file</string>
</property>
</widget>
</item>
<item row="3" column="10" colspan="2">
<spacer name="horizontalSpacer"> <spacer name="horizontalSpacer">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
...@@ -186,41 +255,60 @@ ...@@ -186,41 +255,60 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="0" column="12"> <item row="3" column="12">
<widget class="QPushButton" name="printButton"> <widget class="Line" name="line_2">
<property name="text"> <property name="orientation">
<string>Print</string> <enum>Qt::Vertical</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="12"> <item row="3" column="13">
<widget class="QPushButton" name="saveCsvButton"> <widget class="QLabel" name="label_7">
<property name="text"> <property name="text">
<string>Save CSV</string> <string>Regression</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="9"> <item row="3" column="14" colspan="2">
<widget class="QPushButton" name="selectFileButton"> <widget class="QComboBox" name="xRegressionComboBox"/>
</item>
<item row="3" column="16" colspan="2">
<widget class="QComboBox" name="yRegressionComboBox"/>
</item>
<item row="3" column="19">
<widget class="QPushButton" name="regressionButton">
<property name="text"> <property name="text">
<string>Select file</string> <string>Calculate</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="7"> <item row="3" column="18">
<widget class="QCheckBox" name="symmetricCheckBox"> <widget class="QLineEdit" name="regressionOutput">
<property name="text"> <property name="readOnly">
<string>Symmetric</string> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="8"> <item row="0" column="14">
<widget class="QCheckBox" name="legendCheckBox"> <widget class="QPushButton" name="saveCsvButton">
<property name="text"> <property name="text">
<string>Legend</string> <string>Save Data</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="9" colspan="2">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
<resources/> <resources/>
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Implementation of class IncrementalPlot
* @author Lorenz Meier <mavteam@student.ethz.ch>
*
*/
#include <qwt_plot.h> #include <qwt_plot.h>
#include <qwt_plot_canvas.h> #include <qwt_plot_canvas.h>
#include <qwt_plot_curve.h> #include <qwt_plot_curve.h>
...@@ -9,9 +39,9 @@ ...@@ -9,9 +39,9 @@
#include <Scrollbar.h> #include <Scrollbar.h>
#include <ScrollZoomer.h> #include <ScrollZoomer.h>
#include <float.h> #include <float.h>
#if QT_VERSION >= 0x040000
#include <qpaintengine.h> #include <qpaintengine.h>
#endif
#include <QDebug>
CurveData::CurveData(): CurveData::CurveData():
d_count(0) d_count(0)
...@@ -45,18 +75,23 @@ int CurveData::size() const ...@@ -45,18 +75,23 @@ int CurveData::size() const
return d_x.size(); return d_x.size();
} }
const double *CurveData::x() const const double* CurveData::x() const
{ {
return d_x.data(); return d_x.data();
} }
const double *CurveData::y() const const double* CurveData::y() const
{ {
return d_y.data(); return d_y.data();
} }
IncrementalPlot::IncrementalPlot(QWidget *parent): IncrementalPlot::IncrementalPlot(QWidget *parent):
QwtPlot(parent) QwtPlot(parent),
symbolWidth(1.2f),
curveWidth(1.0f),
gridWidth(0.8f),
scaleWidth(1.0f),
symmetric(false)
{ {
setAutoReplot(false); setAutoReplot(false);
...@@ -67,8 +102,8 @@ IncrementalPlot::IncrementalPlot(QWidget *parent): ...@@ -67,8 +102,8 @@ IncrementalPlot::IncrementalPlot(QWidget *parent):
plotLayout()->setAlignCanvasToScales(true); plotLayout()->setAlignCanvasToScales(true);
QwtPlotGrid *grid = new QwtPlotGrid; grid = new QwtPlotGrid;
grid->setMajPen(QPen(Qt::gray, 0, Qt::DotLine)); grid->setMajPen(QPen(Qt::gray, 0.8f, Qt::DotLine));
grid->attach(this); grid->attach(this);
QwtLinearScaleEngine* yScaleEngine = new QwtLinearScaleEngine(); QwtLinearScaleEngine* yScaleEngine = new QwtLinearScaleEngine();
...@@ -82,7 +117,7 @@ IncrementalPlot::IncrementalPlot(QWidget *parent): ...@@ -82,7 +117,7 @@ IncrementalPlot::IncrementalPlot(QWidget *parent):
// enable zooming // enable zooming
zoomer = new ScrollZoomer(canvas()); zoomer = new ScrollZoomer(canvas());
zoomer->setRubberBandPen(QPen(Qt::red, 2, Qt::DotLine)); zoomer->setRubberBandPen(QPen(Qt::red, 1.5f, Qt::DotLine));
zoomer->setTrackerPen(QPen(Qt::red)); zoomer->setTrackerPen(QPen(Qt::red));
//zoomer->setZoomBase(QwtDoubleRect()); //zoomer->setZoomBase(QwtDoubleRect());
legend = NULL; legend = NULL;
...@@ -112,6 +147,8 @@ IncrementalPlot::IncrementalPlot(QWidget *parent): ...@@ -112,6 +147,8 @@ IncrementalPlot::IncrementalPlot(QWidget *parent):
colors.append(QColor(161,252,116)); colors.append(QColor(161,252,116));
colors.append(QColor(87,231,246)); colors.append(QColor(87,231,246));
colors.append(QColor(230,126,23)); colors.append(QColor(230,126,23));
connect(this, SIGNAL(legendChecked(QwtPlotItem*,bool)), this, SLOT(handleLegendClick(QwtPlotItem*,bool)));
} }
IncrementalPlot::~IncrementalPlot() IncrementalPlot::~IncrementalPlot()
...@@ -119,6 +156,23 @@ IncrementalPlot::~IncrementalPlot() ...@@ -119,6 +156,23 @@ IncrementalPlot::~IncrementalPlot()
} }
/**
* @param symmetric true will enforce that both axes have the same interval,
* centered around the data plot. A circle will thus remain a circle if true,
* if set to false it might become an ellipse because of axis scaling.
*/
void IncrementalPlot::setSymmetric(bool symmetric)
{
this->symmetric = symmetric;
updateScale(); // Updates the scaling at replots
}
void IncrementalPlot::handleLegendClick(QwtPlotItem* item, bool on)
{
item->setVisible(!on);
replot();
}
void IncrementalPlot::showLegend(bool show) void IncrementalPlot::showLegend(bool show)
{ {
if (show) if (show)
...@@ -127,6 +181,7 @@ void IncrementalPlot::showLegend(bool show) ...@@ -127,6 +181,7 @@ void IncrementalPlot::showLegend(bool show)
{ {
legend = new QwtLegend; legend = new QwtLegend;
legend->setFrameStyle(QFrame::Box); legend->setFrameStyle(QFrame::Box);
legend->setItemMode(QwtLegend::CheckableItem);
} }
insertLegend(legend, QwtPlot::RightLegend); insertLegend(legend, QwtPlot::RightLegend);
} }
...@@ -135,7 +190,7 @@ void IncrementalPlot::showLegend(bool show) ...@@ -135,7 +190,7 @@ void IncrementalPlot::showLegend(bool show)
delete legend; delete legend;
legend = NULL; legend = NULL;
} }
replot(); updateScale(); // Updates the scaling at replots
} }
/** /**
...@@ -159,19 +214,25 @@ void IncrementalPlot::setStyleText(QString style) ...@@ -159,19 +214,25 @@ void IncrementalPlot::setStyleText(QString style)
if (style.toLower().contains("circles")) if (style.toLower().contains("circles"))
{ {
curve->setSymbol(QwtSymbol(QwtSymbol::Ellipse, curve->setSymbol(QwtSymbol(QwtSymbol::Ellipse,
QBrush(curve->pen().color()), curve->pen(), QSize(5, 5)) ); Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) );
} }
else if (style.toLower().contains("crosses")) else if (style.toLower().contains("crosses"))
{ {
curve->setSymbol(QwtSymbol(QwtSymbol::XCross, curve->setSymbol(QwtSymbol(QwtSymbol::XCross,
QBrush(curve->pen().color()), curve->pen(), QSize(5, 5)) ); Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(5, 5)) );
} }
else // Always show dots (style.toLower().contains("dots")) else if (style.toLower().contains("rect"))
{ {
curve->setSymbol(QwtSymbol(QwtSymbol::Rect, curve->setSymbol(QwtSymbol(QwtSymbol::Rect,
QBrush(curve->pen().color()), curve->pen(), QSize(1, 1)) ); Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) );
}
else if (style.toLower().contains("line")) // Show no symbol
{
curve->setSymbol(QwtSymbol(QwtSymbol::NoSymbol,
Qt::NoBrush, QPen(QBrush(curve->symbol().pen().color()), symbolWidth), QSize(6, 6)) );
} }
curve->setPen(QPen(QBrush(curve->symbol().pen().color().darker()), curveWidth));
// Style of lines // Style of lines
if (style.toLower().contains("dotted")) if (style.toLower().contains("dotted"))
{ {
...@@ -181,19 +242,25 @@ void IncrementalPlot::setStyleText(QString style) ...@@ -181,19 +242,25 @@ void IncrementalPlot::setStyleText(QString style)
{ {
curve->setStyle(QwtPlotCurve::Lines); curve->setStyle(QwtPlotCurve::Lines);
} }
else if (style.toLower().contains("dashed") || style.toLower().contains("solid"))
{
curve->setStyle(QwtPlotCurve::Steps);
}
else else
{ {
curve->setStyle(QwtPlotCurve::NoCurve); curve->setStyle(QwtPlotCurve::NoCurve);
} }
} }
replot();
} }
void IncrementalPlot::resetScaling() void IncrementalPlot::resetScaling()
{ {
xmin = 0; xmin = 0;
xmax = 500; xmax = 500;
ymin = 0; ymin = xmin;
ymax = 500; ymax = xmax;
setAxisScale(xBottom, xmin+xmin*0.05, xmax+xmax*0.05); setAxisScale(xBottom, xmin+xmin*0.05, xmax+xmax*0.05);
setAxisScale(yLeft, ymin+ymin*0.05, ymax+ymax*0.05); setAxisScale(yLeft, ymin+ymin*0.05, ymax+ymax*0.05);
...@@ -207,6 +274,46 @@ void IncrementalPlot::resetScaling() ...@@ -207,6 +274,46 @@ void IncrementalPlot::resetScaling()
ymax = DBL_MIN; ymax = DBL_MIN;
} }
/**
* Updates the scale calculation and re-plots the whole plot
*/
void IncrementalPlot::updateScale()
{
const double margin = 0.05;
double xMinRange = xmin+(xmin*margin);
double xMaxRange = xmax+(xmax*margin);
double yMinRange = ymin+(ymin*margin);
double yMaxRange = ymax+(ymax*margin);
if (symmetric)
{
double xRange = xMaxRange - xMinRange;
double yRange = yMaxRange - yMinRange;
// Get the aspect ratio of the plot
float xSize = width();
if (legend != NULL) xSize -= legend->width();
float ySize = height();
float aspectRatio = xSize / ySize;
if (xRange > yRange)
{
double yCenter = yMinRange + yRange/2.0;
yMinRange = yCenter - xRange/2.0;
yMaxRange = yCenter + xRange/2.0;
}
else
{
double xCenter = xMinRange + xRange/2.0;
xMinRange = xCenter - yRange/2.0;
xMaxRange = xCenter + yRange/2.0;
}
}
setAxisScale(xBottom, xMinRange, xMaxRange);
setAxisScale(yLeft, yMinRange, yMaxRange);
zoomer->setZoomBase(true);
}
void IncrementalPlot::appendData(QString key, double x, double y) void IncrementalPlot::appendData(QString key, double x, double y)
{ {
appendData(key, &x, &y, 1); appendData(key, &x, &y, 1);
...@@ -235,7 +342,7 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size) ...@@ -235,7 +342,7 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size)
const QColor &c = getNextColor(); const QColor &c = getNextColor();
curve->setSymbol(QwtSymbol(QwtSymbol::XCross, curve->setSymbol(QwtSymbol(QwtSymbol::XCross,
QBrush(c), QPen(c), QSize(5, 5)) ); QBrush(c), QPen(c, 1.2f), QSize(5, 5)) );
curve->attach(this); curve->attach(this);
} }
...@@ -285,9 +392,7 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size) ...@@ -285,9 +392,7 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size)
if(scaleChanged) if(scaleChanged)
{ {
setAxisScale(xBottom, xmin+xmin*0.05, xmax+xmax*0.05); updateScale();
setAxisScale(yLeft, ymin+ymin*0.05, ymax+ymax*0.05);
zoomer->setZoomBase(true);
} }
else else
{ {
...@@ -316,9 +421,44 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size) ...@@ -316,9 +421,44 @@ void IncrementalPlot::appendData(QString key, double *x, double *y, int size)
#if QT_VERSION >= 0x040000 && defined(Q_WS_X11) #if QT_VERSION >= 0x040000 && defined(Q_WS_X11)
canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, false); canvas()->setAttribute(Qt::WA_PaintOutsidePaintEvent, false);
#endif #endif
}
}
/**
* @return Number of copied data points, 0 on failure
*/
int IncrementalPlot::data(QString key, double* r_x, double* r_y, int maxSize)
{
int result = 0;
if (d_data.contains(key))
{
CurveData* d = d_data.value(key);
if (maxSize >= d->count())
{
result = d->count();
memcpy(r_x, d->x(), sizeof(double) * d->count());
memcpy(r_y, d->y(), sizeof(double) * d->count());
}
else
{
result = 0;
}
} }
return result;
}
/**
* @param show true to show the grid, false else
*/
void IncrementalPlot::showGrid(bool show)
{
grid->setVisible(show);
replot();
}
bool IncrementalPlot::gridEnabled()
{
return grid->isVisible();
} }
QList<QColor> IncrementalPlot::getColorMap() QList<QColor> IncrementalPlot::getColorMap()
...@@ -330,7 +470,7 @@ QColor IncrementalPlot::getNextColor() ...@@ -330,7 +470,7 @@ QColor IncrementalPlot::getNextColor()
{ {
/* Return current color and increment counter for next round */ /* Return current color and increment counter for next round */
nextColor++; nextColor++;
if(nextColor >= colors.size()) nextColor = 0; if(nextColor >= colors.count()) nextColor = 0;
return colors[nextColor++]; return colors[nextColor++];
} }
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009, 2010 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Defition of class IncrementalPlot
* @author Lorenz Meier <mavteam@student.ethz.ch>
*
*/
#ifndef INCREMENTALPLOT_H #ifndef INCREMENTALPLOT_H
#define INCREMENTALPLOT_H #define INCREMENTALPLOT_H
...@@ -5,21 +35,25 @@ ...@@ -5,21 +35,25 @@
#include <qwt_array.h> #include <qwt_array.h>
#include <qwt_plot.h> #include <qwt_plot.h>
#include <qwt_legend.h> #include <qwt_legend.h>
#include <qwt_plot_grid.h>
#include <QMap> #include <QMap>
#include "ScrollZoomer.h" #include "ScrollZoomer.h"
class QwtPlotCurve; class QwtPlotCurve;
/**
* @brief Plot data container for growing data
*/
class CurveData class CurveData
{ {
// A container class for growing data
public: public:
CurveData(); CurveData();
void append(double *x, double *y, int count); void append(double *x, double *y, int count);
/** @brief The number of datasets held in the data structure */
int count() const; int count() const;
/** @brief The reserved size of the data structure in units */
int size() const; int size() const;
const double *x() const; const double *x() const;
const double *y() const; const double *y() const;
...@@ -32,44 +66,89 @@ private: ...@@ -32,44 +66,89 @@ private:
int d_timerCount; int d_timerCount;
}; };
/**
* @brief Incremental plotting widget
*
* This widget plots data incrementally when new data arrives.
* It will only repaint the minimum screen content necessary to avoid
* a too high CPU consumption. It auto-scales the plot to new data.
*/
class IncrementalPlot : public QwtPlot class IncrementalPlot : public QwtPlot
{ {
Q_OBJECT Q_OBJECT
public: public:
/** @brief Create a new, empty incremental plot */
IncrementalPlot(QWidget *parent = NULL); IncrementalPlot(QWidget *parent = NULL);
virtual ~IncrementalPlot(); virtual ~IncrementalPlot();
/** @brief Get color map of this plot */ /** @brief Get color map of this plot */
QList<QColor> getColorMap(); QList<QColor> getColorMap();
/** @brief Get next color of color map */ /** @brief Get next color of color map */
QColor getNextColor(); QColor getNextColor();
/** @brief Get color for curve id */ /** @brief Get color for curve id */
QColor getColorForCurve(QString id); QColor getColorForCurve(QString id);
/** @brief Get the state of the grid */
bool gridEnabled();
/** @brief Read out data from a curve */
int data(QString key, double* r_x, double* r_y, int maxSize);
float symbolWidth;
float curveWidth;
float gridWidth;
float scaleWidth;
public slots: public slots:
/** @brief Append one data point */
void appendData(QString key, double x, double y); void appendData(QString key, double x, double y);
void appendData(QString key, double *x, double *y, int size);
/** @brief Append multiple data points */
void appendData(QString key, double* x, double* y, int size);
/** @brief Reset the plot scaling to the default value */
void resetScaling(); void resetScaling();
/** @brief Update the plot scale based on current data/symmetric mode */
void updateScale();
/** @brief Remove all data from the plot and repaint */
void removeData(); void removeData();
/** @brief Show the plot legend */ /** @brief Show the plot legend */
void showLegend(bool show); void showLegend(bool show);
/** @brief Show the plot grid */
void showGrid(bool show);
/** @brief Set new plot style */ /** @brief Set new plot style */
void setStyleText(QString style); void setStyleText(QString style);
/** @brief Set symmetric axis scaling mode */
void setSymmetric(bool symmetric);
protected slots:
/** @brief Handle the click on a legend item */
void handleLegendClick(QwtPlotItem* item, bool on);
protected: protected:
QList<QColor> colors; bool symmetric; ///< Enable symmetric plotting
int nextColor; QList<QColor> colors; ///< Colormap for curves
ScrollZoomer* zoomer; int nextColor; ///< Next index in color map
QwtLegend* legend; ScrollZoomer* zoomer; ///< Zoomer class for widget
double xmin; QwtLegend* legend; ///< Plot legend
double xmax; QwtPlotGrid* grid; ///< Plot grid
double ymin; double xmin; ///< Minimum x value seen
double ymax; double xmax; ///< Maximum x value seen
double ymin; ///< Minimum y value seen
double ymax; ///< Maximum y value seen
private: private:
QMap<QString, CurveData* > d_data; QMap<QString, CurveData* > d_data; ///< Data points
QMap<QString, QwtPlotCurve* > d_curve; QMap<QString, QwtPlotCurve* > d_curve; ///< Plot curves
}; };
#endif /* INCREMENTALPLOT_H */ #endif /* INCREMENTALPLOT_H */
...@@ -136,7 +136,7 @@ d_curve(NULL) ...@@ -136,7 +136,7 @@ d_curve(NULL)
// Enable zooming // Enable zooming
//zoomer = new Zoomer(canvas()); //zoomer = new Zoomer(canvas());
zoomer = new ScrollZoomer(canvas()); zoomer = new ScrollZoomer(canvas());
zoomer->setRubberBandPen(QPen(Qt::blue, 2, Qt::DotLine)); zoomer->setRubberBandPen(QPen(Qt::blue, 1.2, Qt::DotLine));
zoomer->setTrackerPen(QPen(Qt::blue)); zoomer->setTrackerPen(QPen(Qt::blue));
// Start QTimer for plot update // Start QTimer for plot update
...@@ -314,7 +314,7 @@ QColor LinechartPlot::getNextColor() ...@@ -314,7 +314,7 @@ QColor LinechartPlot::getNextColor()
{ {
/* Return current color and increment counter for next round */ /* Return current color and increment counter for next round */
nextColor++; nextColor++;
if(nextColor >= colors.size()) nextColor = 0; if(nextColor >= colors.count()) nextColor = 0;
return colors[nextColor++]; return colors[nextColor++];
} }
...@@ -762,15 +762,15 @@ void TimeSeriesData::append(quint64 ms, double value) ...@@ -762,15 +762,15 @@ void TimeSeriesData::append(quint64 ms, double value)
mean = mean / static_cast<double>(qMin(averageWindow,static_cast<unsigned int>(count))); mean = mean / static_cast<double>(qMin(averageWindow,static_cast<unsigned int>(count)));
qSort(medianList); qSort(medianList);
if (medianList.size() > 2) if (medianList.count() > 2)
{ {
if (medianList.size() % 2 == 0) if (medianList.count() % 2 == 0)
{ {
median = (medianList.at(medianList.size()/2) + medianList.at(medianList.size()/2+1)) / 2.0; median = (medianList.at(medianList.count()/2) + medianList.at(medianList.count()/2+1)) / 2.0;
} }
else else
{ {
median = medianList.at(medianList.size()/2+1); median = medianList.at(medianList.count()/2+1);
} }
} }
......
...@@ -141,8 +141,9 @@ void LinechartWidget::createLayout() ...@@ -141,8 +141,9 @@ void LinechartWidget::createLayout()
// Averaging spin box // Averaging spin box
averageSpinBox = new QSpinBox(this); averageSpinBox = new QSpinBox(this);
averageSpinBox->setValue(2); averageSpinBox->setValue(200);
averageSpinBox->setMinimum(2); averageSpinBox->setMinimum(2);
averageSpinBox->setMaximum(9999);
layout->addWidget(averageSpinBox, 1, 2); layout->addWidget(averageSpinBox, 1, 2);
layout->setColumnStretch(2, 0); layout->setColumnStretch(2, 0);
connect(averageSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAverageWindow(int))); connect(averageSpinBox, SIGNAL(valueChanged(int)), this, SLOT(setAverageWindow(int)));
...@@ -306,6 +307,8 @@ void LinechartWidget::stopLogging() ...@@ -306,6 +307,8 @@ void LinechartWidget::stopLogging()
logFile->close(); logFile->close();
// Postprocess log file // Postprocess log file
compressor = new LogCompressor(logFile->fileName()); compressor = new LogCompressor(logFile->fileName());
connect(compressor, SIGNAL(finishedFile(QString)), this, SIGNAL(logfileWritten(QString)));
compressor->startCompression();
} }
logButton->setText(tr("Start logging")); logButton->setText(tr("Start logging"));
disconnect(logButton, SIGNAL(clicked()), this, SLOT(stopLogging())); disconnect(logButton, SIGNAL(clicked()), this, SLOT(stopLogging()));
......
...@@ -163,6 +163,9 @@ signals: ...@@ -163,6 +163,9 @@ signals:
void plotWindowPositionUpdated(quint64 position); void plotWindowPositionUpdated(quint64 position);
void plotWindowPositionUpdated(int position); void plotWindowPositionUpdated(int position);
/** @brief This signal is emitted once a logfile has been finished writing */
void logfileWritten(QString fileName);
}; };
#endif // LINECHARTWIDGET_H #endif // LINECHARTWIDGET_H
...@@ -55,6 +55,7 @@ void Linecharts::addSystem(UASInterface* uas) ...@@ -55,6 +55,7 @@ void Linecharts::addSystem(UASInterface* uas)
addWidget(widget); addWidget(widget);
plots.insert(uas->getUASID(), widget); plots.insert(uas->getUASID(), widget);
connect(uas, SIGNAL(valueChanged(int,QString,double,quint64)), widget, SLOT(appendData(int,QString,double,quint64))); connect(uas, SIGNAL(valueChanged(int,QString,double,quint64)), widget, SLOT(appendData(int,QString,double,quint64)));
connect(widget, SIGNAL(logfileWritten(QString)), this, SIGNAL(logfileWritten(QString)));
// Set system active if this is the only system // Set system active if this is the only system
if (active) if (active)
{ {
......
...@@ -14,6 +14,8 @@ public: ...@@ -14,6 +14,8 @@ public:
explicit Linecharts(QWidget *parent = 0); explicit Linecharts(QWidget *parent = 0);
signals: signals:
/** @brief This signal is emitted once a logfile has been finished writing */
void logfileWritten(QString fileName);
public slots: public slots:
/** @brief Set all plots active/inactive */ /** @brief Set all plots active/inactive */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment