@@ -1,8 +1,9 | |||
|
1 | 1 | #ifndef SCIQLOP_ARRAYDATA_H |
|
2 | 2 | #define SCIQLOP_ARRAYDATA_H |
|
3 | 3 | |
|
4 | #include <QReadLocker> | |
|
5 | #include <QReadWriteLock> | |
|
4 | 6 | #include <QVector> |
|
5 | ||
|
6 | 7 | /** |
|
7 | 8 | * @brief The ArrayData class represents a dataset for a data series. |
|
8 | 9 | * |
@@ -22,10 +23,22 public: | |||
|
22 | 23 | template <int D = Dim, typename = std::enable_if_t<D == 1> > |
|
23 | 24 | explicit ArrayData(int nbColumns) : m_Data{1, QVector<double>{}} |
|
24 | 25 | { |
|
26 | QWriteLocker locker(&m_Lock); | |
|
25 | 27 | m_Data[0].resize(nbColumns); |
|
26 | 28 | } |
|
27 | 29 | |
|
28 | 30 | /** |
|
31 | * Ctor for a unidimensional ArrayData | |
|
32 | * @param nbColumns the number of values the ArrayData will hold | |
|
33 | */ | |
|
34 | explicit ArrayData(const ArrayData &other) | |
|
35 | { | |
|
36 | QReadLocker otherLocker(&other.m_Lock); | |
|
37 | QWriteLocker locker(&m_Lock); | |
|
38 | m_Data = other.m_Data; | |
|
39 | } | |
|
40 | ||
|
41 | /** | |
|
29 | 42 | * Sets a data at a specified index. The index has to be valid to be effective |
|
30 | 43 | * @param index the index to which the data will be set |
|
31 | 44 | * @param data the data to set |
@@ -34,6 +47,7 public: | |||
|
34 | 47 | template <int D = Dim, typename = std::enable_if_t<D == 1> > |
|
35 | 48 | void setData(int index, double data) noexcept |
|
36 | 49 | { |
|
50 | QWriteLocker locker(&m_Lock); | |
|
37 | 51 | if (index >= 0 && index < m_Data.at(0).size()) { |
|
38 | 52 | m_Data[0].replace(index, data); |
|
39 | 53 | } |
@@ -44,8 +58,9 public: | |||
|
44 | 58 | * @remarks this method is only available for a unidimensional ArrayData |
|
45 | 59 | */ |
|
46 | 60 | template <int D = Dim, typename = std::enable_if_t<D == 1> > |
|
47 |
|
|
|
61 | QVector<double> data() const noexcept | |
|
48 | 62 | { |
|
63 | QReadLocker locker(&m_Lock); | |
|
49 | 64 | return m_Data[0]; |
|
50 | 65 | } |
|
51 | 66 | |
@@ -54,8 +69,9 public: | |||
|
54 | 69 | * @remarks this method is only available for a unidimensional ArrayData |
|
55 | 70 | */ |
|
56 | 71 | template <int D = Dim, typename = std::enable_if_t<D == 1> > |
|
57 |
|
|
|
72 | QVector<double> data(double tStart, double tEnd) const noexcept | |
|
58 | 73 | { |
|
74 | QReadLocker locker(&m_Lock); | |
|
59 | 75 | return m_Data.at(tStart); |
|
60 | 76 | } |
|
61 | 77 | |
@@ -63,20 +79,30 public: | |||
|
63 | 79 | template <int D = Dim, typename = std::enable_if_t<D == 1> > |
|
64 | 80 | void merge(const ArrayData<1> &arrayData) |
|
65 | 81 | { |
|
82 | QWriteLocker locker(&m_Lock); | |
|
66 | 83 | if (!m_Data.empty()) { |
|
84 | QReadLocker otherLocker(&arrayData.m_Lock); | |
|
67 | 85 | m_Data[0] += arrayData.data(); |
|
68 | 86 | } |
|
69 | 87 | } |
|
70 | 88 | |
|
71 | 89 | template <int D = Dim, typename = std::enable_if_t<D == 1> > |
|
72 | int size() | |
|
90 | int size() const | |
|
73 | 91 | { |
|
92 | QReadLocker locker(&m_Lock); | |
|
74 | 93 | return m_Data[0].size(); |
|
75 | 94 | } |
|
76 | 95 | |
|
96 | void clear() | |
|
97 | { | |
|
98 | QWriteLocker locker(&m_Lock); | |
|
99 | m_Data.clear(); | |
|
100 | } | |
|
101 | ||
|
77 | 102 | |
|
78 | 103 | private: |
|
79 | 104 | QVector<QVector<double> > m_Data; |
|
105 | mutable QReadWriteLock m_Lock; | |
|
80 | 106 | }; |
|
81 | 107 | |
|
82 | 108 | #endif // SCIQLOP_ARRAYDATA_H |
@@ -6,9 +6,10 | |||
|
6 | 6 | |
|
7 | 7 | #include <QLoggingCategory> |
|
8 | 8 | |
|
9 | #include <QReadLocker> | |
|
10 | #include <QReadWriteLock> | |
|
9 | 11 | #include <memory> |
|
10 | 12 | |
|
11 | ||
|
12 | 13 | Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries) |
|
13 | 14 | Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries") |
|
14 | 15 | |
@@ -38,12 +39,19 public: | |||
|
38 | 39 | /// @sa IDataSeries::valuesUnit() |
|
39 | 40 | Unit valuesUnit() const override { return m_ValuesUnit; } |
|
40 | 41 | |
|
42 | void clear() | |
|
43 | { | |
|
44 | m_XAxisData->clear(); | |
|
45 | m_ValuesData->clear(); | |
|
46 | } | |
|
47 | ||
|
41 | 48 | /// @sa IDataSeries::merge() |
|
42 | 49 | void merge(IDataSeries *dataSeries) override |
|
43 | 50 | { |
|
44 | 51 | if (auto dimDataSeries = dynamic_cast<DataSeries<Dim> *>(dataSeries)) { |
|
45 | 52 | m_XAxisData->merge(*dimDataSeries->xAxisData()); |
|
46 | 53 | m_ValuesData->merge(*dimDataSeries->valuesData()); |
|
54 | dimDataSeries->clear(); | |
|
47 | 55 | } |
|
48 | 56 | else { |
|
49 | 57 | qCWarning(LOG_DataSeries()) |
@@ -51,6 +59,10 public: | |||
|
51 | 59 | } |
|
52 | 60 | } |
|
53 | 61 | |
|
62 | virtual void lockRead() { m_Lock.lockForRead(); } | |
|
63 | virtual void lockWrite() { m_Lock.lockForWrite(); } | |
|
64 | virtual void unlock() { m_Lock.unlock(); } | |
|
65 | ||
|
54 | 66 | protected: |
|
55 | 67 | /// Protected ctor (DataSeries is abstract) |
|
56 | 68 | explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit, |
@@ -88,6 +100,8 private: | |||
|
88 | 100 | Unit m_XAxisUnit; |
|
89 | 101 | std::shared_ptr<ArrayData<Dim> > m_ValuesData; |
|
90 | 102 | Unit m_ValuesUnit; |
|
103 | ||
|
104 | QReadWriteLock m_Lock; | |
|
91 | 105 | }; |
|
92 | 106 | |
|
93 | 107 | #endif // SCIQLOP_DATASERIES_H |
@@ -51,6 +51,10 public: | |||
|
51 | 51 | virtual void merge(IDataSeries *dataSeries) = 0; |
|
52 | 52 | |
|
53 | 53 | virtual std::unique_ptr<IDataSeries> clone() const = 0; |
|
54 | ||
|
55 | virtual void lockRead() = 0; | |
|
56 | virtual void lockWrite() = 0; | |
|
57 | virtual void unlock() = 0; | |
|
54 | 58 | }; |
|
55 | 59 | |
|
56 | 60 | // Required for using shared_ptr in signals/slots |
@@ -3,6 +3,9 | |||
|
3 | 3 | #include <Data/IDataSeries.h> |
|
4 | 4 | #include <Data/SqpDateTime.h> |
|
5 | 5 | |
|
6 | #include <QReadWriteLock> | |
|
7 | #include <QThread> | |
|
8 | ||
|
6 | 9 | Q_LOGGING_CATEGORY(LOG_Variable, "Variable") |
|
7 | 10 | |
|
8 | 11 | struct Variable::VariablePrivate { |
@@ -57,6 +60,7 void Variable::setDateTime(const SqpDateTime &dateTime) noexcept | |||
|
57 | 60 | |
|
58 | 61 | void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept |
|
59 | 62 | { |
|
63 | qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName(); | |
|
60 | 64 | if (!dataSeries) { |
|
61 | 65 | /// @todo ALX : log |
|
62 | 66 | return; |
@@ -67,8 +71,11 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept | |||
|
67 | 71 | impl->m_DataSeries = dataSeries->clone(); |
|
68 | 72 | } |
|
69 | 73 | else { |
|
74 | dataSeries->lockWrite(); | |
|
75 | impl->m_DataSeries->lockWrite(); | |
|
70 | 76 | impl->m_DataSeries->merge(dataSeries.get()); |
|
71 | ||
|
77 | impl->m_DataSeries->unlock(); | |
|
78 | dataSeries->unlock(); | |
|
72 | 79 | emit updated(); |
|
73 | 80 | } |
|
74 | 81 | } |
@@ -3,6 +3,7 | |||
|
3 | 3 | #include "Variable/Variable.h" |
|
4 | 4 | #include <unordered_map> |
|
5 | 5 | |
|
6 | #include <QThread> | |
|
6 | 7 | Q_LOGGING_CATEGORY(LOG_VariableCacheController, "VariableCacheController") |
|
7 | 8 | |
|
8 | 9 | struct VariableCacheController::VariableCacheControllerPrivate { |
@@ -32,6 +33,8 VariableCacheController::VariableCacheController(QObject *parent) | |||
|
32 | 33 | void VariableCacheController::addDateTime(std::shared_ptr<Variable> variable, |
|
33 | 34 | const SqpDateTime &dateTime) |
|
34 | 35 | { |
|
36 | qCDebug(LOG_VariableCacheController()) << "VariableCacheController::addDateTime" | |
|
37 | << QThread::currentThread()->objectName(); | |
|
35 | 38 | if (variable) { |
|
36 | 39 | auto findVariableIte = impl->m_VariableToSqpDateTimeListMap.find(variable); |
|
37 | 40 | if (findVariableIte == impl->m_VariableToSqpDateTimeListMap.end()) { |
@@ -81,6 +84,9 QVector<SqpDateTime> | |||
|
81 | 84 | VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable, |
|
82 | 85 | const SqpDateTime &dateTime) |
|
83 | 86 | { |
|
87 | qCDebug(LOG_VariableCacheController()) | |
|
88 | << "VariableCacheController::provideNotInCacheDateTimeList" | |
|
89 | << QThread::currentThread()->objectName(); | |
|
84 | 90 | auto notInCache = QVector<SqpDateTime>{}; |
|
85 | 91 | |
|
86 | 92 | // This algorithm is recursif. The idea is to localise the start time then the end time in the |
@@ -101,6 +107,8 VariableCacheController::provideNotInCacheDateTimeList(std::shared_ptr<Variable> | |||
|
101 | 107 | QVector<SqpDateTime> |
|
102 | 108 | VariableCacheController::dateCacheList(std::shared_ptr<Variable> variable) const noexcept |
|
103 | 109 | { |
|
110 | qCDebug(LOG_VariableCacheController()) << "VariableCacheController::dateCacheList" | |
|
111 | << QThread::currentThread()->objectName(); | |
|
104 | 112 | try { |
|
105 | 113 | return impl->m_VariableToSqpDateTimeListMap.at(variable); |
|
106 | 114 | } |
@@ -152,6 +152,8 void VariableController::createVariable(const QString &name, | |||
|
152 | 152 | |
|
153 | 153 | void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime) |
|
154 | 154 | { |
|
155 | qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection" | |
|
156 | << QThread::currentThread()->objectName(); | |
|
155 | 157 | auto selectedRows = impl->m_VariableSelectionModel->selectedRows(); |
|
156 | 158 | |
|
157 | 159 | for (const auto &selectedRow : qAsConst(selectedRows)) { |
@@ -166,6 +168,8 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime) | |||
|
166 | 168 | void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable, |
|
167 | 169 | const SqpDateTime &dateTime) |
|
168 | 170 | { |
|
171 | qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading" | |
|
172 | << QThread::currentThread()->objectName(); | |
|
169 | 173 | // we want to load data of the variable for the dateTime. |
|
170 | 174 | // First we check if the cache contains some of them. |
|
171 | 175 | // For the other, we ask the provider to give them. |
@@ -18,6 +18,14 public: | |||
|
18 | 18 | m_VariableController{std::make_unique<VariableController>()}, |
|
19 | 19 | m_VisualizationController{std::make_unique<VisualizationController>()} |
|
20 | 20 | { |
|
21 | QThread::currentThread()->setObjectName("MainThread"); | |
|
22 | m_DataSourceController->moveToThread(&m_DataSourceControllerThread); | |
|
23 | m_DataSourceControllerThread.setObjectName("DataSourceControllerThread"); | |
|
24 | m_VariableController->moveToThread(&m_VariableControllerThread); | |
|
25 | m_VariableControllerThread.setObjectName("VariableControllerThread"); | |
|
26 | m_VisualizationController->moveToThread(&m_VisualizationControllerThread); | |
|
27 | m_VisualizationControllerThread.setObjectName("VisualizationControllerThread"); | |
|
28 | ||
|
21 | 29 | // /////////////////////////////// // |
|
22 | 30 | // Connections between controllers // |
|
23 | 31 | // /////////////////////////////// // |
@@ -34,9 +42,6 public: | |||
|
34 | 42 | m_VisualizationController.get(), |
|
35 | 43 | SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection); |
|
36 | 44 | |
|
37 | m_DataSourceController->moveToThread(&m_DataSourceControllerThread); | |
|
38 | m_VariableController->moveToThread(&m_VariableControllerThread); | |
|
39 | m_VisualizationController->moveToThread(&m_VisualizationControllerThread); | |
|
40 | 45 | |
|
41 | 46 | // Additionnal init |
|
42 | 47 | m_VariableController->setTimeController(m_TimeController.get()); |
@@ -5,12 +5,16 | |||
|
5 | 5 | |
|
6 | 6 | #include <Variable/Variable.h> |
|
7 | 7 | |
|
8 | #include <QElapsedTimer> | |
|
9 | ||
|
10 | 8 | Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper") |
|
11 | 9 | |
|
12 | 10 | namespace { |
|
13 | 11 | |
|
12 | class SqpDataContainer : public QCPGraphDataContainer { | |
|
13 | public: | |
|
14 | void appendGraphDataUnsorted(const QCPGraphData &data) { mData.append(data); } | |
|
15 | }; | |
|
16 | ||
|
17 | ||
|
14 | 18 | /// Format for datetimes on a axis |
|
15 | 19 | const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss"); |
|
16 | 20 | |
@@ -33,35 +37,36 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis) | |||
|
33 | 37 | void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries, |
|
34 | 38 | const SqpDateTime &dateTime) |
|
35 | 39 | { |
|
36 | QElapsedTimer timer; | |
|
37 | timer.start(); | |
|
40 | qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData" | |
|
41 | << QThread::currentThread()->objectName(); | |
|
38 | 42 | if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) { |
|
39 | 43 | // Clean the graph |
|
40 | 44 | // NAIVE approch |
|
41 | const auto &xData = scalarSeries.xAxisData()->data(); | |
|
42 | const auto &valuesData = scalarSeries.valuesData()->data(); | |
|
43 | const auto count = xData.count(); | |
|
44 | qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache" << xData.count(); | |
|
45 | auto xValue = QVector<double>(count); | |
|
46 | auto vValue = QVector<double>(count); | |
|
47 | ||
|
48 | int n = 0; | |
|
49 | for (auto i = 0; i < count; ++i) { | |
|
50 | const auto x = xData[i]; | |
|
51 | if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) { | |
|
52 | xValue[n] = x; | |
|
53 | vValue[n] = valuesData[i]; | |
|
54 | ++n; | |
|
45 | scalarSeries.lockRead(); | |
|
46 | { | |
|
47 | const auto xData = scalarSeries.xAxisData()->data(); | |
|
48 | const auto valuesData = scalarSeries.valuesData()->data(); | |
|
49 | const auto count = xData.count(); | |
|
50 | qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache" | |
|
51 | << xData.count(); | |
|
52 | ||
|
53 | auto dataContainer = qcpGraph->data(); | |
|
54 | dataContainer->clear(); | |
|
55 | auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create(); | |
|
56 | qcpGraph->setData(sqpDataContainer); | |
|
57 | ||
|
58 | for (auto i = 0; i < count; ++i) { | |
|
59 | const auto x = xData[i]; | |
|
60 | if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) { | |
|
61 | sqpDataContainer->appendGraphDataUnsorted(QCPGraphData(x, valuesData[i])); | |
|
62 | } | |
|
55 | 63 | } |
|
64 | sqpDataContainer->sort(); | |
|
65 | qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed" | |
|
66 | << sqpDataContainer->size(); | |
|
56 | 67 | } |
|
68 | scalarSeries.unlock(); | |
|
57 | 69 | |
|
58 | xValue.resize(n); | |
|
59 | vValue.resize(n); | |
|
60 | ||
|
61 | qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed" | |
|
62 | << xValue.count(); | |
|
63 | ||
|
64 | qcpGraph->setData(xValue, vValue); | |
|
65 | 70 | |
|
66 | 71 | // Display all data |
|
67 | 72 | component->rescaleAxes(); |
@@ -79,7 +79,6 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable) | |||
|
79 | 79 | |
|
80 | 80 | connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated())); |
|
81 | 81 | } |
|
82 | ||
|
83 | 82 | void VisualizationGraphWidget::addVariableUsingGraph(std::shared_ptr<Variable> variable) |
|
84 | 83 | { |
|
85 | 84 | |
@@ -178,7 +177,8 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept | |||
|
178 | 177 | |
|
179 | 178 | void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1) |
|
180 | 179 | { |
|
181 |
qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged") |
|
|
180 | qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::onRangeChanged") | |
|
181 | << QThread::currentThread()->objectName(); | |
|
182 | 182 | |
|
183 | 183 | for (auto it = impl->m_VariableToPlotMultiMap.cbegin(); |
|
184 | 184 | it != impl->m_VariableToPlotMultiMap.cend(); ++it) { |
@@ -18570,7 +18570,7 void QCPLegend::setIconSize(const QSize &size) | |||
|
18570 | 18570 | } |
|
18571 | 18571 | |
|
18572 | 18572 | /*! \overload |
|
18573 | */ | |
|
18573 | */ | |
|
18574 | 18574 | void QCPLegend::setIconSize(int width, int height) |
|
18575 | 18575 | { |
|
18576 | 18576 | mIconSize.setWidth(width); |
@@ -6,6 +6,7 | |||
|
6 | 6 | #include <cmath> |
|
7 | 7 | |
|
8 | 8 | #include <QDateTime> |
|
9 | #include <QThread> | |
|
9 | 10 | |
|
10 | 11 | Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider") |
|
11 | 12 | |
@@ -39,6 +40,8 CosinusProvider::retrieveData(const DataProviderParameters ¶meters) const | |||
|
39 | 40 | |
|
40 | 41 | void CosinusProvider::requestDataLoading(const QVector<SqpDateTime> &dateTimeList) |
|
41 | 42 | { |
|
43 | qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading" | |
|
44 | << QThread::currentThread()->objectName(); | |
|
42 | 45 | // NOTE: Try to use multithread if possible |
|
43 | 46 | for (const auto &dateTime : dateTimeList) { |
|
44 | 47 | auto scalarSeries = this->retrieveData(DataProviderParameters{dateTime}); |
General Comments 0
You need to be logged in to leave comments.
Login now