##// 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 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 116 #endif // SCIQLOP_SORTUTILS_H
@@ -70,6 +70,26 public:
70 70 double at(int index) const { return *m_Its.at(index); }
71 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 93 void next()
74 94 {
75 95 for (auto &it : m_Its) {
@@ -65,6 +65,8 public:
65 65 double x() const override { return m_XIt->at(0); }
66 66 double value() const override { return m_ValuesIt->at(0); }
67 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 71 private:
70 72 ArrayData<1>::Iterator m_XIt;
@@ -191,16 +193,16 public:
191 193 std::make_unique<dataseries_detail::IteratorValue<Dim> >(*this, false)}};
192 194 }
193 195
194 /// @sa IDataSeries::minData()
195 DataSeriesIterator minData(double minXAxisData) const override
196 /// @sa IDataSeries::minXAxisData()
197 DataSeriesIterator minXAxisData(double minXAxisData) const override
196 198 {
197 199 return std::lower_bound(
198 200 cbegin(), cend(), minXAxisData,
199 201 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
200 202 }
201 203
202 /// @sa IDataSeries::maxData()
203 DataSeriesIterator maxData(double maxXAxisData) const override
204 /// @sa IDataSeries::maxXAxisData()
205 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
204 206 {
205 207 // Gets the first element that greater than max value
206 208 auto it = std::upper_bound(
@@ -210,25 +212,50 public:
210 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) {
216 std::swap(min, max);
218 if (minXAxisData > maxXAxisData) {
219 std::swap(minXAxisData, maxXAxisData);
217 220 }
218 221
219 222 auto begin = cbegin();
220 223 auto end = cend();
221 224
222 auto lowerIt
223 = std::lower_bound(begin, end, min, [](const auto &itValue, const auto &value) {
224 return itValue.x() < value;
225 auto lowerIt = std::lower_bound(
226 begin, end, minXAxisData,
227 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
228 auto upperIt = std::upper_bound(
229 begin, end, maxXAxisData,
230 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
231
232 return std::make_pair(lowerIt, upperIt);
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());
225 250 });
226 auto upperIt
227 = std::upper_bound(begin, end, max, [](const auto &value, const auto &itValue) {
228 return value < itValue.x();
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());
229 256 });
230 257
231 return std::make_pair(lowerIt, upperIt);
258 return std::make_pair(minIt, maxIt);
232 259 }
233 260
234 261 // /////// //
@@ -24,6 +24,8 public:
24 24 virtual double x() const = 0;
25 25 virtual double value() const = 0;
26 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 31 explicit DataSeriesIteratorValue(std::unique_ptr<Impl> impl);
@@ -43,6 +45,10 public:
43 45 double value() const;
44 46 /// Gets value data depending on an index
45 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 53 private:
48 54 std::unique_ptr<Impl> m_Impl;
@@ -72,14 +72,22 public:
72 72
73 73 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
74 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 77 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
78 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;
80
81 virtual std::pair<DataSeriesIterator, DataSeriesIterator> subData(double min,
82 double max) const = 0;
79 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
80
81 /// @return the iterators pointing to the range of data whose x-axis values are between min and
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 93 // Mutexes //
@@ -47,6 +47,16 double DataSeriesIteratorValue::value(int componentIndex) const
47 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 60 DataSeriesIterator::DataSeriesIterator(DataSeriesIteratorValue value)
51 61 : m_CurrentValue{std::move(value)}
52 62 {
@@ -18,7 +18,7 std::shared_ptr<IDataSeries> ScalarSeries::subDataSeries(const SqpRange &range)
18 18 auto subValuesData = QVector<double>();
19 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 22 for (auto it = bounds.first; it != bounds.second; ++it) {
23 23 subXAxisData.append(it->x());
24 24 subValuesData.append(it->value());
@@ -24,7 +24,7 std::shared_ptr<IDataSeries> VectorSeries::subDataSeries(const SqpRange &range)
24 24
25 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 28 for (auto it = bounds.first; it != bounds.second; ++it) {
29 29 subXAxisData.append(it->x());
30 30 subXValuesData.append(it->value(0));
@@ -174,11 +174,11 QVariant VariableModel::data(const QModelIndex &index, int role) const
174 174 case TSTART_COLUMN:
175 175 // Shows the min value of the data series above the range tstart
176 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 178 case TEND_COLUMN:
179 179 // Shows the max value of the data series under the range tend
180 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 182 case UNIT_COLUMN:
183 183 return variable->metadata().value(QStringLiteral("units"));
184 184 case MISSION_COLUMN:
@@ -1,13 +1,64
1 1 #include "Data/DataSeries.h"
2 2 #include "Data/ScalarSeries.h"
3 #include "Data/VectorSeries.h"
3 4
4 5 #include <QObject>
5 6 #include <QtTest>
6 7
7 8 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
9 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
8 10
9 11 class TestDataSeries : public QObject {
10 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 62 private slots:
12 63 /// Input test data
13 64 /// @sa testCtor()
@@ -24,25 +75,39 private slots:
24 75 void testMerge();
25 76
26 77 /// Input test data
27 /// @sa testMinData()
28 void testMinData_data();
78 /// @sa testMinXAxisData()
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();
29 87
30 /// Tests get min data of a data series
31 void testMinData();
88 /// Tests get max x-axis data of a data series
89 void testMaxXAxisData();
32 90
33 91 /// Input test data
34 /// @sa testMaxData()
35 void testMaxData_data();
92 /// @sa testXAxisRange()
93 void testXAxisRange_data();
36 94
37 /// Tests get max data of a data series
38 void testMaxData();
95 /// Tests get x-axis range of a data series
96 void testXAxisRange();
39 97
40 98 /// Input test data
41 /// @sa testSubdata()
42 void testSubdata_data();
99 /// @sa testValuesBoundsScalar()
100 void testValuesBoundsScalar_data();
101
102 /// Tests get values bounds of a scalar series
103 void testValuesBoundsScalar();
43 104
44 /// Tests get subdata of two data series
45 void testSubdata();
105 /// Input test data
106 /// @sa testValuesBoundsVector()
107 void testValuesBoundsVector_data();
108
109 /// Tests get values bounds of a vector series
110 void testValuesBoundsVector();
46 111 };
47 112
48 113 void TestDataSeries::testCtor_data()
@@ -108,12 +173,23 void TestDataSeries::testCtor()
108 173
109 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 179 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
114 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 193 } // namespace
118 194
119 195 void TestDataSeries::testMerge_data()
@@ -135,26 +211,26 void TestDataSeries::testMerge_data()
135 211 // ////////// //
136 212
137 213 QTest::newRow("sortedMerge")
138 << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
139 << createSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
214 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
215 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
140 216 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
141 217 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
142 218
143 219 QTest::newRow("unsortedMerge")
144 << createSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
145 << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
220 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
221 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
146 222 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
147 223 << QVector<double>{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
148 224
149 225 QTest::newRow("unsortedMerge2")
150 << createSeries({1., 2., 8., 9., 10}, {100., 200., 300., 400., 500.})
151 << createSeries({3., 4., 5., 6., 7.}, {600., 700., 800., 900., 1000.})
226 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 300., 400., 500.})
227 << createScalarSeries({3., 4., 5., 6., 7.}, {600., 700., 800., 900., 1000.})
152 228 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
153 229 << QVector<double>{100., 200., 600., 700., 800., 900., 1000., 300., 400., 500.};
154 230
155 231 QTest::newRow("unsortedMerge3")
156 << createSeries({3., 5., 8., 7., 2}, {100., 200., 300., 400., 500.})
157 << createSeries({6., 4., 9., 10., 1.}, {600., 700., 800., 900., 1000.})
232 << createScalarSeries({3., 5., 8., 7., 2}, {100., 200., 300., 400., 500.})
233 << createScalarSeries({6., 4., 9., 10., 1.}, {600., 700., 800., 900., 1000.})
158 234 << QVector<double>{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
159 235 << QVector<double>{1000., 500., 100., 700., 200., 600., 400., 300., 800., 900.};
160 236 }
@@ -181,7 +257,7 void TestDataSeries::testMerge()
181 257 seriesValuesData.cbegin()));
182 258 }
183 259
184 void TestDataSeries::testMinData_data()
260 void TestDataSeries::testMinXAxisData_data()
185 261 {
186 262 // ////////////// //
187 263 // Test structure //
@@ -203,21 +279,26 void TestDataSeries::testMinData_data()
203 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 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 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 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 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 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 298 << std::numeric_limits<double>::quiet_NaN();
218 299 }
219 300
220 void TestDataSeries::testMinData()
301 void TestDataSeries::testMinXAxisData()
221 302 {
222 303 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
223 304 QFETCH(double, min);
@@ -225,7 +306,7 void TestDataSeries::testMinData()
225 306 QFETCH(bool, expectedOK);
226 307 QFETCH(double, expectedMin);
227 308
228 auto it = dataSeries->minData(min);
309 auto it = dataSeries->minXAxisData(min);
229 310
230 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 322 // Test structure //
@@ -257,21 +338,26 void TestDataSeries::testMaxData_data()
257 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 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 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 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 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 355 << 1. << true << 1.;
270 QTest::newRow("maxData6") << createSeries({}, {}) << 1.1 << false
356 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
271 357 << std::numeric_limits<double>::quiet_NaN();
272 358 }
273 359
274 void TestDataSeries::testMaxData()
360 void TestDataSeries::testMaxXAxisData()
275 361 {
276 362 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
277 363 QFETCH(double, max);
@@ -279,7 +365,7 void TestDataSeries::testMaxData()
279 365 QFETCH(bool, expectedOK);
280 366 QFETCH(double, expectedMax);
281 367
282 auto it = dataSeries->maxData(max);
368 auto it = dataSeries->maxXAxisData(max);
283 369
284 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 381 // Test structure //
296 382 // ////////////// //
297 383
298 // Data series to get subdata
384 // Data series to get x-axis range
299 385 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
300 386
301 387 // Min/max values
302 388 QTest::addColumn<double>("min");
303 389 QTest::addColumn<double>("max");
304 390
305 // Expected values after subdata
391 // Expected values
306 392 QTest::addColumn<QVector<double> >("expectedXAxisData");
307 393 QTest::addColumn<QVector<double> >("expectedValuesData");
308 394
@@ -310,29 +396,37 void TestDataSeries::testSubdata_data()
310 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.},
400 {100., 200., 300., 400., 500.})
314 401 << -1. << 3.2 << QVector<double>{1., 2., 3.}
315 402 << QVector<double>{100., 200., 300.};
316 QTest::newRow("subData2") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
403 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
404 {100., 200., 300., 400., 500.})
317 405 << 1. << 4. << QVector<double>{1., 2., 3., 4.}
318 406 << QVector<double>{100., 200., 300., 400.};
319 QTest::newRow("subData3") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
407 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
408 {100., 200., 300., 400., 500.})
320 409 << 1. << 3.9 << QVector<double>{1., 2., 3.}
321 410 << QVector<double>{100., 200., 300.};
322 QTest::newRow("subData4") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
411 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
412 {100., 200., 300., 400., 500.})
323 413 << 0. << 0.9 << QVector<double>{} << QVector<double>{};
324 QTest::newRow("subData5") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
414 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
415 {100., 200., 300., 400., 500.})
325 416 << 0. << 1. << QVector<double>{1.} << QVector<double>{100.};
326 QTest::newRow("subData6") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
417 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
418 {100., 200., 300., 400., 500.})
327 419 << 2.1 << 6. << QVector<double>{3., 4., 5.}
328 420 << QVector<double>{300., 400., 500.};
329 QTest::newRow("subData7") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
421 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
422 {100., 200., 300., 400., 500.})
330 423 << 6. << 9. << QVector<double>{} << QVector<double>{};
331 QTest::newRow("subData8") << createSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
424 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
425 {100., 200., 300., 400., 500.})
332 426 << 5. << 9. << QVector<double>{5.} << QVector<double>{500.};
333 427 }
334 428
335 void TestDataSeries::testSubdata()
429 void TestDataSeries::testXAxisRange()
336 430 {
337 431 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
338 432 QFETCH(double, min);
@@ -341,7 +435,7 void TestDataSeries::testSubdata()
341 435 QFETCH(QVector<double>, expectedXAxisData);
342 436 QFETCH(QVector<double>, expectedValuesData);
343 437
344 auto bounds = dataSeries->subData(min, max);
438 auto bounds = dataSeries->xAxisRange(min, max);
345 439 QVERIFY(std::equal(bounds.first, bounds.second, expectedXAxisData.cbegin(),
346 440 expectedXAxisData.cend(),
347 441 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
@@ -350,5 +444,77 void TestDataSeries::testSubdata()
350 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 519 QTEST_MAIN(TestDataSeries)
354 520 #include "TestDataSeries.moc"
@@ -149,7 +149,7 struct PlottablesUpdater<T,
149 149 // - Gets the data of the series included in the current range
150 150 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
151 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 153 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
154 154 for (const auto &dataContainer : dataContainers) {
155 155 auto componentIndex = dataContainer.first;
General Comments 0
You need to be logged in to leave comments. Login now