[Companion][logsDialog]Fixes for #1863 in next.
This commit is contained in:
+273
-248
@@ -1,7 +1,6 @@
|
||||
#include "logsdialog.h"
|
||||
#include "appdata.h"
|
||||
#include "ui_logsdialog.h"
|
||||
#include "qcustomplot.h"
|
||||
#include "helpers.h"
|
||||
#if defined WIN32 || !defined __GNUC__
|
||||
#include <windows.h>
|
||||
@@ -14,25 +13,43 @@ logsDialog::logsDialog(QWidget *parent) :
|
||||
ui(new Ui::logsDialog)
|
||||
{
|
||||
csvlog.clear();
|
||||
srand(QDateTime::currentDateTime().toTime_t());
|
||||
|
||||
ui->setupUi(this);
|
||||
this->setWindowIcon(CompanionIcon("logs.png"));
|
||||
palette.clear();
|
||||
|
||||
plotLock=false;
|
||||
for (int i=0; i< 60; i++)
|
||||
palette << QColor(rand()%245+10, rand()%245+10, rand()%245+10);
|
||||
|
||||
colors.append(Qt::green);
|
||||
colors.append(Qt::red);
|
||||
colors.append(Qt::yellow);
|
||||
colors.append(Qt::magenta);
|
||||
colors.append(Qt::cyan);
|
||||
colors.append(Qt::darkBlue);
|
||||
colors.append(Qt::darkGreen);
|
||||
colors.append(Qt::darkRed);
|
||||
colors.append(Qt::darkYellow);
|
||||
colors.append(Qt::darkMagenta);
|
||||
colors.append(Qt::darkCyan);
|
||||
colors.append(Qt::blue);
|
||||
pen.setWidthF(1.5);
|
||||
|
||||
ui->customPlot->setInteractions(QCustomPlot::iRangeDrag | QCustomPlot::iRangeZoom | QCustomPlot::iSelectAxes |
|
||||
QCustomPlot::iSelectLegend | QCustomPlot::iSelectPlottables | QCustomPlot::iSelectTitle | QCustomPlot::iSelectItems);
|
||||
ui->customPlot->setRangeDrag(Qt::Horizontal|Qt::Vertical);
|
||||
ui->customPlot->setRangeZoom(Qt::Horizontal|Qt::Vertical);
|
||||
ui->customPlot->yAxis->setRange(-1100, 1100);
|
||||
ui->customPlot->setupFullAxesBox();
|
||||
ui->customPlot->setTitle(tr("Telemetry logs"));
|
||||
ui->customPlot->xAxis->setLabel(tr("Time"));
|
||||
|
||||
ui->customPlot->xAxis->setLabel(tr("Time (hh:mm:ss)"));
|
||||
ui->customPlot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
|
||||
ui->customPlot->xAxis->setDateTimeFormat("hh:mm:ss");
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
ui->customPlot->xAxis->setRange(now.addSecs(-60*60*2).toTime_t(),
|
||||
now.toTime_t());
|
||||
|
||||
ui->customPlot->legend->setVisible(true);
|
||||
ui->customPlot->yAxis->setTickLabels(false);
|
||||
ui->customPlot->yAxis->setAutoTickCount(10);
|
||||
ui->customPlot->xAxis2->setTicks(false);
|
||||
ui->customPlot->yAxis2->setTicks(false);
|
||||
ui->customPlot->setRangeZoomFactor(2, 2);
|
||||
QFont legendFont = font();
|
||||
@@ -44,23 +61,22 @@ logsDialog::logsDialog(QWidget *parent) :
|
||||
QString Path=g.gePath();
|
||||
if (Path.isEmpty() || !QFile(Path).exists()) {
|
||||
ui->mapsButton->hide();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// connect slot that ties some axis selections together (especially opposite axes):
|
||||
connect(ui->customPlot, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged()));
|
||||
// connect slots that takes care that when an axis is selected, only that direction can be dragged and zoomed:
|
||||
connect(ui->customPlot, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress()));
|
||||
connect(ui->customPlot, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel()));
|
||||
|
||||
// make bottom and left axes transfer their ranges to top and right axes:
|
||||
connect(ui->customPlot->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->xAxis2, SLOT(setRange(QCPRange)));
|
||||
connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->customPlot->yAxis2, SLOT(setRange(QCPRange)));
|
||||
|
||||
|
||||
// make left axes transfer its ranges to right axes:
|
||||
connect(ui->customPlot->yAxis, SIGNAL(rangeChanged(QCPRange)), this, SLOT(setRangeyAxis2(QCPRange)));
|
||||
|
||||
// connect some interaction slots:
|
||||
connect(ui->customPlot, SIGNAL(titleDoubleClick(QMouseEvent*)), this, SLOT(titleDoubleClick()));
|
||||
connect(ui->customPlot, SIGNAL(axisDoubleClick(QCPAxis*,QCPAxis::SelectablePart,QMouseEvent*)), this, SLOT(axisLabelDoubleClick(QCPAxis*,QCPAxis::SelectablePart)));
|
||||
connect(ui->customPlot, SIGNAL(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*,QMouseEvent*)), this, SLOT(legendDoubleClick(QCPLegend*,QCPAbstractLegendItem*)));
|
||||
connect(ui->customPlot, SIGNAL(plottableDoubleClick(QCPAbstractPlottable *, QMouseEvent *)), this, SLOT(plottableItemDoubleClick(QCPAbstractPlottable *, QMouseEvent *)));
|
||||
// connect(ui->customPlot, SIGNAL(plottableDoubleClick(QCPAbstractPlottable *, QMouseEvent *)), this, SLOT(plottableItemDoubleClick(QCPAbstractPlottable *, QMouseEvent *)));
|
||||
connect(ui->FieldsTW, SIGNAL(itemSelectionChanged()), this, SLOT(plotLogs()));
|
||||
connect(ui->logTable, SIGNAL(itemSelectionChanged()), this, SLOT(plotLogs()));
|
||||
connect(ui->Reset_PB, SIGNAL(clicked()), this, SLOT(plotLogs()));
|
||||
@@ -71,24 +87,12 @@ logsDialog::~logsDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
double logsDialog::GetScale(QString channel) {
|
||||
QString Analog="Rud,Ele,Thr,Ail,P1,P2,P3";
|
||||
QString Switches="THR,RUD,ELE,ID0,ID1,ID2,AIL,GEA,TRN";
|
||||
if (Analog.contains(channel)) {
|
||||
return 1.0;
|
||||
}
|
||||
if (Switches.contains(channel)) {
|
||||
return 0.001;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void logsDialog::titleDoubleClick()
|
||||
{
|
||||
// Set the plot title by double clicking on it
|
||||
|
||||
|
||||
bool ok;
|
||||
QString newTitle = QInputDialog::getText(this, "QCustomPlot example", "New plot title:", QLineEdit::Normal, ui->customPlot->title(), &ok);
|
||||
QString newTitle = QInputDialog::getText(this, "Plot Title Change", "New plot title:", QLineEdit::Normal, ui->customPlot->title(), &ok);
|
||||
if (ok)
|
||||
{
|
||||
ui->customPlot->setTitle(newTitle);
|
||||
@@ -99,11 +103,11 @@ void logsDialog::titleDoubleClick()
|
||||
void logsDialog::axisLabelDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart part)
|
||||
{
|
||||
// Set an axis label by double clicking on it
|
||||
|
||||
|
||||
if (part == QCPAxis::spAxisLabel) // only react when the actual axis label is clicked, not tick label or axis backbone
|
||||
{
|
||||
bool ok;
|
||||
QString newLabel = QInputDialog::getText(this, "QCustomPlot example", "New axis label:", QLineEdit::Normal, axis->label(), &ok);
|
||||
QString newLabel = QInputDialog::getText(this, "Axis Label Change", "New axis label:", QLineEdit::Normal, axis->label(), &ok);
|
||||
if (ok)
|
||||
{
|
||||
axis->setLabel(newLabel);
|
||||
@@ -115,13 +119,11 @@ void logsDialog::axisLabelDoubleClick(QCPAxis *axis, QCPAxis::SelectablePart par
|
||||
void logsDialog::legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *item)
|
||||
{
|
||||
// Rename a graph by double clicking on its legend item
|
||||
|
||||
Q_UNUSED(legend)
|
||||
if (item) // only react if item was clicked (user could have clicked on border padding of legend where there is no item, then item is 0)
|
||||
{
|
||||
QCPPlottableLegendItem *plItem = qobject_cast<QCPPlottableLegendItem*>(item);
|
||||
bool ok;
|
||||
QString newName = QInputDialog::getText(this, "QCustomPlot example", "New graph name:", QLineEdit::Normal, plItem->plottable()->name(), &ok);
|
||||
QString newName = QInputDialog::getText(this, "Graph Name Change", "New graph name:", QLineEdit::Normal, plItem->plottable()->name(), &ok);
|
||||
if (ok)
|
||||
{
|
||||
plItem->plottable()->setName(newName);
|
||||
@@ -129,10 +131,11 @@ void logsDialog::legendDoubleClick(QCPLegend *legend, QCPAbstractLegendItem *ite
|
||||
}
|
||||
}
|
||||
}
|
||||
void logsDialog::plottableItemDoubleClick(QCPAbstractPlottable * plottable, QMouseEvent * event)
|
||||
{
|
||||
|
||||
// void logsDialog::plottableItemDoubleClick(QCPAbstractPlottable * plottable, QMouseEvent * event)
|
||||
// {
|
||||
// qDebug() << plottable->
|
||||
}
|
||||
// }
|
||||
|
||||
void logsDialog::selectionChanged()
|
||||
{
|
||||
@@ -140,31 +143,33 @@ void logsDialog::selectionChanged()
|
||||
normally, axis base line, axis tick labels and axis labels are selectable separately, but we want
|
||||
the user only to be able to select the axis as a whole, so we tie the selected states of the tick labels
|
||||
and the axis base line together. However, the axis label shall be selectable individually.
|
||||
|
||||
|
||||
The selection state of the left and right axes shall be synchronized as well as the state of the
|
||||
bottom and top axes.
|
||||
|
||||
|
||||
Further, we want to synchronize the selection of the graphs with the selection state of the respective
|
||||
legend item belonging to that graph. So the user can select a graph by either clicking on the graph itself
|
||||
or on its legend item.
|
||||
*/
|
||||
if (plotLock)
|
||||
return;
|
||||
// make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:
|
||||
if (ui->customPlot->xAxis->selected().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis->selected().testFlag(QCPAxis::spTickLabels) ||
|
||||
ui->customPlot->xAxis2->selected().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis2->selected().testFlag(QCPAxis::spTickLabels))
|
||||
|
||||
if (plotLock) return;
|
||||
|
||||
// handle bottom axis and tick labels as one selectable object:
|
||||
if (ui->customPlot->xAxis->selected().testFlag(QCPAxis::spAxis) || ui->customPlot->xAxis->selected().testFlag(QCPAxis::spTickLabels))
|
||||
{
|
||||
ui->customPlot->xAxis2->setSelected(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||
ui->customPlot->xAxis->setSelected(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||
}
|
||||
// make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:
|
||||
// make left and right axes be selected synchronously,
|
||||
// and handle axis and tick labels as one selectable object:
|
||||
if (ui->customPlot->yAxis->selected().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis->selected().testFlag(QCPAxis::spTickLabels) ||
|
||||
ui->customPlot->yAxis2->selected().testFlag(QCPAxis::spAxis) || ui->customPlot->yAxis2->selected().testFlag(QCPAxis::spTickLabels))
|
||||
{
|
||||
ui->customPlot->yAxis2->setSelected(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||
ui->customPlot->yAxis->setSelected(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||
if (hasyAxis2) {
|
||||
ui->customPlot->yAxis2->setSelected(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// synchronize selection of graphs with selection of corresponding legend items:
|
||||
for (int i=0; i<ui->customPlot->graphCount(); ++i)
|
||||
{
|
||||
@@ -178,7 +183,8 @@ void logsDialog::selectionChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void logsDialog::on_mapsButton_clicked() {
|
||||
void logsDialog::on_mapsButton_clicked()
|
||||
{
|
||||
int n = csvlog.count(); // number of points in graph
|
||||
if (n==0) return;
|
||||
int latcol=0, longcol=0, altcol=0, speedcol=0;
|
||||
@@ -186,13 +192,13 @@ void logsDialog::on_mapsButton_clicked() {
|
||||
bool rangeSelected=false;
|
||||
ui->FieldsTW->setDisabled(true);
|
||||
ui->logTable->setDisabled(true);
|
||||
|
||||
|
||||
QString gePath=g.gePath();
|
||||
if (gePath.isEmpty() || !QFile(gePath).exists()) {
|
||||
ui->FieldsTW->setDisabled(false);
|
||||
ui->logTable->setDisabled(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
QSet<int> nondataCols;
|
||||
for (int i=1; i<csvlog.at(0).count(); i++) {
|
||||
//Long,Lat,Course,GPS Speed,GPS Alt
|
||||
@@ -225,7 +231,7 @@ void logsDialog::on_mapsButton_clicked() {
|
||||
if (itemSelected==0) {
|
||||
itemSelected=n-1;
|
||||
}
|
||||
|
||||
|
||||
QString geIconFilename = generateProcessUniqueTempFileName("track0.png");
|
||||
if (QFile::exists(geIconFilename)) {
|
||||
QFile::remove(geIconFilename);
|
||||
@@ -247,7 +253,7 @@ void logsDialog::on_mapsButton_clicked() {
|
||||
return;
|
||||
}
|
||||
QString latitude,longitude;
|
||||
double flatitude, flongitude,temp;
|
||||
double flatitude, flongitude,temp;
|
||||
QTextStream outputStream(&geFile);
|
||||
outputStream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\">\n";
|
||||
outputStream << "\t<Document>\n\t\t<name>" << logFilename << "</name>\n";
|
||||
@@ -269,7 +275,7 @@ void logsDialog::on_mapsButton_clicked() {
|
||||
}
|
||||
}
|
||||
outputStream << "\t\t</Schema>\n";
|
||||
|
||||
|
||||
QString planeName;
|
||||
if (logFilename.indexOf("-")>0) {
|
||||
planeName=logFilename.left(logFilename.indexOf("-"));
|
||||
@@ -286,7 +292,7 @@ void logsDialog::on_mapsButton_clicked() {
|
||||
outputStream << "\t\t\t\t\t<when>"<< tstamp <<"</when>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i=1; i<n; i++) {
|
||||
if ((ui->logTable->item(i-1,1)->isSelected() &&rangeSelected) || !rangeSelected) {
|
||||
latitude=csvlog.at(i).at(latcol).trimmed();
|
||||
@@ -348,7 +354,7 @@ void logsDialog::mousePress()
|
||||
{
|
||||
// if an axis is selected, only allow the direction of that axis to be dragged
|
||||
// if no axis is selected, both directions may be dragged
|
||||
|
||||
|
||||
if (ui->customPlot->xAxis->selected().testFlag(QCPAxis::spAxis))
|
||||
ui->customPlot->setRangeDrag(ui->customPlot->xAxis->orientation());
|
||||
else if (ui->customPlot->yAxis->selected().testFlag(QCPAxis::spAxis))
|
||||
@@ -370,173 +376,8 @@ void logsDialog::mouseWheel()
|
||||
}
|
||||
if (orientation) {
|
||||
ui->customPlot->setRangeZoom((Qt::Orientation)orientation);
|
||||
}
|
||||
}
|
||||
|
||||
void logsDialog::plotValue(int index, int plot, int numplots)
|
||||
{
|
||||
if (plotLock)
|
||||
return;
|
||||
int n = csvlog.count(); // number of points in graph
|
||||
bool rangeSelected=false;
|
||||
uint minx;
|
||||
uint maxx;
|
||||
uint itemSelected=0;
|
||||
uint itemCount=0;
|
||||
double miny=9999;
|
||||
double maxy=-9999;
|
||||
minx=-1;
|
||||
maxx=0;
|
||||
double tmpval,yscale;
|
||||
for (int i=1; i<n; i++) {
|
||||
if (ui->logTable->item(i-1,1)->isSelected()) {
|
||||
rangeSelected=true;
|
||||
itemSelected++;
|
||||
}
|
||||
}
|
||||
if (itemSelected==0) {
|
||||
itemSelected=n-1;
|
||||
}
|
||||
QVector<double> x(itemSelected), y(itemSelected);
|
||||
if (numplots<3) {
|
||||
for (int i=1; i<n; i++) {
|
||||
if ((ui->logTable->item(i-1,1)->isSelected() &&rangeSelected) || !rangeSelected) {
|
||||
double tmp;
|
||||
QString tstamp=csvlog.at(i).at(0)+QString(" ")+csvlog.at(i).at(1);
|
||||
if (csvlog.at(i).at(1).contains(".")) {
|
||||
tmp=QDateTime::fromString(tstamp, "yyyy-MM-dd HH:mm:ss.zzz").toTime_t();
|
||||
tmp+=csvlog.at(i).at(1).mid(csvlog.at(i).at(1).indexOf(".")).toDouble();
|
||||
} else {
|
||||
tmp=QDateTime::fromString(tstamp, "yyyy-MM-dd HH:mm:ss").toTime_t();
|
||||
}
|
||||
if (minx>tmp) {
|
||||
minx=tmp;
|
||||
}
|
||||
if (maxx<tmp) {
|
||||
maxx=tmp;
|
||||
}
|
||||
tmpval = csvlog.at(i).at(index).toDouble();
|
||||
if (tmpval>maxy) {
|
||||
maxy=tmpval;
|
||||
}
|
||||
if (tmpval<miny) {
|
||||
miny=tmpval;
|
||||
}
|
||||
}
|
||||
}
|
||||
yscale=1;
|
||||
} else {
|
||||
yscale=GetScale(csvlog.at(0).at(index));
|
||||
for (int i=1; i<n; i++)
|
||||
{
|
||||
if ((ui->logTable->item(i-1,1)->isSelected() &&rangeSelected) || !rangeSelected) {
|
||||
double tmp;
|
||||
QString tstamp=csvlog.at(i).at(0)+QString(" ")+csvlog.at(i).at(1);
|
||||
if (csvlog.at(i).at(1).contains(".")) {
|
||||
tmp=QDateTime::fromString(tstamp, "yyyy-MM-dd HH:mm:ss.zzz").toTime_t();
|
||||
tmp+=csvlog.at(i).at(1).mid(csvlog.at(i).at(1).indexOf(".")).toDouble();
|
||||
} else {
|
||||
tmp=QDateTime::fromString(tstamp, "yyyy-MM-dd HH:mm:ss").toTime_t();
|
||||
}
|
||||
if (minx>tmp) {
|
||||
minx=tmp;
|
||||
}
|
||||
if (maxx<tmp) {
|
||||
maxx=tmp;
|
||||
}
|
||||
if (yscale<0) {
|
||||
tmpval = csvlog.at(i).at(index).toDouble();
|
||||
if (tmpval>maxy) {
|
||||
maxy=tmpval;
|
||||
}
|
||||
if (tmpval<miny) {
|
||||
miny=tmpval;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (yscale<0) {
|
||||
if (miny<0) {
|
||||
miny=-miny;
|
||||
}
|
||||
if (maxy<0) {
|
||||
maxy=-maxy;
|
||||
}
|
||||
if (miny>maxy) {
|
||||
yscale=miny/1000.0;
|
||||
} else {
|
||||
yscale=maxy/1000.0;
|
||||
}
|
||||
if (yscale==0) {
|
||||
yscale=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i=1; i<n; i++) {
|
||||
if ((ui->logTable->item(i-1,1)->isSelected() &&rangeSelected) || !rangeSelected) {
|
||||
double tmp;
|
||||
QString tstamp=csvlog.at(i).at(0)+QString(" ")+csvlog.at(i).at(1);
|
||||
if (csvlog.at(i).at(1).contains(".")) {
|
||||
tmp=QDateTime::fromString(tstamp, "yyyy-MM-dd HH:mm:ss.zzz").toTime_t();
|
||||
tmp+=csvlog.at(i).at(1).mid(csvlog.at(i).at(1).indexOf(".")).toDouble();
|
||||
} else {
|
||||
tmp=QDateTime::fromString(tstamp, "yyyy-MM-dd HH:mm:ss").toTime_t();
|
||||
}
|
||||
x[itemCount] = tmp-minx;
|
||||
y[itemCount] = csvlog.at(i).at(index).toDouble()/yscale;
|
||||
itemCount++;
|
||||
}
|
||||
}
|
||||
QPen graphPen;
|
||||
QColor color=palette.at(index % 60);
|
||||
graphPen.setColor(color);
|
||||
graphPen.setWidthF(1.5);
|
||||
if (numplots<3) {
|
||||
if (plot==1) {
|
||||
ui->customPlot->xAxis->setRange(0, maxx-minx);
|
||||
ui->customPlot->yAxis->setRange(miny,maxy);
|
||||
ui->customPlot->yAxis->setLabelColor(color);
|
||||
ui->customPlot->yAxis->setLabel(csvlog.at(0).at(index));
|
||||
ui->customPlot->yAxis->setTickLabels(true);
|
||||
ui->customPlot->yAxis->setVisible(true);
|
||||
ui->customPlot->yAxis2->setVisible(false);
|
||||
ui->customPlot->addGraph(ui->customPlot->xAxis, ui->customPlot->yAxis);
|
||||
ui->customPlot->graph(0)->setName(csvlog.at(0).at(index));
|
||||
ui->customPlot->graph(0)->setData(x, y);
|
||||
ui->customPlot->graph(0)->setLineStyle(QCPGraph::lsLine);
|
||||
ui->customPlot->graph(0)->setScatterStyle(QCP::ssNone);
|
||||
//ui->customPlot->graph()->setLineStyle((QCPGraph::LineStyle)(rand()%5+1));
|
||||
ui->customPlot->graph(0)->setPen(graphPen);
|
||||
}
|
||||
else {
|
||||
ui->customPlot->xAxis2->setRange(0, maxx-minx);
|
||||
ui->customPlot->yAxis2->setTickLabels(true);
|
||||
ui->customPlot->yAxis2->setRange(miny,maxy);
|
||||
ui->customPlot->yAxis2->setVisible(true);
|
||||
ui->customPlot->yAxis2->setLabelColor(color);
|
||||
ui->customPlot->yAxis2->setLabel(csvlog.at(0).at(index));
|
||||
ui->customPlot->addGraph(ui->customPlot->xAxis2, ui->customPlot->yAxis2);
|
||||
ui->customPlot->graph(1)->setName(csvlog.at(0).at(index));
|
||||
ui->customPlot->graph(1)->setData(x, y);
|
||||
ui->customPlot->graph(1)->setLineStyle(QCPGraph::lsLine);
|
||||
ui->customPlot->graph(1)->setScatterStyle(QCP::ssNone);
|
||||
//ui->customPlot->graph()->setLineStyle((QCPGraph::LineStyle)(rand()%5+1));
|
||||
ui->customPlot->graph(1)->setPen(graphPen);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ui->customPlot->yAxis->setTickLabels(false);
|
||||
ui->customPlot->yAxis2->setTickLabels(false);
|
||||
ui->customPlot->yAxis->setRange(-1100, 1100);
|
||||
ui->customPlot->yAxis->setVisible(false);
|
||||
ui->customPlot->yAxis2->setVisible(false);
|
||||
ui->customPlot->addGraph();
|
||||
ui->customPlot->graph()->setName(csvlog.at(0).at(index));
|
||||
ui->customPlot->graph()->setData(x, y);
|
||||
ui->customPlot->graph()->setLineStyle(QCPGraph::lsLine);
|
||||
ui->customPlot->graph()->setScatterStyle(QCP::ssNone);
|
||||
//ui->customPlot->graph()->setLineStyle((QCPGraph::LineStyle)(rand()%5+1));
|
||||
ui->customPlot->graph()->setPen(graphPen);
|
||||
ui->customPlot->setRangeZoom(Qt::Horizontal|Qt::Vertical);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -552,6 +393,9 @@ void logsDialog::removeSelectedGraph()
|
||||
void logsDialog::removeAllGraphs()
|
||||
{
|
||||
ui->customPlot->clearGraphs();
|
||||
ui->customPlot->legend->setVisible(false);
|
||||
ui->customPlot->yAxis2->setVisible(false);
|
||||
ui->customPlot->yAxis->setTickLabels(false);
|
||||
ui->customPlot->replot();
|
||||
}
|
||||
|
||||
@@ -602,7 +446,7 @@ void logsDialog::on_fileOpen_BT_clicked()
|
||||
}
|
||||
ui->logTable->setItem(i-1,j,item );
|
||||
}
|
||||
}
|
||||
}
|
||||
ui->logTable->resizeColumnsToContents();
|
||||
ui->logTable->resizeRowsToContents();
|
||||
// Hack - add some pixel of space to columns as Qt resize them too small
|
||||
@@ -614,7 +458,7 @@ void logsDialog::on_fileOpen_BT_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
bool logsDialog::cvsFileParse()
|
||||
bool logsDialog::cvsFileParse()
|
||||
{
|
||||
QFile file(ui->FileName_LE->text());
|
||||
int errors=0;
|
||||
@@ -676,7 +520,7 @@ bool logsDialog::cvsFileParse()
|
||||
}
|
||||
logFilename=QFileInfo(file.fileName()).baseName();
|
||||
}
|
||||
|
||||
|
||||
file.close();
|
||||
if (errors>1) {
|
||||
QMessageBox::warning(this, "Companion", tr("The selected logfile contains %1 invalid lines out of %2 total lines").arg(errors).arg(lines));
|
||||
@@ -687,8 +531,8 @@ bool logsDialog::cvsFileParse()
|
||||
csvlog.clear();
|
||||
return false;
|
||||
}
|
||||
int lastvalue=0;
|
||||
int tmp;
|
||||
double lastvalue=0;
|
||||
double tmp;
|
||||
ui->sessions_CB->addItem("---");
|
||||
for (int i=1; i<n; i++) {
|
||||
QString tstamp=csvlog.at(i).at(0)+QString(" ")+csvlog.at(i).at(1);
|
||||
@@ -715,19 +559,19 @@ void logsDialog::on_sessions_CB_currentIndexChanged(int index)
|
||||
if (plotLock)
|
||||
return;
|
||||
plotLock=true;
|
||||
int start=0;
|
||||
int stop=-1;
|
||||
double start=0;
|
||||
double stop=-1;
|
||||
if (index!=0) {
|
||||
start=ui->sessions_CB->itemData(index,Qt::UserRole).toInt();
|
||||
start=ui->sessions_CB->itemData(index,Qt::UserRole).toDouble();
|
||||
if (index<(ui->sessions_CB->count()-1)) {
|
||||
stop=ui->sessions_CB->itemData(index+1,Qt::UserRole).toInt();
|
||||
stop=ui->sessions_CB->itemData(index+1,Qt::UserRole).toDouble();
|
||||
}
|
||||
}
|
||||
// if (ui->logTable->item(i-1,1)->isSelected()) {
|
||||
ui->logTable->clearSelection();
|
||||
if (start>0) {
|
||||
int n=csvlog.count();
|
||||
int tmp;
|
||||
double tmp;
|
||||
ui->logTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
for (int i=1; i<n; i++) {
|
||||
QString tstamp=csvlog.at(i).at(0)+QString(" ")+csvlog.at(i).at(1);
|
||||
@@ -750,7 +594,7 @@ void logsDialog::on_sessions_CB_currentIndexChanged(int index)
|
||||
ui->logTable->selectionModel()->select(ui->logTable->model()->index(i-1,0), QItemSelectionModel::Select|QItemSelectionModel::Rows);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
plotLock=false;
|
||||
plotLogs();
|
||||
@@ -758,24 +602,205 @@ void logsDialog::on_sessions_CB_currentIndexChanged(int index)
|
||||
|
||||
void logsDialog::plotLogs()
|
||||
{
|
||||
if (plotLock)
|
||||
if (plotLock) return;
|
||||
|
||||
if (!ui->FieldsTW->selectedItems().length()) {
|
||||
removeAllGraphs();
|
||||
return;
|
||||
int n = csvlog.at(0).count(); // number of points in graph
|
||||
}
|
||||
|
||||
plotsCollection plots;
|
||||
|
||||
QList<QTableWidgetSelectionRange> selections = ui->logTable->selectedRanges();
|
||||
int rowCount = selections.length();
|
||||
bool hasLogSelection;
|
||||
QVarLengthArray<int> selectedRows;
|
||||
|
||||
if (rowCount) {
|
||||
hasLogSelection = true;
|
||||
foreach (QTableWidgetSelectionRange range, selections) {
|
||||
for (int i = range.topRow(); i <= range.bottomRow(); i++) {
|
||||
selectedRows.append(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hasLogSelection = false;
|
||||
rowCount = ui->logTable->rowCount();
|
||||
}
|
||||
|
||||
plots.min_x = QDateTime::currentDateTime().toTime_t();
|
||||
plots.max_x = 0;
|
||||
|
||||
foreach (QTableWidgetItem *plot, ui->FieldsTW->selectedItems()) {
|
||||
coords plotCoords;
|
||||
int plotColumn = plot->row() + 2; // Date and Time first
|
||||
|
||||
plotCoords.min_y = 999999;
|
||||
plotCoords.max_y = -999999;
|
||||
plotCoords.secondRange = false;
|
||||
plotCoords.name = plot->text();
|
||||
|
||||
for (int row = 0; row < rowCount; row++) {
|
||||
QTableWidgetItem *logValue;
|
||||
|
||||
if (hasLogSelection) {
|
||||
logValue = ui->logTable->item(selectedRows.at(row), plotColumn);
|
||||
} else {
|
||||
logValue = ui->logTable->item(row, plotColumn);
|
||||
}
|
||||
|
||||
double y;
|
||||
double time;
|
||||
QString time_str;
|
||||
|
||||
y = logValue->text().toDouble();
|
||||
plotCoords.y.push_back(y);
|
||||
|
||||
if (plotCoords.min_y > y) {
|
||||
plotCoords.min_y = y;
|
||||
} else if (plotCoords.max_y < y) {
|
||||
plotCoords.max_y = y;
|
||||
}
|
||||
|
||||
time_str = ui->logTable->item(row, 0)->text() + QString(" ")
|
||||
+ ui->logTable->item(row, 1)->text();
|
||||
if (time_str.contains('.')) {
|
||||
time = QDateTime::fromString(time_str, "yyyy-MM-dd HH:mm:ss.zzz")
|
||||
.toTime_t();
|
||||
time += time_str.mid(time_str.indexOf('.')).toDouble();
|
||||
} else {
|
||||
time = QDateTime::fromString(time_str, "yyyy-MM-dd HH:mm:ss")
|
||||
.toTime_t();
|
||||
}
|
||||
plotCoords.x.push_back(time);
|
||||
|
||||
if (plots.min_x > time) {
|
||||
plots.min_x = time;
|
||||
} else if (plots.max_x < time) {
|
||||
plots.max_x = time;
|
||||
}
|
||||
}
|
||||
plots.coords.append(plotCoords);
|
||||
}
|
||||
|
||||
plots.rangeOneMin = plots.coords.at(0).min_y;
|
||||
plots.rangeOneMax = plots.coords.at(0).max_y;
|
||||
plots.twoRanges = false;
|
||||
plots.tooManyRanges = false;
|
||||
|
||||
for (int i = 1; i < plots.coords.size(); i++) {
|
||||
if (plots.tooManyRanges) {
|
||||
if (plots.coords.at(i).min_y < plots.rangeOneMin) {
|
||||
plots.rangeOneMin = plots.coords.at(i).min_y;
|
||||
}
|
||||
if (plots.coords.at(i).max_y > plots.rangeOneMax) {
|
||||
plots.rangeOneMax = plots.coords.at(i).max_y;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
double actualRange = plots.rangeOneMax - plots.rangeOneMin;
|
||||
double thisRange = plots.coords.at(i).max_y - plots.coords.at(i).min_y;
|
||||
|
||||
if (thisRange > actualRange * 1.3 || thisRange * 1.3 < actualRange ||
|
||||
plots.coords.at(i).min_y > plots.rangeOneMax ||
|
||||
plots.coords.at(i).max_y < plots.rangeOneMin) {
|
||||
plots.coords[i].secondRange = true;
|
||||
if (plots.twoRanges) {
|
||||
actualRange = plots.rangeTwoMax - plots.rangeTwoMin;
|
||||
if (thisRange > actualRange * 1.3 || thisRange * 1.3 < actualRange ||
|
||||
plots.coords.at(i).min_y > plots.rangeTwoMax ||
|
||||
plots.coords.at(i).max_y < plots.rangeTwoMin) {
|
||||
plots.tooManyRanges = true;
|
||||
plots.twoRanges = false;
|
||||
if (plots.rangeTwoMin < plots.rangeOneMin) {
|
||||
plots.rangeOneMin = plots.rangeTwoMin;
|
||||
}
|
||||
if (plots.rangeTwoMax > plots.rangeOneMax) {
|
||||
plots.rangeOneMax = plots.rangeTwoMax;
|
||||
}
|
||||
if (plots.coords.at(i).min_y < plots.rangeOneMin) {
|
||||
plots.rangeOneMin = plots.coords.at(i).min_y;
|
||||
}
|
||||
if (plots.coords.at(i).max_y > plots.rangeOneMax) {
|
||||
plots.rangeOneMax = plots.coords.at(i).max_y;
|
||||
}
|
||||
} else {
|
||||
if (plots.coords.at(i).min_y < plots.rangeTwoMin) {
|
||||
plots.rangeTwoMin = plots.coords.at(i).min_y;
|
||||
}
|
||||
if (plots.coords.at(i).max_y > plots.rangeTwoMax) {
|
||||
plots.rangeTwoMax = plots.coords.at(i).max_y;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
plots.twoRanges = true;
|
||||
plots.rangeTwoMax = plots.coords.at(i).max_y;
|
||||
plots.rangeTwoMin = plots.coords.at(i).min_y;
|
||||
}
|
||||
} else {
|
||||
if (plots.coords.at(i).min_y < plots.rangeOneMin) {
|
||||
plots.rangeOneMin = plots.coords.at(i).min_y;
|
||||
}
|
||||
if (plots.coords.at(i).max_y > plots.rangeOneMax) {
|
||||
plots.rangeOneMax = plots.coords.at(i).max_y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (plots.twoRanges) {
|
||||
rangeRatio = (plots.rangeTwoMax - plots.rangeTwoMin) /
|
||||
(plots.rangeOneMax - plots.rangeOneMin);
|
||||
rangeyAxisMin = plots.rangeOneMin;
|
||||
rangeyAxisMax = plots.rangeOneMax;
|
||||
rangeyAxis2Min = plots.rangeTwoMin;
|
||||
rangeyAxis2Max = plots.rangeTwoMax;
|
||||
|
||||
hasyAxis2 = true;
|
||||
} else {
|
||||
hasyAxis2 = false;
|
||||
}
|
||||
|
||||
removeAllGraphs();
|
||||
int numplots=0;
|
||||
int plots=0;
|
||||
for (int i=0; i<n-2; i++) {
|
||||
if (ui->FieldsTW->item(0,i)->isSelected()) {
|
||||
numplots++;
|
||||
}
|
||||
|
||||
ui->customPlot->xAxis->setRange(plots.min_x, plots.max_x);
|
||||
|
||||
ui->customPlot->yAxis->setRange(plots.rangeOneMin, plots.rangeOneMax);
|
||||
ui->customPlot->yAxis->setTickLabels(true);
|
||||
|
||||
if (plots.twoRanges) {
|
||||
ui->customPlot->yAxis2->setRange(plots.rangeTwoMin, plots.rangeTwoMax);
|
||||
ui->customPlot->yAxis2->setVisible(true);
|
||||
}
|
||||
for (int i=0; i<n-2; i++) {
|
||||
if (ui->FieldsTW->item(0,i)->isSelected()) {
|
||||
plots++;
|
||||
plotValue(i+2,plots, numplots);
|
||||
|
||||
for (int i = 0; i < plots.coords.size(); i++) {
|
||||
if (plots.coords.at(i).secondRange && plots.twoRanges) {
|
||||
ui->customPlot->addGraph(ui->customPlot->xAxis, ui->customPlot->yAxis2);
|
||||
} else {
|
||||
ui->customPlot->addGraph();
|
||||
}
|
||||
ui->customPlot->graph(i)->setData(plots.coords.at(i).x,
|
||||
plots.coords.at(i).y);
|
||||
pen.setColor(colors.at(i % colors.size()));
|
||||
ui->customPlot->graph(i)->setPen(pen);
|
||||
ui->customPlot->graph(i)->setName(plots.coords.at(i).name);
|
||||
}
|
||||
ui->customPlot->legend->setVisible((numplots>2));
|
||||
ui->customPlot->replot();
|
||||
|
||||
ui->customPlot->legend->setVisible(true);
|
||||
ui->customPlot->replot();
|
||||
}
|
||||
|
||||
void logsDialog::setRangeyAxis2(QCPRange range)
|
||||
{
|
||||
if (hasyAxis2) {
|
||||
double lowerChange = (range.lower - rangeyAxisMin) * rangeRatio;
|
||||
double upperChange = (range.upper - rangeyAxisMax) * rangeRatio;
|
||||
rangeyAxisMin = range.lower;
|
||||
rangeyAxisMax = range.upper;
|
||||
rangeyAxis2Min += lowerChange;
|
||||
rangeyAxis2Max += upperChange;
|
||||
|
||||
ui->customPlot->yAxis2->setRange(rangeyAxis2Min, rangeyAxis2Max);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,26 @@
|
||||
#include <QtGui>
|
||||
#include "qcustomplot.h"
|
||||
|
||||
struct coords {
|
||||
QVector<double> x, y;
|
||||
double min_y;
|
||||
double max_y;
|
||||
bool secondRange;
|
||||
QString name;
|
||||
};
|
||||
|
||||
struct plotsCollection {
|
||||
QVarLengthArray<struct coords> coords;
|
||||
double min_x;
|
||||
double max_x;
|
||||
bool twoRanges;
|
||||
bool tooManyRanges;
|
||||
double rangeOneMin;
|
||||
double rangeOneMax;
|
||||
double rangeTwoMin;
|
||||
double rangeTwoMax;
|
||||
};
|
||||
|
||||
namespace Ui {
|
||||
class logsDialog;
|
||||
}
|
||||
@@ -12,12 +32,11 @@ namespace Ui {
|
||||
class logsDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
|
||||
public:
|
||||
explicit logsDialog(QWidget *parent = 0);
|
||||
~logsDialog();
|
||||
|
||||
|
||||
private slots:
|
||||
void titleDoubleClick();
|
||||
void axisLabelDoubleClick(QCPAxis* axis, QCPAxis::SelectablePart part);
|
||||
@@ -29,21 +48,29 @@ private slots:
|
||||
void removeAllGraphs();
|
||||
void moveLegend();
|
||||
void plotLogs();
|
||||
void plotValue(int index, int plot, int numplots);
|
||||
void plottableItemDoubleClick(QCPAbstractPlottable * plottable, QMouseEvent * event);
|
||||
// void plottableItemDoubleClick(QCPAbstractPlottable * plottable, QMouseEvent * event);
|
||||
// void graphClicked(QCPAbstractPlottable *plottable);
|
||||
void on_fileOpen_BT_clicked();
|
||||
void on_sessions_CB_currentIndexChanged(int index);
|
||||
void on_mapsButton_clicked();
|
||||
|
||||
void setRangeyAxis2(QCPRange range);
|
||||
|
||||
private:
|
||||
QList<QStringList> csvlog;
|
||||
Ui::logsDialog *ui;
|
||||
bool cvsFileParse();
|
||||
double GetScale(QString channel);
|
||||
QList<QColor> palette;
|
||||
bool plotLock;
|
||||
QString logFilename;
|
||||
|
||||
QVarLengthArray<Qt::GlobalColor> colors;
|
||||
QPen pen;
|
||||
|
||||
bool hasyAxis2;
|
||||
double rangeRatio;
|
||||
double rangeyAxisMin;
|
||||
double rangeyAxisMax;
|
||||
double rangeyAxis2Min;
|
||||
double rangeyAxis2Max;
|
||||
};
|
||||
|
||||
#endif // LOGSDIALOG_H
|
||||
|
||||
Reference in New Issue
Block a user