a lot!!! of changes
added main menu added debug display many debug widgets for plotting live data worked on android live sensors added offline-data sensor feeding some dummy data sensors worked on the map display added ui debug for grid-points, particles and weights added a cool dude to display the estimation added real filtering based on the Indoor components c++11 fixes for android compilation online and offline filtering support new resampling technique for testing map loading via dialog
This commit is contained in:
49
ui/debug/PlotTurns.cpp
Normal file
49
ui/debug/PlotTurns.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "PlotTurns.h"
|
||||
#include <QPainter>
|
||||
|
||||
PlotTurns::PlotTurns(QWidget *parent) : QWidget(parent) {
|
||||
|
||||
setMinimumWidth(96);
|
||||
setMinimumHeight(96);
|
||||
|
||||
resize(96, 96);
|
||||
|
||||
// setMaximumWidth(64);
|
||||
// setMaximumHeight(64);
|
||||
|
||||
}
|
||||
|
||||
void PlotTurns::add(const Timestamp ts, const TurnData& data) {
|
||||
(void) ts;
|
||||
this->data = data;
|
||||
static int i = 0;
|
||||
if (++i % 4 == 0) {
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
void PlotTurns::paintEvent(QPaintEvent* evt) {
|
||||
|
||||
(void) evt;
|
||||
QPainter p(this);
|
||||
|
||||
const float s = std::min(width(), height());
|
||||
const float s1 = s / 1.9;
|
||||
|
||||
const float cx = width() / 2;
|
||||
const float cy = height() / 2;
|
||||
|
||||
const float x1 = cx + std::cos(data.radSinceStart-M_PI_2) * s1;
|
||||
const float y1 = cy + std::sin(data.radSinceStart-M_PI_2) * s1;
|
||||
|
||||
p.fillRect(0,0,width(),height(),QColor(255,255,255,192));
|
||||
p.setPen(Qt::black);
|
||||
p.drawRect(0,0,width()-1,height()-1);
|
||||
|
||||
const QPen pen(Qt::black, 2);
|
||||
p.setPen(pen);
|
||||
p.drawLine(cx, cy, x1, y1);
|
||||
|
||||
p.end();
|
||||
|
||||
}
|
||||
30
ui/debug/PlotTurns.h
Normal file
30
ui/debug/PlotTurns.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef PLOTTURNS_H
|
||||
#define PLOTTURNS_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "../sensors/TurnSensor.h"
|
||||
#include <Indoor/data/Timestamp.h>
|
||||
|
||||
class PlotTurns : public QWidget {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
||||
TurnData data;
|
||||
|
||||
public:
|
||||
|
||||
explicit PlotTurns(QWidget *parent = 0);
|
||||
|
||||
void add(const Timestamp ts, const TurnData& data);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
void paintEvent(QPaintEvent*);
|
||||
|
||||
};
|
||||
|
||||
#endif // PLOTTURNS_H
|
||||
53
ui/debug/PlotWiFiScan.cpp
Normal file
53
ui/debug/PlotWiFiScan.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "../misc/fixc11.h"
|
||||
#include "PlotWiFiScan.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStaticText>
|
||||
|
||||
PlotWiFiScan::PlotWiFiScan(QWidget *parent) : QWidget(parent) {
|
||||
|
||||
setMinimumWidth(96);
|
||||
setMinimumHeight(96);
|
||||
|
||||
//setAutoFillBackground(false);
|
||||
|
||||
}
|
||||
|
||||
void PlotWiFiScan::add(const Timestamp ts, const WiFiMeasurements& data) {
|
||||
(void) ts;
|
||||
this->data = data;
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void PlotWiFiScan::paintEvent(QPaintEvent* evt) {
|
||||
|
||||
(void) evt;
|
||||
QPainter p(this);
|
||||
|
||||
const int x0 = 4; const int xw = 150;
|
||||
const int y0 = 3;
|
||||
const int lh = 13;
|
||||
|
||||
int x = x0;
|
||||
int y = y0;
|
||||
|
||||
|
||||
p.fillRect(0,0,width(),height(),QColor(255,255,255,192));
|
||||
p.setPen(Qt::black);
|
||||
p.drawRect(0,0,width()-1,height()-1);
|
||||
|
||||
const QFont font("Arial", 9);
|
||||
p.setFont(font);
|
||||
p.setPen(Qt::black);
|
||||
|
||||
for (const WiFiMeasurement& m : data.entries) {
|
||||
const std::string& mac = m.getAP().getMAC().asString();
|
||||
std::string str = mac + ": " + std::to_string((int)m.getRSSI());
|
||||
p.drawStaticText(x, y, QStaticText(str.c_str()));
|
||||
y += lh;
|
||||
if (y > 90) {y = y0; x += xw;}
|
||||
}
|
||||
|
||||
p.end();
|
||||
|
||||
}
|
||||
30
ui/debug/PlotWiFiScan.h
Normal file
30
ui/debug/PlotWiFiScan.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef PLOTWIFISCAN_H
|
||||
#define PLOTWIFISCAN_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "../sensors/WiFiSensor.h"
|
||||
|
||||
class PlotWiFiScan : public QWidget {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
||||
WiFiMeasurements data;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
explicit PlotWiFiScan(QWidget *parent = 0);
|
||||
|
||||
void add(const Timestamp ts, const WiFiMeasurements& data);
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
void paintEvent(QPaintEvent*);
|
||||
|
||||
};
|
||||
|
||||
#endif // PLOTWIFISCAN_H
|
||||
217
ui/debug/SensorDataWidget.cpp
Normal file
217
ui/debug/SensorDataWidget.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
#include "../misc/fixc11.h"
|
||||
#include "SensorDataWidget.h"
|
||||
|
||||
#include "plot/PlottWidget.h"
|
||||
#include <QGridLayout>
|
||||
#include <QColor>
|
||||
|
||||
#include "../sensors/SensorFactory.h"
|
||||
#include "PlotTurns.h"
|
||||
#include "PlotWiFiScan.h"
|
||||
|
||||
|
||||
template <typename Data> void removeOld(Data& data, const Timestamp limit) {
|
||||
if (data.size() < 2) {return;}
|
||||
while ( (data.back().key - data.front().key) > limit.ms()) {
|
||||
data.remove(0);
|
||||
}
|
||||
}
|
||||
|
||||
template <int num> class PlotXLines : public PlotWidget {
|
||||
|
||||
protected:
|
||||
|
||||
QColor colors[4] = {QColor(255,0,0), QColor(0,192,0), QColor(0,0,255), QColor(0,0,0)};
|
||||
LinePlot line[num];
|
||||
|
||||
public:
|
||||
|
||||
PlotXLines(QWidget* parent) : PlotWidget(parent) {
|
||||
for (int i = 0; i < num; ++i) {
|
||||
pc.addPlot(&line[i]);
|
||||
line[i].setColor(colors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void addLineNode(const Timestamp ts, const float y, const int idx) {
|
||||
LinePlot& lp = line[idx];
|
||||
lp.getData().add(ts.ms(), y);
|
||||
}
|
||||
|
||||
Timestamp lastRefresh;
|
||||
bool needsRefresh(const Timestamp ts) {
|
||||
const Timestamp diff = ts - lastRefresh;
|
||||
return (diff > Timestamp::fromMS(100));
|
||||
}
|
||||
|
||||
|
||||
void refresh(const Timestamp ts) {
|
||||
|
||||
// ensure event from main-thread using queued-connection
|
||||
QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
|
||||
|
||||
lastRefresh = ts;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class PlotAcc : public PlotXLines<3> {
|
||||
|
||||
protected:
|
||||
|
||||
PointPlot steps;
|
||||
|
||||
public:
|
||||
|
||||
PlotAcc(QWidget* parent) : PlotXLines(parent) {
|
||||
steps.setColor(colors[2]);
|
||||
steps.setPointSize(8);
|
||||
pc.addPlot(&steps);
|
||||
const float s = 4.2;
|
||||
const float ref = 9.81;
|
||||
pc.setValRange(Range(ref-s, ref+s));
|
||||
}
|
||||
|
||||
void addStep(const Timestamp ts) {
|
||||
steps.getData().add(ts.ms(), 9.81);
|
||||
}
|
||||
|
||||
void add(const Timestamp ts, const AccelerometerData& data) {
|
||||
addLineNode(ts, data.x, 0);
|
||||
addLineNode(ts, data.y, 1);
|
||||
addLineNode(ts, data.z, 2);
|
||||
if (needsRefresh(ts)) {
|
||||
limit();
|
||||
refresh(ts);
|
||||
}
|
||||
}
|
||||
|
||||
void limit() {
|
||||
const Timestamp limit = Timestamp::fromMS(3000);
|
||||
removeOld(line[0].getData(), limit);
|
||||
removeOld(line[1].getData(), limit);
|
||||
removeOld(line[2].getData(), limit);
|
||||
removeOld(steps.getData(), limit - Timestamp::fromMS(100)); // remove steps a little before. prevents errors
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class PlotGyro : public PlotXLines<3> {
|
||||
|
||||
public:
|
||||
|
||||
PlotGyro(QWidget* parent) : PlotXLines(parent) {
|
||||
const float s = 1;
|
||||
const float ref = 0;
|
||||
pc.setValRange(Range(ref-s, ref+s));
|
||||
}
|
||||
|
||||
void add(const Timestamp ts, const GyroscopeData& data) {
|
||||
addLineNode(ts, data.x, 0);
|
||||
addLineNode(ts, data.y, 1);
|
||||
addLineNode(ts, data.z, 2);
|
||||
if (needsRefresh(ts)) {
|
||||
limit();
|
||||
refresh(ts);
|
||||
}
|
||||
}
|
||||
|
||||
void limit() {
|
||||
const Timestamp limit = Timestamp::fromMS(3000);
|
||||
removeOld(line[0].getData(), limit);
|
||||
removeOld(line[1].getData(), limit);
|
||||
removeOld(line[2].getData(), limit);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class PlotBaro : public PlotXLines<1> {
|
||||
|
||||
public:
|
||||
|
||||
PlotBaro(QWidget* parent) : PlotXLines(parent) {
|
||||
|
||||
}
|
||||
|
||||
void add(const Timestamp ts, const BarometerData& data) {
|
||||
addLineNode(ts, data.hPa, 0);
|
||||
if (needsRefresh(ts)) {
|
||||
limit();
|
||||
refresh(ts);
|
||||
}
|
||||
const float s = 0.5;
|
||||
const float ref = line[0].getData().front().val;
|
||||
pc.setValRange(Range(ref-s, ref+s));
|
||||
}
|
||||
|
||||
void limit() {
|
||||
removeOld(line[0].getData(), Timestamp::fromMS(8000));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class PlotTurn : public QWidget {
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
SensorDataWidget::SensorDataWidget(QWidget* parent) : QWidget(parent) {
|
||||
|
||||
QGridLayout* lay = new QGridLayout(this);
|
||||
|
||||
plotGyro = new PlotGyro(this);
|
||||
plotAcc = new PlotAcc(this);
|
||||
plotBaro = new PlotBaro(this);
|
||||
plotTurn = new PlotTurns(this);
|
||||
plotWiFi = new PlotWiFiScan(this);
|
||||
|
||||
lay->addWidget(plotGyro, 0, 0, 1, 4, Qt::AlignTop);
|
||||
lay->addWidget(plotAcc, 1, 0, 1, 4, Qt::AlignTop);
|
||||
lay->addWidget(plotBaro, 2, 0, 1, 4, Qt::AlignTop);
|
||||
lay->addWidget(plotTurn, 3, 0, 1, 1, Qt::AlignTop);
|
||||
lay->addWidget(plotWiFi, 3, 1, 1, 3, Qt::AlignTop);
|
||||
|
||||
SensorFactory::get().getAccelerometer().addListener(this);
|
||||
SensorFactory::get().getGyroscope().addListener(this);
|
||||
SensorFactory::get().getBarometer().addListener(this);
|
||||
SensorFactory::get().getSteps().addListener(this);
|
||||
SensorFactory::get().getTurns().addListener(this);
|
||||
SensorFactory::get().getWiFi().addListener(this);
|
||||
|
||||
//setAutoFillBackground(false);
|
||||
|
||||
}
|
||||
|
||||
void SensorDataWidget::onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) {
|
||||
(void) sensor;
|
||||
((PlotAcc*)plotAcc)->add(ts, data);
|
||||
}
|
||||
|
||||
void SensorDataWidget::onSensorData(Sensor<StepData>* sensor, const Timestamp ts, const StepData& data) {
|
||||
(void) sensor;
|
||||
(void) data;
|
||||
((PlotAcc*)plotAcc)->addStep(ts);
|
||||
}
|
||||
|
||||
void SensorDataWidget::onSensorData(Sensor<GyroscopeData>* sensor, const Timestamp ts, const GyroscopeData& data) {
|
||||
(void) sensor;
|
||||
((PlotGyro*)plotGyro)->add(ts, data);
|
||||
}
|
||||
|
||||
void SensorDataWidget::onSensorData(Sensor<BarometerData>* sensor, const Timestamp ts, const BarometerData& data) {
|
||||
(void) sensor;
|
||||
((PlotBaro*)plotBaro)->add(ts, data);
|
||||
}
|
||||
|
||||
void SensorDataWidget::onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) {
|
||||
(void) sensor;
|
||||
((PlotTurns*)plotTurn)->add(ts, data);
|
||||
}
|
||||
|
||||
void SensorDataWidget::onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) {
|
||||
(void) sensor;
|
||||
((PlotWiFiScan*)plotWiFi)->add(ts, data);
|
||||
}
|
||||
|
||||
53
ui/debug/SensorDataWidget.h
Normal file
53
ui/debug/SensorDataWidget.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#ifndef SENSORDATAWIDGET_H
|
||||
#define SENSORDATAWIDGET_H
|
||||
|
||||
#include "../misc/fixc11.h"
|
||||
#include "plot/PlottWidget.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "../sensors/AccelerometerSensor.h"
|
||||
#include "../sensors/GyroscopeSensor.h"
|
||||
#include "../sensors/BarometerSensor.h"
|
||||
#include "../sensors/StepSensor.h"
|
||||
#include "../sensors/TurnSensor.h"
|
||||
#include "../sensors/WiFiSensor.h"
|
||||
|
||||
class PlotWidget;
|
||||
|
||||
/** debug display for sensor data */
|
||||
class SensorDataWidget :
|
||||
public QWidget,
|
||||
public SensorListener<AccelerometerData>,
|
||||
public SensorListener<GyroscopeData>,
|
||||
public SensorListener<BarometerData>,
|
||||
public SensorListener<StepData>,
|
||||
public SensorListener<TurnData>,
|
||||
public SensorListener<WiFiMeasurements> {
|
||||
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
SensorDataWidget(QWidget* parent);
|
||||
|
||||
void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override;
|
||||
void onSensorData(Sensor<GyroscopeData>* sensor, const Timestamp ts, const GyroscopeData& data) override;
|
||||
void onSensorData(Sensor<BarometerData>* sensor, const Timestamp ts, const BarometerData& data) override;
|
||||
void onSensorData(Sensor<StepData>* sensor, const Timestamp ts, const StepData& data) override;
|
||||
void onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) override;
|
||||
void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override;
|
||||
|
||||
private:
|
||||
|
||||
PlotWidget* plotGyro;
|
||||
PlotWidget* plotAcc;
|
||||
PlotWidget* plotBaro;
|
||||
QWidget* plotTurn;
|
||||
QWidget* plotWiFi;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // SENSORDATAWIDGET_H
|
||||
66
ui/debug/plot/Axes.h
Normal file
66
ui/debug/plot/Axes.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef AXES_H
|
||||
#define AXES_H
|
||||
|
||||
#include "Range.h"
|
||||
|
||||
class Axes {
|
||||
|
||||
/** min/max value to display */
|
||||
Range range;
|
||||
|
||||
/** number of available pixels for above range */
|
||||
int pixels;
|
||||
|
||||
/** whether to invert the axes */
|
||||
bool invert = false;
|
||||
|
||||
public:
|
||||
|
||||
void setMin(const float min) {this->range.min = min;}
|
||||
float getMin() const {return this->range.min;}
|
||||
|
||||
void setMax(const float max) {this->range.max = max;}
|
||||
float getMax() const {return this->range.max;}
|
||||
|
||||
void setRange(const Range& range) {this->range = range;}
|
||||
const Range& getRange() const {return this->range;}
|
||||
|
||||
void setPixels(const int px) {this->pixels = px;}
|
||||
int getPixels() const {return this->pixels;}
|
||||
|
||||
void setInverted(const bool inverted) {this->invert = inverted;}
|
||||
bool isInverted() const {return this->invert;}
|
||||
|
||||
float convert(const float val) const {
|
||||
float percent = (val - range.min) / (range.getSize());
|
||||
if (invert) {percent = 1-percent;}
|
||||
return percent * pixels;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class AxesX : public Axes {
|
||||
|
||||
public:
|
||||
|
||||
AxesX() {
|
||||
setInverted(false);
|
||||
}
|
||||
|
||||
void setWidth(const int px) {setPixels(px);}
|
||||
|
||||
};
|
||||
|
||||
class AxesY : public Axes {
|
||||
|
||||
public:
|
||||
|
||||
AxesY() {
|
||||
setInverted(true);
|
||||
}
|
||||
|
||||
void setHeight(const int px) {setPixels(px);}
|
||||
|
||||
};
|
||||
|
||||
#endif // AXES_H
|
||||
80
ui/debug/plot/Data.h
Normal file
80
ui/debug/plot/Data.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef PLOT_DATA_H
|
||||
#define PLOT_DATA_H
|
||||
|
||||
#include <vector>
|
||||
#include "Range.h"
|
||||
#include <cmath>
|
||||
|
||||
class Data {
|
||||
|
||||
using Key = float;
|
||||
using Value = float;
|
||||
|
||||
public:
|
||||
|
||||
struct KeyVal {
|
||||
Key key;
|
||||
Value val;
|
||||
KeyVal(const Key& key, const Value& val) : key(key), val(val) {;}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
/** contained data */
|
||||
std::vector<KeyVal> data;
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/** add a new value */
|
||||
void add(const Key key, const Value val) {
|
||||
data.push_back(KeyVal(key,val));
|
||||
}
|
||||
|
||||
/** remove the given index */
|
||||
void remove(const int idx) {
|
||||
data.erase(data.begin()+idx);
|
||||
}
|
||||
|
||||
Key getKey(const int idx) const {
|
||||
return data[idx].key;
|
||||
}
|
||||
|
||||
Value getValue(const int idx) const {
|
||||
return data[idx].val;
|
||||
}
|
||||
|
||||
const KeyVal& getKeyValue(const int idx) const {
|
||||
return data[idx];
|
||||
}
|
||||
|
||||
const KeyVal& operator [] (const int idx) const {
|
||||
return data[idx];
|
||||
}
|
||||
|
||||
const KeyVal& front() const {return data.front();}
|
||||
const KeyVal& back() const {return data.back();}
|
||||
|
||||
/** get the range (min/max) for the key-data (x-axes) */
|
||||
Range getKeyRange() const {
|
||||
Range range(+INFINITY,-INFINITY);
|
||||
for (const KeyVal& kv : data) {range.adjust(kv.key);}
|
||||
return range;
|
||||
}
|
||||
|
||||
/** get the range (min/max) for the value-data (y-axes) */
|
||||
Range getValueRange() const {
|
||||
Range range(+INFINITY,-INFINITY);
|
||||
for (const KeyVal& kv : data) {range.adjust(kv.val);}
|
||||
return range;
|
||||
}
|
||||
|
||||
/** get the number of entries */
|
||||
size_t size() const {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // PLOT_DATA_H
|
||||
215
ui/debug/plot/Plot.h
Normal file
215
ui/debug/plot/Plot.h
Normal file
@@ -0,0 +1,215 @@
|
||||
#ifndef PLOT_H
|
||||
#define PLOT_H
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
#include "Axes.h"
|
||||
#include "Data.h"
|
||||
|
||||
#include <Indoor/geo/Point2.h>
|
||||
|
||||
/** describes a plot-setup */
|
||||
struct PlotParameters {
|
||||
|
||||
AxesX xAxes;
|
||||
AxesY yAxes;
|
||||
|
||||
int w;
|
||||
int h;
|
||||
|
||||
/** helper method */
|
||||
Point2 getPoint(const typename Data::KeyVal& kv) const {
|
||||
const float x1 = xAxes.convert(kv.key);
|
||||
const float y1 = yAxes.convert(kv.val);
|
||||
return Point2(x1, y1);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/** interface for all plots */
|
||||
class Plot {
|
||||
|
||||
protected:
|
||||
|
||||
Data data;
|
||||
|
||||
QColor bg = QColor(255,255,255,128);
|
||||
|
||||
public:
|
||||
|
||||
virtual ~Plot() {;}
|
||||
|
||||
void render(QPainter& p, const PlotParameters& params) {
|
||||
// maybe do something here?
|
||||
renderSub(p, params);
|
||||
}
|
||||
|
||||
Data& getData() {return data;}
|
||||
|
||||
Range getKeyRange() const {return data.getKeyRange();}
|
||||
|
||||
Range getValueRange() const {return data.getValueRange();}
|
||||
|
||||
protected:
|
||||
|
||||
/** subclasses must render themselves here */
|
||||
virtual void renderSub(QPainter& p, const PlotParameters& params) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** combine several plots (several lines, points, ...) together into one plot */
|
||||
class PlotContainer {
|
||||
|
||||
private:
|
||||
|
||||
PlotParameters params;
|
||||
|
||||
std::vector<Plot*> plots;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
PlotContainer() {
|
||||
;
|
||||
}
|
||||
|
||||
AxesX& getAxesX() {return params.xAxes;}
|
||||
AxesY& getAxesY() {return params.yAxes;}
|
||||
|
||||
Range overwriteRangeKey = Range(0,0);
|
||||
Range overwriteRangeVal = Range(0,0);
|
||||
|
||||
void setValRange(const Range& range) {overwriteRangeVal = range;}
|
||||
void setKeyRange(const Range& range) {overwriteRangeKey = range;}
|
||||
|
||||
|
||||
void resize(const int w, const int h) {
|
||||
params.w = w;
|
||||
params.h = h;
|
||||
}
|
||||
|
||||
void addPlot(Plot* plt) {
|
||||
plots.push_back(plt);
|
||||
}
|
||||
|
||||
void render(QPainter& p) {
|
||||
|
||||
setupAxes();
|
||||
|
||||
QColor bg(255,255,255,192);
|
||||
p.fillRect(0,0,params.w,params.h,bg);
|
||||
p.setPen(Qt::black);
|
||||
p.drawRect(0,0,params.w-1,params.h-1);
|
||||
|
||||
for (Plot* plt : plots) {
|
||||
plt->render(p, params);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setupAxes() {
|
||||
|
||||
params.xAxes.setPixels(params.w);
|
||||
params.yAxes.setPixels(params.h);
|
||||
|
||||
Range keyRange(+INFINITY,-INFINITY);
|
||||
Range valRange(+INFINITY,-INFINITY);
|
||||
|
||||
if (overwriteRangeKey.isValid()) {keyRange.adjust(overwriteRangeKey);}
|
||||
if (overwriteRangeVal.isValid()) {valRange.adjust(overwriteRangeVal);}
|
||||
|
||||
/** calculate min/max for both x and y axis */
|
||||
for (Plot* plt : plots) {
|
||||
if (!overwriteRangeKey.isValid()) {keyRange.adjust(plt->getKeyRange());}
|
||||
if (!overwriteRangeVal.isValid()) {valRange.adjust(plt->getValueRange());}
|
||||
}
|
||||
|
||||
valRange.scale(1.1);
|
||||
|
||||
params.xAxes.setRange(keyRange);
|
||||
params.yAxes.setRange(valRange);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LinePlot : public Plot {
|
||||
|
||||
private:
|
||||
|
||||
QColor lineColor = QColor(0,0,255);
|
||||
|
||||
public:
|
||||
|
||||
void setColor(const QColor c) {
|
||||
this->lineColor = c;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void renderSub(QPainter& p , const PlotParameters& params) override {
|
||||
|
||||
p.setPen(lineColor);
|
||||
|
||||
for (int i = 0; i < (int) data.size()-1; ++i) {
|
||||
|
||||
const typename Data::KeyVal kv1 = data[i+0];
|
||||
const typename Data::KeyVal kv2 = data[i+1];
|
||||
|
||||
const Point2 p1 = params.getPoint(kv1);
|
||||
const Point2 p2 = params.getPoint(kv2);
|
||||
|
||||
p.drawLine(p1.x, p1.y, p2.x, p2.y);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class PointPlot : public Plot {
|
||||
|
||||
private:
|
||||
|
||||
QColor pointColor = QColor(0,0,255);
|
||||
float pointSize = 4;
|
||||
|
||||
public:
|
||||
|
||||
void setColor(const QColor c) {
|
||||
this->pointColor = c;
|
||||
}
|
||||
|
||||
void setPointSize(const float size) {
|
||||
this->pointSize = size;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void renderSub(QPainter& p , const PlotParameters& params) override {
|
||||
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(pointColor);
|
||||
|
||||
for (int i = 0; i < (int) data.size(); ++i) {
|
||||
|
||||
const typename Data::KeyVal kv1 = data[i+0];
|
||||
|
||||
const Point2 p1 = params.getPoint(kv1);
|
||||
|
||||
p.drawEllipse(p1.x, p1.y, pointSize, pointSize);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // PLOT_H
|
||||
37
ui/debug/plot/PlottWidget.cpp
Normal file
37
ui/debug/plot/PlottWidget.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "PlottWidget.h"
|
||||
|
||||
#include <QResizeEvent>
|
||||
#include <QPaintEvent>
|
||||
#include <QPainter>
|
||||
|
||||
PlotWidget::PlotWidget(QWidget *parent) : QWidget(parent) {
|
||||
|
||||
setMinimumSize(100, 100);
|
||||
|
||||
// LinePlot* lp = new LinePlot();
|
||||
// pc.addPlot(lp);
|
||||
|
||||
// lp->getData().add(1, 1);
|
||||
// lp->getData().add(2, 2);
|
||||
// lp->getData().add(3, 3);
|
||||
// lp->getData().add(4, 1);
|
||||
// lp->getData().add(5, 2);
|
||||
// lp->getData().add(6, 3);
|
||||
// lp->getData().add(7, 1);
|
||||
// lp->getData().add(8, 2);
|
||||
// lp->getData().add(9, 3);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PlotWidget::resizeEvent(QResizeEvent* evt) {
|
||||
(void) evt;
|
||||
pc.resize(width(), height());
|
||||
}
|
||||
|
||||
void PlotWidget::paintEvent(QPaintEvent* evt) {
|
||||
(void) evt;
|
||||
QPainter p(this);
|
||||
pc.render(p);
|
||||
p.end();
|
||||
}
|
||||
30
ui/debug/plot/PlottWidget.h
Normal file
30
ui/debug/plot/PlottWidget.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef PLOTTI_H
|
||||
#define PLOTTI_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "Plot.h"
|
||||
|
||||
/** widget to render one plot */
|
||||
class PlotWidget : public QWidget {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
explicit PlotWidget(QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
|
||||
PlotContainer pc;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
void paintEvent(QPaintEvent*);
|
||||
void resizeEvent(QResizeEvent*);
|
||||
|
||||
};
|
||||
|
||||
#endif // PLOTTI_H
|
||||
48
ui/debug/plot/Range.h
Normal file
48
ui/debug/plot/Range.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef PLOT_RANGE_H
|
||||
#define PLOT_RANGE_H
|
||||
|
||||
struct Range {
|
||||
|
||||
float min;
|
||||
float max;
|
||||
|
||||
Range() : min(0), max(0) {;}
|
||||
|
||||
Range(const float min, const float max) : min(min), max(max) {
|
||||
;
|
||||
}
|
||||
|
||||
float getSize() const {
|
||||
return max-min;
|
||||
}
|
||||
|
||||
float getCenter() const {
|
||||
return (max+min)/2;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return getSize() > 0;
|
||||
}
|
||||
|
||||
/** resize the region. 1.0 = keep-as-is */
|
||||
void scale(const float val) {
|
||||
const float center = getCenter();
|
||||
const float size = getSize();
|
||||
min = center - size / 2 * val;
|
||||
max = center + size / 2 * val;
|
||||
}
|
||||
|
||||
/** adjust (grow) the range */
|
||||
void adjust(const float val) {
|
||||
if (val < min) {min = val;}
|
||||
if (val > max) {max = val;}
|
||||
}
|
||||
|
||||
void adjust(const Range& o) {
|
||||
if (o.min < min) {min = o.min;}
|
||||
if (o.max > max) {max = o.max;}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // PLOT_RANGE_H
|
||||
Reference in New Issue
Block a user