##// END OF EJS Templates
Merge branch 'feature/ValueRange' into develop
Alexandre Leroux -
r614:d53842017d03 merge
parent child
Show More
@@ -59,6 +59,58 struct SortUtils {
59
59
60 return sortedData;
60 return sortedData;
61 }
61 }
62
63 /**
64 * Compares two values that can be NaN. This method is intended to be used as a compare function
65 * for searching min value by excluding NaN values.
66 *
67 * Examples of use:
68 * - f({1, 3, 2, 4, 5}) will return 1
69 * - f({NaN, 3, 2, 4, 5}) will return 2 (NaN is excluded)
70 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
71 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
72 *
73 * @param v1 first value
74 * @param v2 second value
75 * @return true if v1 < v2, false otherwise
76 * @sa std::min_element
77 */
78 template <typename T>
79 static bool minCompareWithNaN(const T &v1, const T &v2)
80 {
81 // Table used with NaN values:
82 // NaN < v2 -> false
83 // v1 < NaN -> true
84 // NaN < NaN -> false
85 // v1 < v2 -> v1 < v2
86 return std::isnan(v1) ? false : std::isnan(v2) || (v1 < v2);
87 }
88
89 /**
90 * Compares two values that can be NaN. This method is intended to be used as a compare function
91 * for searching max value by excluding NaN values.
92 *
93 * Examples of use:
94 * - f({1, 3, 2, 4, 5}) will return 5
95 * - f({1, 3, 2, 4, NaN}) will return 4 (NaN is excluded)
96 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
97 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
98 *
99 * @param v1 first value
100 * @param v2 second value
101 * @return true if v1 < v2, false otherwise
102 * @sa std::max_element
103 */
104 template <typename T>
105 static bool maxCompareWithNaN(const T &v1, const T &v2)
106 {
107 // Table used with NaN values:
108 // NaN < v2 -> true
109 // v1 < NaN -> false
110 // NaN < NaN -> false
111 // v1 < v2 -> v1 < v2
112 return std::isnan(v1) ? true : !std::isnan(v2) && (v1 < v2);
113 }
62 };
114 };
63
115
64 #endif // SCIQLOP_SORTUTILS_H
116 #endif // SCIQLOP_SORTUTILS_H
@@ -70,6 +70,26 public:
70 double at(int index) const { return *m_Its.at(index); }
70 double at(int index) const { return *m_Its.at(index); }
71 double first() const { return *m_Its.front(); }
71 double first() const { return *m_Its.front(); }
72
72
73 /// @return the min value among all components
74 double min() const
75 {
76 auto end = m_Its.cend();
77 auto it = std::min_element(m_Its.cbegin(), end, [](const auto &it1, const auto &it2) {
78 return SortUtils::minCompareWithNaN(*it1, *it2);
79 });
80 return it != end ? **it : std::numeric_limits<double>::quiet_NaN();
81 }
82
83 /// @return the max value among all components
84 double max() const
85 {
86 auto end = m_Its.cend();
87 auto it = std::max_element(m_Its.cbegin(), end, [](const auto &it1, const auto &it2) {
88 return SortUtils::maxCompareWithNaN(*it1, *it2);
89 });
90 return it != end ? **it : std::numeric_limits<double>::quiet_NaN();
91 }
92
73 void next()
93 void next()
74 {
94 {
75 for (auto &it : m_Its) {
95 for (auto &it : m_Its) {
@@ -65,6 +65,8 public:
65 double x() const override { return m_XIt->at(0); }
65 double x() const override { return m_XIt->at(0); }
66 double value() const override { return m_ValuesIt->at(0); }
66 double value() const override { return m_ValuesIt->at(0); }
67 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
67 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
68 double minValue() const override { return m_ValuesIt->min(); }
69 double maxValue() const override { return m_ValuesIt->max(); }
68
70
69 private:
71 private:
70 ArrayData<1>::Iterator m_XIt;
72 ArrayData<1>::Iterator m_XIt;
@@ -191,16 +193,16 public:
191 std::make_unique<dataseries_detail::IteratorValue<Dim> >(*this, false)}};
193 std::make_unique<dataseries_detail::IteratorValue<Dim> >(*this, false)}};
192 }
194 }
193
195
194 /// @sa IDataSeries::minData()
196 /// @sa IDataSeries::minXAxisData()
195 DataSeriesIterator minData(double minXAxisData) const override
197 DataSeriesIterator minXAxisData(double minXAxisData) const override
196 {
198 {
197 return std::lower_bound(
199 return std::lower_bound(
198 cbegin(), cend(), minXAxisData,
200 cbegin(), cend(), minXAxisData,
199 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
201 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
200 }
202 }
201
203
202 /// @sa IDataSeries::maxData()
204 /// @sa IDataSeries::maxXAxisData()
203 DataSeriesIterator maxData(double maxXAxisData) const override
205 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
204 {
206 {
205 // Gets the first element that greater than max value
207 // Gets the first element that greater than max value
206 auto it = std::upper_bound(
208 auto it = std::upper_bound(
@@ -210,27 +212,52 public:
210 return it == cbegin() ? cend() : --it;
212 return it == cbegin() ? cend() : --it;
211 }
213 }
212
214
213 std::pair<DataSeriesIterator, DataSeriesIterator> subData(double min, double max) const override
215 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
216 double maxXAxisData) const override
214 {
217 {
215 if (min > max) {
218 if (minXAxisData > maxXAxisData) {
216 std::swap(min, max);
219 std::swap(minXAxisData, maxXAxisData);
217 }
220 }
218
221
219 auto begin = cbegin();
222 auto begin = cbegin();
220 auto end = cend();
223 auto end = cend();
221
224
222 auto lowerIt
225 auto lowerIt = std::lower_bound(
223 = std::lower_bound(begin, end, min, [](const auto &itValue, const auto &value) {
226 begin, end, minXAxisData,
224 return itValue.x() < value;
227 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
225 });
228 auto upperIt = std::upper_bound(
226 auto upperIt
229 begin, end, maxXAxisData,
227 = std::upper_bound(begin, end, max, [](const auto &value, const auto &itValue) {
230 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
228 return value < itValue.x();
229 });
230
231
231 return std::make_pair(lowerIt, upperIt);
232 return std::make_pair(lowerIt, upperIt);
232 }
233 }
233
234
235 std::pair<DataSeriesIterator, DataSeriesIterator>
236 valuesBounds(double minXAxisData, double maxXAxisData) const override
237 {
238 // Places iterators to the correct x-axis range
239 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
240
241 // Returns end iterators if the range is empty
242 if (xAxisRangeIts.first == xAxisRangeIts.second) {
243 return std::make_pair(cend(), cend());
244 }
245
246 // Gets the iterator on the min of all values data
247 auto minIt = std::min_element(
248 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
249 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
250 });
251
252 // Gets the iterator on the max of all values data
253 auto maxIt = std::max_element(
254 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
255 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
256 });
257
258 return std::make_pair(minIt, maxIt);
259 }
260
234 // /////// //
261 // /////// //
235 // Mutexes //
262 // Mutexes //
236 // /////// //
263 // /////// //
@@ -24,6 +24,8 public:
24 virtual double x() const = 0;
24 virtual double x() const = 0;
25 virtual double value() const = 0;
25 virtual double value() const = 0;
26 virtual double value(int componentIndex) const = 0;
26 virtual double value(int componentIndex) const = 0;
27 virtual double minValue() const = 0;
28 virtual double maxValue() const = 0;
27 };
29 };
28
30
29 explicit DataSeriesIteratorValue(std::unique_ptr<Impl> impl);
31 explicit DataSeriesIteratorValue(std::unique_ptr<Impl> impl);
@@ -43,6 +45,10 public:
43 double value() const;
45 double value() const;
44 /// Gets value data depending on an index
46 /// Gets value data depending on an index
45 double value(int componentIndex) const;
47 double value(int componentIndex) const;
48 /// Gets min of all values data
49 double minValue() const;
50 /// Gets max of all values data
51 double maxValue() const;
46
52
47 private:
53 private:
48 std::unique_ptr<Impl> m_Impl;
54 std::unique_ptr<Impl> m_Impl;
@@ -72,14 +72,22 public:
72
72
73 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
73 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
74 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
74 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
75 virtual DataSeriesIterator minData(double minXAxisData) const = 0;
75 virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0;
76
76
77 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
77 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
78 /// equal to the value passed in parameter, or the end iterator if there is no matching value
78 /// equal to the value passed in parameter, or the end iterator if there is no matching value
79 virtual DataSeriesIterator maxData(double maxXAxisData) const = 0;
79 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
80
80
81 virtual std::pair<DataSeriesIterator, DataSeriesIterator> subData(double min,
81 /// @return the iterators pointing to the range of data whose x-axis values are between min and
82 double max) const = 0;
82 /// max passed in parameters
83 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
84 xAxisRange(double minXAxisData, double maxXAxisData) const = 0;
85
86 /// @return two iterators pointing to the data that have respectively the min and the max value
87 /// data of a data series' range. The search is performed for a given x-axis range.
88 /// @sa xAxisRange()
89 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
90 valuesBounds(double minXAxisData, double maxXAxisData) const = 0;
83
91
84 // /////// //
92 // /////// //
85 // Mutexes //
93 // Mutexes //
@@ -47,6 +47,16 double DataSeriesIteratorValue::value(int componentIndex) const
47 return m_Impl->value(componentIndex);
47 return m_Impl->value(componentIndex);
48 }
48 }
49
49
50 double DataSeriesIteratorValue::minValue() const
51 {
52 return m_Impl->minValue();
53 }
54
55 double DataSeriesIteratorValue::maxValue() const
56 {
57 return m_Impl->maxValue();
58 }
59
50 DataSeriesIterator::DataSeriesIterator(DataSeriesIteratorValue value)
60 DataSeriesIterator::DataSeriesIterator(DataSeriesIteratorValue value)
51 : m_CurrentValue{std::move(value)}
61 : m_CurrentValue{std::move(value)}
52 {
62 {
@@ -18,7 +18,7 std::shared_ptr<IDataSeries> ScalarSeries::subDataSeries(const SqpRange &range)
18 auto subValuesData = QVector<double>();
18 auto subValuesData = QVector<double>();
19 this->lockRead();
19 this->lockRead();
20 {
20 {
21 auto bounds = subData(range.m_TStart, range.m_TEnd);
21 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
22 for (auto it = bounds.first; it != bounds.second; ++it) {
22 for (auto it = bounds.first; it != bounds.second; ++it) {
23 subXAxisData.append(it->x());
23 subXAxisData.append(it->x());
24 subValuesData.append(it->value());
24 subValuesData.append(it->value());
@@ -24,7 +24,7 std::shared_ptr<IDataSeries> VectorSeries::subDataSeries(const SqpRange &range)
24
24
25 this->lockRead();
25 this->lockRead();
26 {
26 {
27 auto bounds = subData(range.m_TStart, range.m_TEnd);
27 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
28 for (auto it = bounds.first; it != bounds.second; ++it) {
28 for (auto it = bounds.first; it != bounds.second; ++it) {
29 subXAxisData.append(it->x());
29 subXAxisData.append(it->x());
30 subXValuesData.append(it->value(0));
30 subXValuesData.append(it->value(0));
@@ -174,11 +174,11 QVariant VariableModel::data(const QModelIndex &index, int role) const
174 case TSTART_COLUMN:
174 case TSTART_COLUMN:
175 // Shows the min value of the data series above the range tstart
175 // Shows the min value of the data series above the range tstart
176 return dateTimeVariant([min = variable->range().m_TStart](
176 return dateTimeVariant([min = variable->range().m_TStart](
177 const auto &dataSeries) { return dataSeries.minData(min); });
177 const auto &dataSeries) { return dataSeries.minXAxisData(min); });
178 case TEND_COLUMN:
178 case TEND_COLUMN:
179 // Shows the max value of the data series under the range tend
179 // Shows the max value of the data series under the range tend
180 return dateTimeVariant([max = variable->range().m_TEnd](
180 return dateTimeVariant([max = variable->range().m_TEnd](
181 const auto &dataSeries) { return dataSeries.maxData(max); });
181 const auto &dataSeries) { return dataSeries.maxXAxisData(max); });
182 case UNIT_COLUMN:
182 case UNIT_COLUMN:
183 return variable->metadata().value(QStringLiteral("units"));
183 return variable->metadata().value(QStringLiteral("units"));
184 case MISSION_COLUMN:
184 case MISSION_COLUMN:
@@ -1,13 +1,64
1 #include "Data/DataSeries.h"
1 #include "Data/DataSeries.h"
2 #include "Data/ScalarSeries.h"
2 #include "Data/ScalarSeries.h"
3 #include "Data/VectorSeries.h"
3
4
4 #include <QObject>
5 #include <QObject>
5 #include <QtTest>
6 #include <QtTest>
6
7
7 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
8 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
9 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
8
10
9 class TestDataSeries : public QObject {
11 class TestDataSeries : public QObject {
10 Q_OBJECT
12 Q_OBJECT
13 private:
14 template <typename T>
15 void testValuesBoundsStructure()
16 {
17 // ////////////// //
18 // Test structure //
19 // ////////////// //
20
21 // Data series to get values bounds
22 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
23
24 // x-axis range
25 QTest::addColumn<double>("minXAxis");
26 QTest::addColumn<double>("maxXAxis");
27
28 // Expected results
29 QTest::addColumn<bool>(
30 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
31 QTest::addColumn<double>("expectedMinValue");
32 QTest::addColumn<double>("expectedMaxValue");
33 }
34
35 template <typename T>
36 void testValuesBounds()
37 {
38 QFETCH(std::shared_ptr<T>, dataSeries);
39 QFETCH(double, minXAxis);
40 QFETCH(double, maxXAxis);
41
42 QFETCH(bool, expectedOK);
43 QFETCH(double, expectedMinValue);
44 QFETCH(double, expectedMaxValue);
45
46 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
47 auto end = dataSeries->cend();
48
49 // Checks iterators with expected result
50 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
51
52 if (expectedOK) {
53 auto compare = [](const auto &v1, const auto &v2) {
54 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
55 };
56
57 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
58 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
59 }
60 }
61
11 private slots:
62 private slots:
12 /// Input test data
63 /// Input test data
13 /// @sa testCtor()
64 /// @sa testCtor()
@@ -24,25 +75,39 private slots:
24 void testMerge();
75 void testMerge();
25
76
26 /// Input test data
77 /// Input test data
27 /// @sa testMinData()
78 /// @sa testMinXAxisData()
28 void testMinData_data();
79 void testMinXAxisData_data();
80
81 /// Tests get min x-axis data of a data series
82 void testMinXAxisData();
83
84 /// Input test data
85 /// @sa testMaxXAxisData()
86 void testMaxXAxisData_data();
87
88 /// Tests get max x-axis data of a data series
89 void testMaxXAxisData();
90
91 /// Input test data
92 /// @sa testXAxisRange()
93 void testXAxisRange_data();
29
94
30 /// Tests get min data of a data series
95 /// Tests get x-axis range of a data series
31 void testMinData();
96 void testXAxisRange();
32
97
33 /// Input test data
98 /// Input test data
34 /// @sa testMaxData()
99 /// @sa testValuesBoundsScalar()
35 void testMaxData_data();
100 void testValuesBoundsScalar_data();
36
101
37 /// Tests get max data of a data series
102 /// Tests get values bounds of a scalar series
38 void testMaxData();
103 void testValuesBoundsScalar();
39
104
40 /// Input test data
105 /// Input test data
41 /// @sa testSubdata()
106 /// @sa testValuesBoundsVector()
42 void testSubdata_data();
107 void testValuesBoundsVector_data();
43
108
44 /// Tests get subdata of two data series
109 /// Tests get values bounds of a vector series
45 void testSubdata();
110 void testValuesBoundsVector();
46 };
111 };
47
112
48 void TestDataSeries::testCtor_data()
113 void TestDataSeries::testCtor_data()
@@ -108,12 +173,23 void TestDataSeries::testCtor()
108
173
109 namespace {
174 namespace {
110
175
111 std::shared_ptr<ScalarSeries> createSeries(QVector<double> xAxisData, QVector<double> valuesData)
176 std::shared_ptr<ScalarSeries> createScalarSeries(QVector<double> xAxisData,
177 QVector<double> valuesData)
112 {
178 {
113 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
179 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
114 Unit{});
180 Unit{});
115 }
181 }
116
182
183 std::shared_ptr<VectorSeries> createVectorSeries(QVector<double> xAxisData,
184 QVector<double> xValuesData,
185 QVector<double> yValuesData,
186 QVector<double> zValuesData)
187 {
188 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
189 std::move(yValuesData), std::move(zValuesData), Unit{},
190 Unit{});
191 }
192
117 } // namespace
193 } // namespace
118
194
119 void TestDataSeries::testMerge_data()
195 void TestDataSeries::testMerge_data()
@@ -135,26 +211,26 void TestDataSeries::testMerge_data()
135 // ////////// //
211 // ////////// //
136
212
137 QTest::newRow("sortedMerge")
213 QTest::newRow("sortedMerge")
138 << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
214 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
139 << createSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
215 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
140 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
216 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
141 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
217 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
142
218
143 QTest::newRow("unsortedMerge")
219 QTest::newRow("unsortedMerge")
144 << createSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
220 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
145 << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
221 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
146 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
222 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
147 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
223 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
148
224
149 QTest::newRow("unsortedMerge2")
225 QTest::newRow("unsortedMerge2")
150 << createSeries({1., 2., 8., 9., 10}, {100., 200., 300., 400., 500.})
226 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 300., 400., 500.})
151 << createSeries({3., 4., 5., 6., 7.}, {600., 700., 800., 900., 1000.})
227 << createScalarSeries({3., 4., 5., 6., 7.}, {600., 700., 800., 900., 1000.})
152 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
228 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
153 << QVector<double>{100., 200., 600., 700., 800., 900., 1000., 300., 400., 500.};
229 << QVector<double>{100., 200., 600., 700., 800., 900., 1000., 300., 400., 500.};
154
230
155 QTest::newRow("unsortedMerge3")
231 QTest::newRow("unsortedMerge3")
156 << createSeries({3., 5., 8., 7., 2}, {100., 200., 300., 400., 500.})
232 << createScalarSeries({3., 5., 8., 7., 2}, {100., 200., 300., 400., 500.})
157 << createSeries({6., 4., 9., 10., 1.}, {600., 700., 800., 900., 1000.})
233 << createScalarSeries({6., 4., 9., 10., 1.}, {600., 700., 800., 900., 1000.})
158 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
234 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
159 << QVector<double>{1000., 500., 100., 700., 200., 600., 400., 300., 800., 900.};
235 << QVector<double>{1000., 500., 100., 700., 200., 600., 400., 300., 800., 900.};
160 }
236 }
@@ -181,7 +257,7 void TestDataSeries::testMerge()
181 seriesValuesData.cbegin()));
257 seriesValuesData.cbegin()));
182 }
258 }
183
259
184 void TestDataSeries::testMinData_data()
260 void TestDataSeries::testMinXAxisData_data()
185 {
261 {
186 // ////////////// //
262 // ////////////// //
187 // Test structure //
263 // Test structure //
@@ -203,21 +279,26 void TestDataSeries::testMinData_data()
203 // Test cases //
279 // Test cases //
204 // ////////// //
280 // ////////// //
205
281
206 QTest::newRow("minData1") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
282 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
283 {100., 200., 300., 400., 500.})
207 << 0. << true << 1.;
284 << 0. << true << 1.;
208 QTest::newRow("minData2") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
285 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
286 {100., 200., 300., 400., 500.})
209 << 1. << true << 1.;
287 << 1. << true << 1.;
210 QTest::newRow("minData3") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
288 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
289 {100., 200., 300., 400., 500.})
211 << 1.1 << true << 2.;
290 << 1.1 << true << 2.;
212 QTest::newRow("minData4") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
291 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
292 {100., 200., 300., 400., 500.})
213 << 5. << true << 5.;
293 << 5. << true << 5.;
214 QTest::newRow("minData5") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
294 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
295 {100., 200., 300., 400., 500.})
215 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
296 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
216 QTest::newRow("minData6") << createSeries({}, {}) << 1.1 << false
297 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
217 << std::numeric_limits<double>::quiet_NaN();
298 << std::numeric_limits<double>::quiet_NaN();
218 }
299 }
219
300
220 void TestDataSeries::testMinData()
301 void TestDataSeries::testMinXAxisData()
221 {
302 {
222 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
303 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
223 QFETCH(double, min);
304 QFETCH(double, min);
@@ -225,7 +306,7 void TestDataSeries::testMinData()
225 QFETCH(bool, expectedOK);
306 QFETCH(bool, expectedOK);
226 QFETCH(double, expectedMin);
307 QFETCH(double, expectedMin);
227
308
228 auto it = dataSeries->minData(min);
309 auto it = dataSeries->minXAxisData(min);
229
310
230 QCOMPARE(expectedOK, it != dataSeries->cend());
311 QCOMPARE(expectedOK, it != dataSeries->cend());
231
312
@@ -235,7 +316,7 void TestDataSeries::testMinData()
235 }
316 }
236 }
317 }
237
318
238 void TestDataSeries::testMaxData_data()
319 void TestDataSeries::testMaxXAxisData_data()
239 {
320 {
240 // ////////////// //
321 // ////////////// //
241 // Test structure //
322 // Test structure //
@@ -257,21 +338,26 void TestDataSeries::testMaxData_data()
257 // Test cases //
338 // Test cases //
258 // ////////// //
339 // ////////// //
259
340
260 QTest::newRow("maxData1") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
341 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
342 {100., 200., 300., 400., 500.})
261 << 6. << true << 5.;
343 << 6. << true << 5.;
262 QTest::newRow("maxData2") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
344 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
345 {100., 200., 300., 400., 500.})
263 << 5. << true << 5.;
346 << 5. << true << 5.;
264 QTest::newRow("maxData3") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
347 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
348 {100., 200., 300., 400., 500.})
265 << 4.9 << true << 4.;
349 << 4.9 << true << 4.;
266 QTest::newRow("maxData4") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
350 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
351 {100., 200., 300., 400., 500.})
267 << 1.1 << true << 1.;
352 << 1.1 << true << 1.;
268 QTest::newRow("maxData5") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
353 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
354 {100., 200., 300., 400., 500.})
269 << 1. << true << 1.;
355 << 1. << true << 1.;
270 QTest::newRow("maxData6") << createSeries({}, {}) << 1.1 << false
356 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
271 << std::numeric_limits<double>::quiet_NaN();
357 << std::numeric_limits<double>::quiet_NaN();
272 }
358 }
273
359
274 void TestDataSeries::testMaxData()
360 void TestDataSeries::testMaxXAxisData()
275 {
361 {
276 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
362 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
277 QFETCH(double, max);
363 QFETCH(double, max);
@@ -279,7 +365,7 void TestDataSeries::testMaxData()
279 QFETCH(bool, expectedOK);
365 QFETCH(bool, expectedOK);
280 QFETCH(double, expectedMax);
366 QFETCH(double, expectedMax);
281
367
282 auto it = dataSeries->maxData(max);
368 auto it = dataSeries->maxXAxisData(max);
283
369
284 QCOMPARE(expectedOK, it != dataSeries->cend());
370 QCOMPARE(expectedOK, it != dataSeries->cend());
285
371
@@ -289,20 +375,20 void TestDataSeries::testMaxData()
289 }
375 }
290 }
376 }
291
377
292 void TestDataSeries::testSubdata_data()
378 void TestDataSeries::testXAxisRange_data()
293 {
379 {
294 // ////////////// //
380 // ////////////// //
295 // Test structure //
381 // Test structure //
296 // ////////////// //
382 // ////////////// //
297
383
298 // Data series to get subdata
384 // Data series to get x-axis range
299 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
385 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
300
386
301 // Min/max values
387 // Min/max values
302 QTest::addColumn<double>("min");
388 QTest::addColumn<double>("min");
303 QTest::addColumn<double>("max");
389 QTest::addColumn<double>("max");
304
390
305 // Expected values after subdata
391 // Expected values
306 QTest::addColumn<QVector<double> >("expectedXAxisData");
392 QTest::addColumn<QVector<double> >("expectedXAxisData");
307 QTest::addColumn<QVector<double> >("expectedValuesData");
393 QTest::addColumn<QVector<double> >("expectedValuesData");
308
394
@@ -310,29 +396,37 void TestDataSeries::testSubdata_data()
310 // Test cases //
396 // Test cases //
311 // ////////// //
397 // ////////// //
312
398
313 QTest::newRow("subData1") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
399 QTest::newRow("xAxisRange1") << createScalarSeries({1., 2., 3., 4., 5.},
314 << -1. << 3.2 << QVector<double>{1., 2., 3.}
400 {100., 200., 300., 400., 500.})
315 << QVector<double>{100., 200., 300.};
401 << -1. << 3.2 << QVector<double>{1., 2., 3.}
316 QTest::newRow("subData2") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
402 << QVector<double>{100., 200., 300.};
317 << 1. << 4. << QVector<double>{1., 2., 3., 4.}
403 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
318 << QVector<double>{100., 200., 300., 400.};
404 {100., 200., 300., 400., 500.})
319 QTest::newRow("subData3") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
405 << 1. << 4. << QVector<double>{1., 2., 3., 4.}
320 << 1. << 3.9 << QVector<double>{1., 2., 3.}
406 << QVector<double>{100., 200., 300., 400.};
321 << QVector<double>{100., 200., 300.};
407 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
322 QTest::newRow("subData4") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
408 {100., 200., 300., 400., 500.})
323 << 0. << 0.9 << QVector<double>{} << QVector<double>{};
409 << 1. << 3.9 << QVector<double>{1., 2., 3.}
324 QTest::newRow("subData5") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
410 << QVector<double>{100., 200., 300.};
325 << 0. << 1. << QVector<double>{1.} << QVector<double>{100.};
411 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
326 QTest::newRow("subData6") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
412 {100., 200., 300., 400., 500.})
327 << 2.1 << 6. << QVector<double>{3., 4., 5.}
413 << 0. << 0.9 << QVector<double>{} << QVector<double>{};
328 << QVector<double>{300., 400., 500.};
414 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
329 QTest::newRow("subData7") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
415 {100., 200., 300., 400., 500.})
330 << 6. << 9. << QVector<double>{} << QVector<double>{};
416 << 0. << 1. << QVector<double>{1.} << QVector<double>{100.};
331 QTest::newRow("subData8") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
417 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
332 << 5. << 9. << QVector<double>{5.} << QVector<double>{500.};
418 {100., 200., 300., 400., 500.})
419 << 2.1 << 6. << QVector<double>{3., 4., 5.}
420 << QVector<double>{300., 400., 500.};
421 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
422 {100., 200., 300., 400., 500.})
423 << 6. << 9. << QVector<double>{} << QVector<double>{};
424 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
425 {100., 200., 300., 400., 500.})
426 << 5. << 9. << QVector<double>{5.} << QVector<double>{500.};
333 }
427 }
334
428
335 void TestDataSeries::testSubdata()
429 void TestDataSeries::testXAxisRange()
336 {
430 {
337 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
431 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
338 QFETCH(double, min);
432 QFETCH(double, min);
@@ -341,7 +435,7 void TestDataSeries::testSubdata()
341 QFETCH(QVector<double>, expectedXAxisData);
435 QFETCH(QVector<double>, expectedXAxisData);
342 QFETCH(QVector<double>, expectedValuesData);
436 QFETCH(QVector<double>, expectedValuesData);
343
437
344 auto bounds = dataSeries->subData(min, max);
438 auto bounds = dataSeries->xAxisRange(min, max);
345 QVERIFY(std::equal(bounds.first, bounds.second, expectedXAxisData.cbegin(),
439 QVERIFY(std::equal(bounds.first, bounds.second, expectedXAxisData.cbegin(),
346 expectedXAxisData.cend(),
440 expectedXAxisData.cend(),
347 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
441 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
@@ -350,5 +444,77 void TestDataSeries::testSubdata()
350 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
444 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
351 }
445 }
352
446
447 void TestDataSeries::testValuesBoundsScalar_data()
448 {
449 testValuesBoundsStructure<ScalarSeries>();
450
451 // ////////// //
452 // Test cases //
453 // ////////// //
454 auto nan = std::numeric_limits<double>::quiet_NaN();
455
456 QTest::newRow("scalarBounds1")
457 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
458 << true << 100. << 500.;
459 QTest::newRow("scalarBounds2")
460 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
461 << true << 200. << 400.;
462 QTest::newRow("scalarBounds3")
463 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
464 << false << nan << nan;
465 QTest::newRow("scalarBounds4")
466 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
467 << false << nan << nan;
468 QTest::newRow("scalarBounds5")
469 << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100. << 100.;
470 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
471
472 // Tests with NaN values: NaN values are not included in min/max search
473 QTest::newRow("scalarBounds7")
474 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
475 << true << 200. << 400.;
476 QTest::newRow("scalarBounds8")
477 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
478 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
479 }
480
481 void TestDataSeries::testValuesBoundsScalar()
482 {
483 testValuesBounds<ScalarSeries>();
484 }
485
486 void TestDataSeries::testValuesBoundsVector_data()
487 {
488 testValuesBoundsStructure<VectorSeries>();
489
490 // ////////// //
491 // Test cases //
492 // ////////// //
493 auto nan = std::numeric_limits<double>::quiet_NaN();
494
495 QTest::newRow("vectorBounds1")
496 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
497 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
498 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
499 QTest::newRow("vectorBounds2")
500 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
501 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
502 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
503 QTest::newRow("vectorBounds3")
504 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
505 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
506 << 2. << 3. << true << 10. << 24.;
507
508 // Tests with NaN values: NaN values are not included in min/max search
509 QTest::newRow("vectorBounds4")
510 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
511 << nan << nan;
512 }
513
514 void TestDataSeries::testValuesBoundsVector()
515 {
516 testValuesBounds<VectorSeries>();
517 }
518
353 QTEST_MAIN(TestDataSeries)
519 QTEST_MAIN(TestDataSeries)
354 #include "TestDataSeries.moc"
520 #include "TestDataSeries.moc"
@@ -149,7 +149,7 struct PlottablesUpdater<T,
149 // - Gets the data of the series included in the current range
149 // - Gets the data of the series included in the current range
150 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
150 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
151 // and value data. The correct value is retrieved according to the index of the component
151 // and value data. The correct value is retrieved according to the index of the component
152 auto subDataIts = dataSeries.subData(range.m_TStart, range.m_TEnd);
152 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
153 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
153 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
154 for (const auto &dataContainer : dataContainers) {
154 for (const auto &dataContainer : dataContainers) {
155 auto componentIndex = dataContainer.first;
155 auto componentIndex = dataContainer.first;
General Comments 0
You need to be logged in to leave comments. Login now