From ce45a1340ef40c56e2c36cc0abf437ec8228264a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Mal=C3=BD?= Date: Sun, 9 Mar 2014 17:32:51 +0100 Subject: [PATCH] Heavy redesign to better separate drawing from the user input and signal handling logic. All signal drawers can now be a separate classes with shared common functionality. --- Anyanka.pro | 7 +- datamanager.cpp | 51 +++-------- enumflags.h | 90 +++++++++++++++++++ graphtoimageexporter.cpp | 48 ----------- graphtoimageexporter.h | 45 ---------- gui/exportgraphtoimagedialog.cpp | 5 ++ gui/graphview.cpp | 2 - imagedrawer.cpp | 44 ++++------ imagedrawer.h | 26 ++---- integrationtablemodel.cpp | 31 ++++++- integrationtablemodel.h | 11 ++- integrator.cpp | 144 ++++++++++++++++++++++++++++--- integrator.h | 40 +++++++-- signalcontroller.cpp | 23 +++-- signalcontroller.h | 4 +- signaldrawer.cpp | 42 +++++---- signaldrawer.h | 13 ++- 17 files changed, 392 insertions(+), 234 deletions(-) create mode 100644 enumflags.h delete mode 100644 graphtoimageexporter.cpp delete mode 100644 graphtoimageexporter.h diff --git a/Anyanka.pro b/Anyanka.pro index ebc0bae..0833939 100644 --- a/Anyanka.pro +++ b/Anyanka.pro @@ -14,7 +14,7 @@ TEMPLATE = app unix { LIBS += -ldl - QMAKE_CXXFLAGS += -std=c++11 -Wall + QMAKE_CXXFLAGS += -std=c++11 -Wall -Wextra } win32 { SOURCES += windows_defines.h @@ -51,7 +51,6 @@ SOURCES += main.cpp\ datawriterbackend.cpp \ csvdatawriterbackend.cpp \ gui/exportgraphtoimagedialog.cpp \ - graphtoimageexporter.cpp \ imagedrawer.cpp \ signaldrawer.cpp @@ -85,9 +84,9 @@ HEADERS += \ datawriterbackend.h \ csvdatawriterbackend.h \ gui/exportgraphtoimagedialog.h \ - graphtoimageexporter.h \ imagedrawer.h \ - signaldrawer.h + signaldrawer.h \ + enumflags.h FORMS += \ gui/mainwindow.ui \ diff --git a/datamanager.cpp b/datamanager.cpp index c10e0de..96cec2a 100644 --- a/datamanager.cpp +++ b/datamanager.cpp @@ -25,7 +25,6 @@ #include "logger.h" #include "gui/exportgraphtoimagedialog.h" #include "gui/exportrawdatadialog.h" -#include #include #include @@ -56,7 +55,8 @@ void DataManager::generateIntegDataWriteList(DataFileExporter::WriteList& writeL std::vector lines; std::pair> p; const std::shared_ptr ctrl = sr->controllerAt(key); - std::shared_ptr integrator; + std::shared_ptr integrator; + std::vector> allPeaks; if (ctrl == nullptr) continue; @@ -64,10 +64,12 @@ void DataManager::generateIntegDataWriteList(DataFileExporter::WriteList& writeL + QString::fromStdString(ctrl->signal()->yunitToString()) + "]" << "width [" + QString::fromStdString(ctrl->signal()->xunitToString()) + "]" << "height [" + QString::fromStdString(ctrl->signal()->yunitToString()) + "]"; integrator = ctrl->cIntegrator(); - for (std::multimap>::const_iterator cit = integrator->peaksCBegin(); - cit != integrator->peaksCEnd(); cit++) { + /*for (std::multimap>::const_iterator cit = integrator->peaksCBegin(); + cit != integrator->peaksCEnd(); cit++) {*/ + allPeaks = integrator->allPeaks(); + for (std::shared_ptr peak : allPeaks) { QVariantList line; - line << cit->second->peakTime() << cit->second->auc() << cit->second->width() << cit->second->height(); + line << peak->peakTime() << peak->auc() << peak->width() << peak->height(); lines.push_back(line); } p = std::pair>(header, lines); @@ -376,8 +378,7 @@ void DataManager::showOneSignal(std::shared_ptr ctrl) void DataManager::onExportGraphToImage() { - QImageWriter imageWriter; - ExportGraphToImageDialog dlg(imageWriter.supportedImageFormats()); + ExportGraphToImageDialog dlg(ImageDrawer::supportedImageFormats()); std::shared_ptr sr; if (m_activeSequence == nullptr) @@ -391,54 +392,30 @@ void DataManager::onExportGraphToImage() } if (dlg.exec() == QDialog::Accepted) { - double fromX = 0, toX = 0; - double fromY = 0, toY = 0; - int iw, ih; const std::string key = dlg.selectedSignal().toStdString(); std::shared_ptr ctrl = sr->controllerAt(key); - std::shared_ptr sig; + GraphLayers gl = GraphLayers::GRAPH | GraphLayers::SCALE; if (ctrl == nullptr) { Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Invalid key " + QString::fromStdString(key) + " passed to image exporter"); return; } - fromX = dlg.fromX(); - toX = dlg.toX(); - fromY = dlg.fromY(); - toY = dlg.toY(); - iw = dlg.imageWidth(); - ih = dlg.imageHeight(); - sig = ctrl->signal(); - - if (iw < 1) { - QMessageBox::warning(nullptr, "Error while exporting to image", "Invalid width value"); - return; - } - if (ih < 1) { - QMessageBox::warning(nullptr, "Error while exporting to image", "Invalid width value"); - return; - } + if (dlg.path().length() == 0) { QMessageBox::warning(nullptr, "Error while exporting to image", "Invalid path"); return; } - qDebug() << fromX << fromY << toX << toY; /*if (data == nullptr) { QMessageBox::warning(nullptr, "Error while exporting to image", "Cannot generate data to draw. Some values are probably invalid."); return; }*/ - ImageDrawer imgDrawer(iw, ih, this); - connect(ctrl.get(), SIGNAL(viewDrawGraph(double*,size_t,double,double)), &imgDrawer, SLOT(onUpdateGraph(double*,size_t,double,double))); - connect(ctrl.get(), SIGNAL(viewDrawIntegration(int,double,int,double,int,double,QString,QString)), &imgDrawer, SLOT(onDrawIntegration(int,double,int,double,int,double,QString,QString))); - //ctrl->onViewResized(iw, ih); - //ctrl->onViewZoomedByValues(fromX, fromY, toX, toY); + if (dlg.includePeaks()) + gl |= GraphLayers::INTEGRATION; - QImage result = imgDrawer.pixmap()->toImage(); - imageWriter.setFileName(dlg.path() + "." + dlg.imageFormat()); - imageWriter.setFormat(dlg.imageFormat().toLatin1()); - if (!imageWriter.write(result)) + ImageDrawer imageDrawer(ctrl); + if (!imageDrawer.render(dlg.path() + "." + dlg.imageFormat(), dlg.imageFormat().toLatin1(), dlg.imageWidth(), dlg.imageHeight(), gl)) QMessageBox::critical(nullptr, "Error while exporting to image", "Image could not have been written."); } diff --git a/enumflags.h b/enumflags.h new file mode 100644 index 0000000..d94c3eb --- /dev/null +++ b/enumflags.h @@ -0,0 +1,90 @@ +/* +Copyright (c) 2013, Yuri Yaryshev (aka Lord Odin) + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* +Usage sample: + +#indlude "enum_flags.h" + +ENUM_FLAGS(foo_t) +enum class foo_t + { + none = 0x00 + ,a = 0x01 + ,b = 0x02 + }; + +ENUM_FLAGS(foo2_t) +enum class foo2_t + { + none = 0x00 + ,d = 0x01 + ,e = 0x02 + }; + +int _tmain(int argc, _TCHAR* argv[]) + { + if(flags(foo_t::a & foo_t::b)) {}; + // if(flags(foo2_t::d & foo_t::b)) {}; // Type safety test - won't compile if uncomment + }; + +*/ + +#ifndef ENUM_FLAGS_H +#define ENUM_FLAGS_H + +/* +Use this line before header, if you don't want flags(T x) function to be implemented for your enum. +#define USE_ENUM_FLAGS_FUNCTION 0 +*/ + +#ifndef USE_ENUM_FLAGS_FUNCTION +#define USE_ENUM_FLAGS_FUNCTION 1 +#endif + + +#define ENUM_FLAGS_EX_NO_FLAGS_FUNC(T,INT_T) \ +enum class T; \ +inline T operator & (T x, T y) { return static_cast (static_cast(x) & static_cast(y)); }; \ +inline T operator | (T x, T y) { return static_cast (static_cast(x) | static_cast(y)); }; \ +inline T operator ^ (T x, T y) { return static_cast (static_cast(x) ^ static_cast(y)); }; \ +inline T operator ~ (T x) { return static_cast (~static_cast(x)); }; \ +inline T& operator &= (T& x, T y) { x = x & y; return x; }; \ +inline T& operator |= (T& x, T y) { x = x | y; return x; }; \ +inline T& operator ^= (T& x, T y) { x = x ^ y; return x; }; + +#if(USE_ENUM_FLAGS_FUNCTION) + + #define ENUM_FLAGS_EX(T,INT_T) ENUM_FLAGS_EX_NO_FLAGS_FUNC(T,INT_T) \ + inline bool flags(T x) { return static_cast(x) != 0;}; + +#else + + #define ENUM_FLAGS_EX(T,INT_T) ENUM_FLAGS_EX_NO_FLAGS_FUNC(T,INT_T) + +#endif + +#define ENUM_FLAGS(T) ENUM_FLAGS_EX(T,intptr_t) + +#endif //ENUM_FLAGS_H diff --git a/graphtoimageexporter.cpp b/graphtoimageexporter.cpp deleted file mode 100644 index 5ce57c5..0000000 --- a/graphtoimageexporter.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "graphtoimageexporter.h" - -GraphToImageExporter::GraphToImageExporter(QObject* parent) : - QObject(parent) -{ -} - -GraphToImageExporter::ReturnCode GraphToImageExporter::setParameters(const double fromX, const double fromY, const double toX, const double toY, const int width, - const int height, const QByteArray format, const QString& filename, - const std::shared_ptr ctrl) -{ - uint idx; - - if (fromX >= toX) - return ReturnCode::E_INVALID_BOUNDS; - if (filename.length() == 0) - return ReturnCode::E_INVALID_FILENAME; - if (ctrl == nullptr) - return ReturnCode::E_NULL_CONTROLLER; - if (width < 1 || height < 1) - return ReturnCode::E_INVALID_SIZE; - - /* Get from an to indices */ - const std::vector& tvpairs = ctrl->signal()->values(); - for (idx = 0; idx < tvpairs.size(); idx++) { - if (tvpairs.at(idx).first >= fromX) { - m_fromIdx = idx; - break; - } - } - if (idx == tvpairs.size()) - return ReturnCode::E_INVALID_BOUNDS; - for (;idx < tvpairs.size(); idx++) { - if (tvpairs.at(idx).first >= toX) { - m_toIdx = idx; - break; - } - } - if (idx == tvpairs.size()) - m_toIdx = idx - 1; - - - //m_data = ctrl->generateDrawData(m_fromIdx, m_toIdx); - if (m_data == nullptr) - return ReturnCode::E_NULL_DATA; - - return ReturnCode::SUCCESS; -} diff --git a/graphtoimageexporter.h b/graphtoimageexporter.h deleted file mode 100644 index d16cb0f..0000000 --- a/graphtoimageexporter.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef GRAPHTOIMAGEEXPORTER_H -#define GRAPHTOIMAGEEXPORTER_H - -#include "signalcontroller.h" -#include -#include - -class GraphToImageExporter : public QObject -{ - Q_OBJECT -public: - enum class ReturnCode { - SUCCESS, - E_INVALID_BOUNDS, - E_INVALID_FORMAT, - E_INVALID_FILENAME, - E_NULL_CONTROLLER, - E_INVALID_SIZE, - E_NULL_DATA - }; - - explicit GraphToImageExporter(QObject* parent = nullptr); - ReturnCode setParameters(const double fromX, const double fromY, const double toX, const double toY, const int width, const int height, - const QByteArray format, const QString& filename, const std::shared_ptr ctrl); - QList supportedImageFormats(); - -private: - const std::shared_ptr m_ctrl; - double* m_data; - QString m_filename; - double m_fromIdx; - double m_fromY; - double m_toIdx; - double m_toY; - int m_height; - int m_width; - QImageWriter m_writer; - -signals: - -public slots: - -}; - -#endif // GRAPHTOIMAGEEXPORTER_H diff --git a/gui/exportgraphtoimagedialog.cpp b/gui/exportgraphtoimagedialog.cpp index eea1c1d..04568ae 100644 --- a/gui/exportgraphtoimagedialog.cpp +++ b/gui/exportgraphtoimagedialog.cpp @@ -52,6 +52,11 @@ QString ExportGraphToImageDialog::imageFormat() const return ui->qcbox_outputFormat->currentText(); } +bool ExportGraphToImageDialog::includePeaks() const +{ + return ui->qck_includeInteg->isChecked(); +} + int ExportGraphToImageDialog::imageHeight() const { bool ok; diff --git a/gui/graphview.cpp b/gui/graphview.cpp index 42c337d..20c5519 100644 --- a/gui/graphview.cpp +++ b/gui/graphview.cpp @@ -447,8 +447,6 @@ void GraphView::unzoom() void GraphView::setDefaultZoom() { - double range = SignalController::RELATIVE_MAX - SignalController::RELATIVE_MIN; - m_relXMax = SignalController::RELATIVE_MAX; m_relXMin = SignalController::RELATIVE_MIN; m_relYMax = RELATIVE_Y_MAX_WITH_MARGIN(); diff --git a/imagedrawer.cpp b/imagedrawer.cpp index 0ba340c..430ee77 100644 --- a/imagedrawer.cpp +++ b/imagedrawer.cpp @@ -2,39 +2,29 @@ #include -ImageDrawer::ImageDrawer(const int width, const int height, QObject* parent) : - QObject(parent), - m_height(height), - m_width(width) +ImageDrawer::ImageDrawer(std::shared_ptr controller) : + SignalDrawer(controller), + m_controller(controller) { + m_imageWriter.setCompression(0); } -void ImageDrawer::onUpdateGraph(double* data, size_t len, double min, double max) +bool ImageDrawer::render(const QString& filename, const QByteArray format, const int width, const int height, const GraphLayers layers) { - if (data == nullptr) - return; - m_drawDataMin = min; - m_drawDataMax = max; + QImage image; - //m_pixmap = m_graphDrawer->drawGraph(data, len, m_width, m_height, min, max); -} - -void ImageDrawer::onDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakStartX, const double peakStartY, - const QString& time, const QString& area) -{ - double xStep = static_cast(m_width); - double yStep = static_cast(m_height) / (m_drawDataMax - m_drawDataMin); - int startX = floor(fromX * xStep + 0.5); - int stopX = floor(toX * xStep + 0.5); - int startY = floor((m_height - yStep * (fromY - m_drawDataMin)) + 0.5); - int stopY = floor((m_height - yStep * (toY - m_drawDataMin)) + 0.5); - int peakX = floor(peakStartX * xStep + 0.5); - int peakY = floor(m_height - yStep * (peakStartY - m_drawDataMin) + 0.5); + setDimensions(width, height); + if (!draw(SignalController::RELATIVE_MIN, SignalController::RELATIVE_MIN, SignalController::RELATIVE_MAX, SignalController::RELATIVE_MAX, layers)) + return false; - if (m_pixmap == nullptr) - return; + m_imageWriter.setFileName(filename); + m_imageWriter.setFormat(format); + image = m_pixmap->toImage(); - qDebug() << "drawing peak"; + return m_imageWriter.write(image); +} - //m_graphDrawer->overlayIntegratedPeak(m_pixmap, startX, startY, stopX, stopY, peakX, peakY, time, area); +QList ImageDrawer::supportedImageFormats() +{ + return QImageWriter::supportedImageFormats(); } diff --git a/imagedrawer.h b/imagedrawer.h index c3c2973..b27922e 100644 --- a/imagedrawer.h +++ b/imagedrawer.h @@ -1,29 +1,21 @@ #ifndef IMAGEDRAWER_H #define IMAGEDRAWER_H -#include +#include "signaldrawer.h" +#include -class ImageDrawer : public QObject +class ImageDrawer : protected SignalDrawer { - Q_OBJECT public: - explicit ImageDrawer(const int width, const int height, QObject* parent = nullptr); - const QPixmap* pixmap() const { return m_pixmap; } + explicit ImageDrawer(std::shared_ptr controller); + bool render(const QString& filename, const QByteArray format, const int width, const int height, const GraphLayers layers); -private: - QPixmap* m_pixmap; - int m_drawDataMin; - int m_drawDataMax; - - const int m_height; - const int m_width; + static QList supportedImageFormats(); -signals: +private: + std::shared_ptr m_controller; + QImageWriter m_imageWriter; -public slots: - void onDrawIntegration(const int fromX, const double fromY, const int toX, const double toY, const int peakStartX, const double peakStartY, - const QString& time, const QString& area); - void onUpdateGraph(double* data, size_t len, double min, double max); }; diff --git a/integrationtablemodel.cpp b/integrationtablemodel.cpp index a217282..de3ccce 100644 --- a/integrationtablemodel.cpp +++ b/integrationtablemodel.cpp @@ -21,8 +21,11 @@ */ #include "integrationtablemodel.h" +#include "logger.h" #include +const QString IntegrationTableModel::ME_SENDER_STR("IntegrationTableModel"); + IntegrationTableModel::IntegrationTableModel(const std::shared_ptr integrator, QObject* parent) : QAbstractTableModel(parent), m_integrator(integrator) @@ -35,7 +38,11 @@ QVariant IntegrationTableModel::data(const QModelIndex& index, int role) const if (index.row() >= m_integrator->peakCount()) return QVariant(); - const std::shared_ptr peak = m_integrator->peakByIdx(index.row()); + std::shared_ptr peak = m_integrator->peakByListIdx(index.row()); + if (peak == nullptr) { + Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, "Null pointer to peak"); + return QVariant(); + } switch (role) { case Qt::DisplayRole: switch (index.column()) { @@ -85,3 +92,25 @@ int IntegrationTableModel::rowCount(const QModelIndex& parent) const return m_integrator->peakCount(); } + +void IntegrationTableModel::prepToAdd(const int idx) +{ + + beginInsertRows(QModelIndex(), idx ,idx); +} + +void IntegrationTableModel::addDone() +{ + endInsertRows(); +} + +void IntegrationTableModel::prepToDelete(const int idx) +{ + beginRemoveRows(QModelIndex(), idx, idx); +} + +void IntegrationTableModel::deleteDone() +{ + endRemoveRows(); +} + diff --git a/integrationtablemodel.h b/integrationtablemodel.h index 90daac4..83c241d 100644 --- a/integrationtablemodel.h +++ b/integrationtablemodel.h @@ -29,17 +29,24 @@ class IntegrationTableModel : public QAbstractTableModel { + Q_OBJECT public: IntegrationTableModel(const std::shared_ptr integrator, QObject* parent = nullptr); QVariant data(const QModelIndex& index, int role) const; - void doneReset() { endResetModel(); } int columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 4; } QVariant headerData(int section, Qt::Orientation orientation, int role) const; - void prepReset() { beginResetModel(); } int rowCount(const QModelIndex& parent) const; private: const std::shared_ptr m_integrator; + + static const QString ME_SENDER_STR; + +public slots: + void prepToAdd(const int idx); + void prepToDelete(const int idx); + void addDone(); + void deleteDone(); }; #endif // INTEGRATIONTABLEMODEL_H diff --git a/integrator.cpp b/integrator.cpp index 9c5daab..5e8365c 100644 --- a/integrator.cpp +++ b/integrator.cpp @@ -32,22 +32,44 @@ Integrator::Integrator(std::shared_ptr signal, QObject* parent) : m_signal(signal) {} -std::shared_ptr Integrator::deletePeak(size_t idx) +std::shared_ptr Integrator::deletePeak(size_t idx) { + size_t ctr = 0; std::shared_ptr peak; - std::multimap>::iterator it = m_peaks.begin(); - while (it != m_peaks.end() && it->first <= idx) { - if (it->first <= idx && it->second->toIdx() > idx) { /* Peak is surrounding the cursor */ - peak = it->second; - m_peaks.erase(it); - return peak; + m_peaksList.setToFirst(); + while ((peak = m_peaksList.getCurrent()) != nullptr) { + if (peak->fromIdx() <= idx && peak->toIdx() >= idx) { /* Peak is surrounding the cursor */ + qDebug() << "Deleting peak ctr" << ctr << "auc" << peak->auc(); + std::shared_ptr copyPeak = peak; + emit deletingPeak(ctr); + m_peaksList.removeCurrent(); + emit peakRemoved(); + return copyPeak; } - it++; + m_peaksList.next(); + + qDebug() << "Going through peaks to delete, ctr " << ctr << "peak auc" << peak->auc(); + ctr++; } + return nullptr; } +std::vector> Integrator::allPeaks() +{ + std::shared_ptr peak; + std::vector> allPeaks; + + m_peaksList.setToFirst(); + while ((peak = m_peaksList.getCurrent()) != nullptr) { + allPeaks.push_back(peak); + m_peaksList.next(); + } + + return allPeaks; +} + Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr& peak) { size_t peakValueIdx; @@ -150,15 +172,109 @@ Integrator::ReturnCode Integrator::integrate(size_t startIdx, size_t stopIdx, do peak = std::shared_ptr(new IntegratedPeak(peakType, auc, peakValueIdx, m_signal->timeAt(peakValueIdx), m_signal->valueAt(peakValueIdx), startIntersIdx, stopIntersIdx, m_signal->timeAt(startIntersIdx), m_signal->timeAt(stopIntersIdx), startYVal, stopYVal)); - m_peaks.insert(std::pair>(startIdx, peak)); - + emit addingPeak(m_peaksList.count()); + m_peaksList.append(peak); + emit peakAdded(); + qDebug() << "Peak added, count" << m_peaksList.count(); return ReturnCode::SUCCESS; } -const std::shared_ptr Integrator::peakByIdx(const int idx) const +std::shared_ptr Integrator::peakByListIdx(const size_t idx) +{ + if (m_peaksList.count() == 0) + return nullptr; + if (idx >= m_peaksList.count()) + return nullptr; + + m_peaksList.setToFirst(); + + /*while (ctr++ != idx && (peak = m_peaksList.getCurrent()) != nullptr) { + peak = m_peaksList.getCurrent(); + m_peaksList.next(); + }*/ + for (size_t i = 0; i < idx; i++) + m_peaksList.next(); + + return m_peaksList.getCurrent(); +} + +/* Linked list methods */ +Integrator::PeaksLinkedList::PeaksLinkedList() : + first(nullptr), + current(nullptr), + last(nullptr), + ctr(0) +{} + +void Integrator::PeaksLinkedList::append(std::shared_ptr peak) +{ + ListItem* item = new ListItem(peak); + + if (first == nullptr) { + first = item; + item->prev = nullptr; + } else { + last->next = item; + item->prev = last; + } + + last = item; + ctr++; +} + +std::shared_ptr Integrator::PeaksLinkedList::getCurrent() +{ + if (current == nullptr) + return nullptr; + + return current->m_peak; +} + +std::shared_ptr Integrator::PeaksLinkedList::getFirst() +{ + if (first == nullptr) + return nullptr; + + return first->m_peak; +} + +void Integrator::PeaksLinkedList::removeCurrent() { - std::multimap>::const_iterator it = m_peaks.begin(); - std::advance(it, idx); + ListItem* deleteMe; - return it->second; + if (current == nullptr) + return; + + if (ctr == 1) { + first = nullptr; + last = nullptr; + } else if (current == first) { + first = first->next; + if (first != nullptr) + first->prev = nullptr; + } else if (current == last) { + last = current->prev; + last->next = nullptr; + } else { + ListItem* prev = current->prev; + prev->next = current->next; + } + + deleteMe = current; + current = current->next; + ctr--; + delete deleteMe; +} + +void Integrator::PeaksLinkedList::next() +{ + if (current == nullptr) + current = first; + else + current = current->next; +} + +void Integrator::PeaksLinkedList::setToFirst() +{ + current = first; } diff --git a/integrator.h b/integrator.h index 8b76108..08c0fe1 100644 --- a/integrator.h +++ b/integrator.h @@ -42,20 +42,48 @@ public: }; explicit Integrator(std::shared_ptr signal, QObject* parent = nullptr); - std::shared_ptr deletePeak(size_t idx); + std::shared_ptr deletePeak(size_t idx); + std::vector> allPeaks(); ReturnCode integrate(size_t startIdx, size_t stopIdx, double startY, double stopY, std::shared_ptr& peak); - const std::shared_ptr peakByIdx(const int idx) const; - std::multimap>::const_iterator peaksCBegin() const { return m_peaks.cbegin(); } - std::multimap>::const_iterator peaksCEnd() const { return m_peaks.cend(); } - size_t peakCount() const { return m_peaks.size(); } + std::shared_ptr peakByListIdx(const size_t idx); + //std::multimap>::const_iterator peaksCBegin() const { return m_peaks.cbegin(); } + //std::multimap>::const_iterator peaksCEnd() const { return m_peaks.cend(); } + size_t peakCount() const { return m_peaksList.count(); } private: - std::multimap> m_peaks; + struct ListItem { + ListItem(std::shared_ptr peak) : m_peak(peak), next(nullptr) {} + std::shared_ptr m_peak; + ListItem* prev; + ListItem* next; + }; + class PeaksLinkedList { + public: + explicit PeaksLinkedList(); + void append(std::shared_ptr peak); + size_t count() const { return ctr; } + std::shared_ptr getCurrent(); + std::shared_ptr getFirst(); + void next(); + void removeCurrent(); + void setToFirst(); + private: + ListItem* first; + ListItem* current; + ListItem* last; + size_t ctr; + }; + + PeaksLinkedList m_peaksList; std::shared_ptr m_signal; static const QString ME_SENDER_STR; signals: + void addingPeak(const int idx); + void deletingPeak(const int idx); + void peakAdded(); + void peakRemoved(); public slots: diff --git a/signalcontroller.cpp b/signalcontroller.cpp index 14a7764..94880fb 100644 --- a/signalcontroller.cpp +++ b/signalcontroller.cpp @@ -37,6 +37,11 @@ SignalController::SignalController(std::shared_ptr signal, QObject* pare m_integrator = std::shared_ptr(new Integrator(signal)); m_integTblModel = new IntegrationTableModel(m_integrator); m_dtblModel = new SignalDataTableModel(signal); + + connect(m_integrator.get(), SIGNAL(addingPeak(int)), m_integTblModel, SLOT(prepToAdd(int))); + connect(m_integrator.get(), SIGNAL(peakAdded()), m_integTblModel, SLOT(addDone())); + connect(m_integrator.get(), SIGNAL(deletingPeak(int)), m_integTblModel, SLOT(prepToDelete(int))); + connect(m_integrator.get(), SIGNAL(peakRemoved()), m_integTblModel, SLOT(deleteDone())); } /** Public methods **/ @@ -44,22 +49,19 @@ SignalController::SignalController(std::shared_ptr signal, QObject* pare PeakDrawData SignalController::deletePeak(const double x) { size_t idx = relToIdx(x); - std::shared_ptr peak; + std::shared_ptr peak; if (idx > m_signal->count()-1) { Logger::log(Logger::Level::CRITICAL, ME_SENDER_STR, __QFUNC__ + " idx value " + QString::number(idx) + " out of bounds!"); return PeakDrawData(); } - m_integTblModel->prepReset(); peak = m_integrator->deletePeak(idx); if (peak == nullptr) { Logger::log(Logger::Level::DEBUG, ME_SENDER_STR, __QFUNC__ + " no peak to delete (idx " + QString::number(idx) + ")"); - m_integTblModel->doneReset(); return PeakDrawData(); } - m_integTblModel->doneReset(); return genPeakDrawData(peak); } @@ -97,7 +99,8 @@ std::vector SignalController::getPeaksDrawData(const double fromX, { std::vector peaks; size_t fromIdx, toIdx; - std::multimap>::const_iterator cit = m_integrator->peaksCBegin(); + std::vector> allPeaks; + // std::multimap>::const_iterator cit = m_integrator->peaksCBegin(); if (toX <= fromX) { Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " toX is lower than fromX"); @@ -116,14 +119,12 @@ std::vector SignalController::getPeaksDrawData(const double fromX, return peaks; } - while (cit != m_integrator->peaksCEnd()) { - std::shared_ptr peak = cit->second; - + allPeaks = m_integrator->allPeaks(); + for (std::shared_ptr peak : allPeaks) { if (peak->toIdx() < fromIdx || peak->fromIdx() > toIdx) /* Peak is not in view X-wise, skip it */ continue; peaks.push_back(genPeakDrawData(peak)); - cit++; } return peaks; @@ -194,12 +195,10 @@ PeakDrawData SignalController::integratePeak(const double fromX, const double fr fromVal = relToValue(fromY); toVal = relToValue(toY); - m_integTblModel->prepReset(); ret = m_integrator->integrate(fromIdx, toIdx, fromVal, toVal, peak); switch (ret) { case Integrator::ReturnCode::SUCCESS: - m_integTblModel->doneReset(); return genPeakDrawData(peak); break; case Integrator::ReturnCode::E_NO_FIRST_INTERSECT: @@ -217,7 +216,7 @@ PeakDrawData SignalController::integratePeak(const double fromX, const double fr /** Private methods **/ -PeakDrawData SignalController::genPeakDrawData(const std::shared_ptr peak) +PeakDrawData SignalController::genPeakDrawData(const std::shared_ptr peak) { return PeakDrawData(idxToRel(peak->fromIdx()), valueToRel(peak->fromY()), idxToRel(peak->toIdx()), valueToRel(peak->toY()), diff --git a/signalcontroller.h b/signalcontroller.h index ee84f09..f5c17f2 100644 --- a/signalcontroller.h +++ b/signalcontroller.h @@ -106,8 +106,8 @@ private: size_t relToIdx(const double rel); double relToValue(const double rel); - void drawIntegratedPeak(const std::shared_ptr peak); - PeakDrawData genPeakDrawData(const std::shared_ptr peak); + void drawIntegratedPeak(const std::shared_ptr peak); + PeakDrawData genPeakDrawData(const std::shared_ptr peak); static const QString ME_SENDER_STR; diff --git a/signaldrawer.cpp b/signaldrawer.cpp index 345ad2a..678aeca 100644 --- a/signaldrawer.cpp +++ b/signaldrawer.cpp @@ -25,7 +25,7 @@ Constraints SignalDrawer::currentConstraints() return Constraints(m_relXMin, m_relYMin, m_relXMax, m_relYMax); } -bool SignalDrawer::draw(const double fromX, const double fromY, const double toX, const double toY) +bool SignalDrawer::draw(const double fromX, const double fromY, const double toX, const double toY, const GraphLayers layers) { QPixmap* fresh; bool ret; @@ -35,21 +35,33 @@ bool SignalDrawer::draw(const double fromX, const double fromY, const double toX fresh = createFreshPixmap(); if (fresh == nullptr) return false; - ret = drawGraph(fresh); - if (!ret) { - Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " cannot draw graph"); - restoreRelativeConstraints(); - delete fresh; - return ret; + + /* Draw the signal itself */ + if (flags(GraphLayers::GRAPH & layers)) { + ret = drawGraph(fresh); + if (!ret) { + Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " cannot draw graph"); + restoreRelativeConstraints(); + delete fresh; + return ret; + } + } + + /* Draw the scale */ + if (flags(GraphLayers::SCALE & layers)) { + ret = renderScale(SignalController::Axis::VALUE, fresh); + ret = renderScale(SignalController::Axis::TIME, fresh); } - ret = renderScale(SignalController::Axis::VALUE, fresh); - ret = renderScale(SignalController::Axis::TIME, fresh); - ret = drawPeaks(fresh); - if (!ret) { - Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " cannot draw integrated peaks"); - restoreRelativeConstraints(); - delete fresh; - return ret; + + /* Draw integrated peaks */ + if (flags(GraphLayers::INTEGRATION & layers)) { + ret = drawPeaks(fresh); + if (!ret) { + Logger::log(Logger::Level::WARNING, ME_SENDER_STR, __QFUNC__ + " cannot draw integrated peaks"); + restoreRelativeConstraints(); + delete fresh; + return ret; + } } renderFresh(fresh); diff --git a/signaldrawer.h b/signaldrawer.h index 0c89ff3..9efcae5 100644 --- a/signaldrawer.h +++ b/signaldrawer.h @@ -1,6 +1,7 @@ #ifndef SIGNALDRAWER_H #define SIGNALDRAWER_H +#include "enumflags.h" #include "signalcontroller.h" #include #include @@ -17,14 +18,22 @@ struct Constraints { const double fromX, fromY, toX, toY; }; +ENUM_FLAGS(GraphLayers) +enum class GraphLayers { + GRAPH = 0x01, + INTEGRATION = 0x02, + SCALE = 0x04, + ALL = INT_MAX +}; + class SignalDrawer { public: - SignalDrawer(std::shared_ptr controller, const Constraints& constraints = Constraints()); + SignalDrawer(std::shared_ptr controller, const Constraints& constraints = Constraints()); ~SignalDrawer(); Constraints currentConstraints(); int dheight() const { return m_height; } - bool draw(const double fromX, const double fromY, const double toX, const double toY); + bool draw(const double fromX, const double fromY, const double toX, const double toY, const GraphLayers layers = GraphLayers::ALL); bool drawGraph(QPixmap* const target); bool drawPeaks(QPixmap* const target); QRect erasePeak(const PeakDrawData& pd); -- 2.43.5