##// END OF EJS Templates
Merge branch 'feature/SortDataSeries' into develop
Alexandre Leroux -
r456:e7ac423673d6 merge
parent child
Show More
@@ -0,0 +1,38
1 #ifndef SCIQLOP_SORTUTILS_H
2 #define SCIQLOP_SORTUTILS_H
3
4 #include <algorithm>
5 #include <vector>
6
7 /**
8 * Utility class with methods for sorting data
9 */
10 struct SortUtils {
11 /**
12 * Generates a vector representing the index of insertion of each data of a container if this
13 * one had to be sorted according to a comparison function.
14 *
15 * For example:
16 * If the container is a vector {1; 4; 2; 5; 3} and the comparison function is std::less, the
17 * result would be : {0; 3; 1; 4; 2}
18 *
19 * @tparam Container the type of the container.
20 * @tparam Compare the type of the comparison function
21 * @param container the container from which to generate the result. The container must have a
22 * at() method that returns a value associated to an index
23 * @param compare the comparison function
24 */
25 template <typename Container, typename Compare>
26 static std::vector<int> sortPermutation(const Container &container, const Compare &compare)
27 {
28 auto permutation = std::vector<int>{};
29 permutation.resize(container.size());
30
31 std::iota(permutation.begin(), permutation.end(), 0);
32 std::sort(permutation.begin(), permutation.end(),
33 [&](int i, int j) { return compare(container.at(i), container.at(j)); });
34 return permutation;
35 }
36 };
37
38 #endif // SCIQLOP_SORTUTILS_H
@@ -0,0 +1,164
1 #include "Data/DataSeries.h"
2 #include "Data/ScalarSeries.h"
3
4 #include <QObject>
5 #include <QtTest>
6
7 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
8
9 class TestDataSeries : public QObject {
10 Q_OBJECT
11 private slots:
12 /// Input test data
13 /// @sa testCtor()
14 void testCtor_data();
15
16 /// Tests construction of a data series
17 void testCtor();
18
19 /// Input test data
20 /// @sa testMerge()
21 void testMerge_data();
22
23 /// Tests merge of two data series
24 void testMerge();
25 };
26
27 void TestDataSeries::testCtor_data()
28 {
29 // ////////////// //
30 // Test structure //
31 // ////////////// //
32
33 // x-axis data
34 QTest::addColumn<QVector<double> >("xAxisData");
35 // values data
36 QTest::addColumn<QVector<double> >("valuesData");
37
38 // expected x-axis data
39 QTest::addColumn<QVector<double> >("expectedXAxisData");
40 // expected values data
41 QTest::addColumn<QVector<double> >("expectedValuesData");
42
43 // ////////// //
44 // Test cases //
45 // ////////// //
46
47 QTest::newRow("invalidData (different sizes of vectors)")
48 << QVector<double>{1., 2., 3., 4., 5.} << QVector<double>{100., 200., 300.}
49 << QVector<double>{} << QVector<double>{};
50
51 QTest::newRow("sortedData") << QVector<double>{1., 2., 3., 4., 5.}
52 << QVector<double>{100., 200., 300., 400., 500.}
53 << QVector<double>{1., 2., 3., 4., 5.}
54 << QVector<double>{100., 200., 300., 400., 500.};
55
56 QTest::newRow("unsortedData") << QVector<double>{5., 4., 3., 2., 1.}
57 << QVector<double>{100., 200., 300., 400., 500.}
58 << QVector<double>{1., 2., 3., 4., 5.}
59 << QVector<double>{500., 400., 300., 200., 100.};
60
61 QTest::newRow("unsortedData2")
62 << QVector<double>{1., 4., 3., 5., 2.} << QVector<double>{100., 200., 300., 400., 500.}
63 << QVector<double>{1., 2., 3., 4., 5.} << QVector<double>{100., 500., 300., 200., 400.};
64 }
65
66 void TestDataSeries::testCtor()
67 {
68 // Creates series
69 QFETCH(QVector<double>, xAxisData);
70 QFETCH(QVector<double>, valuesData);
71
72 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
73 Unit{}, Unit{});
74
75 // Validates results : we check that the data series is sorted on its x-axis data
76 QFETCH(QVector<double>, expectedXAxisData);
77 QFETCH(QVector<double>, expectedValuesData);
78
79 auto seriesXAxisData = series->xAxisData()->data();
80 auto seriesValuesData = series->valuesData()->data();
81
82 QVERIFY(
83 std::equal(expectedXAxisData.cbegin(), expectedXAxisData.cend(), seriesXAxisData.cbegin()));
84 QVERIFY(std::equal(expectedValuesData.cbegin(), expectedValuesData.cend(),
85 seriesValuesData.cbegin()));
86 }
87
88 namespace {
89
90 std::shared_ptr<ScalarSeries> createSeries(QVector<double> xAxisData, QVector<double> valuesData)
91 {
92 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
93 Unit{});
94 }
95
96 } // namespace
97
98 void TestDataSeries::testMerge_data()
99 {
100 // ////////////// //
101 // Test structure //
102 // ////////////// //
103
104 // Data series to merge
105 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
106 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
107
108 // Expected values in the first data series after merge
109 QTest::addColumn<QVector<double> >("expectedXAxisData");
110 QTest::addColumn<QVector<double> >("expectedValuesData");
111
112 // ////////// //
113 // Test cases //
114 // ////////// //
115
116 QTest::newRow("sortedMerge")
117 << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
118 << createSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
119 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
120 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
121
122 QTest::newRow("unsortedMerge")
123 << createSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
124 << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
125 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
126 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
127
128 QTest::newRow("unsortedMerge2")
129 << createSeries({1., 2., 8., 9., 10}, {100., 200., 300., 400., 500.})
130 << createSeries({3., 4., 5., 6., 7.}, {600., 700., 800., 900., 1000.})
131 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
132 << QVector<double>{100., 200., 600., 700., 800., 900., 1000., 300., 400., 500.};
133
134 QTest::newRow("unsortedMerge3")
135 << createSeries({3., 5., 8., 7., 2}, {100., 200., 300., 400., 500.})
136 << createSeries({6., 4., 9., 10., 1.}, {600., 700., 800., 900., 1000.})
137 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
138 << QVector<double>{1000., 500., 100., 700., 200., 600., 400., 300., 800., 900.};
139 }
140
141 void TestDataSeries::testMerge()
142 {
143 // Merges series
144 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
145 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
146
147 dataSeries->merge(dataSeries2.get());
148
149 // Validates results : we check that the merge is valid and the data series is sorted on its
150 // x-axis data
151 QFETCH(QVector<double>, expectedXAxisData);
152 QFETCH(QVector<double>, expectedValuesData);
153
154 auto seriesXAxisData = dataSeries->xAxisData()->data();
155 auto seriesValuesData = dataSeries->valuesData()->data();
156
157 QVERIFY(
158 std::equal(expectedXAxisData.cbegin(), expectedXAxisData.cend(), seriesXAxisData.cbegin()));
159 QVERIFY(std::equal(expectedValuesData.cbegin(), expectedValuesData.cend(),
160 seriesValuesData.cbegin()));
161 }
162
163 QTEST_MAIN(TestDataSeries)
164 #include "TestDataSeries.moc"
@@ -1,116 +1,169
1 #ifndef SCIQLOP_ARRAYDATA_H
1 #ifndef SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
3
3
4 #include <QReadLocker>
4 #include <QReadLocker>
5 #include <QReadWriteLock>
5 #include <QReadWriteLock>
6 #include <QVector>
6 #include <QVector>
7
8 #include <memory>
9
7 /**
10 /**
8 * @brief The ArrayData class represents a dataset for a data series.
11 * @brief The ArrayData class represents a dataset for a data series.
9 *
12 *
10 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
13 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
11 * template-parameter.
14 * template-parameter.
12 *
15 *
13 * @tparam Dim the dimension of the ArrayData (one or two)
16 * @tparam Dim the dimension of the ArrayData (one or two)
14 * @sa IDataSeries
17 * @sa IDataSeries
15 */
18 */
16 template <int Dim>
19 template <int Dim>
17 class ArrayData {
20 class ArrayData {
18 public:
21 public:
19 /**
22 /**
20 * Ctor for a unidimensional ArrayData
23 * Ctor for a unidimensional ArrayData
21 * @param nbColumns the number of values the ArrayData will hold
24 * @param nbColumns the number of values the ArrayData will hold
22 */
25 */
23 template <int D = Dim, typename = std::enable_if_t<D == 1> >
26 template <int D = Dim, typename = std::enable_if_t<D == 1> >
24 explicit ArrayData(int nbColumns) : m_Data{1, QVector<double>{}}
27 explicit ArrayData(int nbColumns) : m_Data{1, QVector<double>{}}
25 {
28 {
26 QWriteLocker locker{&m_Lock};
29 QWriteLocker locker{&m_Lock};
27 m_Data[0].resize(nbColumns);
30 m_Data[0].resize(nbColumns);
28 }
31 }
29
32
30 /**
33 /**
31 * Ctor for a unidimensional ArrayData
34 * Ctor for a unidimensional ArrayData
32 * @param data the data the ArrayData will hold
35 * @param data the data the ArrayData will hold
33 */
36 */
34 template <int D = Dim, typename = std::enable_if_t<D == 1> >
37 template <int D = Dim, typename = std::enable_if_t<D == 1> >
35 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
38 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
36 {
39 {
37 QWriteLocker locker{&m_Lock};
40 QWriteLocker locker{&m_Lock};
38 m_Data[0] = std::move(data);
41 m_Data[0] = std::move(data);
39 }
42 }
40
43
41 /// Copy ctor
44 /// Copy ctor
42 explicit ArrayData(const ArrayData &other)
45 explicit ArrayData(const ArrayData &other)
43 {
46 {
44 QReadLocker otherLocker{&other.m_Lock};
47 QReadLocker otherLocker{&other.m_Lock};
45 QWriteLocker locker{&m_Lock};
48 QWriteLocker locker{&m_Lock};
46 m_Data = other.m_Data;
49 m_Data = other.m_Data;
47 }
50 }
48
51
49 /**
52 /**
53 * @return the data at a specified index
54 * @remarks index must be a valid position
55 * @remarks this method is only available for a unidimensional ArrayData
56 */
57 template <int D = Dim, typename = std::enable_if_t<D == 1> >
58 double at(int index) const noexcept
59 {
60 QReadLocker locker{&m_Lock};
61 return m_Data[0].at(index);
62 }
63
64 /**
50 * Sets a data at a specified index. The index has to be valid to be effective
65 * Sets a data at a specified index. The index has to be valid to be effective
51 * @param index the index to which the data will be set
66 * @param index the index to which the data will be set
52 * @param data the data to set
67 * @param data the data to set
53 * @remarks this method is only available for a unidimensional ArrayData
68 * @remarks this method is only available for a unidimensional ArrayData
54 */
69 */
55 template <int D = Dim, typename = std::enable_if_t<D == 1> >
70 template <int D = Dim, typename = std::enable_if_t<D == 1> >
56 void setData(int index, double data) noexcept
71 void setData(int index, double data) noexcept
57 {
72 {
58 QWriteLocker locker{&m_Lock};
73 QWriteLocker locker{&m_Lock};
59 if (index >= 0 && index < m_Data.at(0).size()) {
74 if (index >= 0 && index < m_Data.at(0).size()) {
60 m_Data[0].replace(index, data);
75 m_Data[0].replace(index, data);
61 }
76 }
62 }
77 }
63
78
64 /**
79 /**
65 * @return the data as a vector
80 * @return the data as a vector
66 * @remarks this method is only available for a unidimensional ArrayData
81 * @remarks this method is only available for a unidimensional ArrayData
67 */
82 */
68 template <int D = Dim, typename = std::enable_if_t<D == 1> >
83 template <int D = Dim, typename = std::enable_if_t<D == 1> >
69 QVector<double> data() const noexcept
84 QVector<double> data() const noexcept
70 {
85 {
71 QReadLocker locker{&m_Lock};
86 QReadLocker locker{&m_Lock};
72 return m_Data[0];
87 return m_Data[0];
73 }
88 }
74
89
75 /**
90 /**
76 * @return the data as a vector
91 * @return the data as a vector, as a const reference
77 * @remarks this method is only available for a unidimensional ArrayData
92 * @remarks this method is only available for a unidimensional ArrayData
78 */
93 */
79 template <int D = Dim, typename = std::enable_if_t<D == 1> >
94 template <int D = Dim, typename = std::enable_if_t<D == 1> >
80 QVector<double> data(double tStart, double tEnd) const noexcept
95 const QVector<double> &cdata() const noexcept
81 {
96 {
82 QReadLocker locker{&m_Lock};
97 QReadLocker locker{&m_Lock};
83 return m_Data.at(tStart);
98 return m_Data.at(0);
84 }
99 }
85
100
86 // TODO Comment
101 /**
102 * Merges into the array data an other array data
103 * @param other the array data to merge with
104 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
105 * inserted at the end
106 * @remarks this method is only available for a unidimensional ArrayData
107 */
87 template <int D = Dim, typename = std::enable_if_t<D == 1> >
108 template <int D = Dim, typename = std::enable_if_t<D == 1> >
88 void merge(const ArrayData<1> &arrayData)
109 void add(const ArrayData<1> &other, bool prepend = false)
89 {
110 {
90 QWriteLocker locker{&m_Lock};
111 QWriteLocker locker{&m_Lock};
91 if (!m_Data.empty()) {
112 if (!m_Data.empty()) {
92 QReadLocker otherLocker{&arrayData.m_Lock};
113 QReadLocker otherLocker{&other.m_Lock};
93 m_Data[0] += arrayData.data();
114
115 if (prepend) {
116 const auto &otherData = other.data();
117 const auto otherDataSize = otherData.size();
118
119 auto &data = m_Data[0];
120 data.insert(data.begin(), otherDataSize, 0.);
121
122 for (auto i = 0; i < otherDataSize; ++i) {
123 data.replace(i, otherData.at(i));
124 }
125 }
126 else {
127 m_Data[0] += other.data();
128 }
94 }
129 }
95 }
130 }
96
131
97 template <int D = Dim, typename = std::enable_if_t<D == 1> >
132 template <int D = Dim, typename = std::enable_if_t<D == 1> >
98 int size() const
133 int size() const
99 {
134 {
100 QReadLocker locker{&m_Lock};
135 QReadLocker locker{&m_Lock};
101 return m_Data[0].size();
136 return m_Data[0].size();
102 }
137 }
103
138
139 template <int D = Dim, typename = std::enable_if_t<D == 1> >
140 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> sortPermutation)
141 {
142 QReadLocker locker{&m_Lock};
143
144 const auto &data = m_Data.at(0);
145
146 // Inits result
147 auto sortedData = QVector<double>{};
148 sortedData.resize(data.size());
149
150 std::transform(sortPermutation.cbegin(), sortPermutation.cend(), sortedData.begin(),
151 [&data](int i) { return data[i]; });
152
153 return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
154 }
155
156 template <int D = Dim, typename = std::enable_if_t<D == 1> >
104 void clear()
157 void clear()
105 {
158 {
106 QWriteLocker locker{&m_Lock};
159 QWriteLocker locker{&m_Lock};
107 m_Data.clear();
160 m_Data[0].clear();
108 }
161 }
109
162
110
163
111 private:
164 private:
112 QVector<QVector<double> > m_Data;
165 QVector<QVector<double> > m_Data;
113 mutable QReadWriteLock m_Lock;
166 mutable QReadWriteLock m_Lock;
114 };
167 };
115
168
116 #endif // SCIQLOP_ARRAYDATA_H
169 #endif // SCIQLOP_ARRAYDATA_H
@@ -1,107 +1,180
1 #ifndef SCIQLOP_DATASERIES_H
1 #ifndef SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
3
3
4 #include <Common/SortUtils.h>
5
4 #include <Data/ArrayData.h>
6 #include <Data/ArrayData.h>
5 #include <Data/IDataSeries.h>
7 #include <Data/IDataSeries.h>
6
8
7 #include <QLoggingCategory>
9 #include <QLoggingCategory>
8
10
9 #include <QReadLocker>
11 #include <QReadLocker>
10 #include <QReadWriteLock>
12 #include <QReadWriteLock>
11 #include <memory>
13 #include <memory>
12
14
13 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
14 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
15
17
16
18
17 /**
19 /**
18 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
19 *
21 *
20 * It proposes to set a dimension for the values ​​data
22 * It proposes to set a dimension for the values ​​data.
23 *
24 * A DataSeries is always sorted on its x-axis data.
21 *
25 *
22 * @tparam Dim The dimension of the values data
26 * @tparam Dim The dimension of the values data
23 *
27 *
24 */
28 */
25 template <int Dim>
29 template <int Dim>
26 class DataSeries : public IDataSeries {
30 class DataSeries : public IDataSeries {
27 public:
31 public:
28 /// @sa IDataSeries::xAxisData()
32 /// @sa IDataSeries::xAxisData()
29 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
33 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
30 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
34 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
31
35
32 /// @sa IDataSeries::xAxisUnit()
36 /// @sa IDataSeries::xAxisUnit()
33 Unit xAxisUnit() const override { return m_XAxisUnit; }
37 Unit xAxisUnit() const override { return m_XAxisUnit; }
34
38
35 /// @return the values dataset
39 /// @return the values dataset
36 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
40 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
37 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
41 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
38
42
39 /// @sa IDataSeries::valuesUnit()
43 /// @sa IDataSeries::valuesUnit()
40 Unit valuesUnit() const override { return m_ValuesUnit; }
44 Unit valuesUnit() const override { return m_ValuesUnit; }
41
45
42 void clear()
46 void clear()
43 {
47 {
44 m_XAxisData->clear();
48 m_XAxisData->clear();
45 m_ValuesData->clear();
49 m_ValuesData->clear();
46 }
50 }
47
51
48 /// @sa IDataSeries::merge()
52 /// Merges into the data series an other data series
53 /// @remarks the data series to merge with is cleared after the operation
49 void merge(IDataSeries *dataSeries) override
54 void merge(IDataSeries *dataSeries) override
50 {
55 {
51 if (auto dimDataSeries = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
56 dataSeries->lockWrite();
52 m_XAxisData->merge(*dimDataSeries->xAxisData());
57 lockWrite();
53 m_ValuesData->merge(*dimDataSeries->valuesData());
58
54 dimDataSeries->clear();
59 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
60 const auto &otherXAxisData = other->xAxisData()->cdata();
61 const auto &xAxisData = m_XAxisData->cdata();
62
63 // As data series are sorted, we can improve performances of merge, by call the sort
64 // method only if the two data series overlap.
65 if (!otherXAxisData.empty()) {
66 auto firstValue = otherXAxisData.front();
67 auto lastValue = otherXAxisData.back();
68
69 auto xAxisDataBegin = xAxisData.cbegin();
70 auto xAxisDataEnd = xAxisData.cend();
71
72 bool prepend;
73 bool sortNeeded;
74
75 if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) {
76 // Other data series if after data series
77 prepend = false;
78 sortNeeded = false;
79 }
80 else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue)
81 == xAxisDataBegin) {
82 // Other data series if before data series
83 prepend = true;
84 sortNeeded = false;
85 }
86 else {
87 // The two data series overlap
88 prepend = false;
89 sortNeeded = true;
90 }
91
92 // Makes the merge
93 m_XAxisData->add(*other->xAxisData(), prepend);
94 m_ValuesData->add(*other->valuesData(), prepend);
95
96 if (sortNeeded) {
97 sort();
98 }
99 }
100
101 // Clears the other data series
102 other->clear();
55 }
103 }
56 else {
104 else {
57 qCWarning(LOG_DataSeries())
105 qCWarning(LOG_DataSeries())
58 << QObject::tr("Dection of a type of IDataSeries we cannot merge with !");
106 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
59 }
107 }
108 unlock();
109 dataSeries->unlock();
60 }
110 }
61
111
62 virtual void lockRead() { m_Lock.lockForRead(); }
112 virtual void lockRead() { m_Lock.lockForRead(); }
63 virtual void lockWrite() { m_Lock.lockForWrite(); }
113 virtual void lockWrite() { m_Lock.lockForWrite(); }
64 virtual void unlock() { m_Lock.unlock(); }
114 virtual void unlock() { m_Lock.unlock(); }
65
115
66 protected:
116 protected:
67 /// Protected ctor (DataSeries is abstract)
117 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
118 /// DataSeries with no values will be created.
119 /// @remarks data series is automatically sorted on its x-axis data
68 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
120 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
69 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
121 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
70 : m_XAxisData{xAxisData},
122 : m_XAxisData{xAxisData},
71 m_XAxisUnit{xAxisUnit},
123 m_XAxisUnit{xAxisUnit},
72 m_ValuesData{valuesData},
124 m_ValuesData{valuesData},
73 m_ValuesUnit{valuesUnit}
125 m_ValuesUnit{valuesUnit}
74 {
126 {
127 if (m_XAxisData->size() != m_ValuesData->size()) {
128 clear();
129 }
130
131 // Sorts data if it's not the case
132 const auto &xAxisCData = m_XAxisData->cdata();
133 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
134 sort();
135 }
75 }
136 }
76
137
77 /// Copy ctor
138 /// Copy ctor
78 explicit DataSeries(const DataSeries<Dim> &other)
139 explicit DataSeries(const DataSeries<Dim> &other)
79 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
140 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
80 m_XAxisUnit{other.m_XAxisUnit},
141 m_XAxisUnit{other.m_XAxisUnit},
81 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
142 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
82 m_ValuesUnit{other.m_ValuesUnit}
143 m_ValuesUnit{other.m_ValuesUnit}
83 {
144 {
145 // Since a series is ordered from its construction and is always ordered, it is not
146 // necessary to call the sort method here ('other' is sorted)
84 }
147 }
85
148
86 /// Assignment operator
149 /// Assignment operator
87 template <int D>
150 template <int D>
88 DataSeries &operator=(DataSeries<D> other)
151 DataSeries &operator=(DataSeries<D> other)
89 {
152 {
90 std::swap(m_XAxisData, other.m_XAxisData);
153 std::swap(m_XAxisData, other.m_XAxisData);
91 std::swap(m_XAxisUnit, other.m_XAxisUnit);
154 std::swap(m_XAxisUnit, other.m_XAxisUnit);
92 std::swap(m_ValuesData, other.m_ValuesData);
155 std::swap(m_ValuesData, other.m_ValuesData);
93 std::swap(m_ValuesUnit, other.m_ValuesUnit);
156 std::swap(m_ValuesUnit, other.m_ValuesUnit);
94
157
95 return *this;
158 return *this;
96 }
159 }
97
160
98 private:
161 private:
162 /**
163 * Sorts data series on its x-axis data
164 */
165 void sort() noexcept
166 {
167 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
168 m_XAxisData = m_XAxisData->sort(permutation);
169 m_ValuesData = m_ValuesData->sort(permutation);
170 }
171
99 std::shared_ptr<ArrayData<1> > m_XAxisData;
172 std::shared_ptr<ArrayData<1> > m_XAxisData;
100 Unit m_XAxisUnit;
173 Unit m_XAxisUnit;
101 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
174 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
102 Unit m_ValuesUnit;
175 Unit m_ValuesUnit;
103
176
104 QReadWriteLock m_Lock;
177 QReadWriteLock m_Lock;
105 };
178 };
106
179
107 #endif // SCIQLOP_DATASERIES_H
180 #endif // SCIQLOP_DATASERIES_H
@@ -1,39 +1,23
1 #ifndef SCIQLOP_SCALARSERIES_H
1 #ifndef SCIQLOP_SCALARSERIES_H
2 #define SCIQLOP_SCALARSERIES_H
2 #define SCIQLOP_SCALARSERIES_H
3
3
4 #include <Data/DataSeries.h>
4 #include <Data/DataSeries.h>
5
5
6 /**
6 /**
7 * @brief The ScalarSeries class is the implementation for a data series representing a scalar.
7 * @brief The ScalarSeries class is the implementation for a data series representing a scalar.
8 */
8 */
9 class ScalarSeries : public DataSeries<1> {
9 class ScalarSeries : public DataSeries<1> {
10 public:
10 public:
11 /**
11 /**
12 * Ctor
13 * @param size the number of data the series will hold
14 * @param xAxisUnit x-axis unit
15 * @param valuesUnit values unit
16 */
17 explicit ScalarSeries(int size, const Unit &xAxisUnit, const Unit &valuesUnit);
18
19 /**
20 * Ctor with two vectors. The vectors must have the same size, otherwise a ScalarSeries with no
12 * Ctor with two vectors. The vectors must have the same size, otherwise a ScalarSeries with no
21 * values will be created.
13 * values will be created.
22 * @param xAxisData x-axis data
14 * @param xAxisData x-axis data
23 * @param valuesData values data
15 * @param valuesData values data
24 */
16 */
25 explicit ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
17 explicit ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
26 const Unit &xAxisUnit, const Unit &valuesUnit);
18 const Unit &xAxisUnit, const Unit &valuesUnit);
27
19
28 /**
29 * Sets data for a specific index. The index has to be valid to be effective
30 * @param index the index to which the data will be set
31 * @param x the x-axis data
32 * @param value the value data
33 */
34 void setData(int index, double x, double value) noexcept;
35
36 std::unique_ptr<IDataSeries> clone() const;
20 std::unique_ptr<IDataSeries> clone() const;
37 };
21 };
38
22
39 #endif // SCIQLOP_SCALARSERIES_H
23 #endif // SCIQLOP_SCALARSERIES_H
@@ -1,25 +1,13
1 #include <Data/ScalarSeries.h>
1 #include <Data/ScalarSeries.h>
2
2
3 ScalarSeries::ScalarSeries(int size, const Unit &xAxisUnit, const Unit &valuesUnit)
4 : DataSeries{std::make_shared<ArrayData<1> >(size), xAxisUnit,
5 std::make_shared<ArrayData<1> >(size), valuesUnit}
6 {
7 }
8
9 ScalarSeries::ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
3 ScalarSeries::ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
10 const Unit &xAxisUnit, const Unit &valuesUnit)
4 const Unit &xAxisUnit, const Unit &valuesUnit)
11 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
5 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
12 std::make_shared<ArrayData<1> >(std::move(valuesData)), valuesUnit}
6 std::make_shared<ArrayData<1> >(std::move(valuesData)), valuesUnit}
13 {
7 {
14 }
8 }
15
9
16 void ScalarSeries::setData(int index, double x, double value) noexcept
17 {
18 xAxisData()->setData(index, x);
19 valuesData()->setData(index, value);
20 }
21
22 std::unique_ptr<IDataSeries> ScalarSeries::clone() const
10 std::unique_ptr<IDataSeries> ScalarSeries::clone() const
23 {
11 {
24 return std::make_unique<ScalarSeries>(*this);
12 return std::make_unique<ScalarSeries>(*this);
25 }
13 }
@@ -1,90 +1,86
1 #include "Variable/Variable.h"
1 #include "Variable/Variable.h"
2
2
3 #include <Data/IDataSeries.h>
3 #include <Data/IDataSeries.h>
4 #include <Data/SqpDateTime.h>
4 #include <Data/SqpDateTime.h>
5
5
6 #include <QReadWriteLock>
6 #include <QReadWriteLock>
7 #include <QThread>
7 #include <QThread>
8
8
9 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
9 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
10
10
11 struct Variable::VariablePrivate {
11 struct Variable::VariablePrivate {
12 explicit VariablePrivate(const QString &name, const SqpDateTime &dateTime,
12 explicit VariablePrivate(const QString &name, const SqpDateTime &dateTime,
13 const QVariantHash &metadata)
13 const QVariantHash &metadata)
14 : m_Name{name}, m_DateTime{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
14 : m_Name{name}, m_DateTime{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
15 {
15 {
16 }
16 }
17
17
18 QString m_Name;
18 QString m_Name;
19
19
20 SqpDateTime m_DateTime; // The dateTime available in the view and loaded. not the cache.
20 SqpDateTime m_DateTime; // The dateTime available in the view and loaded. not the cache.
21 QVariantHash m_Metadata;
21 QVariantHash m_Metadata;
22 std::unique_ptr<IDataSeries> m_DataSeries;
22 std::unique_ptr<IDataSeries> m_DataSeries;
23 };
23 };
24
24
25 Variable::Variable(const QString &name, const SqpDateTime &dateTime, const QVariantHash &metadata)
25 Variable::Variable(const QString &name, const SqpDateTime &dateTime, const QVariantHash &metadata)
26 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
26 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
27 {
27 {
28 }
28 }
29
29
30 QString Variable::name() const noexcept
30 QString Variable::name() const noexcept
31 {
31 {
32 return impl->m_Name;
32 return impl->m_Name;
33 }
33 }
34
34
35 SqpDateTime Variable::dateTime() const noexcept
35 SqpDateTime Variable::dateTime() const noexcept
36 {
36 {
37 return impl->m_DateTime;
37 return impl->m_DateTime;
38 }
38 }
39
39
40 void Variable::setDateTime(const SqpDateTime &dateTime) noexcept
40 void Variable::setDateTime(const SqpDateTime &dateTime) noexcept
41 {
41 {
42 impl->m_DateTime = dateTime;
42 impl->m_DateTime = dateTime;
43 }
43 }
44
44
45 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
45 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
46 {
46 {
47 qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName();
47 qCDebug(LOG_Variable()) << "Variable::setDataSeries" << QThread::currentThread()->objectName();
48 if (!dataSeries) {
48 if (!dataSeries) {
49 /// @todo ALX : log
49 /// @todo ALX : log
50 return;
50 return;
51 }
51 }
52
52
53 // Inits the data series of the variable
53 // Inits the data series of the variable
54 if (!impl->m_DataSeries) {
54 if (!impl->m_DataSeries) {
55 impl->m_DataSeries = dataSeries->clone();
55 impl->m_DataSeries = dataSeries->clone();
56 }
56 }
57 else {
57 else {
58 dataSeries->lockWrite();
59 impl->m_DataSeries->lockWrite();
60 impl->m_DataSeries->merge(dataSeries.get());
58 impl->m_DataSeries->merge(dataSeries.get());
61 impl->m_DataSeries->unlock();
62 dataSeries->unlock();
63 // emit updated();
59 // emit updated();
64 }
60 }
65 }
61 }
66
62
67 IDataSeries *Variable::dataSeries() const noexcept
63 IDataSeries *Variable::dataSeries() const noexcept
68 {
64 {
69 return impl->m_DataSeries.get();
65 return impl->m_DataSeries.get();
70 }
66 }
71
67
72 QVariantHash Variable::metadata() const noexcept
68 QVariantHash Variable::metadata() const noexcept
73 {
69 {
74 return impl->m_Metadata;
70 return impl->m_Metadata;
75 }
71 }
76
72
77 bool Variable::contains(const SqpDateTime &dateTime) const noexcept
73 bool Variable::contains(const SqpDateTime &dateTime) const noexcept
78 {
74 {
79 return impl->m_DateTime.contains(dateTime);
75 return impl->m_DateTime.contains(dateTime);
80 }
76 }
81
77
82 bool Variable::intersect(const SqpDateTime &dateTime) const noexcept
78 bool Variable::intersect(const SqpDateTime &dateTime) const noexcept
83 {
79 {
84 return impl->m_DateTime.intersect(dateTime);
80 return impl->m_DateTime.intersect(dateTime);
85 }
81 }
86
82
87 bool Variable::isInside(const SqpDateTime &dateTime) const noexcept
83 bool Variable::isInside(const SqpDateTime &dateTime) const noexcept
88 {
84 {
89 return dateTime.contains(SqpDateTime{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
85 return dateTime.contains(SqpDateTime{impl->m_DateTime.m_TStart, impl->m_DateTime.m_TEnd});
90 }
86 }
@@ -1,159 +1,161
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7
7
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
8 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
9
9
10 namespace {
10 namespace {
11
11
12 class SqpDataContainer : public QCPGraphDataContainer {
12 class SqpDataContainer : public QCPGraphDataContainer {
13 public:
13 public:
14 void appendGraphDataUnsorted(const QCPGraphData &data) { mData.append(data); }
14 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
15 };
15 };
16
16
17
17
18 /// Format for datetimes on a axis
18 /// Format for datetimes on a axis
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20
20
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
21 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
22 /// non-time data
22 /// non-time data
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
23 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
24 {
24 {
25 if (isTimeAxis) {
25 if (isTimeAxis) {
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
26 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
27 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
28
28
29 return dateTicker;
29 return dateTicker;
30 }
30 }
31 else {
31 else {
32 // default ticker
32 // default ticker
33 return QSharedPointer<QCPAxisTicker>::create();
33 return QSharedPointer<QCPAxisTicker>::create();
34 }
34 }
35 }
35 }
36
36
37 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
37 void updateScalarData(QCPAbstractPlottable *component, ScalarSeries &scalarSeries,
38 const SqpDateTime &dateTime)
38 const SqpDateTime &dateTime)
39 {
39 {
40 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
40 qCDebug(LOG_VisualizationGraphHelper()) << "TORM: updateScalarData"
41 << QThread::currentThread()->objectName();
41 << QThread::currentThread()->objectName();
42 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
42 if (auto qcpGraph = dynamic_cast<QCPGraph *>(component)) {
43 // Clean the graph
44 // NAIVE approch
45 scalarSeries.lockRead();
43 scalarSeries.lockRead();
46 {
44 {
47 const auto xData = scalarSeries.xAxisData()->data();
45 const auto &xData = scalarSeries.xAxisData()->cdata();
48 const auto valuesData = scalarSeries.valuesData()->data();
46 const auto &valuesData = scalarSeries.valuesData()->cdata();
49 const auto count = xData.count();
47
50 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points in cache"
48 auto xDataBegin = xData.cbegin();
51 << xData.count();
49 auto xDataEnd = xData.cend();
52
50
53 auto dataContainer = qcpGraph->data();
51 qCInfo(LOG_VisualizationGraphHelper())
54 dataContainer->clear();
52 << "TORM: Current points in cache" << xData.count();
53
55 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
54 auto sqpDataContainer = QSharedPointer<SqpDataContainer>::create();
56 qcpGraph->setData(sqpDataContainer);
55 qcpGraph->setData(sqpDataContainer);
57
56
58 for (auto i = 0; i < count; ++i) {
57 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, dateTime.m_TStart);
59 const auto x = xData[i];
58 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, dateTime.m_TEnd);
60 if (x >= dateTime.m_TStart && x <= dateTime.m_TEnd) {
59 auto distance = std::distance(xDataBegin, lowerIt);
61 sqpDataContainer->appendGraphDataUnsorted(QCPGraphData(x, valuesData[i]));
60
62 }
61 auto valuesDataIt = valuesData.cbegin() + distance;
62 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt;
63 ++xAxisDataIt, ++valuesDataIt) {
64 sqpDataContainer->appendGraphData(QCPGraphData(*xAxisDataIt, *valuesDataIt));
63 }
65 }
64 sqpDataContainer->sort();
66
65 qCInfo(LOG_VisualizationGraphHelper()) << "TORM: Current points displayed"
67 qCInfo(LOG_VisualizationGraphHelper())
66 << sqpDataContainer->size();
68 << "TORM: Current points displayed" << sqpDataContainer->size();
67 }
69 }
68 scalarSeries.unlock();
70 scalarSeries.unlock();
69
71
70
72
71 // Display all data
73 // Display all data
72 component->parentPlot()->replot();
74 component->parentPlot()->replot();
73 }
75 }
74 else {
76 else {
75 /// @todo DEBUG
77 /// @todo DEBUG
76 }
78 }
77 }
79 }
78
80
79 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
81 QCPAbstractPlottable *createScalarSeriesComponent(ScalarSeries &scalarSeries, QCustomPlot &plot,
80 const SqpDateTime &dateTime)
82 const SqpDateTime &dateTime)
81 {
83 {
82 auto component = plot.addGraph();
84 auto component = plot.addGraph();
83
85
84 if (component) {
86 if (component) {
85 // // Graph data
87 // // Graph data
86 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
88 component->setData(scalarSeries.xAxisData()->data(), scalarSeries.valuesData()->data(),
87 true);
89 true);
88
90
89 updateScalarData(component, scalarSeries, dateTime);
91 updateScalarData(component, scalarSeries, dateTime);
90
92
91 // Axes properties
93 // Axes properties
92 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
94 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
93 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
95 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
94
96
95 auto setAxisProperties = [](auto axis, const auto &unit) {
97 auto setAxisProperties = [](auto axis, const auto &unit) {
96 // label (unit name)
98 // label (unit name)
97 axis->setLabel(unit.m_Name);
99 axis->setLabel(unit.m_Name);
98
100
99 // ticker (depending on the type of unit)
101 // ticker (depending on the type of unit)
100 axis->setTicker(axisTicker(unit.m_TimeUnit));
102 axis->setTicker(axisTicker(unit.m_TimeUnit));
101 };
103 };
102 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
104 setAxisProperties(plot.xAxis, scalarSeries.xAxisUnit());
103 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
105 setAxisProperties(plot.yAxis, scalarSeries.valuesUnit());
104
106
105 // Display all data
107 // Display all data
106 component->rescaleAxes();
108 component->rescaleAxes();
107 plot.replot();
109 plot.replot();
108 }
110 }
109 else {
111 else {
110 qCDebug(LOG_VisualizationGraphHelper())
112 qCDebug(LOG_VisualizationGraphHelper())
111 << QObject::tr("Can't create graph for the scalar series");
113 << QObject::tr("Can't create graph for the scalar series");
112 }
114 }
113
115
114 return component;
116 return component;
115 }
117 }
116
118
117 } // namespace
119 } // namespace
118
120
119 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
121 QVector<QCPAbstractPlottable *> VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
120 QCustomPlot &plot) noexcept
122 QCustomPlot &plot) noexcept
121 {
123 {
122 auto result = QVector<QCPAbstractPlottable *>{};
124 auto result = QVector<QCPAbstractPlottable *>{};
123
125
124 if (variable) {
126 if (variable) {
125 // Gets the data series of the variable to call the creation of the right components
127 // Gets the data series of the variable to call the creation of the right components
126 // according to its type
128 // according to its type
127 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
129 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(variable->dataSeries())) {
128 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
130 result.append(createScalarSeriesComponent(*scalarSeries, plot, variable->dateTime()));
129 }
131 }
130 else {
132 else {
131 qCDebug(LOG_VisualizationGraphHelper())
133 qCDebug(LOG_VisualizationGraphHelper())
132 << QObject::tr("Can't create graph plottables : unmanaged data series type");
134 << QObject::tr("Can't create graph plottables : unmanaged data series type");
133 }
135 }
134 }
136 }
135 else {
137 else {
136 qCDebug(LOG_VisualizationGraphHelper())
138 qCDebug(LOG_VisualizationGraphHelper())
137 << QObject::tr("Can't create graph plottables : the variable is null");
139 << QObject::tr("Can't create graph plottables : the variable is null");
138 }
140 }
139
141
140 return result;
142 return result;
141 }
143 }
142
144
143 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
145 void VisualizationGraphHelper::updateData(QVector<QCPAbstractPlottable *> plotableVect,
144 IDataSeries *dataSeries, const SqpDateTime &dateTime)
146 IDataSeries *dataSeries, const SqpDateTime &dateTime)
145 {
147 {
146 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
148 if (auto scalarSeries = dynamic_cast<ScalarSeries *>(dataSeries)) {
147 if (plotableVect.size() == 1) {
149 if (plotableVect.size() == 1) {
148 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
150 updateScalarData(plotableVect.at(0), *scalarSeries, dateTime);
149 }
151 }
150 else {
152 else {
151 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
153 qCCritical(LOG_VisualizationGraphHelper()) << QObject::tr(
152 "Can't update Data of a scalarSeries because there is not only one component "
154 "Can't update Data of a scalarSeries because there is not only one component "
153 "associated");
155 "associated");
154 }
156 }
155 }
157 }
156 else {
158 else {
157 /// @todo DEBUG
159 /// @todo DEBUG
158 }
160 }
159 }
161 }
@@ -1,95 +1,101
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2
2
3 #include <Data/DataProviderParameters.h>
3 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <cmath>
6 #include <cmath>
7
7
8 #include <QDateTime>
8 #include <QDateTime>
9 #include <QFuture>
9 #include <QFuture>
10 #include <QThread>
10 #include <QThread>
11 #include <QtConcurrent/QtConcurrent>
11 #include <QtConcurrent/QtConcurrent>
12
12
13 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
14
14
15 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpDateTime &dateTime)
15 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid token, const SqpDateTime &dateTime)
16 {
16 {
17 // TODO: Add Mutex
17 // TODO: Add Mutex
18 auto dataIndex = 0;
18 auto dataIndex = 0;
19
19
20 // Gets the timerange from the parameters
20 // Gets the timerange from the parameters
21 double freq = 100.0;
21 double freq = 100.0;
22 double start = dateTime.m_TStart * freq; // 100 htz
22 double start = std::ceil(dateTime.m_TStart * freq); // 100 htz
23 double end = dateTime.m_TEnd * freq; // 100 htz
23 double end = std::floor(dateTime.m_TEnd * freq); // 100 htz
24
24
25 // We assure that timerange is valid
25 // We assure that timerange is valid
26 if (end < start) {
26 if (end < start) {
27 std::swap(start, end);
27 std::swap(start, end);
28 }
28 }
29
29
30 // Generates scalar series containing cosinus values (one value per second)
30 // Generates scalar series containing cosinus values (one value per second)
31 auto scalarSeries
31 auto dataCount = end - start;
32 = std::make_shared<ScalarSeries>(end - start, Unit{QStringLiteral("t"), true}, Unit{});
33
32
33 auto xAxisData = QVector<double>{};
34 xAxisData.resize(dataCount);
35
36 auto valuesData = QVector<double>{};
37 valuesData.resize(dataCount);
34
38
35 int progress = 0;
39 int progress = 0;
36 auto progressEnd = end - start;
40 auto progressEnd = dataCount;
37 for (auto time = start; time < end; ++time, ++dataIndex) {
41 for (auto time = start; time < end; ++time, ++dataIndex) {
38 auto it = m_VariableToEnableProvider.find(token);
42 auto it = m_VariableToEnableProvider.find(token);
39 if (it != m_VariableToEnableProvider.end() && it.value()) {
43 if (it != m_VariableToEnableProvider.end() && it.value()) {
40 const auto timeOnFreq = time / freq;
44 const auto timeOnFreq = time / freq;
41 scalarSeries->setData(dataIndex, timeOnFreq, std::cos(timeOnFreq));
45
46 xAxisData.replace(dataIndex, timeOnFreq);
47 valuesData.replace(dataIndex, std::cos(timeOnFreq));
42
48
43 // progression
49 // progression
44 int currentProgress = (time - start) * 100.0 / progressEnd;
50 int currentProgress = (time - start) * 100.0 / progressEnd;
45 if (currentProgress != progress) {
51 if (currentProgress != progress) {
46 progress = currentProgress;
52 progress = currentProgress;
47
53
48 emit dataProvidedProgress(token, progress);
54 emit dataProvidedProgress(token, progress);
49 }
55 }
50 }
56 }
51 else {
57 else {
52 if (!it.value()) {
58 if (!it.value()) {
53 qCDebug(LOG_CosinusProvider())
59 qCDebug(LOG_CosinusProvider())
54 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
60 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
55 << end - time;
61 << end - time;
56 }
62 }
57 }
63 }
58 }
64 }
59 emit dataProvidedProgress(token, 0.0);
65 emit dataProvidedProgress(token, 0.0);
60
66
61
67 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
62 return scalarSeries;
68 Unit{QStringLiteral("t"), true}, Unit{});
63 }
69 }
64
70
65 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
71 void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParameters &parameters)
66 {
72 {
67 // TODO: Add Mutex
73 // TODO: Add Mutex
68 m_VariableToEnableProvider[token] = true;
74 m_VariableToEnableProvider[token] = true;
69 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
75 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataLoading"
70 << QThread::currentThread()->objectName();
76 << QThread::currentThread()->objectName();
71 // NOTE: Try to use multithread if possible
77 // NOTE: Try to use multithread if possible
72 const auto times = parameters.m_Times;
78 const auto times = parameters.m_Times;
73
79
74 for (const auto &dateTime : qAsConst(times)) {
80 for (const auto &dateTime : qAsConst(times)) {
75 if (m_VariableToEnableProvider[token]) {
81 if (m_VariableToEnableProvider[token]) {
76 auto scalarSeries = this->retrieveData(token, dateTime);
82 auto scalarSeries = this->retrieveData(token, dateTime);
77 emit dataProvided(token, scalarSeries, dateTime);
83 emit dataProvided(token, scalarSeries, dateTime);
78 }
84 }
79 }
85 }
80 }
86 }
81
87
82 void CosinusProvider::requestDataAborting(QUuid identifier)
88 void CosinusProvider::requestDataAborting(QUuid identifier)
83 {
89 {
84 // TODO: Add Mutex
90 // TODO: Add Mutex
85 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << identifier
91 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << identifier
86 << QThread::currentThread()->objectName();
92 << QThread::currentThread()->objectName();
87 auto it = m_VariableToEnableProvider.find(identifier);
93 auto it = m_VariableToEnableProvider.find(identifier);
88 if (it != m_VariableToEnableProvider.end()) {
94 if (it != m_VariableToEnableProvider.end()) {
89 it.value() = false;
95 it.value() = false;
90 }
96 }
91 else {
97 else {
92 qCWarning(LOG_CosinusProvider())
98 qCWarning(LOG_CosinusProvider())
93 << tr("Aborting progression of inexistant identifier detected !!!");
99 << tr("Aborting progression of inexistant identifier detected !!!");
94 }
100 }
95 }
101 }
General Comments 0
You need to be logged in to leave comments. Login now