From 3c788f57c23a23a08eecd59ba9c209b48b890e49 Mon Sep 17 00:00:00 2001 From: uvos Date: Sat, 17 Jul 2021 22:24:44 +0200 Subject: [PATCH] Version Bump Remember Save paths add missing files --- src/main.cpp | 2 +- src/regessioncalculator.cpp | 34 +++++ src/regessioncalculator.h | 19 +++ src/ui/aboutdiag.cpp | 23 +++ src/ui/aboutdiag.h | 22 +++ src/ui/aboutdiag.ui | 85 +++++++++++ src/ui/cvimageviewer.cpp | 5 +- src/ui/cvimageviewer.h | 2 +- src/ui/mainwindow.cpp | 5 +- src/ui/mainwindow.h | 3 +- src/ui/plot.cpp | 279 ++++++++++++++++++++++++++++++++++++ src/ui/plot.h | 64 +++++++++ src/ui/regressiondiag.cpp | 24 ++++ src/ui/regressiondiag.h | 24 ++++ src/ui/regressiondiag.ui | 160 +++++++++++++++++++++ src/ui/statisticsdialog.cpp | 82 +++++++++++ src/ui/statisticsdialog.h | 29 ++++ src/ui/statisticsdialog.ui | 269 ++++++++++++++++++++++++++++++++++ src/utilites.cpp | 33 +++++ src/utilites.h | 11 ++ 20 files changed, 1168 insertions(+), 7 deletions(-) create mode 100755 src/regessioncalculator.cpp create mode 100755 src/regessioncalculator.h create mode 100755 src/ui/aboutdiag.cpp create mode 100755 src/ui/aboutdiag.h create mode 100755 src/ui/aboutdiag.ui create mode 100755 src/ui/plot.cpp create mode 100755 src/ui/plot.h create mode 100755 src/ui/regressiondiag.cpp create mode 100755 src/ui/regressiondiag.h create mode 100755 src/ui/regressiondiag.ui create mode 100755 src/ui/statisticsdialog.cpp create mode 100755 src/ui/statisticsdialog.h create mode 100755 src/ui/statisticsdialog.ui create mode 100755 src/utilites.cpp create mode 100755 src/utilites.h diff --git a/src/main.cpp b/src/main.cpp index e0b4b78..c0f9404 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -68,7 +68,7 @@ int main(int argc, char *argv[]) QCoreApplication::setOrganizationName("UVOS"); QCoreApplication::setOrganizationDomain("uvos.xyz"); QCoreApplication::setApplicationName("MAClient"); - QCoreApplication::setApplicationVersion("0.1"); + QCoreApplication::setApplicationVersion("0.5"); //parse comand line QCommandLineParser parser; diff --git a/src/regessioncalculator.cpp b/src/regessioncalculator.cpp new file mode 100755 index 0000000..0a95154 --- /dev/null +++ b/src/regessioncalculator.cpp @@ -0,0 +1,34 @@ +#include "regessioncalculator.h" +#include +#include +#include + +RegessionCalculator::RegessionCalculator(const std::vector& xValues, const std::vector& yValues) +{ + if(xValues.size() == yValues.size()) + { + this->xValues = xValues; + this->yValues = yValues; + + double sumY = 0; + double sumX = 0; + double sumXTimesY = 0; + double sumSquaredX = 0; + double sumSquaredY = 0; + for (unsigned i = 0; i < xValues.size(); i++) + { + sumY += yValues[i]; + sumX += xValues[i]; + sumSquaredX += xValues[i]*xValues[i]; + sumSquaredY += yValues[i]*yValues[i]; + sumXTimesY += xValues[i]*yValues[i]; + } + + slope = (sumXTimesY - (sumX*sumY)/xValues.size()) / (sumSquaredX - (sumX*sumX)/xValues.size()); + offset = sumY/xValues.size() - slope*(sumX/xValues.size()); + + double error = (xValues.size()*sumSquaredY-sumY*sumY-slope*slope*(xValues.size()*sumSquaredX-sumX*sumX)) / (xValues.size()*(xValues.size()-2)); + stdError = sqrt( (error*error*xValues.size() ) / ( xValues.size()*sumSquaredX-sumX*sumX)); + } + else throw std::invalid_argument("xValues and yValues need to be the same size"); +} diff --git a/src/regessioncalculator.h b/src/regessioncalculator.h new file mode 100755 index 0000000..4a54dbe --- /dev/null +++ b/src/regessioncalculator.h @@ -0,0 +1,19 @@ +#ifndef REGESSIONCALCULATOR_H +#define REGESSIONCALCULATOR_H + +#include + +class RegessionCalculator +{ +public: + std::vector xValues; + std::vector yValues; + + double slope; + double offset; + double stdError; + + RegessionCalculator(const std::vector& xValues, const std::vector& yValues); +}; + +#endif // REGESSIONCALCULATOR_H diff --git a/src/ui/aboutdiag.cpp b/src/ui/aboutdiag.cpp new file mode 100755 index 0000000..208d7f2 --- /dev/null +++ b/src/ui/aboutdiag.cpp @@ -0,0 +1,23 @@ +#include "aboutdiag.h" +#include "ui_aboutdiag.h" +#include + +AboutDiag::AboutDiag(QWidget *parent) : + QDialog(parent), + ui(new Ui::AboutDiag) +{ + ui->setupUi(this); + setFixedSize(size()); + + QPalette pal = palette(); + pal.setColor(QPalette::Window, QColor(52,52,60)); + pal.setColor(QPalette::WindowText, QColor(255,255,255)); + pal.setColor(QPalette::Text, QColor(255,255,255)); + setAutoFillBackground(true); + setPalette(pal); +} + +AboutDiag::~AboutDiag() +{ + delete ui; +} diff --git a/src/ui/aboutdiag.h b/src/ui/aboutdiag.h new file mode 100755 index 0000000..e85e43a --- /dev/null +++ b/src/ui/aboutdiag.h @@ -0,0 +1,22 @@ +#ifndef ABOUTTELSYS_H +#define ABOUTTELSYS_H + +#include + +namespace Ui { +class AboutDiag; +} + +class AboutDiag : public QDialog +{ + Q_OBJECT + +public: + explicit AboutDiag(QWidget *parent = 0); + ~AboutDiag(); + +private: + Ui::AboutDiag *ui; +}; + +#endif // ABOUTTELSYS_H diff --git a/src/ui/aboutdiag.ui b/src/ui/aboutdiag.ui new file mode 100755 index 0000000..5875c45 --- /dev/null +++ b/src/ui/aboutdiag.ui @@ -0,0 +1,85 @@ + + + AboutDiag + + + + 0 + 0 + 812 + 315 + + + + + 0 + 0 + + + + + 80000 + 15200 + + + + About + + + + + + + 30 + 50 + + + + + 800 + 200 + + + + + + + :/images/splash.png + + + true + + + Qt::AlignCenter + + + false + + + + + + + <html><head/><body><p><span style=" font-weight:600;">UVOS MAClient Version: 0.5</span></p><p>© 2021 Carl Philipp Klemm</p></body></html> + + + Qt::RichText + + + false + + + Qt::AlignCenter + + + false + + + + + + + + + + diff --git a/src/ui/cvimageviewer.cpp b/src/ui/cvimageviewer.cpp index de5e83a..882c525 100644 --- a/src/ui/cvimageviewer.cpp +++ b/src/ui/cvimageviewer.cpp @@ -48,14 +48,15 @@ void CvImageViewer::saveImage() QString fileName; if(origImage_.type() == CV_8UC3 || origImage_.type() == CV_8SC3 || origImage_.type() == CV_8UC1 || origImage_.type() == CV_8SC1) { - fileName = QFileDialog::getSaveFileName(this, "Save Image", "./", "*.mat *.png" ); + fileName = QFileDialog::getSaveFileName(this, "Save Image", lastSavePath_, "*.mat *.png" ); } else { - fileName = QFileDialog::getSaveFileName(this, "Save Image", "./", "*.mat" ); + fileName = QFileDialog::getSaveFileName(this, "Save Image", lastSavePath_, "*.mat" ); } if(!fileName.isEmpty()) { + lastSavePath_= fileName.mid(0, fileName.lastIndexOf('/')); QStringList tokens = fileName.split('.'); if(tokens.back() != "mat" && tokens.back() != "png") fileName.append(".mat"); diff --git a/src/ui/cvimageviewer.h b/src/ui/cvimageviewer.h index 6799a01..2166e91 100644 --- a/src/ui/cvimageviewer.h +++ b/src/ui/cvimageviewer.h @@ -34,7 +34,7 @@ private: QLine yLine_; bool selectionStarted_ = false; double clamp_ = std::numeric_limits::max(); - static QString lastSavePath_; + inline static QString lastSavePath_ = "./"; void transfromToSourceCoordinates(int inX, int inY, int& outX, int& outY); void convertImage(cv::Mat image); diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 454878f..28f6a35 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -55,9 +55,10 @@ void MainWindow::saveImage() return; } - QString fileName = QFileDialog::getSaveFileName(this, "Save Image", "./", "*.mat"); + QString fileName = QFileDialog::getSaveFileName(this, "Save Image", lastSavedPath_, "*.mat"); if(!fileName.isEmpty()) { + lastSavedPath_= fileName.mid(0, fileName.lastIndexOf('/')); QStringList tokens = fileName.split('.'); if(tokens.back() != "mat") fileName.append(".mat"); @@ -69,7 +70,7 @@ void MainWindow::saveImage() void MainWindow::openImage() { - QString fileName = QFileDialog::getOpenFileName(this, "Open Image", "./", "*.mat"); + QString fileName = QFileDialog::getOpenFileName(this, "Open Image", lastSavedPath_, "*.mat"); if(!fileName.isEmpty()) { cv::Mat image; diff --git a/src/ui/mainwindow.h b/src/ui/mainwindow.h index 21bf98d..ce3e46d 100644 --- a/src/ui/mainwindow.h +++ b/src/ui/mainwindow.h @@ -16,7 +16,8 @@ class MainWindow : public QMainWindow Q_OBJECT private: std::vector viewers_; - AboutDiag about_; + AboutDiag about_; + inline static QString lastSavedPath_ = "./"; private slots: void setImageValue(size_t x, size_t y, double value); diff --git a/src/ui/plot.cpp b/src/ui/plot.cpp new file mode 100755 index 0000000..c3f1d31 --- /dev/null +++ b/src/ui/plot.cpp @@ -0,0 +1,279 @@ +#include "plot.h" + +#include +#include + +#include "statisticsdialog.h" +#include "regressiondiag.h" + +Plot::Plot(QWidget* parent): + QCustomPlot(parent), + actionStatistics("Show statistics", nullptr), + actionAdd_Regression("Add regression", nullptr), + actionDelete_Regression("Delete regression", nullptr), + actionExport_Selection("Export selection", nullptr), + actionSetValueString("Set Y Axis Label", nullptr) +{ + xAxis->setLabel("Coordinate"); + yAxis->setLabel("Counts"); + xAxis->setRange(0, 10); + yAxis->setRange(0, 65535); + addMainGraph(); + setInteraction(QCP::iSelectPlottables, true); + setInteraction(QCP::iRangeDrag, true); + setInteraction(QCP::iRangeZoom); + axisRect()->setRangeDrag(Qt::Horizontal); + axisRect()->setRangeZoom(Qt::Horizontal); + setSelectionRectMode(QCP::srmNone); + + //setup actions + actionStatistics.setShortcut(Qt::Key_S); + actionStatistics.setShortcutVisibleInContextMenu(true); + addAction(&actionStatistics); + + actionAdd_Regression.setShortcut(Qt::Key_R); + actionAdd_Regression.setShortcutVisibleInContextMenu(true); + addAction(&actionAdd_Regression); + + actionDelete_Regression.setShortcut(Qt::Key_Delete); + actionDelete_Regression.setShortcutVisibleInContextMenu(true); + addAction(&actionDelete_Regression); + + actionExport_Selection.setShortcut(Qt::CTRL + Qt::Key_E); + actionExport_Selection.setShortcutVisibleInContextMenu(true); + addAction(&actionExport_Selection); + + //graph context menu + + connect(&actionStatistics, &QAction::triggered, this, &Plot::showStatistics); + connect(&actionAdd_Regression, &QAction::triggered, this, &Plot::addRegression); + connect(&actionDelete_Regression, &QAction::triggered, this, &Plot::deleteRegression); + connect(&actionExport_Selection, &QAction::triggered, this, &Plot::saveCsvDiag); + connect(&actionSetValueString, &QAction::triggered, this, &Plot::askForValueString); + + graphContextMenu.addAction(&actionStatistics); + graphContextMenu.addAction(&actionAdd_Regression); + graphContextMenu.addAction(&actionDelete_Regression); + graphContextMenu.addAction(&actionExport_Selection); + graphContextMenu.addAction(&actionSetValueString); +} + +Plot::~Plot() +{ + +} + +bool Plot::event(QEvent *event) +{ + if(event->type()==QEvent::Gesture) graphContextMenu.show(); + return QCustomPlot::event(event); +} + +void Plot::setLabel(QString label) +{ + yAxis->setLabel(label); +} + +void Plot::addMainGraph() +{ + addGraph(); + graph(graphCount()-1)->setSelectable(QCP::stDataRange); + QPen selectionPen = graph(graphCount()-1)->pen(); + selectionPen.setColor(QColor(255,0,0)); + graph(graphCount()-1)->selectionDecorator()->setPen(selectionPen); +} + +void Plot::clear() +{ + clearGraphs(); + addMainGraph(); + xAxis->setRange(0, 10); + replot(); +} + +void Plot::askForValueString() +{ + bool ok = false; + QString label = QInputDialog::getText(this, "Y Axis Label", "New Label:", QLineEdit::Normal, yAxis->label(), &ok); + if(ok) + { + setLabel(label); + replot(); + } +} + +void Plot::setMaxValue(double maxVal) +{ + yAxis->setRange(0, maxVal); +} + +void Plot::saveCsvDiag() +{ + if(graphCount() > 0 && !graph(0)->selection().dataRanges().at(0).isEmpty()) + { + QString fileName = QFileDialog::getSaveFileName(this, "Save selection as CSV", "./", "*.csv" ); + saveCsv(fileName); + } + else QMessageBox::warning(this, "Warning", "No selection has been made", QMessageBox::Ok); +} + +void Plot::saveCsv(QString fileName) +{ + if(!fileName.isEmpty()) + { + QCPDataRange range = graph(0)->selection().dataRanges().at(0); + QCPGraphDataContainer::const_iterator begin = graph(0)->data()->at(range.begin()); + QCPGraphDataContainer::const_iterator end = graph(0)->data()->at(range.end()); + + std::vector keys; + keys.resize(end-begin); + + std::vector values; + values.resize(end-begin); + + for (QCPGraphDataContainer::const_iterator item=begin; item != end; ++item) + { + keys[item-begin]=item->key; + values[item-begin]=item->value; + } + saveToCsv(fileName, keys, values, xAxis->label(), yAxis->label()); + } +} + + +void Plot::addRegression() +{ + if(graphCount() > 0 && !graph(0)->selection().dataRanges().at(0).isEmpty()) + { + QCPDataRange range = graph(0)->selection().dataRanges().at(0); + QCPGraphDataContainer::const_iterator begin = graph(0)->data()->at(range.begin()); + QCPGraphDataContainer::const_iterator end = graph(0)->data()->at(range.end()); + + std::vector values; + std::vector keys; + + values.resize(end-begin); + keys.resize(end-begin); + + for (QCPGraphDataContainer::const_iterator item=begin; item != end; ++item) + { + values[item-begin] = item->value; + keys[item-begin] = item->key; + } + + regressions.push_back(RegessionCalculator(keys, values)); + + QPen regressionPen =graph(0)->pen(); + regressionPen.setColor(QColor(0,255,0)); + + QPen selectionPen = graph(0)->pen(); + selectionPen.setColor(QColor(255,0,0)); + + QCPGraphDataContainer::const_iterator center = begin + (end - begin)/2; + + addGraph(); + graph(graphCount()-1)->setPen(regressionPen); + graph(graphCount()-1)->addData(100+center->key, regressions.back().slope*(100+center->key) + regressions.back().offset); + graph(graphCount()-1)->addData(-100+center->key, regressions.back().slope*(-100+center->key) + regressions.back().offset); + graph(graphCount()-1)->selectionDecorator()->setPen(selectionPen); + replot(); + + } + else QMessageBox::warning(this, "Warning", "No selection has been made", QMessageBox::Ok); +} + +void Plot::deleteRegression() +{ + if(graphCount() > 0 && selectedGraphs().size() > 1 && selectedGraphs().at(1) != graph(0)) + { + int i = 0; + while(selectedGraphs().at(1) != graph(i) ) i++; + regressions.erase(regressions.begin()+i-1); + removeGraph(selectedGraphs().at(1)); + replot(); + } +} + + +void Plot::showStatistics() +{ + if(graphCount() > 0 && !graph(0)->selection().dataRanges().at(0).isEmpty()) + { + QCPDataRange dataRange = graph(0)->selection().dataRanges().at(0); + QCPGraphDataContainer::const_iterator begin = graph(0)->data()->at(dataRange.begin()); + QCPGraphDataContainer::const_iterator end = graph(0)->data()->at(dataRange.end()); + std::vector dataVct; + dataVct.reserve(dataRange.size()); + for (QCPGraphDataContainer::const_iterator item = begin; item != end; item++) + dataVct.push_back(item->value); + StatisticsDialog statDiag(dataVct, this); + statDiag.show(); + statDiag.exec(); + } + else if(graphCount() > 0 && selectedGraphs().size() > 1 && selectedGraphs().at(1) != graph(0)) + { + unsigned i = 0; + while(selectedGraphs().at(1) != graph(i)) i++; + RegressionDiag regDiag(regressions.at(i-1), this); + regDiag.show(); + regDiag.exec(); + } + else QMessageBox::warning(this, "Warning", "No selection has been made", QMessageBox::Ok); +} + +void Plot::addData(QVector keys, QVector values, bool inOrder, bool ignoreLimit) +{ + if(graphCount() > 0) + { + graph(0)->addData(keys, values, inOrder); + if(!ignoreLimit)while(graph(0)->data()->size() > graphPointLimit) graph(0)->data()->remove(graph(0)->data()->begin()->key); + xAxis->setRange( graph(0)->data()->begin()->key, keys.back() ); + replot(); + } +} + +void Plot::addData(double key, double value, bool ignoreLimit) +{ + if(graphCount() > 0) + { + graph(0)->addData(key, value); + if(!ignoreLimit)while(graph(0)->data()->size() > graphPointLimit) graph(0)->data()->remove(graph(0)->data()->begin()->key); + xAxis->setRange( graph(0)->data()->begin()->key, key ); + } +} + +void Plot::setLimit(int graphPointLimit) +{ + this->graphPointLimit = graphPointLimit; + if(graphCount() > 0) while(graph(0)->data()->size() > graphPointLimit) graph(0)->data()->remove(graph(0)->data()->begin()->key); +} + +int Plot::getLimit() +{ + return graphPointLimit; +} + +void Plot::mousePressEvent(QMouseEvent *event) +{ + if(event->button() == Qt::MiddleButton || (event->button() == Qt::LeftButton && event->modifiers() == Qt::Modifier::SHIFT) ) + { + setCursor(Qt::ClosedHandCursor); + setSelectionRectMode(QCP::srmNone); + } + else if(event->button() == Qt::LeftButton) + { + setSelectionRectMode(QCP::srmSelect); + } + else if(event->button() == Qt::RightButton) + { + graphContextMenu.popup(event->globalPos()); + setSelectionRectMode(QCP::srmNone); + } + QCustomPlot::mousePressEvent(event); +} + +void Plot::mouseReleaseEvent(QMouseEvent *event) +{ + setCursor(Qt::ArrowCursor); + QCustomPlot::mouseReleaseEvent(event); +} diff --git a/src/ui/plot.h b/src/ui/plot.h new file mode 100755 index 0000000..e097671 --- /dev/null +++ b/src/ui/plot.h @@ -0,0 +1,64 @@ +#ifndef PLOT_H +#define PLOT_H + +#include +#include +#include + +#include "qcustomplot/qcustomplot.h" +#include "regessioncalculator.h" +#include "statisticsdialog.h" +#include "utilites.h" + +class Plot : public QCustomPlot +{ +private: + std::vector regressions; + + QMenu graphContextMenu; + + int graphPointLimit = 10000; + QAction actionStatistics; + QAction actionAdd_Regression; + QAction actionDelete_Regression; + QAction actionExport_Selection; + QAction actionSetValueString; + +public: + Plot(QWidget* parent = nullptr); + ~Plot(); + + void setLabel(QString label); + + void clear(); + void setLimit(int graphPointLimit); + int getLimit(); + + void setMaxValue(double maxVal); + +signals: + void sigSaveCsv(); + +public slots: + void addPoints(QVector keys, QVector values); + void saveCsv(QString fileName); + void saveCsvDiag(); + void showStatistics(); + void deleteRegression(); + void addRegression(); + void askForValueString(); + + void addData(QVector keys, QVector values, bool inOrder = false, bool ignoreLimit = false); + void addData(double key, double value, bool ignoreLimit = false); + +protected: + virtual void mousePressEvent(QMouseEvent *event); + virtual void mouseReleaseEvent(QMouseEvent *event); + virtual bool event(QEvent *event); + +private: + void addMainGraph(); +}; + +#endif // PLOT_H + diff --git a/src/ui/regressiondiag.cpp b/src/ui/regressiondiag.cpp new file mode 100755 index 0000000..4ae407c --- /dev/null +++ b/src/ui/regressiondiag.cpp @@ -0,0 +1,24 @@ +#include "regressiondiag.h" +#include "ui_regressiondiag.h" + +RegressionDiag::RegressionDiag(const RegessionCalculator& reg, QWidget *parent) : + QDialog(parent), + ui(new Ui::RegressionDiag) +{ + ui->setupUi(this); + + ui->lcdNumber_slope->display(reg.slope); + ui->lcdNumber_offset->display(reg.offset); + ui->lcdNumber_StdError->display(reg.stdError); + ui->lcdNumbe_count->display((int)reg.xValues.size()); + +#ifdef Q_OS_ANDROID + setWindowState(Qt::WindowMaximized); +#endif +} + +RegressionDiag::~RegressionDiag() +{ + delete ui; +} + diff --git a/src/ui/regressiondiag.h b/src/ui/regressiondiag.h new file mode 100755 index 0000000..32fd7b0 --- /dev/null +++ b/src/ui/regressiondiag.h @@ -0,0 +1,24 @@ +#ifndef REGRESSIONDIAG_H +#define REGRESSIONDIAG_H + +#include + +#include "regessioncalculator.h" + +namespace Ui { +class RegressionDiag; +} + +class RegressionDiag : public QDialog +{ + Q_OBJECT + +public: + explicit RegressionDiag(const RegessionCalculator& reg, QWidget *parent = 0); + ~RegressionDiag(); + +private: + Ui::RegressionDiag *ui; +}; + +#endif // REGRESSIONDIAG_H diff --git a/src/ui/regressiondiag.ui b/src/ui/regressiondiag.ui new file mode 100755 index 0000000..b7f5c83 --- /dev/null +++ b/src/ui/regressiondiag.ui @@ -0,0 +1,160 @@ + + + RegressionDiag + + + + 0 + 0 + 377 + 208 + + + + Regression + + + + + + + + Slope: + + + + + + + QFrame::NoFrame + + + 8 + + + 99999999.000000000000000 + + + 99999999 + + + + + + + QFrame::NoFrame + + + 8 + + + 99999999.000000000000000 + + + 99999999 + + + + + + + Slope standard error: + + + + + + + QFrame::NoFrame + + + false + + + 8 + + + 99999999.000000000000000 + + + 99999999 + + + + + + + Offset: + + + + + + + Count: + + + + + + + QFrame::NoFrame + + + 8 + + + 99999999 + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + RegressionDiag + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + RegressionDiag + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/ui/statisticsdialog.cpp b/src/ui/statisticsdialog.cpp new file mode 100755 index 0000000..9316056 --- /dev/null +++ b/src/ui/statisticsdialog.cpp @@ -0,0 +1,82 @@ +#include "statisticsdialog.h" +#include "ui_statisticsdialog.h" + +#include +#include +#include + +StatisticsDialog::StatisticsDialog(const std::vector& data, QWidget *parent): + QDialog(parent), + ui(new Ui::StatisticsDialog) +{ + ui->setupUi(this); + + connect(ui->pushButton_1, &QPushButton::clicked, this, &StatisticsDialog::copyCount); + connect(ui->pushButton_4, &QPushButton::clicked, this, &StatisticsDialog::copyMean); + connect(ui->pushButton_5, &QPushButton::clicked, this, &StatisticsDialog::copyMinMax); + connect(ui->pushButton_Sd, &QPushButton::clicked, this, &StatisticsDialog::copySd); + + ui->lcdNumber_Count->display(static_cast(data.size())); + + double mean = 0; + double max = std::numeric_limits::min(); + double min = std::numeric_limits::max(); + for(double point : data) + { + mean += point; + if(point < min) + min = point; + if(point > max) + max = point; + } + mean = mean / data.size(); + ui->lcdNumber_Mean->display(mean); + + double sd = 0; + for(double point : data) + { + sd += (point - mean)*(point - mean); + } + sd /= data.size(); + sd = sqrt(sd); + ui->lcdNumber_Sd->display(sd); + + ui->lcdNumber_Max->display(max); + ui->lcdNumber_Min->display(min); +} + +void StatisticsDialog::copyCount() +{ + QString buffer(QString::number(ui->lcdNumber_Count->value(), 'g', 10)); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection); +} + +void StatisticsDialog::copyMean() +{ + QString buffer(QString::number(ui->lcdNumber_Mean->value(), 'g', 10)); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection); +} + +void StatisticsDialog::copyMinMax() +{ + QString buffer(QString::number(ui->lcdNumber_Min->value(), 'g', 10)); + buffer.append(","); + buffer.append(QString::number(ui->lcdNumber_Max->value(), 'g', 10)); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection); +} + +void StatisticsDialog::copySd() +{ + QString buffer(QString::number(ui->lcdNumber_Sd->value(), 'g', 10)); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Clipboard); + QGuiApplication::clipboard()->setText(buffer, QClipboard::Selection); +} + +StatisticsDialog::~StatisticsDialog() +{ + delete ui; +} + diff --git a/src/ui/statisticsdialog.h b/src/ui/statisticsdialog.h new file mode 100755 index 0000000..f0927c6 --- /dev/null +++ b/src/ui/statisticsdialog.h @@ -0,0 +1,29 @@ +#ifndef STATISTICSDIALOG_H +#define STATISTICSDIALOG_H + +#include +#include + +namespace Ui { +class StatisticsDialog; +} + +class StatisticsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit StatisticsDialog(const std::vector& data, QWidget *parent = 0); + ~StatisticsDialog(); + +private slots: + void copyCount(); + void copyMean(); + void copyMinMax(); + void copySd(); + +private: + Ui::StatisticsDialog *ui; +}; + +#endif // STATISTICSDIALOG_H diff --git a/src/ui/statisticsdialog.ui b/src/ui/statisticsdialog.ui new file mode 100755 index 0000000..fb049d9 --- /dev/null +++ b/src/ui/statisticsdialog.ui @@ -0,0 +1,269 @@ + + + StatisticsDialog + + + + 0 + 0 + 491 + 201 + + + + Statistics + + + + + + + + Count: + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 10 + + + QLCDNumber::Flat + + + + + + + + 0 + 0 + + + + Copy + + + + + + + + + + + Geometric mean: + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 10 + + + QLCDNumber::Flat + + + + + + + + 0 + 0 + + + + Copy + + + + + + + + + + + Standard deviation: + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 10 + + + QLCDNumber::Flat + + + + + + + + 0 + 0 + + + + Copy + + + + + + + + + + + Maximum: + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 10 + + + QLCDNumber::Flat + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Minimum: + + + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + 10 + + + QLCDNumber::Flat + + + + + + + Copy + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + StatisticsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + StatisticsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/utilites.cpp b/src/utilites.cpp new file mode 100755 index 0000000..8656cc0 --- /dev/null +++ b/src/utilites.cpp @@ -0,0 +1,33 @@ +#include "utilites.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +bool saveToCsv(const QString& filename, const std::vector &keys, const std::vector &values, const QString& keyLable, const QString& valueLable ) +{ + if(keys.size() != values.size()) + { + throw std::invalid_argument("keys and values need to be the same size"); + return false; + } + QFile file(filename); + if(file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + QTextStream fileStream(&file); + fileStream<<"id"<<','< +#include +#include + +bool saveToCsv(const QString& filename, const std::vector &keys, const std::vector &values, const QString& keyLable, const QString& valueLable); + + +#endif // UTILITYS_H