Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*=====================================================================
PIXHAWK Micro Air Vehicle Flying Robotics Toolkit
(c) 2009, 2010 PIXHAWK PROJECT <http://pixhawk.ethz.ch>
This file is part of the PIXHAWK project
PIXHAWK 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.
PIXHAWK 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 PIXHAWK. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
/**
* @file
* @brief Plot of a Linechart
*
* @author Lorenz Meier <mavteam@student.ethz.ch>
*
*/
#ifndef _LINECHARTPLOT_H_
#define _LINECHARTPLOT_H_
#define QUINT64_MIN Q_UINT64_C(0)
#define QUINT64_MAX Q_UINT64_C(18446744073709551615)
#include <QMap>
#include <QList>
#include <QMutex>
#include <QTime>
#include <QTimer>
#include <qwt_plot_panner.h>
#include <qwt_plot_curve.h>
#include <qwt_scale_draw.h>
#include <qwt_scale_widget.h>
#include <qwt_scale_engine.h>
#include <qwt_array.h>
#include <qwt_plot.h>
#include <ScrollZoomer.h>
#include "MG.h"
virtual QwtText label(double v) const {
QDateTime time = MG::TIME::msecToQDateTime(static_cast<quint64>(v));
return time.toString("hh:mm:ss"); // was hh:mm:ss:zzz
// Show seconds since system startup
//return QString::number(static_cast<int>(v)/1000000);
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
}
};
/**
* @brief Zoomer for plot
*/
class Zoomer: public ScrollZoomer
{
public:
Zoomer(QwtPlotCanvas *canvas) : ScrollZoomer(canvas) {}
virtual void rescale() {
QwtScaleWidget *scaleWidget = plot()->axisWidget(yAxis());
QwtScaleDraw *sd = scaleWidget->scaleDraw();
int minExtent = 0;
if ( zoomRectIndex() > 0 ) {
// When scrolling in vertical direction
// the plot is jumping in horizontal direction
// because of the different widths of the labels
// So we better use a fixed extent.
minExtent = sd->spacing() + sd->majTickLength() + 1;
minExtent += sd->labelSize(scaleWidget->font(), 1000).width();
}
sd->setMinimumExtent(minExtent);
ScrollZoomer::rescale();
}
};
/**
* @brief Data container
*/
class QwtPlotCurve;
/**
* @brief Container class for the time series data
*
**/
class TimeSeriesData
{
public:
TimeSeriesData(QwtPlot* plot, QString friendlyName = "data", quint64 plotInterval = 10000, quint64 maxInterval = 0, double zeroValue = 0);
~TimeSeriesData();
void append(quint64 ms, double value);
QwtScaleMap* getScaleMap();
int getCount() const;
int size() const;
const double* getX() const;
const double* getY() const;
const double* getPlotX() const;
const double* getPlotY() const;
int getPlotCount() const;
int getID();
QString getFriendlyName();
double getMinValue();
double getMaxValue();
double getZeroValue();
/** @brief Get the short-term mean */
double getMean();
/** @brief Get the short-term median */
double getMedian();
/** @brief Get the short-term variance */
double getVariance();
/** @brief Get the current value */
void setZeroValue(double zeroValue);
void setInterval(quint64 ms);
void setAverageWindowSize(int windowSize);
protected:
QwtPlot* plot;
quint64 startTime;
quint64 stopTime;
quint64 interval;
quint64 plotInterval;
quint64 maxInterval;
int id;
quint64 plotCount;
QString friendlyName;
double lastValue; ///< The last inserted value
double minValue; ///< The smallest value in the dataset
double maxValue; ///< The largest value in the dataset
double zeroValue; ///< The expected value in the dataset
QMutex dataMutex;
QwtScaleMap* scaleMap;
void updateScaleMap();
private:
quint64 count;
QwtArray<double> ms;
QwtArray<double> value;
double mean;
double median;
unsigned int averageWindow;
QwtArray<double> outputMs;
QwtArray<double> outputValue;
};
/**
* @brief Time series plot
**/
class LinechartPlot : public QwtPlot
{
Q_OBJECT
public:
LinechartPlot(QWidget *parent = NULL, int plotid=0, quint64 interval = LinechartPlot::DEFAULT_PLOT_INTERVAL);
virtual ~LinechartPlot();
void setZeroValue(QString id, double zeroValue);
void removeAllData();
QList<QwtPlotCurve*> getCurves();
bool isVisible(QString id);
/** @brief Check if any curve is visible */
bool anyCurveVisible();
int getPlotId();
/** @brief Get the number of values to average over */
int getAverageWindow();
quint64 getMinTime();
quint64 getMaxTime();
quint64 getPlotInterval();
quint64 getDataInterval();
quint64 getWindowPosition();
QList<QColor> getColorMap();
/** @brief Get the short-term mean of a curve */
double getMean(QString id);
/** @brief Get the short-term median of a curve */
double getMedian(QString id);
/** @brief Get the short-term variance of a curve */
double getVariance(QString id);
/** @brief Get the last inserted value */
double getCurrentValue(QString id);
static const int SCALE_ABSOLUTE = 0;
static const int SCALE_BEST_FIT = 1;
static const int SCALE_LOGARITHMIC = 2;
static const int DEFAULT_REFRESH_RATE = 100; ///< The default refresh rate is 10 Hz / every 100 ms
static const int DEFAULT_PLOT_INTERVAL = 1000 * 8; ///< The default plot interval is 15 seconds
static const int DEFAULT_SCALE_INTERVAL = 1000 * 8;
public slots:
void setRefreshRate(int ms);
/**
* @brief Append data to the plot
*
* The new data point is appended to the curve with the id-String id. If the curve
* doesn't yet exist it is created and added to the plot.
*
* @param uasId id of originating UAS
* @param dataname unique string (also used to label the data)
* @param ms time measure of the data point, in milliseconds
* @param value value of the data point
*/
void appendData(QString dataname, quint64 ms, double value);
void hideCurve(QString id);
void showCurve(QString id);
/** @brief Enable auto-refreshing of plot */
void setActive(bool active);
// Functions referring to the currently active plot
void setVisible(QString id, bool visible);
//void showCurve(QString id, int position);
void setCurveColor(QString id, QColor color);
/** @brief Enforce the use of the receive timestamp */
void enforceGroundTime(bool enforce);
/** @brief Check if the receive timestamp is enforced */
bool groundTime();
// General interaction
void setWindowPosition(quint64 end);
void setPlotInterval(int interval);
void setScaling(int scaling);
void setAutoScroll(bool active);
void paintRealtime();
/** @brief Set logarithmic plot y-axis scaling */
void setLogarithmicScaling();
/** @brief Set linear plot y-axis scaling */
void setLinearScaling();
/** @brief Set the number of values to average over */
void setAverageWindow(int windowSize);
void removeTimedOutCurves();
/** @brief Reset color map */
void shuffleColors()
{
foreach (QwtPlotCurve* curve, curves)
{
QPen pen(curve->pen());
pen.setColor(getNextColor());
curve->setPen(pen);
}
}
public:
QColor getColorForCurve(QString id);
protected:
QMap<QString, QwtPlotCurve*> curves;
QMap<QString, TimeSeriesData*> data;
QMap<QString, QwtScaleMap*> scaleMaps;
QMap<QString, quint64> lastUpdate;
QList<QColor> colors;
int nextColor;
//static const quint64 MAX_STORAGE_INTERVAL = Q_UINT64_C(300000);
static const quint64 MAX_STORAGE_INTERVAL = Q_UINT64_C(0); ///< The maximum interval which is stored
// TODO CHECK THIS!!!
int scaling;
QwtScaleEngine* yScaleEngine;
quint64 minTime; ///< The smallest timestamp occured so far
quint64 maxTime; ///< The biggest timestamp occured so far
quint64 maxInterval;
quint64 storageInterval;
double maxValue;
double minValue;
double valueInterval;
int averageWindowSize; ///< Size of sliding average / sliding median
quint64 plotInterval;
quint64 plotPosition;
QTimer* updateTimer;
QMutex datalock;
QMutex windowLock;
quint64 timeScaleStep;
bool automaticScrollActive;
QTime lastMaxTimeAdded;
int plotid;
bool m_active; ///< Decides wether the plot is active or not
bool m_groundTime; ///< Enforce the use of the receive timestamp instead of the data timestamp
QTimer timeoutTimer;
// Methods
void addCurve(QString id);
QColor getNextColor();
void showEvent(QShowEvent* event);
void hideEvent(QHideEvent* event);
private:
TimeSeriesData* d_data;
QwtPlotCurve* d_curve;
signals:
/**
* @brief This signal is emitted when a new curve is added
*
* @param color The curve color in the diagram
**/
void curveAdded(QString idstring);
/**
* @brief This signal is emitted when a curve gets assigned a color
*
* @param idstring The id-string of the curve
* @param color The curve color in the diagram
**/
void colorSet(QString idstring, QColor color);
/**
* @brief This signal is emitted when a curve is removed
*
* @param name The id-string of the curve
**/
void curveRemoved(QString name);
/**
* @brief This signal is emitted when the plot window position changes
*
* @param position The position of the right edge of the window, in milliseconds
**/
void windowPositionChanged(quint64 position);
};
#endif // _LINECHARTPLOT_H_