Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Q
qgroundcontrol
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Valentin Platzgummer
qgroundcontrol
Commits
1b89b4c1
Commit
1b89b4c1
authored
Dec 30, 2016
by
Don Gagne
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove dead code
parent
671a465f
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
0 additions
and
1125 deletions
+0
-1125
qgroundcontrol.pro
qgroundcontrol.pro
+0
-3
MainWindow.cc
src/ui/MainWindow.cc
+0
-1
MainWindow.h
src/ui/MainWindow.h
+0
-1
QGCDataPlot2D.cc
src/ui/QGCDataPlot2D.cc
+0
-734
QGCDataPlot2D.h
src/ui/QGCDataPlot2D.h
+0
-77
QGCDataPlot2D.ui
src/ui/QGCDataPlot2D.ui
+0
-309
No files found.
qgroundcontrol.pro
View file @
1b89b4c1
...
...
@@ -314,7 +314,6 @@ FORMS += \
FORMS += \
src/ui/Linechart.ui \
src/ui/MultiVehicleDockWidget.ui \
src/ui/QGCDataPlot2D.ui \
src/ui/QGCHilConfiguration.ui \
src/ui/QGCHilFlightGearConfiguration.ui \
src/ui/QGCHilJSBSimConfiguration.ui \
...
...
@@ -545,7 +544,6 @@ HEADERS += \
src/ui/MAVLinkDecoder.h \
src/ui/MainWindow.h \
src/ui/MultiVehicleDockWidget.h \
src/ui/QGCDataPlot2D.h \
src/ui/QGCHilConfiguration.h \
src/ui/QGCHilFlightGearConfiguration.h \
src/ui/QGCHilJSBSimConfiguration.h \
...
...
@@ -694,7 +692,6 @@ SOURCES += \
src/ui/MAVLinkDecoder.cc \
src/ui/MainWindow.cc \
src/ui/MultiVehicleDockWidget.cc \
src/ui/QGCDataPlot2D.cc \
src/ui/QGCHilConfiguration.cc \
src/ui/QGCHilFlightGearConfiguration.cc \
src/ui/QGCHilJSBSimConfiguration.cc \
...
...
src/ui/MainWindow.cc
View file @
1b89b4c1
...
...
@@ -43,7 +43,6 @@
#include "QGCImageProvider.h"
#ifndef __mobile__
#include "QGCDataPlot2D.h"
#include "Linecharts.h"
#include "QGCUASFileViewMulti.h"
#include "UASQuickView.h"
...
...
src/ui/MainWindow.h
View file @
1b89b4c1
...
...
@@ -47,7 +47,6 @@
class
QGCStatusBar
;
class
Linecharts
;
class
QGCDataPlot2D
;
/**
* @brief Main Application Window
...
...
src/ui/QGCDataPlot2D.cc
deleted
100644 → 0
View file @
671a465f
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
/**
* @file
* @brief Implementation of QGCDataPlot2D
* @author Lorenz Meier <mavteam@student.ethz.ch>
*
*/
#include <QTemporaryFile>
#ifndef __mobile__
#include <QPrintDialog>
#include <QPrinter>
#endif
#include <QProgressDialog>
#include <QHBoxLayout>
#include <QSvgGenerator>
#include <QStandardPaths>
#include <QDebug>
#include <cmath>
#include "QGCDataPlot2D.h"
#include "ui_QGCDataPlot2D.h"
#include "MG.h"
#include "QGCFileDialog.h"
#include "QGCMessageBox.h"
QGCDataPlot2D
::
QGCDataPlot2D
(
QWidget
*
parent
)
:
QWidget
(
parent
),
plot
(
new
IncrementalPlot
(
parent
)),
logFile
(
NULL
),
ui
(
new
Ui
::
QGCDataPlot2D
)
{
ui
->
setupUi
(
this
);
// Add plot to ui
QHBoxLayout
*
layout
=
new
QHBoxLayout
(
ui
->
plotFrame
);
layout
->
addWidget
(
plot
);
ui
->
plotFrame
->
setLayout
(
layout
);
ui
->
gridCheckBox
->
setChecked
(
plot
->
gridEnabled
());
// Connect user actions
connect
(
ui
->
selectFileButton
,
&
QPushButton
::
clicked
,
this
,
&
QGCDataPlot2D
::
selectFile
);
connect
(
ui
->
saveCsvButton
,
&
QPushButton
::
clicked
,
this
,
&
QGCDataPlot2D
::
saveCsvLog
);
connect
(
ui
->
reloadButton
,
&
QPushButton
::
clicked
,
this
,
&
QGCDataPlot2D
::
reloadFile
);
connect
(
ui
->
savePlotButton
,
&
QPushButton
::
clicked
,
this
,
&
QGCDataPlot2D
::
savePlot
);
connect
(
ui
->
printButton
,
&
QPushButton
::
clicked
,
this
,
&
QGCDataPlot2D
::
print
);
connect
(
ui
->
legendCheckBox
,
&
QCheckBox
::
clicked
,
plot
,
&
IncrementalPlot
::
showLegend
);
connect
(
ui
->
symmetricCheckBox
,
&
QCheckBox
::
clicked
,
plot
,
&
IncrementalPlot
::
setSymmetric
);
connect
(
ui
->
gridCheckBox
,
&
QCheckBox
::
clicked
,
plot
,
&
IncrementalPlot
::
showGrid
);
connect
(
ui
->
style
,
static_cast
<
void
(
QComboBox
::*
)(
const
QString
&
)
>
(
&
QComboBox
::
currentIndexChanged
),
plot
,
&
IncrementalPlot
::
setStyleText
);
//TODO: calculateRegression returns bool, slots are expected to return void, this makes
// converting to new style way too hard.
connect
(
ui
->
regressionButton
,
SIGNAL
(
clicked
()),
this
,
SLOT
(
calculateRegression
()));
// Allow style changes to propagate through this widget
connect
(
qgcApp
(),
&
QGCApplication
::
styleChanged
,
plot
,
&
IncrementalPlot
::
styleChanged
);
}
void
QGCDataPlot2D
::
reloadFile
()
{
if
(
QFileInfo
(
fileName
).
isReadable
())
{
if
(
ui
->
inputFileType
->
currentText
().
contains
(
"pxIMU"
)
||
ui
->
inputFileType
->
currentText
().
contains
(
"RAW"
))
{
loadRawLog
(
fileName
,
ui
->
xAxis
->
currentText
(),
ui
->
yAxis
->
text
());
}
else
if
(
ui
->
inputFileType
->
currentText
().
contains
(
"CSV"
))
{
loadCsvLog
(
fileName
,
ui
->
xAxis
->
currentText
(),
ui
->
yAxis
->
text
());
}
}
}
void
QGCDataPlot2D
::
loadFile
()
{
qDebug
()
<<
"DATA PLOT: Loading file:"
<<
fileName
;
if
(
QFileInfo
(
fileName
).
isReadable
())
{
if
(
ui
->
inputFileType
->
currentText
().
contains
(
"pxIMU"
)
||
ui
->
inputFileType
->
currentText
().
contains
(
"RAW"
))
{
loadRawLog
(
fileName
);
}
else
if
(
ui
->
inputFileType
->
currentText
().
contains
(
"CSV"
))
{
loadCsvLog
(
fileName
);
}
}
}
void
QGCDataPlot2D
::
loadFile
(
QString
file
)
{
// TODO This "filename" is a private/protected member variable. It should be named in such way
// it indicates so. This same name is used in several places within this file in local scopes.
fileName
=
file
;
QFileInfo
fi
(
fileName
);
if
(
fi
.
isReadable
())
{
if
(
fi
.
suffix
()
==
QString
(
"raw"
)
||
fi
.
suffix
()
==
QString
(
"imu"
))
{
loadRawLog
(
fileName
);
}
else
if
(
fi
.
suffix
()
==
QString
(
"txt"
)
||
fi
.
suffix
()
==
QString
(
"csv"
))
{
loadCsvLog
(
fileName
);
}
// TODO Else, tell the user it doesn't know what to do with the file...
}
}
/**
* This function brings up a file name dialog and asks the user to enter a file to save to
*/
QString
QGCDataPlot2D
::
getSavePlotFilename
()
{
QString
fileName
=
QGCFileDialog
::
getSaveFileName
(
this
,
"Save Plot File"
,
QStandardPaths
::
writableLocation
(
QStandardPaths
::
DesktopLocation
),
"PDF Documents (*.pdf);;SVG Images (*.svg)"
,
"pdf"
);
return
fileName
;
}
/**
* This function aks the user for a filename and exports to either PDF or SVG, depending on the filename
*/
void
QGCDataPlot2D
::
savePlot
()
{
QString
fileName
=
getSavePlotFilename
();
if
(
fileName
.
isEmpty
())
return
;
while
(
!
(
fileName
.
endsWith
(
".svg"
)
||
fileName
.
endsWith
(
".pdf"
)))
{
QMessageBox
::
StandardButton
button
=
QGCMessageBox
::
warning
(
tr
(
"Unsuitable file extension for Plot document type."
),
tr
(
"Please choose .pdf or .svg as file extension. Click OK to change the file extension, cancel to not save the file."
),
QMessageBox
::
Ok
|
QMessageBox
::
Cancel
,
QMessageBox
::
Ok
);
// Abort if cancelled
if
(
button
==
QMessageBox
::
Cancel
)
{
return
;
}
fileName
=
getSavePlotFilename
();
if
(
fileName
.
isEmpty
())
return
;
//Abort if cancelled
}
if
(
fileName
.
endsWith
(
".pdf"
))
{
exportPDF
(
fileName
);
}
else
if
(
fileName
.
endsWith
(
".svg"
))
{
exportSVG
(
fileName
);
}
}
void
QGCDataPlot2D
::
print
()
{
#ifndef __mobile__
QPrinter
printer
(
QPrinter
::
HighResolution
);
// printer.setOutputFormat(QPrinter::PdfFormat);
// //QPrinter printer(QPrinter::HighResolution);
// printer.setOutputFileName(fileName);
QString
docName
=
plot
->
title
().
text
();
if
(
!
docName
.
isEmpty
()
)
{
docName
.
replace
(
QRegExp
(
QString
::
fromLatin1
(
"
\n
"
)),
tr
(
" -- "
));
printer
.
setDocName
(
docName
);
}
printer
.
setCreator
(
"QGroundControl"
);
printer
.
setOrientation
(
QPrinter
::
Landscape
);
QPrintDialog
dialog
(
&
printer
);
if
(
dialog
.
exec
()
)
{
plot
->
setStyleSheet
(
"QWidget { background-color: #FFFFFF; color: #000000; background-clip: border; font-size: 10pt;}"
);
plot
->
setCanvasBackground
(
Qt
::
white
);
// FIXME: QwtPlotPrintFilter no longer exists in Qwt 6.1
//QwtPlotPrintFilter filter;
//filter.color(Qt::white, QwtPlotPrintFilter::CanvasBackground);
//filter.color(Qt::black, QwtPlotPrintFilter::AxisScale);
//filter.color(Qt::black, QwtPlotPrintFilter::AxisTitle);
//filter.color(Qt::black, QwtPlotPrintFilter::MajorGrid);
//filter.color(Qt::black, QwtPlotPrintFilter::MinorGrid);
//if ( printer.colorMode() == QPrinter::GrayScale ) {
// int options = QwtPlotPrintFilter::PrintAll;
// options &= ~QwtPlotPrintFilter::PrintBackground;
// options |= QwtPlotPrintFilter::PrintFrameWithScales;
// filter.setOptions(options);
//}
//plot->print(printer);
plot
->
setStyleSheet
(
"QWidget { background-color: #050508; color: #DDDDDF; background-clip: border; font-size: 11pt;}"
);
//plot->setCanvasBackground(QColor(5, 5, 8));
}
#endif
}
void
QGCDataPlot2D
::
exportPDF
(
QString
fileName
)
{
#ifdef __mobile__
Q_UNUSED
(
fileName
)
#else
QPrinter
printer
;
printer
.
setOutputFormat
(
QPrinter
::
PdfFormat
);
printer
.
setOutputFileName
(
fileName
);
//printer.setFullPage(true);
printer
.
setPageMargins
(
10.0
,
10.0
,
10.0
,
10.0
,
QPrinter
::
Millimeter
);
printer
.
setPageSize
(
QPrinter
::
A4
);
QString
docName
=
plot
->
title
().
text
();
if
(
!
docName
.
isEmpty
()
)
{
docName
.
replace
(
QRegExp
(
QString
::
fromLatin1
(
"
\n
"
)),
tr
(
" -- "
));
printer
.
setDocName
(
docName
);
}
printer
.
setCreator
(
"QGroundControl"
);
printer
.
setOrientation
(
QPrinter
::
Landscape
);
plot
->
setStyleSheet
(
"QWidget { background-color: #FFFFFF; color: #000000; background-clip: border; font-size: 10pt;}"
);
// plot->setCanvasBackground(Qt::white);
// FIXME: QwtPlotPrintFilter no longer exists in Qwt 6.1
// QwtPlotPrintFilter filter;
// filter.color(Qt::white, QwtPlotPrintFilter::CanvasBackground);
// filter.color(Qt::black, QwtPlotPrintFilter::AxisScale);
// filter.color(Qt::black, QwtPlotPrintFilter::AxisTitle);
// filter.color(Qt::black, QwtPlotPrintFilter::MajorGrid);
// filter.color(Qt::black, QwtPlotPrintFilter::MinorGrid);
// if ( printer.colorMode() == QPrinter::GrayScale )
// {
// int options = QwtPlotPrintFilter::PrintAll;
// options &= ~QwtPlotPrintFilter::PrintBackground;
// options |= QwtPlotPrintFilter::PrintFrameWithScales;
// filter.setOptions(options);
// }
//plot->print(printer);
plot
->
setStyleSheet
(
"QWidget { background-color: #050508; color: #DDDDDF; background-clip: border; font-size: 11pt;}"
);
//plot->setCanvasBackground(QColor(5, 5, 8));
#endif
}
void
QGCDataPlot2D
::
exportSVG
(
QString
fileName
)
{
#ifdef __mobile__
Q_UNUSED
(
fileName
)
#else
if
(
!
fileName
.
isEmpty
()
)
{
plot
->
setStyleSheet
(
"QWidget { background-color: #FFFFFF; color: #000000; background-clip: border; font-size: 10pt;}"
);
//plot->setCanvasBackground(Qt::white);
QSvgGenerator
generator
;
generator
.
setFileName
(
fileName
);
generator
.
setSize
(
QSize
(
800
,
600
));
// FIXME: QwtPlotPrintFilter no longer exists in Qwt 6.1
//QwtPlotPrintFilter filter;
//filter.color(Qt::white, QwtPlotPrintFilter::CanvasBackground);
//filter.color(Qt::black, QwtPlotPrintFilter::AxisScale);
//filter.color(Qt::black, QwtPlotPrintFilter::AxisTitle);
//filter.color(Qt::black, QwtPlotPrintFilter::MajorGrid);
//filter.color(Qt::black, QwtPlotPrintFilter::MinorGrid);
//plot->print(generator);
plot
->
setStyleSheet
(
"QWidget { background-color: #050508; color: #DDDDDF; background-clip: border; font-size: 11pt;}"
);
}
#endif
}
/**
* Selects a filename and attempts immediately to load it.
*/
void
QGCDataPlot2D
::
selectFile
()
{
// Open a file dialog prompting the user for the file to load.
// Note the special case for the Pixhawk.
if
(
ui
->
inputFileType
->
currentText
().
contains
(
"pxIMU"
)
||
ui
->
inputFileType
->
currentText
().
contains
(
"RAW"
))
{
fileName
=
QGCFileDialog
::
getOpenFileName
(
this
,
tr
(
"Load Log File"
),
QString
(),
"Log Files (*.imu *.raw)"
);
}
else
{
fileName
=
QGCFileDialog
::
getOpenFileName
(
this
,
tr
(
"Load Log File"
),
QString
(),
"Log Files (*.csv);;All Files (*)"
);
}
// Check if the user hit cancel, which results in an empty string.
// If this is the case, we just stop.
if
(
fileName
.
isEmpty
())
{
return
;
}
// Now attempt to open the file
QFileInfo
fileInfo
(
fileName
);
if
(
!
fileInfo
.
isReadable
())
{
// TODO This needs some TLC. File used by another program sounds like a Windows only issue.
QGCMessageBox
::
critical
(
tr
(
"Could not open file"
),
tr
(
"The file is owned by user %1. Is the file currently used by another program?"
).
arg
(
fileInfo
.
owner
()));
ui
->
filenameLabel
->
setText
(
tr
(
"Could not open %1"
).
arg
(
fileInfo
.
fileName
()));
}
else
{
ui
->
filenameLabel
->
setText
(
tr
(
"Opened %1"
).
arg
(
fileInfo
.
completeBaseName
()
+
"."
+
fileInfo
.
completeSuffix
()));
// Open and import the file
loadFile
();
}
}
void
QGCDataPlot2D
::
loadRawLog
(
QString
file
,
QString
xAxisName
,
QString
yAxisFilter
)
{
Q_UNUSED
(
xAxisName
);
Q_UNUSED
(
yAxisFilter
);
if
(
logFile
!=
NULL
)
{
logFile
->
close
();
delete
logFile
;
}
// Postprocess log file
logFile
=
new
QTemporaryFile
(
"qt_qgc_temp_log.XXXXXX.csv"
);
compressor
=
new
LogCompressor
(
file
,
logFile
->
fileName
());
connect
(
compressor
,
&
LogCompressor
::
finishedFile
,
this
,
static_cast
<
void
(
QGCDataPlot2D
::*
)(
QString
)
>
(
&
QGCDataPlot2D
::
loadFile
));
compressor
->
startCompression
();
}
/**
* This function loads a CSV file into the plot. It tries to assign the dimension names
* based on the first data row and tries to guess the separator char.
*
* @param file Name of the file to open
* @param xAxisName Optional paramater. If given, the x axis dimension will be selected to match this string
* @param yAxisFilter Optional parameter. If given, only data dimension names present in the filter string will be
* plotted
*
* @code
*
* QString file = "/home/user/datalog.txt"; // With header: x<tab>y<tab>z
* QString xAxis = "x";
* QString yAxis = "z";
*
* // Plotted result will be x vs z with y ignored.
* @endcode
*/
void
QGCDataPlot2D
::
loadCsvLog
(
QString
file
,
QString
xAxisName
,
QString
yAxisFilter
)
{
if
(
logFile
!=
NULL
)
{
logFile
->
close
();
delete
logFile
;
curveNames
.
clear
();
}
logFile
=
new
QFile
(
file
);
// Load CSV data
if
(
!
logFile
->
open
(
QIODevice
::
ReadOnly
|
QIODevice
::
Text
))
return
;
// Set plot title
if
(
ui
->
plotTitle
->
text
()
!=
""
)
plot
->
setTitle
(
ui
->
plotTitle
->
text
());
if
(
ui
->
plotXAxisLabel
->
text
()
!=
""
)
plot
->
setAxisTitle
(
QwtPlot
::
xBottom
,
ui
->
plotXAxisLabel
->
text
());
if
(
ui
->
plotYAxisLabel
->
text
()
!=
""
)
plot
->
setAxisTitle
(
QwtPlot
::
yLeft
,
ui
->
plotYAxisLabel
->
text
());
// Extract header
// Read in values
// Find all keys
QTextStream
in
(
logFile
);
// First line is header
QString
header
=
in
.
readLine
();
bool
charRead
=
false
;
QString
separator
=
""
;
QList
<
QChar
>
sepCandidates
;
sepCandidates
<<
'\t'
;
sepCandidates
<<
','
;
sepCandidates
<<
';'
;
sepCandidates
<<
' '
;
sepCandidates
<<
'~'
;
sepCandidates
<<
'|'
;
// Iterate until separator is found
// or full header is parsed
for
(
int
i
=
0
;
i
<
header
.
length
();
i
++
)
{
if
(
sepCandidates
.
contains
(
header
.
at
(
i
)))
{
// Separator found
if
(
charRead
)
{
separator
+=
header
[
i
];
}
}
else
{
// Char found
charRead
=
true
;
// If the separator is not empty, this char
// has been read after a separator, so detection
// is now complete
if
(
separator
!=
""
)
break
;
}
}
QString
out
=
separator
;
out
.
replace
(
"
\t
"
,
"<tab>"
);
ui
->
filenameLabel
->
setText
(
file
.
split
(
"/"
).
last
().
split
(
"
\\
"
).
last
()
+
" Separator:
\"
"
+
out
+
"
\"
"
);
//qDebug() << "READING CSV:" << header;
// Clear plot
plot
->
removeData
();
QMap
<
QString
,
QVector
<
double
>*
>
xValues
;
QMap
<
QString
,
QVector
<
double
>*
>
yValues
;
curveNames
.
append
(
header
.
split
(
separator
,
QString
::
SkipEmptyParts
));
// Eliminate any non-string curve names
for
(
int
i
=
0
;
i
<
curveNames
.
count
();
++
i
)
{
if
(
curveNames
.
at
(
i
).
length
()
==
0
||
curveNames
.
at
(
i
)
==
" "
||
curveNames
.
at
(
i
)
==
"
\n
"
||
curveNames
.
at
(
i
)
==
"
\t
"
||
curveNames
.
at
(
i
)
==
"
\r
"
)
{
// Remove bogus curve name
curveNames
.
removeAt
(
i
);
}
}
QString
curveName
;
// Clear UI elements
ui
->
xAxis
->
clear
();
ui
->
yAxis
->
clear
();
ui
->
xRegressionComboBox
->
clear
();
ui
->
yRegressionComboBox
->
clear
();
ui
->
regressionOutput
->
clear
();
int
curveNameIndex
=
0
;
QString
xAxisFilter
;
if
(
xAxisName
==
""
)
{
xAxisFilter
=
curveNames
.
first
();
}
else
{
xAxisFilter
=
xAxisName
;
}
// Fill y-axis renaming lookup table
// Allow the user to rename data dimensions in the plot
QMap
<
QString
,
QString
>
renaming
;
QStringList
yCurves
=
yAxisFilter
.
split
(
"|"
,
QString
::
SkipEmptyParts
);
// Figure out the correct renaming
for
(
int
i
=
0
;
i
<
yCurves
.
count
();
++
i
)
{
if
(
yCurves
.
at
(
i
).
contains
(
":"
))
{
QStringList
parts
=
yCurves
.
at
(
i
).
split
(
":"
,
QString
::
SkipEmptyParts
);
if
(
parts
.
count
()
>
1
)
{
// Insert renaming map
renaming
.
insert
(
parts
.
first
(),
parts
.
last
());
// Replace curve value with first part only
yCurves
.
replace
(
i
,
parts
.
first
());
}
}
// else
// {
// // Insert same value, not renaming anything
// renaming.insert(yCurves.at(i), yCurves.at(i));
// }
}
foreach
(
curveName
,
curveNames
)
{
// Add to plot x axis selection
ui
->
xAxis
->
addItem
(
curveName
);
// Add to regression selection
ui
->
xRegressionComboBox
->
addItem
(
curveName
);
ui
->
yRegressionComboBox
->
addItem
(
curveName
);
if
(
curveName
!=
xAxisFilter
)
{
if
((
yAxisFilter
==
""
)
||
yCurves
.
contains
(
curveName
))
{
yValues
.
insert
(
curveName
,
new
QVector
<
double
>
());
xValues
.
insert
(
curveName
,
new
QVector
<
double
>
());
// Add separator starting with second item
if
(
curveNameIndex
>
0
&&
curveNameIndex
<
curveNames
.
count
())
{
ui
->
yAxis
->
setText
(
ui
->
yAxis
->
text
()
+
"|"
);
}
// If this curve was renamed, re-add the renaming to the text field
QString
renamingText
=
""
;
if
(
renaming
.
contains
(
curveName
))
renamingText
=
QString
(
":%1"
).
arg
(
renaming
.
value
(
curveName
));
ui
->
yAxis
->
setText
(
ui
->
yAxis
->
text
()
+
curveName
+
renamingText
);
// Insert same value, not renaming anything
if
(
!
renaming
.
contains
(
curveName
))
renaming
.
insert
(
curveName
,
curveName
);
curveNameIndex
++
;
}
}
}
// Select current axis in UI
ui
->
xAxis
->
setCurrentIndex
(
curveNames
.
indexOf
(
xAxisFilter
));
// Read data
double
x
=
0
;
double
y
=
0
;
while
(
!
in
.
atEnd
())
{
QString
line
=
in
.
readLine
();
// Keep empty parts here - we still have to act on them
QStringList
values
=
line
.
split
(
separator
,
QString
::
KeepEmptyParts
);
bool
headerfound
=
false
;
// First get header - ORDER MATTERS HERE!
foreach
(
curveName
,
curveNames
)
{
if
(
curveName
==
xAxisFilter
)
{
// X AXIS HANDLING
// Take this value as x if it is selected
QString
text
=
values
.
at
(
curveNames
.
indexOf
(
curveName
));
text
=
text
.
trimmed
();
if
(
text
.
length
()
>
0
&&
text
!=
" "
&&
text
!=
"
\n
"
&&
text
!=
"
\r
"
&&
text
!=
"
\t
"
)
{
bool
okx
=
true
;
x
=
text
.
toDouble
(
&
okx
);
if
(
okx
&&
!
qIsNaN
(
x
)
&&
!
qIsInf
(
x
))
{
headerfound
=
true
;
}
}
}
}
if
(
headerfound
)
{
// Search again from start for values - ORDER MATTERS HERE!
foreach
(
curveName
,
curveNames
)
{
// Y AXIS HANDLING
// Only plot non-x curver and those selected in the yAxisFilter (or all if the filter is not set)
if
(
curveName
!=
xAxisFilter
&&
(
yAxisFilter
==
""
||
yCurves
.
contains
(
curveName
)))
{
bool
oky
;
int
curveNameIndex
=
curveNames
.
indexOf
(
curveName
);
if
(
values
.
count
()
>
curveNameIndex
)
{
QString
text
(
values
.
at
(
curveNameIndex
));
text
=
text
.
trimmed
();
y
=
text
.
toDouble
(
&
oky
);
// Only INF is really an issue for the plot
// NaN is fine
if
(
oky
&&
!
qIsNaN
(
y
)
&&
!
qIsInf
(
y
)
&&
text
.
length
()
>
0
&&
text
!=
" "
&&
text
!=
"
\n
"
&&
text
!=
"
\r
"
&&
text
!=
"
\t
"
)
{
// Only append definitely valid values
xValues
.
value
(
curveName
)
->
append
(
x
);
yValues
.
value
(
curveName
)
->
append
(
y
);
}
}
}
}
}
}
// Add data array of each curve to the plot at once (fast)
// Iterates through all x-y curve combinations
for
(
int
i
=
0
;
i
<
yValues
.
count
();
i
++
)
{
if
(
renaming
.
contains
(
yValues
.
keys
().
at
(
i
)))
{
plot
->
appendData
(
renaming
.
value
(
yValues
.
keys
().
at
(
i
)),
xValues
.
values
().
at
(
i
)
->
data
(),
yValues
.
values
().
at
(
i
)
->
data
(),
xValues
.
values
().
at
(
i
)
->
count
());
}
else
{
plot
->
appendData
(
yValues
.
keys
().
at
(
i
),
xValues
.
values
().
at
(
i
)
->
data
(),
yValues
.
values
().
at
(
i
)
->
data
(),
xValues
.
values
().
at
(
i
)
->
count
());
}
}
plot
->
updateScale
();
plot
->
setStyleText
(
ui
->
style
->
currentText
());
}
bool
QGCDataPlot2D
::
calculateRegression
()
{
// TODO: Add support for quadratic / cubic curve fitting
return
calculateRegression
(
ui
->
xRegressionComboBox
->
currentText
(),
ui
->
yRegressionComboBox
->
currentText
(),
"linear"
);
}
/**
* @param xName Name of the x dimension
* @param yName Name of the y dimension
* @param method Regression method, either "linear", "quadratic" or "cubic". Only linear is supported at this point
*/
bool
QGCDataPlot2D
::
calculateRegression
(
QString
xName
,
QString
yName
,
QString
method
)
{
bool
result
=
false
;
QString
function
;
if
(
xName
!=
yName
)
{
if
(
QFileInfo
(
fileName
).
isReadable
())
{
loadCsvLog
(
fileName
,
xName
,
yName
);
ui
->
xRegressionComboBox
->
setCurrentIndex
(
curveNames
.
indexOf
(
xName
));
ui
->
yRegressionComboBox
->
setCurrentIndex
(
curveNames
.
indexOf
(
yName
));
}
// Create a couple of arrays for us to use to temporarily store some of the data from the plot.
// These arrays are allocated on the heap as they are far too big to go in the stack and will
// cause an overflow.
// TODO: Look into if this would be better done by having a getter return const double pointers instead
// of using memcpy().
const
int
size
=
100000
;
double
*
x
=
new
double
[
size
];
double
*
y
=
new
double
[
size
];
int
copied
=
plot
->
data
(
yName
,
x
,
y
,
size
);
if
(
method
==
"linear"
)
{
double
a
;
// Y-axis crossing
double
b
;
// Slope
double
r
;
// Regression coefficient
if
(
linearRegression
(
x
,
y
,
copied
,
&
a
,
&
b
,
&
r
))
{
function
=
tr
(
"%1 = %2 * %3 + %4 | R-coefficient: %5"
).
arg
(
yName
,
QString
::
number
(
b
),
xName
,
QString
::
number
(
a
),
QString
::
number
(
r
));
// Plot curve
// y-axis crossing (x = 0)
// Set plotting to lines only
plot
->
appendData
(
tr
(
"regression %1-%2"
).
arg
(
xName
,
yName
),
0.0
,
a
);
plot
->
setStyleText
(
"lines"
);
// x-value of the current rightmost x position in the plot
plot
->
appendData
(
tr
(
"regression %1-%2"
).
arg
(
xName
,
yName
),
plot
->
invTransform
(
QwtPlot
::
xBottom
,
plot
->
width
()
-
plot
->
width
()
*
0.08
f
),
(
a
+
b
*
plot
->
invTransform
(
QwtPlot
::
xBottom
,
plot
->
width
()
-
plot
->
width
()
*
0.08
f
)));
result
=
true
;
}
else
{
function
=
tr
(
"Linear regression failed. (Limit: %1 data points. Try with less)"
).
arg
(
size
);
}
}
else
{
function
=
tr
(
"Regression method %1 not found"
).
arg
(
method
);
}
delete
[]
x
;
delete
[]
y
;
}
else
{
// xName == yName
function
=
tr
(
"Please select different X and Y dimensions, not %1 = %2"
).
arg
(
xName
,
yName
);
}
ui
->
regressionOutput
->
setText
(
function
);
return
result
;
}
/**
* Linear regression (least squares) for n data points.
* Computes:
*
* y = a * x + b
*
* @param x values on x axis
* @param y corresponding values on y axis
* @param n Number of values
* @param a returned slope of line
* @param b y-axis intersection
* @param r regression coefficient. The larger the coefficient is, the better is
* the match of the regression.
* @return 1 on success, 0 on failure (e.g. because of infinite slope)
*/
bool
QGCDataPlot2D
::
linearRegression
(
double
*
x
,
double
*
y
,
int
n
,
double
*
a
,
double
*
b
,
double
*
r
)
{
int
i
;
double
sumx
=
0
,
sumy
=
0
,
sumx2
=
0
,
sumy2
=
0
,
sumxy
=
0
;
double
sxx
,
syy
,
sxy
;
*
a
=
0
;
*
b
=
0
;
*
r
=
0
;
if
(
n
<
2
)
return
true
;
/* Conpute some things we need */
for
(
i
=
0
;
i
<
n
;
i
++
)
{
sumx
+=
x
[
i
];
sumy
+=
y
[
i
];
sumx2
+=
(
x
[
i
]
*
x
[
i
]);
sumy2
+=
(
y
[
i
]
*
y
[
i
]);
sumxy
+=
(
x
[
i
]
*
y
[
i
]);
}
sxx
=
sumx2
-
sumx
*
sumx
/
n
;
syy
=
sumy2
-
sumy
*
sumy
/
n
;
sxy
=
sumxy
-
sumx
*
sumy
/
n
;
/* Infinite slope (b), non existent intercept (a) */
if
(
fabs
(
sxx
)
==
0
)
return
false
;
/* Calculate the slope (b) and intercept (a) */
*
b
=
sxy
/
sxx
;
*
a
=
sumy
/
n
-
(
*
b
)
*
sumx
/
n
;
/* Compute the regression coefficient */
if
(
fabs
(
syy
)
==
0
)
*
r
=
1
;
else
*
r
=
sxy
/
sqrt
(
sxx
*
syy
);
return
false
;
}
void
QGCDataPlot2D
::
saveCsvLog
()
{
QString
fileName
=
QGCFileDialog
::
getSaveFileName
(
this
,
"Save CSV Log File"
,
QStandardPaths
::
writableLocation
(
QStandardPaths
::
DesktopLocation
),
"CSV Files (*.csv)"
,
"csv"
,
true
);
if
(
fileName
.
isEmpty
())
{
return
;
//User cancelled
}
bool
success
=
logFile
->
copy
(
fileName
);
qDebug
()
<<
"Saved CSV log ("
<<
fileName
<<
"). Success: "
<<
success
;
//qDebug() << "READE TO SAVE CSV LOG TO " << fileName;
}
QGCDataPlot2D
::~
QGCDataPlot2D
()
{
delete
ui
;
}
void
QGCDataPlot2D
::
changeEvent
(
QEvent
*
e
)
{
QWidget
::
changeEvent
(
e
);
switch
(
e
->
type
())
{
case
QEvent
:
:
LanguageChange
:
ui
->
retranslateUi
(
this
);
break
;
default:
break
;
}
}
src/ui/QGCDataPlot2D.h
deleted
100644 → 0
View file @
671a465f
#ifndef QGCDATAPLOT2D_H
#define QGCDATAPLOT2D_H
#include <QWidget>
#include <QFile>
#include "IncrementalPlot.h"
#include "LogCompressor.h"
namespace
Ui
{
class
QGCDataPlot2D
;
}
class
QGCDataPlot2D
:
public
QWidget
{
Q_OBJECT
public:
QGCDataPlot2D
(
QWidget
*
parent
=
0
);
~
QGCDataPlot2D
();
/** @brief Calculate and display regression function*/
bool
calculateRegression
(
QString
xName
,
QString
yName
,
QString
method
=
"linear"
);
/** @brief Linear regression over data points */
bool
linearRegression
(
double
*
x
,
double
*
y
,
int
n
,
double
*
a
,
double
*
b
,
double
*
r
);
public
slots
:
/** @brief Load previously selected file */
void
loadFile
();
/** @brief Load file with this name */
void
loadFile
(
QString
file
);
/** @brief Reload a file, with filtering enabled */
void
reloadFile
();
void
selectFile
();
void
loadCsvLog
(
QString
file
,
QString
xAxisName
=
""
,
QString
yAxisFilter
=
""
);
void
loadRawLog
(
QString
file
,
QString
xAxisName
=
""
,
QString
yAxisFilter
=
""
);
void
saveCsvLog
();
/** @brief Save plot to PDF or SVG */
void
savePlot
();
/** @brief Export PDF file */
void
exportPDF
(
QString
fileName
);
/** @brief Export SVG file */
void
exportSVG
(
QString
file
);
/** @brief Print or save PDF file (MacOS/Linux) */
void
print
();
/** @brief Calculate and display regression function*/
bool
calculateRegression
();
signals:
void
visibilityChanged
(
bool
visible
);
protected:
void
showEvent
(
QShowEvent
*
event
)
{
QWidget
::
showEvent
(
event
);
emit
visibilityChanged
(
true
);
}
void
hideEvent
(
QHideEvent
*
event
)
{
QWidget
::
hideEvent
(
event
);
emit
visibilityChanged
(
false
);
}
void
changeEvent
(
QEvent
*
e
);
QString
getSavePlotFilename
();
IncrementalPlot
*
plot
;
LogCompressor
*
compressor
;
QFile
*
logFile
;
QString
fileName
;
QStringList
curveNames
;
private:
Ui
::
QGCDataPlot2D
*
ui
;
};
#endif // QGCDATAPLOT2D_H
src/ui/QGCDataPlot2D.ui
deleted
100644 → 0
View file @
671a465f
<?xml version="1.0" encoding="UTF-8"?>
<ui
version=
"4.0"
>
<class>
QGCDataPlot2D
</class>
<widget
class=
"QWidget"
name=
"QGCDataPlot2D"
>
<property
name=
"geometry"
>
<rect>
<x>
0
</x>
<y>
0
</y>
<width>
1463
</width>
<height>
311
</height>
</rect>
</property>
<property
name=
"windowTitle"
>
<string>
Form
</string>
</property>
<layout
class=
"QGridLayout"
name=
"gridLayout"
columnstretch=
"1,1,1,1,100,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"
>
<item
row=
"0"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label_2"
>
<property
name=
"text"
>
<string>
X
</string>
</property>
</widget>
</item>
<item
row=
"0"
column=
"1"
colspan=
"2"
>
<widget
class=
"QComboBox"
name=
"xAxis"
/>
</item>
<item
row=
"0"
column=
"3"
>
<widget
class=
"QLabel"
name=
"label_3"
>
<property
name=
"text"
>
<string>
Y
</string>
</property>
</widget>
</item>
<item
row=
"0"
column=
"4"
>
<widget
class=
"QLineEdit"
name=
"yAxis"
/>
</item>
<item
row=
"0"
column=
"5"
colspan=
"2"
>
<widget
class=
"QComboBox"
name=
"style"
>
<property
name=
"toolTip"
>
<string>
Set line style
</string>
</property>
<item>
<property
name=
"text"
>
<string>
Only lines
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Only crosses
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Only circles
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Only rectangles
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Lines and crosses
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Lines and circles
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Lines and rects
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Dotted lines and crosses
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Dotted lines and circles
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Dotted lines and rects
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Dashed lines and crosses
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Dashed lines and circles
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
Dashed lines and rects
</string>
</property>
</item>
</widget>
</item>
<item
row=
"0"
column=
"7"
colspan=
"2"
>
<widget
class=
"QPushButton"
name=
"reloadButton"
>
<property
name=
"text"
>
<string>
Replot
</string>
</property>
</widget>
</item>
<item
row=
"0"
column=
"11"
>
<widget
class=
"Line"
name=
"line"
>
<property
name=
"orientation"
>
<enum>
Qt::Vertical
</enum>
</property>
</widget>
</item>
<item
row=
"0"
column=
"12"
colspan=
"2"
>
<widget
class=
"QPushButton"
name=
"savePlotButton"
>
<property
name=
"text"
>
<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>
</widget>
</item>
<item
row=
"2"
column=
"0"
colspan=
"20"
>
<widget
class=
"QFrame"
name=
"plotFrame"
>
<property
name=
"frameShape"
>
<enum>
QFrame::StyledPanel
</enum>
</property>
<property
name=
"frameShadow"
>
<enum>
QFrame::Raised
</enum>
</property>
</widget>
</item>
<item
row=
"3"
column=
"0"
>
<widget
class=
"QLabel"
name=
"label"
>
<property
name=
"text"
>
<string>
File
</string>
</property>
</widget>
</item>
<item
row=
"3"
column=
"1"
colspan=
"2"
>
<widget
class=
"QComboBox"
name=
"inputFileType"
>
<item>
<property
name=
"text"
>
<string>
CSV
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
pxIMU
</string>
</property>
</item>
<item>
<property
name=
"text"
>
<string>
RAW
</string>
</property>
</item>
</widget>
</item>
<item
row=
"3"
column=
"3"
colspan=
"4"
>
<widget
class=
"QLabel"
name=
"filenameLabel"
>
<property
name=
"text"
>
<string>
Please select input file..
</string>
</property>
</widget>
</item>
<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"
>
<property
name=
"orientation"
>
<enum>
Qt::Horizontal
</enum>
</property>
<property
name=
"sizeHint"
stdset=
"0"
>
<size>
<width>
40
</width>
<height>
20
</height>
</size>
</property>
</spacer>
</item>
<item
row=
"3"
column=
"12"
>
<widget
class=
"Line"
name=
"line_2"
>
<property
name=
"orientation"
>
<enum>
Qt::Vertical
</enum>
</property>
</widget>
</item>
<item
row=
"3"
column=
"13"
>
<widget
class=
"QLabel"
name=
"label_7"
>
<property
name=
"text"
>
<string>
Regression
</string>
</property>
</widget>
</item>
<item
row=
"3"
column=
"14"
colspan=
"2"
>
<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"
>
<string>
Calculate
</string>
</property>
</widget>
</item>
<item
row=
"3"
column=
"18"
>
<widget
class=
"QLineEdit"
name=
"regressionOutput"
>
<property
name=
"readOnly"
>
<bool>
true
</bool>
</property>
</widget>
</item>
<item
row=
"0"
column=
"14"
>
<widget
class=
"QPushButton"
name=
"saveCsvButton"
>
<property
name=
"text"
>
<string>
Save Data
</string>
</property>
</widget>
</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>
5
</width>
<height>
20
</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment