##// END OF EJS Templates
Merge branch 'feature/TestsDataSeriesVariable' into develop
Alexandre Leroux -
r803:d50ec2968c82 merge
parent child
Show More
@@ -1,400 +1,391
1 #ifndef SCIQLOP_DATASERIES_H
1 #ifndef SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Common/SortUtils.h>
6 #include <Common/SortUtils.h>
7
7
8 #include <Data/ArrayData.h>
8 #include <Data/ArrayData.h>
9 #include <Data/DataSeriesMergeHelper.h>
9 #include <Data/DataSeriesMergeHelper.h>
10 #include <Data/IDataSeries.h>
10 #include <Data/IDataSeries.h>
11
11
12 #include <QLoggingCategory>
12 #include <QLoggingCategory>
13 #include <QReadLocker>
13 #include <QReadLocker>
14 #include <QReadWriteLock>
14 #include <QReadWriteLock>
15 #include <memory>
15 #include <memory>
16
16
17 // We don't use the Qt macro since the log is used in the header file, which causes multiple log
17 // We don't use the Qt macro since the log is used in the header file, which causes multiple log
18 // definitions with inheritance. Inline method is used instead
18 // definitions with inheritance. Inline method is used instead
19 inline const QLoggingCategory &LOG_DataSeries()
19 inline const QLoggingCategory &LOG_DataSeries()
20 {
20 {
21 static const QLoggingCategory category{"DataSeries"};
21 static const QLoggingCategory category{"DataSeries"};
22 return category;
22 return category;
23 }
23 }
24
24
25 template <int Dim>
25 template <int Dim>
26 class DataSeries;
26 class DataSeries;
27
27
28 namespace dataseries_detail {
28 namespace dataseries_detail {
29
29
30 template <int Dim, bool IsConst>
30 template <int Dim, bool IsConst>
31 class IteratorValue : public DataSeriesIteratorValue::Impl {
31 class IteratorValue : public DataSeriesIteratorValue::Impl {
32 public:
32 public:
33 friend class DataSeries<Dim>;
33 friend class DataSeries<Dim>;
34
34
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
39 {
39 {
40 }
40 }
41
41
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
46 : dataSeries.valuesData()->cend())
46 : dataSeries.valuesData()->cend())
47 {
47 {
48 }
48 }
49
49
50 IteratorValue(const IteratorValue &other) = default;
50 IteratorValue(const IteratorValue &other) = default;
51
51
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
53 {
53 {
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
55 }
55 }
56
56
57 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
57 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
59 return m_XIt->distance(*otherImpl.m_XIt);
59 return m_XIt->distance(*otherImpl.m_XIt);
60 }
60 }
61 catch (const std::bad_cast &) {
61 catch (const std::bad_cast &) {
62 return 0;
62 return 0;
63 }
63 }
64
64
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
67 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
67 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
68 }
68 }
69 catch (const std::bad_cast &) {
69 catch (const std::bad_cast &) {
70 return false;
70 return false;
71 }
71 }
72
72
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
76 }
76 }
77 catch (const std::bad_cast &) {
77 catch (const std::bad_cast &) {
78 return false;
78 return false;
79 }
79 }
80
80
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
82 {
82 {
83 auto result = clone();
83 auto result = clone();
84 result->next(offset);
84 result->next(offset);
85 return result;
85 return result;
86 }
86 }
87
87
88 void next(int offset) override
88 void next(int offset) override
89 {
89 {
90 m_XIt->next(offset);
90 m_XIt->next(offset);
91 m_ValuesIt->next(offset);
91 m_ValuesIt->next(offset);
92 }
92 }
93
93
94 void prev() override
94 void prev() override
95 {
95 {
96 --m_XIt;
96 --m_XIt;
97 --m_ValuesIt;
97 --m_ValuesIt;
98 }
98 }
99
99
100 double x() const override { return m_XIt->at(0); }
100 double x() const override { return m_XIt->at(0); }
101 double value() const override { return m_ValuesIt->at(0); }
101 double value() const override { return m_ValuesIt->at(0); }
102 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
102 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
103 double minValue() const override { return m_ValuesIt->min(); }
103 double minValue() const override { return m_ValuesIt->min(); }
104 double maxValue() const override { return m_ValuesIt->max(); }
104 double maxValue() const override { return m_ValuesIt->max(); }
105 QVector<double> values() const override { return m_ValuesIt->values(); }
105 QVector<double> values() const override { return m_ValuesIt->values(); }
106
106
107 void swap(DataSeriesIteratorValue::Impl &other) override
107 void swap(DataSeriesIteratorValue::Impl &other) override
108 {
108 {
109 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
109 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
110 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
110 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
111 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
111 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
112 }
112 }
113
113
114 private:
114 private:
115 ArrayDataIterator m_XIt;
115 ArrayDataIterator m_XIt;
116 ArrayDataIterator m_ValuesIt;
116 ArrayDataIterator m_ValuesIt;
117 };
117 };
118 } // namespace dataseries_detail
118 } // namespace dataseries_detail
119
119
120 /**
120 /**
121 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
121 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
122 *
122 *
123 * It proposes to set a dimension for the values ​​data.
123 * It proposes to set a dimension for the values ​​data.
124 *
124 *
125 * A DataSeries is always sorted on its x-axis data.
125 * A DataSeries is always sorted on its x-axis data.
126 *
126 *
127 * @tparam Dim The dimension of the values data
127 * @tparam Dim The dimension of the values data
128 *
128 *
129 */
129 */
130 template <int Dim>
130 template <int Dim>
131 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
131 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
132 friend class DataSeriesMergeHelper;
132 friend class DataSeriesMergeHelper;
133
133
134 public:
134 public:
135 /// @sa IDataSeries::xAxisData()
135 /// @sa IDataSeries::xAxisData()
136 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
136 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
137 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
137 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
138
138
139 /// @sa IDataSeries::xAxisUnit()
139 /// @sa IDataSeries::xAxisUnit()
140 Unit xAxisUnit() const override { return m_XAxisUnit; }
140 Unit xAxisUnit() const override { return m_XAxisUnit; }
141
141
142 /// @return the values dataset
142 /// @return the values dataset
143 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
143 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
144 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
144 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
145
145
146 /// @sa IDataSeries::valuesUnit()
146 /// @sa IDataSeries::valuesUnit()
147 Unit valuesUnit() const override { return m_ValuesUnit; }
147 Unit valuesUnit() const override { return m_ValuesUnit; }
148
148
149 int nbPoints() const override { return m_XAxisData->totalSize() + m_ValuesData->totalSize(); }
149 int nbPoints() const override { return m_XAxisData->totalSize() + m_ValuesData->totalSize(); }
150
150
151 SqpRange range() const override
152 {
153 if (!m_XAxisData->cdata().empty()) {
154 return SqpRange{m_XAxisData->cdata().front(), m_XAxisData->cdata().back()};
155 }
156
157 return SqpRange{};
158 }
159
160 void clear()
151 void clear()
161 {
152 {
162 m_XAxisData->clear();
153 m_XAxisData->clear();
163 m_ValuesData->clear();
154 m_ValuesData->clear();
164 }
155 }
165
156
166 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
157 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
167
158
168 /// Merges into the data series an other data series
159 /// Merges into the data series an other data series
169 /// @remarks the data series to merge with is cleared after the operation
160 /// @remarks the data series to merge with is cleared after the operation
170 void merge(IDataSeries *dataSeries) override
161 void merge(IDataSeries *dataSeries) override
171 {
162 {
172 dataSeries->lockWrite();
163 dataSeries->lockWrite();
173 lockWrite();
164 lockWrite();
174
165
175 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
166 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
176 DataSeriesMergeHelper::merge(*other, *this);
167 DataSeriesMergeHelper::merge(*other, *this);
177 }
168 }
178 else {
169 else {
179 qCWarning(LOG_DataSeries())
170 qCWarning(LOG_DataSeries())
180 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
171 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
181 }
172 }
182 unlock();
173 unlock();
183 dataSeries->unlock();
174 dataSeries->unlock();
184 }
175 }
185
176
186 void purge(double min, double max) override
177 void purge(double min, double max) override
187 {
178 {
188 // Nothing to purge if series is empty
179 // Nothing to purge if series is empty
189 if (isEmpty()) {
180 if (isEmpty()) {
190 return;
181 return;
191 }
182 }
192
183
193 if (min > max) {
184 if (min > max) {
194 std::swap(min, max);
185 std::swap(min, max);
195 }
186 }
196
187
197 // Nothing to purge if series min/max are inside purge range
188 // Nothing to purge if series min/max are inside purge range
198 auto xMin = cbegin()->x();
189 auto xMin = cbegin()->x();
199 auto xMax = (--cend())->x();
190 auto xMax = (--cend())->x();
200 if (xMin >= min && xMax <= max) {
191 if (xMin >= min && xMax <= max) {
201 return;
192 return;
202 }
193 }
203
194
204 auto lowerIt = std::lower_bound(
195 auto lowerIt = std::lower_bound(
205 begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; });
196 begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; });
206 erase(begin(), lowerIt);
197 erase(begin(), lowerIt);
207 auto upperIt = std::upper_bound(
198 auto upperIt = std::upper_bound(
208 begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); });
199 begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); });
209 erase(upperIt, end());
200 erase(upperIt, end());
210 }
201 }
211
202
212 // ///////// //
203 // ///////// //
213 // Iterators //
204 // Iterators //
214 // ///////// //
205 // ///////// //
215
206
216 DataSeriesIterator begin() override
207 DataSeriesIterator begin() override
217 {
208 {
218 return DataSeriesIterator{DataSeriesIteratorValue{
209 return DataSeriesIterator{DataSeriesIteratorValue{
219 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
210 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
220 }
211 }
221
212
222 DataSeriesIterator end() override
213 DataSeriesIterator end() override
223 {
214 {
224 return DataSeriesIterator{DataSeriesIteratorValue{
215 return DataSeriesIterator{DataSeriesIteratorValue{
225 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
216 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
226 }
217 }
227
218
228 DataSeriesIterator cbegin() const override
219 DataSeriesIterator cbegin() const override
229 {
220 {
230 return DataSeriesIterator{DataSeriesIteratorValue{
221 return DataSeriesIterator{DataSeriesIteratorValue{
231 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
222 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
232 }
223 }
233
224
234 DataSeriesIterator cend() const override
225 DataSeriesIterator cend() const override
235 {
226 {
236 return DataSeriesIterator{DataSeriesIteratorValue{
227 return DataSeriesIterator{DataSeriesIteratorValue{
237 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
228 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
238 }
229 }
239
230
240 void erase(DataSeriesIterator first, DataSeriesIterator last)
231 void erase(DataSeriesIterator first, DataSeriesIterator last)
241 {
232 {
242 auto firstImpl
233 auto firstImpl
243 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
234 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
244 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
235 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
245
236
246 if (firstImpl && lastImpl) {
237 if (firstImpl && lastImpl) {
247 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
238 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
248 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
239 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
249 }
240 }
250 }
241 }
251
242
252 void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false)
243 void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false)
253 {
244 {
254 auto firstImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(first->impl());
245 auto firstImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(first->impl());
255 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(last->impl());
246 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(last->impl());
256
247
257 if (firstImpl && lastImpl) {
248 if (firstImpl && lastImpl) {
258 m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend);
249 m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend);
259 m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend);
250 m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend);
260 }
251 }
261 }
252 }
262
253
263 /// @sa IDataSeries::minXAxisData()
254 /// @sa IDataSeries::minXAxisData()
264 DataSeriesIterator minXAxisData(double minXAxisData) const override
255 DataSeriesIterator minXAxisData(double minXAxisData) const override
265 {
256 {
266 return std::lower_bound(
257 return std::lower_bound(
267 cbegin(), cend(), minXAxisData,
258 cbegin(), cend(), minXAxisData,
268 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
259 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
269 }
260 }
270
261
271 /// @sa IDataSeries::maxXAxisData()
262 /// @sa IDataSeries::maxXAxisData()
272 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
263 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
273 {
264 {
274 // Gets the first element that greater than max value
265 // Gets the first element that greater than max value
275 auto it = std::upper_bound(
266 auto it = std::upper_bound(
276 cbegin(), cend(), maxXAxisData,
267 cbegin(), cend(), maxXAxisData,
277 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
268 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
278
269
279 return it == cbegin() ? cend() : --it;
270 return it == cbegin() ? cend() : --it;
280 }
271 }
281
272
282 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
273 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
283 double maxXAxisData) const override
274 double maxXAxisData) const override
284 {
275 {
285 if (minXAxisData > maxXAxisData) {
276 if (minXAxisData > maxXAxisData) {
286 std::swap(minXAxisData, maxXAxisData);
277 std::swap(minXAxisData, maxXAxisData);
287 }
278 }
288
279
289 auto begin = cbegin();
280 auto begin = cbegin();
290 auto end = cend();
281 auto end = cend();
291
282
292 auto lowerIt = std::lower_bound(
283 auto lowerIt = std::lower_bound(
293 begin, end, minXAxisData,
284 begin, end, minXAxisData,
294 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
285 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
295 auto upperIt = std::upper_bound(
286 auto upperIt = std::upper_bound(
296 lowerIt, end, maxXAxisData,
287 lowerIt, end, maxXAxisData,
297 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
288 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
298
289
299 return std::make_pair(lowerIt, upperIt);
290 return std::make_pair(lowerIt, upperIt);
300 }
291 }
301
292
302 std::pair<DataSeriesIterator, DataSeriesIterator>
293 std::pair<DataSeriesIterator, DataSeriesIterator>
303 valuesBounds(double minXAxisData, double maxXAxisData) const override
294 valuesBounds(double minXAxisData, double maxXAxisData) const override
304 {
295 {
305 // Places iterators to the correct x-axis range
296 // Places iterators to the correct x-axis range
306 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
297 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
307
298
308 // Returns end iterators if the range is empty
299 // Returns end iterators if the range is empty
309 if (xAxisRangeIts.first == xAxisRangeIts.second) {
300 if (xAxisRangeIts.first == xAxisRangeIts.second) {
310 return std::make_pair(cend(), cend());
301 return std::make_pair(cend(), cend());
311 }
302 }
312
303
313 // Gets the iterator on the min of all values data
304 // Gets the iterator on the min of all values data
314 auto minIt = std::min_element(
305 auto minIt = std::min_element(
315 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
306 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
316 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
307 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
317 });
308 });
318
309
319 // Gets the iterator on the max of all values data
310 // Gets the iterator on the max of all values data
320 auto maxIt = std::max_element(
311 auto maxIt = std::max_element(
321 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
312 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
322 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
313 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
323 });
314 });
324
315
325 return std::make_pair(minIt, maxIt);
316 return std::make_pair(minIt, maxIt);
326 }
317 }
327
318
328 // /////// //
319 // /////// //
329 // Mutexes //
320 // Mutexes //
330 // /////// //
321 // /////// //
331
322
332 virtual void lockRead() { m_Lock.lockForRead(); }
323 virtual void lockRead() { m_Lock.lockForRead(); }
333 virtual void lockWrite() { m_Lock.lockForWrite(); }
324 virtual void lockWrite() { m_Lock.lockForWrite(); }
334 virtual void unlock() { m_Lock.unlock(); }
325 virtual void unlock() { m_Lock.unlock(); }
335
326
336 protected:
327 protected:
337 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
328 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
338 /// DataSeries with no values will be created.
329 /// DataSeries with no values will be created.
339 /// @remarks data series is automatically sorted on its x-axis data
330 /// @remarks data series is automatically sorted on its x-axis data
340 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
331 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
341 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
332 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
342 : m_XAxisData{xAxisData},
333 : m_XAxisData{xAxisData},
343 m_XAxisUnit{xAxisUnit},
334 m_XAxisUnit{xAxisUnit},
344 m_ValuesData{valuesData},
335 m_ValuesData{valuesData},
345 m_ValuesUnit{valuesUnit}
336 m_ValuesUnit{valuesUnit}
346 {
337 {
347 if (m_XAxisData->size() != m_ValuesData->size()) {
338 if (m_XAxisData->size() != m_ValuesData->size()) {
348 clear();
339 clear();
349 }
340 }
350
341
351 // Sorts data if it's not the case
342 // Sorts data if it's not the case
352 const auto &xAxisCData = m_XAxisData->cdata();
343 const auto &xAxisCData = m_XAxisData->cdata();
353 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
344 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
354 sort();
345 sort();
355 }
346 }
356 }
347 }
357
348
358 /// Copy ctor
349 /// Copy ctor
359 explicit DataSeries(const DataSeries<Dim> &other)
350 explicit DataSeries(const DataSeries<Dim> &other)
360 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
351 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
361 m_XAxisUnit{other.m_XAxisUnit},
352 m_XAxisUnit{other.m_XAxisUnit},
362 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
353 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
363 m_ValuesUnit{other.m_ValuesUnit}
354 m_ValuesUnit{other.m_ValuesUnit}
364 {
355 {
365 // Since a series is ordered from its construction and is always ordered, it is not
356 // Since a series is ordered from its construction and is always ordered, it is not
366 // necessary to call the sort method here ('other' is sorted)
357 // necessary to call the sort method here ('other' is sorted)
367 }
358 }
368
359
369 /// Assignment operator
360 /// Assignment operator
370 template <int D>
361 template <int D>
371 DataSeries &operator=(DataSeries<D> other)
362 DataSeries &operator=(DataSeries<D> other)
372 {
363 {
373 std::swap(m_XAxisData, other.m_XAxisData);
364 std::swap(m_XAxisData, other.m_XAxisData);
374 std::swap(m_XAxisUnit, other.m_XAxisUnit);
365 std::swap(m_XAxisUnit, other.m_XAxisUnit);
375 std::swap(m_ValuesData, other.m_ValuesData);
366 std::swap(m_ValuesData, other.m_ValuesData);
376 std::swap(m_ValuesUnit, other.m_ValuesUnit);
367 std::swap(m_ValuesUnit, other.m_ValuesUnit);
377
368
378 return *this;
369 return *this;
379 }
370 }
380
371
381 private:
372 private:
382 /**
373 /**
383 * Sorts data series on its x-axis data
374 * Sorts data series on its x-axis data
384 */
375 */
385 void sort() noexcept
376 void sort() noexcept
386 {
377 {
387 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
378 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
388 m_XAxisData = m_XAxisData->sort(permutation);
379 m_XAxisData = m_XAxisData->sort(permutation);
389 m_ValuesData = m_ValuesData->sort(permutation);
380 m_ValuesData = m_ValuesData->sort(permutation);
390 }
381 }
391
382
392 std::shared_ptr<ArrayData<1> > m_XAxisData;
383 std::shared_ptr<ArrayData<1> > m_XAxisData;
393 Unit m_XAxisUnit;
384 Unit m_XAxisUnit;
394 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
385 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
395 Unit m_ValuesUnit;
386 Unit m_ValuesUnit;
396
387
397 QReadWriteLock m_Lock;
388 QReadWriteLock m_Lock;
398 };
389 };
399
390
400 #endif // SCIQLOP_DATASERIES_H
391 #endif // SCIQLOP_DATASERIES_H
@@ -1,113 +1,111
1 #ifndef SCIQLOP_IDATASERIES_H
1 #ifndef SCIQLOP_IDATASERIES_H
2 #define SCIQLOP_IDATASERIES_H
2 #define SCIQLOP_IDATASERIES_H
3
3
4 #include <Common/MetaTypes.h>
4 #include <Common/MetaTypes.h>
5 #include <Data/DataSeriesIterator.h>
5 #include <Data/DataSeriesIterator.h>
6 #include <Data/SqpRange.h>
6 #include <Data/SqpRange.h>
7
7
8 #include <memory>
8 #include <memory>
9
9
10 #include <QString>
10 #include <QString>
11
11
12 template <int Dim>
12 template <int Dim>
13 class ArrayData;
13 class ArrayData;
14
14
15 struct Unit {
15 struct Unit {
16 explicit Unit(const QString &name = {}, bool timeUnit = false)
16 explicit Unit(const QString &name = {}, bool timeUnit = false)
17 : m_Name{name}, m_TimeUnit{timeUnit}
17 : m_Name{name}, m_TimeUnit{timeUnit}
18 {
18 {
19 }
19 }
20
20
21 inline bool operator==(const Unit &other) const
21 inline bool operator==(const Unit &other) const
22 {
22 {
23 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
23 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
24 }
24 }
25 inline bool operator!=(const Unit &other) const { return !(*this == other); }
25 inline bool operator!=(const Unit &other) const { return !(*this == other); }
26
26
27 QString m_Name; ///< Unit name
27 QString m_Name; ///< Unit name
28 bool m_TimeUnit; ///< The unit is a unit of time (UTC)
28 bool m_TimeUnit; ///< The unit is a unit of time (UTC)
29 };
29 };
30
30
31 /**
31 /**
32 * @brief The IDataSeries aims to declare a data series.
32 * @brief The IDataSeries aims to declare a data series.
33 *
33 *
34 * A data series is an entity that contains at least :
34 * A data series is an entity that contains at least :
35 * - one dataset representing the x-axis
35 * - one dataset representing the x-axis
36 * - one dataset representing the values
36 * - one dataset representing the values
37 *
37 *
38 * Each dataset is represented by an ArrayData, and is associated with a unit.
38 * Each dataset is represented by an ArrayData, and is associated with a unit.
39 *
39 *
40 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
40 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
41 * IDataSeries. The x-axis dataset is always unidimensional.
41 * IDataSeries. The x-axis dataset is always unidimensional.
42 *
42 *
43 * @sa ArrayData
43 * @sa ArrayData
44 */
44 */
45 class IDataSeries {
45 class IDataSeries {
46 public:
46 public:
47 virtual ~IDataSeries() noexcept = default;
47 virtual ~IDataSeries() noexcept = default;
48
48
49 /// Returns the x-axis dataset
49 /// Returns the x-axis dataset
50 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
50 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
51
51
52 /// Returns the x-axis dataset (as const)
52 /// Returns the x-axis dataset (as const)
53 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
53 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
54
54
55 virtual Unit xAxisUnit() const = 0;
55 virtual Unit xAxisUnit() const = 0;
56
56
57 virtual Unit valuesUnit() const = 0;
57 virtual Unit valuesUnit() const = 0;
58
58
59 virtual void merge(IDataSeries *dataSeries) = 0;
59 virtual void merge(IDataSeries *dataSeries) = 0;
60 /// Removes from data series all entries whose value on the x-axis is not between min and max
60 /// Removes from data series all entries whose value on the x-axis is not between min and max
61 virtual void purge(double min, double max) = 0;
61 virtual void purge(double min, double max) = 0;
62
62
63 /// @todo Review the name and signature of this method
63 /// @todo Review the name and signature of this method
64 virtual std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) = 0;
64 virtual std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) = 0;
65
65
66 virtual std::unique_ptr<IDataSeries> clone() const = 0;
66 virtual std::unique_ptr<IDataSeries> clone() const = 0;
67
67
68 /// @return the total number of points contained in the data series
68 /// @return the total number of points contained in the data series
69 virtual int nbPoints() const = 0;
69 virtual int nbPoints() const = 0;
70
70
71 virtual SqpRange range() const = 0;
72
73 // ///////// //
71 // ///////// //
74 // Iterators //
72 // Iterators //
75 // ///////// //
73 // ///////// //
76
74
77 virtual DataSeriesIterator cbegin() const = 0;
75 virtual DataSeriesIterator cbegin() const = 0;
78 virtual DataSeriesIterator cend() const = 0;
76 virtual DataSeriesIterator cend() const = 0;
79 virtual DataSeriesIterator begin() = 0;
77 virtual DataSeriesIterator begin() = 0;
80 virtual DataSeriesIterator end() = 0;
78 virtual DataSeriesIterator end() = 0;
81
79
82 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
80 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
83 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
81 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
84 virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0;
82 virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0;
85
83
86 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
84 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
87 /// equal to the value passed in parameter, or the end iterator if there is no matching value
85 /// equal to the value passed in parameter, or the end iterator if there is no matching value
88 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
86 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
89
87
90 /// @return the iterators pointing to the range of data whose x-axis values are between min and
88 /// @return the iterators pointing to the range of data whose x-axis values are between min and
91 /// max passed in parameters
89 /// max passed in parameters
92 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
90 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
93 xAxisRange(double minXAxisData, double maxXAxisData) const = 0;
91 xAxisRange(double minXAxisData, double maxXAxisData) const = 0;
94
92
95 /// @return two iterators pointing to the data that have respectively the min and the max value
93 /// @return two iterators pointing to the data that have respectively the min and the max value
96 /// data of a data series' range. The search is performed for a given x-axis range.
94 /// data of a data series' range. The search is performed for a given x-axis range.
97 /// @sa xAxisRange()
95 /// @sa xAxisRange()
98 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
96 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
99 valuesBounds(double minXAxisData, double maxXAxisData) const = 0;
97 valuesBounds(double minXAxisData, double maxXAxisData) const = 0;
100
98
101 // /////// //
99 // /////// //
102 // Mutexes //
100 // Mutexes //
103 // /////// //
101 // /////// //
104
102
105 virtual void lockRead() = 0;
103 virtual void lockRead() = 0;
106 virtual void lockWrite() = 0;
104 virtual void lockWrite() = 0;
107 virtual void unlock() = 0;
105 virtual void unlock() = 0;
108 };
106 };
109
107
110 // Required for using shared_ptr in signals/slots
108 // Required for using shared_ptr in signals/slots
111 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
109 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
112
110
113 #endif // SCIQLOP_IDATASERIES_H
111 #endif // SCIQLOP_IDATASERIES_H
@@ -1,842 +1,840
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2 #include <Variable/VariableAcquisitionWorker.h>
2 #include <Variable/VariableAcquisitionWorker.h>
3 #include <Variable/VariableCacheStrategy.h>
3 #include <Variable/VariableCacheStrategy.h>
4 #include <Variable/VariableCacheStrategyFactory.h>
4 #include <Variable/VariableCacheStrategyFactory.h>
5 #include <Variable/VariableController.h>
5 #include <Variable/VariableController.h>
6 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel.h>
7 #include <Variable/VariableSynchronizationGroup.h>
7 #include <Variable/VariableSynchronizationGroup.h>
8
8
9 #include <Data/DataProviderParameters.h>
9 #include <Data/DataProviderParameters.h>
10 #include <Data/IDataProvider.h>
10 #include <Data/IDataProvider.h>
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <Data/VariableRequest.h>
12 #include <Data/VariableRequest.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14
14
15 #include <QMutex>
15 #include <QMutex>
16 #include <QThread>
16 #include <QThread>
17 #include <QUuid>
17 #include <QUuid>
18 #include <QtCore/QItemSelectionModel>
18 #include <QtCore/QItemSelectionModel>
19
19
20 #include <deque>
20 #include <deque>
21 #include <set>
21 #include <set>
22 #include <unordered_map>
22 #include <unordered_map>
23
23
24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25
25
26 namespace {
26 namespace {
27
27
28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 const SqpRange &oldGraphRange)
29 const SqpRange &oldGraphRange)
30 {
30 {
31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32
32
33 auto varRangeRequested = varRange;
33 auto varRangeRequested = varRange;
34 switch (zoomType) {
34 switch (zoomType) {
35 case AcquisitionZoomType::ZoomIn: {
35 case AcquisitionZoomType::ZoomIn: {
36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 varRangeRequested.m_TStart += deltaLeft;
38 varRangeRequested.m_TStart += deltaLeft;
39 varRangeRequested.m_TEnd -= deltaRight;
39 varRangeRequested.m_TEnd -= deltaRight;
40 break;
40 break;
41 }
41 }
42
42
43 case AcquisitionZoomType::ZoomOut: {
43 case AcquisitionZoomType::ZoomOut: {
44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 varRangeRequested.m_TStart -= deltaLeft;
46 varRangeRequested.m_TStart -= deltaLeft;
47 varRangeRequested.m_TEnd += deltaRight;
47 varRangeRequested.m_TEnd += deltaRight;
48 break;
48 break;
49 }
49 }
50 case AcquisitionZoomType::PanRight: {
50 case AcquisitionZoomType::PanRight: {
51 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
51 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
52 varRangeRequested.m_TStart += deltaRight;
52 varRangeRequested.m_TStart += deltaRight;
53 varRangeRequested.m_TEnd += deltaRight;
53 varRangeRequested.m_TEnd += deltaRight;
54 break;
54 break;
55 }
55 }
56 case AcquisitionZoomType::PanLeft: {
56 case AcquisitionZoomType::PanLeft: {
57 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
57 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
58 varRangeRequested.m_TStart -= deltaLeft;
58 varRangeRequested.m_TStart -= deltaLeft;
59 varRangeRequested.m_TEnd -= deltaLeft;
59 varRangeRequested.m_TEnd -= deltaLeft;
60 break;
60 break;
61 }
61 }
62 case AcquisitionZoomType::Unknown: {
62 case AcquisitionZoomType::Unknown: {
63 qCCritical(LOG_VariableController())
63 qCCritical(LOG_VariableController())
64 << VariableController::tr("Impossible to synchronize: zoom type unknown");
64 << VariableController::tr("Impossible to synchronize: zoom type unknown");
65 break;
65 break;
66 }
66 }
67 default:
67 default:
68 qCCritical(LOG_VariableController()) << VariableController::tr(
68 qCCritical(LOG_VariableController()) << VariableController::tr(
69 "Impossible to synchronize: zoom type not take into account");
69 "Impossible to synchronize: zoom type not take into account");
70 // No action
70 // No action
71 break;
71 break;
72 }
72 }
73
73
74 return varRangeRequested;
74 return varRangeRequested;
75 }
75 }
76 }
76 }
77
77
78 struct VariableController::VariableControllerPrivate {
78 struct VariableController::VariableControllerPrivate {
79 explicit VariableControllerPrivate(VariableController *parent)
79 explicit VariableControllerPrivate(VariableController *parent)
80 : m_WorkingMutex{},
80 : m_WorkingMutex{},
81 m_VariableModel{new VariableModel{parent}},
81 m_VariableModel{new VariableModel{parent}},
82 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
82 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
83 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
84 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
84 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
85 CacheStrategy::SingleThreshold)},
85 CacheStrategy::SingleThreshold)},
86 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
86 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
87 q{parent}
87 q{parent}
88 {
88 {
89
89
90 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
90 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
91 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
91 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
92 }
92 }
93
93
94
94
95 virtual ~VariableControllerPrivate()
95 virtual ~VariableControllerPrivate()
96 {
96 {
97 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
97 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
98 m_VariableAcquisitionWorkerThread.quit();
98 m_VariableAcquisitionWorkerThread.quit();
99 m_VariableAcquisitionWorkerThread.wait();
99 m_VariableAcquisitionWorkerThread.wait();
100 }
100 }
101
101
102
102
103 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
103 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
104 QUuid varRequestId);
104 QUuid varRequestId);
105
105
106 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
106 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
107 const SqpRange &dateTime);
107 const SqpRange &dateTime);
108
108
109 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
109 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
110 std::shared_ptr<IDataSeries>
110 std::shared_ptr<IDataSeries>
111 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
111 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
112
112
113 void registerProvider(std::shared_ptr<IDataProvider> provider);
113 void registerProvider(std::shared_ptr<IDataProvider> provider);
114
114
115 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
115 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
116 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
116 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
117 void updateVariableRequest(QUuid varRequestId);
117 void updateVariableRequest(QUuid varRequestId);
118 void cancelVariableRequest(QUuid varRequestId);
118 void cancelVariableRequest(QUuid varRequestId);
119
119
120 QMutex m_WorkingMutex;
120 QMutex m_WorkingMutex;
121 /// Variable model. The VariableController has the ownership
121 /// Variable model. The VariableController has the ownership
122 VariableModel *m_VariableModel;
122 VariableModel *m_VariableModel;
123 QItemSelectionModel *m_VariableSelectionModel;
123 QItemSelectionModel *m_VariableSelectionModel;
124
124
125
125
126 TimeController *m_TimeController{nullptr};
126 TimeController *m_TimeController{nullptr};
127 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
127 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
128 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
128 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
129 QThread m_VariableAcquisitionWorkerThread;
129 QThread m_VariableAcquisitionWorkerThread;
130
130
131 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
131 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
132 m_VariableToProviderMap;
132 m_VariableToProviderMap;
133 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
133 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
134 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
134 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
135 m_GroupIdToVariableSynchronizationGroupMap;
135 m_GroupIdToVariableSynchronizationGroupMap;
136 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
136 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
137 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
137 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
138
138
139 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
139 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
140
140
141 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
141 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
142
142
143
143
144 VariableController *q;
144 VariableController *q;
145 };
145 };
146
146
147
147
148 VariableController::VariableController(QObject *parent)
148 VariableController::VariableController(QObject *parent)
149 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
149 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
150 {
150 {
151 qCDebug(LOG_VariableController()) << tr("VariableController construction")
151 qCDebug(LOG_VariableController()) << tr("VariableController construction")
152 << QThread::currentThread();
152 << QThread::currentThread();
153
153
154 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
154 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
155 &VariableController::onAbortProgressRequested);
155 &VariableController::onAbortProgressRequested);
156
156
157 connect(impl->m_VariableAcquisitionWorker.get(),
157 connect(impl->m_VariableAcquisitionWorker.get(),
158 &VariableAcquisitionWorker::variableCanceledRequested, this,
158 &VariableAcquisitionWorker::variableCanceledRequested, this,
159 &VariableController::onAbortAcquisitionRequested);
159 &VariableController::onAbortAcquisitionRequested);
160
160
161 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
161 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
162 &VariableController::onDataProvided);
162 &VariableController::onDataProvided);
163 connect(impl->m_VariableAcquisitionWorker.get(),
163 connect(impl->m_VariableAcquisitionWorker.get(),
164 &VariableAcquisitionWorker::variableRequestInProgress, this,
164 &VariableAcquisitionWorker::variableRequestInProgress, this,
165 &VariableController::onVariableRetrieveDataInProgress);
165 &VariableController::onVariableRetrieveDataInProgress);
166
166
167
167
168 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
168 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
169 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
169 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
170 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
170 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
171 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
171 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
172
172
173
173
174 impl->m_VariableAcquisitionWorkerThread.start();
174 impl->m_VariableAcquisitionWorkerThread.start();
175 }
175 }
176
176
177 VariableController::~VariableController()
177 VariableController::~VariableController()
178 {
178 {
179 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
179 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
180 << QThread::currentThread();
180 << QThread::currentThread();
181 this->waitForFinish();
181 this->waitForFinish();
182 }
182 }
183
183
184 VariableModel *VariableController::variableModel() noexcept
184 VariableModel *VariableController::variableModel() noexcept
185 {
185 {
186 return impl->m_VariableModel;
186 return impl->m_VariableModel;
187 }
187 }
188
188
189 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
189 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
190 {
190 {
191 return impl->m_VariableSelectionModel;
191 return impl->m_VariableSelectionModel;
192 }
192 }
193
193
194 void VariableController::setTimeController(TimeController *timeController) noexcept
194 void VariableController::setTimeController(TimeController *timeController) noexcept
195 {
195 {
196 impl->m_TimeController = timeController;
196 impl->m_TimeController = timeController;
197 }
197 }
198
198
199 std::shared_ptr<Variable>
199 std::shared_ptr<Variable>
200 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
200 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
201 {
201 {
202 if (impl->m_VariableModel->containsVariable(variable)) {
202 if (impl->m_VariableModel->containsVariable(variable)) {
203 // Clones variable
203 // Clones variable
204 auto duplicate = variable->clone();
204 auto duplicate = variable->clone();
205
205
206 // Adds clone to model
206 // Adds clone to model
207 impl->m_VariableModel->addVariable(duplicate);
207 impl->m_VariableModel->addVariable(duplicate);
208
208
209 // Generates clone identifier
209 // Generates clone identifier
210 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
210 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
211
211
212 // Registers provider
212 // Registers provider
213 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
213 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
214 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
214 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
215
215
216 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
216 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
217 if (duplicateProvider) {
217 if (duplicateProvider) {
218 impl->registerProvider(duplicateProvider);
218 impl->registerProvider(duplicateProvider);
219 }
219 }
220
220
221 return duplicate;
221 return duplicate;
222 }
222 }
223 else {
223 else {
224 qCCritical(LOG_VariableController())
224 qCCritical(LOG_VariableController())
225 << tr("Can't create duplicate of variable %1: variable not registered in the model")
225 << tr("Can't create duplicate of variable %1: variable not registered in the model")
226 .arg(variable->name());
226 .arg(variable->name());
227 return nullptr;
227 return nullptr;
228 }
228 }
229 }
229 }
230
230
231 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
231 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
232 {
232 {
233 if (!variable) {
233 if (!variable) {
234 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
234 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
235 return;
235 return;
236 }
236 }
237
237
238 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
238 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
239 // make some treatments before the deletion
239 // make some treatments before the deletion
240 emit variableAboutToBeDeleted(variable);
240 emit variableAboutToBeDeleted(variable);
241
241
242 // Deletes identifier
242 // Deletes identifier
243 impl->m_VariableToIdentifierMap.erase(variable);
243 impl->m_VariableToIdentifierMap.erase(variable);
244
244
245 // Deletes provider
245 // Deletes provider
246 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
246 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
247 qCDebug(LOG_VariableController())
247 qCDebug(LOG_VariableController())
248 << tr("Number of providers deleted for variable %1: %2")
248 << tr("Number of providers deleted for variable %1: %2")
249 .arg(variable->name(), QString::number(nbProvidersDeleted));
249 .arg(variable->name(), QString::number(nbProvidersDeleted));
250
250
251
251
252 // Deletes from model
252 // Deletes from model
253 impl->m_VariableModel->deleteVariable(variable);
253 impl->m_VariableModel->deleteVariable(variable);
254 }
254 }
255
255
256 void VariableController::deleteVariables(
256 void VariableController::deleteVariables(
257 const QVector<std::shared_ptr<Variable> > &variables) noexcept
257 const QVector<std::shared_ptr<Variable> > &variables) noexcept
258 {
258 {
259 for (auto variable : qAsConst(variables)) {
259 for (auto variable : qAsConst(variables)) {
260 deleteVariable(variable);
260 deleteVariable(variable);
261 }
261 }
262 }
262 }
263
263
264 std::shared_ptr<Variable>
264 std::shared_ptr<Variable>
265 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
265 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
266 std::shared_ptr<IDataProvider> provider) noexcept
266 std::shared_ptr<IDataProvider> provider) noexcept
267 {
267 {
268 if (!impl->m_TimeController) {
268 if (!impl->m_TimeController) {
269 qCCritical(LOG_VariableController())
269 qCCritical(LOG_VariableController())
270 << tr("Impossible to create variable: The time controller is null");
270 << tr("Impossible to create variable: The time controller is null");
271 return nullptr;
271 return nullptr;
272 }
272 }
273
273
274 auto range = impl->m_TimeController->dateTime();
274 auto range = impl->m_TimeController->dateTime();
275
275
276 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
276 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
277 auto identifier = QUuid::createUuid();
277 auto identifier = QUuid::createUuid();
278
278
279 // store the provider
279 // store the provider
280 impl->registerProvider(provider);
280 impl->registerProvider(provider);
281
281
282 // Associate the provider
282 // Associate the provider
283 impl->m_VariableToProviderMap[newVariable] = provider;
283 impl->m_VariableToProviderMap[newVariable] = provider;
284 qCInfo(LOG_VariableController()) << "createVariable: " << identifier;
284 qCInfo(LOG_VariableController()) << "createVariable: " << identifier;
285 impl->m_VariableToIdentifierMap[newVariable] = identifier;
285 impl->m_VariableToIdentifierMap[newVariable] = identifier;
286
286
287
287
288 auto varRequestId = QUuid::createUuid();
288 auto varRequestId = QUuid::createUuid();
289 impl->processRequest(newVariable, range, varRequestId);
289 impl->processRequest(newVariable, range, varRequestId);
290 impl->updateVariableRequest(varRequestId);
290 impl->updateVariableRequest(varRequestId);
291
291
292 return newVariable;
292 return newVariable;
293 }
293 }
294 }
294 }
295
295
296 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
296 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
297 {
297 {
298 // TODO check synchronisation and Rescale
298 // TODO check synchronisation and Rescale
299 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
299 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
300 << QThread::currentThread()->objectName();
300 << QThread::currentThread()->objectName();
301 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
301 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
302 auto varRequestId = QUuid::createUuid();
302 auto varRequestId = QUuid::createUuid();
303
303
304 for (const auto &selectedRow : qAsConst(selectedRows)) {
304 for (const auto &selectedRow : qAsConst(selectedRows)) {
305 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
305 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
306 selectedVariable->setRange(dateTime);
306 selectedVariable->setRange(dateTime);
307 impl->processRequest(selectedVariable, dateTime, varRequestId);
307 impl->processRequest(selectedVariable, dateTime, varRequestId);
308
308
309 // notify that rescale operation has to be done
309 // notify that rescale operation has to be done
310 emit rangeChanged(selectedVariable, dateTime);
310 emit rangeChanged(selectedVariable, dateTime);
311 }
311 }
312 }
312 }
313 impl->updateVariableRequest(varRequestId);
313 impl->updateVariableRequest(varRequestId);
314 }
314 }
315
315
316 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
316 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
317 const SqpRange &cacheRangeRequested,
317 const SqpRange &cacheRangeRequested,
318 QVector<AcquisitionDataPacket> dataAcquired)
318 QVector<AcquisitionDataPacket> dataAcquired)
319 {
319 {
320 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
320 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
321 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
321 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
322 if (!varRequestId.isNull()) {
322 if (!varRequestId.isNull()) {
323 impl->updateVariableRequest(varRequestId);
323 impl->updateVariableRequest(varRequestId);
324 }
324 }
325 }
325 }
326
326
327 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
327 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
328 {
328 {
329 qCDebug(LOG_VariableController())
329 qCDebug(LOG_VariableController())
330 << "TORM: variableController::onVariableRetrieveDataInProgress"
330 << "TORM: variableController::onVariableRetrieveDataInProgress"
331 << QThread::currentThread()->objectName() << progress;
331 << QThread::currentThread()->objectName() << progress;
332 if (auto var = impl->findVariable(identifier)) {
332 if (auto var = impl->findVariable(identifier)) {
333 impl->m_VariableModel->setDataProgress(var, progress);
333 impl->m_VariableModel->setDataProgress(var, progress);
334 }
334 }
335 else {
335 else {
336 qCCritical(LOG_VariableController())
336 qCCritical(LOG_VariableController())
337 << tr("Impossible to notify progression of a null variable");
337 << tr("Impossible to notify progression of a null variable");
338 }
338 }
339 }
339 }
340
340
341 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
341 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
342 {
342 {
343 auto it = impl->m_VariableToIdentifierMap.find(variable);
343 auto it = impl->m_VariableToIdentifierMap.find(variable);
344 if (it != impl->m_VariableToIdentifierMap.cend()) {
344 if (it != impl->m_VariableToIdentifierMap.cend()) {
345 impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second);
345 impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second);
346
346
347 QUuid varRequestId;
347 QUuid varRequestId;
348 auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second);
348 auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second);
349 if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) {
349 if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) {
350 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
350 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
351 varRequestId = varRequestIdQueue.front();
351 varRequestId = varRequestIdQueue.front();
352 impl->cancelVariableRequest(varRequestId);
352 impl->cancelVariableRequest(varRequestId);
353
353
354 // Finish the progression for the request
354 // Finish the progression for the request
355 impl->m_VariableModel->setDataProgress(variable, 0.0);
355 impl->m_VariableModel->setDataProgress(variable, 0.0);
356 }
356 }
357 else {
357 else {
358 qCWarning(LOG_VariableController())
358 qCWarning(LOG_VariableController())
359 << tr("Aborting progression of inexistant variable request detected !!!")
359 << tr("Aborting progression of inexistant variable request detected !!!")
360 << QThread::currentThread()->objectName();
360 << QThread::currentThread()->objectName();
361 }
361 }
362 }
362 }
363 else {
363 else {
364 qCWarning(LOG_VariableController())
364 qCWarning(LOG_VariableController())
365 << tr("Aborting progression of inexistant variable detected !!!")
365 << tr("Aborting progression of inexistant variable detected !!!")
366 << QThread::currentThread()->objectName();
366 << QThread::currentThread()->objectName();
367 }
367 }
368 }
368 }
369
369
370 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
370 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
371 {
371 {
372 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
372 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
373 << QThread::currentThread()->objectName() << vIdentifier;
373 << QThread::currentThread()->objectName() << vIdentifier;
374
374
375 if (auto var = impl->findVariable(vIdentifier)) {
375 if (auto var = impl->findVariable(vIdentifier)) {
376 this->onAbortProgressRequested(var);
376 this->onAbortProgressRequested(var);
377 }
377 }
378 else {
378 else {
379 qCCritical(LOG_VariableController())
379 qCCritical(LOG_VariableController())
380 << tr("Impossible to abort Acquisition Requestof a null variable");
380 << tr("Impossible to abort Acquisition Requestof a null variable");
381 }
381 }
382 }
382 }
383
383
384 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
384 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
385 {
385 {
386 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
386 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
387 << QThread::currentThread()->objectName()
387 << QThread::currentThread()->objectName()
388 << synchronizationGroupId;
388 << synchronizationGroupId;
389 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
389 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
390 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
390 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
391 std::make_pair(synchronizationGroupId, vSynchroGroup));
391 std::make_pair(synchronizationGroupId, vSynchroGroup));
392 }
392 }
393
393
394 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
394 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
395 {
395 {
396 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
396 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
397 }
397 }
398
398
399 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
399 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
400 QUuid synchronizationGroupId)
400 QUuid synchronizationGroupId)
401
401
402 {
402 {
403 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
403 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
404 << synchronizationGroupId;
404 << synchronizationGroupId;
405 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
405 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
406 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
406 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
407 auto groupIdToVSGIt
407 auto groupIdToVSGIt
408 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
408 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
409 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
409 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
410 impl->m_VariableIdGroupIdMap.insert(
410 impl->m_VariableIdGroupIdMap.insert(
411 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
411 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
412 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
412 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
413 }
413 }
414 else {
414 else {
415 qCCritical(LOG_VariableController())
415 qCCritical(LOG_VariableController())
416 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
416 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
417 << variable->name();
417 << variable->name();
418 }
418 }
419 }
419 }
420 else {
420 else {
421 qCCritical(LOG_VariableController())
421 qCCritical(LOG_VariableController())
422 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
422 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
423 }
423 }
424 }
424 }
425
425
426 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
426 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
427 QUuid synchronizationGroupId)
427 QUuid synchronizationGroupId)
428 {
428 {
429 // Gets variable id
429 // Gets variable id
430 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
430 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
431 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
431 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
432 qCCritical(LOG_VariableController())
432 qCCritical(LOG_VariableController())
433 << tr("Can't desynchronize variable %1: variable identifier not found")
433 << tr("Can't desynchronize variable %1: variable identifier not found")
434 .arg(variable->name());
434 .arg(variable->name());
435 return;
435 return;
436 }
436 }
437
437
438 // Gets synchronization group
438 // Gets synchronization group
439 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
439 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
440 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
440 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
441 qCCritical(LOG_VariableController())
441 qCCritical(LOG_VariableController())
442 << tr("Can't desynchronize variable %1: unknown synchronization group")
442 << tr("Can't desynchronize variable %1: unknown synchronization group")
443 .arg(variable->name());
443 .arg(variable->name());
444 return;
444 return;
445 }
445 }
446
446
447 auto variableId = variableIt->second;
447 auto variableId = variableIt->second;
448
448
449 // Removes variable from synchronization group
449 // Removes variable from synchronization group
450 auto synchronizationGroup = groupIt->second;
450 auto synchronizationGroup = groupIt->second;
451 synchronizationGroup->removeVariableId(variableId);
451 synchronizationGroup->removeVariableId(variableId);
452
452
453 // Removes link between variable and synchronization group
453 // Removes link between variable and synchronization group
454 impl->m_VariableIdGroupIdMap.erase(variableId);
454 impl->m_VariableIdGroupIdMap.erase(variableId);
455 }
455 }
456
456
457 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
457 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
458 const SqpRange &range, const SqpRange &oldRange,
458 const SqpRange &range, const SqpRange &oldRange,
459 bool synchronise)
459 bool synchronise)
460 {
460 {
461 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
461 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
462
462
463 // we want to load data of the variable for the dateTime.
463 // we want to load data of the variable for the dateTime.
464 // First we check if the cache contains some of them.
464 // First we check if the cache contains some of them.
465 // For the other, we ask the provider to give them.
465 // For the other, we ask the provider to give them.
466
466
467 auto varRequestId = QUuid::createUuid();
467 auto varRequestId = QUuid::createUuid();
468 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
468 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
469 << QThread::currentThread()->objectName() << varRequestId;
469 << QThread::currentThread()->objectName() << varRequestId;
470
470
471 for (const auto &var : variables) {
471 for (const auto &var : variables) {
472 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
472 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
473 impl->processRequest(var, range, varRequestId);
473 impl->processRequest(var, range, varRequestId);
474 }
474 }
475
475
476 if (synchronise) {
476 if (synchronise) {
477 // Get the group ids
477 // Get the group ids
478 qCDebug(LOG_VariableController())
478 qCDebug(LOG_VariableController())
479 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
479 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
480 auto groupIds = std::set<QUuid>{};
480 auto groupIds = std::set<QUuid>{};
481 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
481 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
482 for (const auto &var : variables) {
482 for (const auto &var : variables) {
483 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
483 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
484 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
484 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
485 auto vId = varToVarIdIt->second;
485 auto vId = varToVarIdIt->second;
486 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
486 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
487 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
487 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
488 auto gId = varIdToGroupIdIt->second;
488 auto gId = varIdToGroupIdIt->second;
489 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
489 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
490 if (groupIds.find(gId) == groupIds.cend()) {
490 if (groupIds.find(gId) == groupIds.cend()) {
491 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
491 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
492 groupIds.insert(gId);
492 groupIds.insert(gId);
493 }
493 }
494 }
494 }
495 }
495 }
496 }
496 }
497
497
498 // We assume here all group ids exist
498 // We assume here all group ids exist
499 for (const auto &gId : groupIds) {
499 for (const auto &gId : groupIds) {
500 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
500 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
501 auto vSyncIds = vSynchronizationGroup->getIds();
501 auto vSyncIds = vSynchronizationGroup->getIds();
502 qCDebug(LOG_VariableController()) << "Var in synchro group ";
502 qCDebug(LOG_VariableController()) << "Var in synchro group ";
503 for (auto vId : vSyncIds) {
503 for (auto vId : vSyncIds) {
504 auto var = impl->findVariable(vId);
504 auto var = impl->findVariable(vId);
505
505
506 // Don't process already processed var
506 // Don't process already processed var
507 if (!variables.contains(var)) {
507 if (!variables.contains(var)) {
508 if (var != nullptr) {
508 if (var != nullptr) {
509 qCDebug(LOG_VariableController()) << "processRequest synchro for"
509 qCDebug(LOG_VariableController()) << "processRequest synchro for"
510 << var->name();
510 << var->name();
511 auto vSyncRangeRequested = computeSynchroRangeRequested(
511 auto vSyncRangeRequested = computeSynchroRangeRequested(
512 var->range(), range, groupIdToOldRangeMap.at(gId));
512 var->range(), range, groupIdToOldRangeMap.at(gId));
513 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
513 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
514 impl->processRequest(var, vSyncRangeRequested, varRequestId);
514 impl->processRequest(var, vSyncRangeRequested, varRequestId);
515 }
515 }
516 else {
516 else {
517 qCCritical(LOG_VariableController())
517 qCCritical(LOG_VariableController())
518
518
519 << tr("Impossible to synchronize a null variable");
519 << tr("Impossible to synchronize a null variable");
520 }
520 }
521 }
521 }
522 }
522 }
523 }
523 }
524 }
524 }
525
525
526 impl->updateVariableRequest(varRequestId);
526 impl->updateVariableRequest(varRequestId);
527 }
527 }
528
528
529
529
530 void VariableController::initialize()
530 void VariableController::initialize()
531 {
531 {
532 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
532 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
533 impl->m_WorkingMutex.lock();
533 impl->m_WorkingMutex.lock();
534 qCDebug(LOG_VariableController()) << tr("VariableController init END");
534 qCDebug(LOG_VariableController()) << tr("VariableController init END");
535 }
535 }
536
536
537 void VariableController::finalize()
537 void VariableController::finalize()
538 {
538 {
539 impl->m_WorkingMutex.unlock();
539 impl->m_WorkingMutex.unlock();
540 }
540 }
541
541
542 void VariableController::waitForFinish()
542 void VariableController::waitForFinish()
543 {
543 {
544 QMutexLocker locker{&impl->m_WorkingMutex};
544 QMutexLocker locker{&impl->m_WorkingMutex};
545 }
545 }
546
546
547 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
547 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
548 {
548 {
549 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
549 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
550 auto zoomType = AcquisitionZoomType::Unknown;
550 auto zoomType = AcquisitionZoomType::Unknown;
551 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
551 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
552 zoomType = AcquisitionZoomType::ZoomOut;
552 zoomType = AcquisitionZoomType::ZoomOut;
553 }
553 }
554 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
554 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
555 zoomType = AcquisitionZoomType::PanRight;
555 zoomType = AcquisitionZoomType::PanRight;
556 }
556 }
557 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
557 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
558 zoomType = AcquisitionZoomType::PanLeft;
558 zoomType = AcquisitionZoomType::PanLeft;
559 }
559 }
560 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
560 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
561 zoomType = AcquisitionZoomType::ZoomIn;
561 zoomType = AcquisitionZoomType::ZoomIn;
562 }
562 }
563 else {
563 else {
564 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
564 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
565 }
565 }
566 return zoomType;
566 return zoomType;
567 }
567 }
568
568
569 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
569 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
570 const SqpRange &rangeRequested,
570 const SqpRange &rangeRequested,
571 QUuid varRequestId)
571 QUuid varRequestId)
572 {
572 {
573
573
574 // TODO: protect at
574 // TODO: protect at
575 auto varRequest = VariableRequest{};
575 auto varRequest = VariableRequest{};
576 auto varId = m_VariableToIdentifierMap.at(var);
576 auto varId = m_VariableToIdentifierMap.at(var);
577
577
578 auto varStrategyRangesRequested
578 auto varStrategyRangesRequested
579 = m_VariableCacheStrategy->computeRange(var->range(), rangeRequested);
579 = m_VariableCacheStrategy->computeRange(var->range(), rangeRequested);
580
580
581 auto notInCacheRangeList = QVector<SqpRange>{varStrategyRangesRequested.second};
581 auto notInCacheRangeList = QVector<SqpRange>{varStrategyRangesRequested.second};
582 auto inCacheRangeList = QVector<SqpRange>{};
582 auto inCacheRangeList = QVector<SqpRange>{};
583 if (m_VarIdToVarRequestIdQueueMap.find(varId) == m_VarIdToVarRequestIdQueueMap.cend()) {
583 if (m_VarIdToVarRequestIdQueueMap.find(varId) == m_VarIdToVarRequestIdQueueMap.cend()) {
584 notInCacheRangeList = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
584 notInCacheRangeList = var->provideNotInCacheRangeList(varStrategyRangesRequested.second);
585 inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
585 inCacheRangeList = var->provideInCacheRangeList(varStrategyRangesRequested.second);
586 }
586 }
587
587
588 if (!notInCacheRangeList.empty()) {
588 if (!notInCacheRangeList.empty()) {
589 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
589 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
590 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
590 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
591
591
592 // store VarRequest
592 // store VarRequest
593 storeVariableRequest(varId, varRequestId, varRequest);
593 storeVariableRequest(varId, varRequestId, varRequest);
594
594
595 auto varProvider = m_VariableToProviderMap.at(var);
595 auto varProvider = m_VariableToProviderMap.at(var);
596 if (varProvider != nullptr) {
596 if (varProvider != nullptr) {
597 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
597 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
598 varRequestId, varId, varStrategyRangesRequested.first,
598 varRequestId, varId, varStrategyRangesRequested.first,
599 varStrategyRangesRequested.second,
599 varStrategyRangesRequested.second,
600 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
600 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
601 varProvider);
601 varProvider);
602
602
603 if (!varRequestIdCanceled.isNull()) {
603 if (!varRequestIdCanceled.isNull()) {
604 qCDebug(LOG_VariableAcquisitionWorker()) << tr("vsarRequestIdCanceled: ")
604 qCDebug(LOG_VariableAcquisitionWorker()) << tr("vsarRequestIdCanceled: ")
605 << varRequestIdCanceled;
605 << varRequestIdCanceled;
606 cancelVariableRequest(varRequestIdCanceled);
606 cancelVariableRequest(varRequestIdCanceled);
607 }
607 }
608 }
608 }
609 else {
609 else {
610 qCCritical(LOG_VariableController())
610 qCCritical(LOG_VariableController())
611 << "Impossible to provide data with a null provider";
611 << "Impossible to provide data with a null provider";
612 }
612 }
613
613
614 if (!inCacheRangeList.empty()) {
614 if (!inCacheRangeList.empty()) {
615 emit q->updateVarDisplaying(var, inCacheRangeList.first());
615 emit q->updateVarDisplaying(var, inCacheRangeList.first());
616 }
616 }
617 }
617 }
618 else {
618 else {
619 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
619 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
620 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
620 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
621 // store VarRequest
621 // store VarRequest
622 storeVariableRequest(varId, varRequestId, varRequest);
622 storeVariableRequest(varId, varRequestId, varRequest);
623 acceptVariableRequest(varId,
623 acceptVariableRequest(varId,
624 var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
624 var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
625 }
625 }
626 }
626 }
627
627
628 std::shared_ptr<Variable>
628 std::shared_ptr<Variable>
629 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
629 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
630 {
630 {
631 std::shared_ptr<Variable> var;
631 std::shared_ptr<Variable> var;
632 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
632 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
633
633
634 auto end = m_VariableToIdentifierMap.cend();
634 auto end = m_VariableToIdentifierMap.cend();
635 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
635 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
636 if (it != end) {
636 if (it != end) {
637 var = it->first;
637 var = it->first;
638 }
638 }
639 else {
639 else {
640 qCCritical(LOG_VariableController())
640 qCCritical(LOG_VariableController())
641 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
641 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
642 }
642 }
643
643
644 return var;
644 return var;
645 }
645 }
646
646
647 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
647 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
648 const QVector<AcquisitionDataPacket> acqDataPacketVector)
648 const QVector<AcquisitionDataPacket> acqDataPacketVector)
649 {
649 {
650 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
650 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
651 << acqDataPacketVector.size();
651 << acqDataPacketVector.size();
652 std::shared_ptr<IDataSeries> dataSeries;
652 std::shared_ptr<IDataSeries> dataSeries;
653 if (!acqDataPacketVector.isEmpty()) {
653 if (!acqDataPacketVector.isEmpty()) {
654 dataSeries = acqDataPacketVector[0].m_DateSeries;
654 dataSeries = acqDataPacketVector[0].m_DateSeries;
655 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
655 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
656 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
656 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
657 }
657 }
658 }
658 }
659 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
659 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
660 << acqDataPacketVector.size();
660 << acqDataPacketVector.size();
661 return dataSeries;
661 return dataSeries;
662 }
662 }
663
663
664 void VariableController::VariableControllerPrivate::registerProvider(
664 void VariableController::VariableControllerPrivate::registerProvider(
665 std::shared_ptr<IDataProvider> provider)
665 std::shared_ptr<IDataProvider> provider)
666 {
666 {
667 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
667 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
668 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
668 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
669 << provider->objectName();
669 << provider->objectName();
670 m_ProviderSet.insert(provider);
670 m_ProviderSet.insert(provider);
671 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
671 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
672 &VariableAcquisitionWorker::onVariableDataAcquired);
672 &VariableAcquisitionWorker::onVariableDataAcquired);
673 connect(provider.get(), &IDataProvider::dataProvidedProgress,
673 connect(provider.get(), &IDataProvider::dataProvidedProgress,
674 m_VariableAcquisitionWorker.get(),
674 m_VariableAcquisitionWorker.get(),
675 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
675 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
676 connect(provider.get(), &IDataProvider::dataProvidedFailed,
676 connect(provider.get(), &IDataProvider::dataProvidedFailed,
677 m_VariableAcquisitionWorker.get(),
677 m_VariableAcquisitionWorker.get(),
678 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
678 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
679 }
679 }
680 else {
680 else {
681 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
681 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
682 }
682 }
683 }
683 }
684
684
685 void VariableController::VariableControllerPrivate::storeVariableRequest(
685 void VariableController::VariableControllerPrivate::storeVariableRequest(
686 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
686 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
687 {
687 {
688 // First request for the variable. we can create an entry for it
688 // First request for the variable. we can create an entry for it
689 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
689 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
690 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
690 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
691 auto varRequestIdQueue = std::deque<QUuid>{};
691 auto varRequestIdQueue = std::deque<QUuid>{};
692 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
692 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
693 varRequestIdQueue.push_back(varRequestId);
693 varRequestIdQueue.push_back(varRequestId);
694 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
694 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
695 }
695 }
696 else {
696 else {
697 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
697 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
698 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
698 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
699 varRequestIdQueue.push_back(varRequestId);
699 varRequestIdQueue.push_back(varRequestId);
700 }
700 }
701
701
702 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
702 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
703 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
703 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
704 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
704 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
705 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
705 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
706 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
706 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
707 m_VarRequestIdToVarIdVarRequestMap.insert(
707 m_VarRequestIdToVarIdVarRequestMap.insert(
708 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
708 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
709 }
709 }
710 else {
710 else {
711 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
711 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
712 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
712 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
713 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
713 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
714 }
714 }
715 }
715 }
716
716
717 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
717 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
718 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
718 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
719 {
719 {
720 QUuid varRequestId;
720 QUuid varRequestId;
721 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
721 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
722 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
722 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
723 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
723 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
724 varRequestId = varRequestIdQueue.front();
724 varRequestId = varRequestIdQueue.front();
725 auto varRequestIdToVarIdVarRequestMapIt
725 auto varRequestIdToVarIdVarRequestMapIt
726 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
726 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
727 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
727 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
728 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
728 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
729 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
729 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
730 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
730 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
731 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
731 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
732 auto &varRequest = varIdToVarRequestMapIt->second;
732 auto &varRequest = varIdToVarRequestMapIt->second;
733 varRequest.m_DataSeries = dataSeries;
733 varRequest.m_DataSeries = dataSeries;
734 varRequest.m_CanUpdate = true;
734 varRequest.m_CanUpdate = true;
735 }
735 }
736 else {
736 else {
737 qCDebug(LOG_VariableController())
737 qCDebug(LOG_VariableController())
738 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
738 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
739 "to a variableRequestId")
739 "to a variableRequestId")
740 << varRequestId << varId;
740 << varRequestId << varId;
741 }
741 }
742 }
742 }
743 else {
743 else {
744 qCCritical(LOG_VariableController())
744 qCCritical(LOG_VariableController())
745 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
745 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
746 << varRequestId;
746 << varRequestId;
747 }
747 }
748
748
749 varRequestIdQueue.pop_front();
749 varRequestIdQueue.pop_front();
750 if (varRequestIdQueue.empty()) {
750 if (varRequestIdQueue.empty()) {
751 qCDebug(LOG_VariableController())
751 qCDebug(LOG_VariableController())
752 << tr("TORM Erase REQUEST because it has been accepted") << varId;
752 << tr("TORM Erase REQUEST because it has been accepted") << varId;
753 m_VarIdToVarRequestIdQueueMap.erase(varId);
753 m_VarIdToVarRequestIdQueueMap.erase(varId);
754 }
754 }
755 }
755 }
756 else {
756 else {
757 qCCritical(LOG_VariableController())
757 qCCritical(LOG_VariableController())
758 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
758 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
759 }
759 }
760
760
761 return varRequestId;
761 return varRequestId;
762 }
762 }
763
763
764 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
764 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
765 {
765 {
766
766
767 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
767 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
768 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
768 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
769 bool processVariableUpdate = true;
769 bool processVariableUpdate = true;
770 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
770 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
771 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
771 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
772 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
772 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
773 ++varIdToVarRequestMapIt) {
773 ++varIdToVarRequestMapIt) {
774 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
774 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
775 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
775 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
776 << processVariableUpdate;
776 << processVariableUpdate;
777 }
777 }
778
778
779 if (processVariableUpdate) {
779 if (processVariableUpdate) {
780 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
780 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
781 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
781 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
782 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
782 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
783 auto &varRequest = varIdToVarRequestMapIt->second;
783 auto &varRequest = varIdToVarRequestMapIt->second;
784 var->setRange(varRequest.m_RangeRequested);
784 var->setRange(varRequest.m_RangeRequested);
785 var->setCacheRange(varRequest.m_CacheRangeRequested);
785 var->setCacheRange(varRequest.m_CacheRangeRequested);
786 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
786 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
787 << varRequest.m_RangeRequested;
787 << varRequest.m_RangeRequested;
788 qCDebug(LOG_VariableController()) << tr("2: onDataProvided")
788 qCDebug(LOG_VariableController()) << tr("2: onDataProvided")
789 << varRequest.m_CacheRangeRequested;
789 << varRequest.m_CacheRangeRequested;
790 var->mergeDataSeries(varRequest.m_DataSeries);
790 var->mergeDataSeries(varRequest.m_DataSeries);
791 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
791 qCDebug(LOG_VariableController()) << tr("3: onDataProvided");
792 << varRequest.m_DataSeries->range();
793 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
794
792
795 /// @todo MPL: confirm
793 /// @todo MPL: confirm
796 // Variable update is notified only if there is no pending request for it
794 // Variable update is notified only if there is no pending request for it
797 // if
795 // if
798 // (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first)
796 // (m_VarIdToVarRequestIdQueueMap.count(varIdToVarRequestMapIt->first)
799 // == 0) {
797 // == 0) {
800 emit var->updated();
798 emit var->updated();
801 // }
799 // }
802 }
800 }
803 else {
801 else {
804 qCCritical(LOG_VariableController())
802 qCCritical(LOG_VariableController())
805 << tr("Impossible to update data to a null variable");
803 << tr("Impossible to update data to a null variable");
806 }
804 }
807 }
805 }
808
806
809 // cleaning varRequestId
807 // cleaning varRequestId
810 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
808 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
811 << m_VarRequestIdToVarIdVarRequestMap.size();
809 << m_VarRequestIdToVarIdVarRequestMap.size();
812 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
810 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
813 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
811 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
814 << m_VarRequestIdToVarIdVarRequestMap.size();
812 << m_VarRequestIdToVarIdVarRequestMap.size();
815 }
813 }
816 }
814 }
817 else {
815 else {
818 qCCritical(LOG_VariableController())
816 qCCritical(LOG_VariableController())
819 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
817 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
820 }
818 }
821 }
819 }
822
820
823 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
821 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
824 {
822 {
825 // cleaning varRequestId
823 // cleaning varRequestId
826 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
824 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
827
825
828 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
826 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
829 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
827 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
830 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
828 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
831 varRequestIdQueue.erase(
829 varRequestIdQueue.erase(
832 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
830 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
833 varRequestIdQueue.end());
831 varRequestIdQueue.end());
834 if (varRequestIdQueue.empty()) {
832 if (varRequestIdQueue.empty()) {
835 varIdToVarRequestIdQueueMapIt
833 varIdToVarRequestIdQueueMapIt
836 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
834 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
837 }
835 }
838 else {
836 else {
839 ++varIdToVarRequestIdQueueMapIt;
837 ++varIdToVarRequestIdQueueMapIt;
840 }
838 }
841 }
839 }
842 }
840 }
@@ -1,636 +1,707
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 #include "Data/VectorSeries.h"
4
4
5 #include <cmath>
5 #include <cmath>
6
6
7 #include <QObject>
7 #include <QObject>
8 #include <QtTest>
8 #include <QtTest>
9
9
10 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
10 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
11 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
11 Q_DECLARE_METATYPE(std::shared_ptr<VectorSeries>)
12
12
13 namespace {
13 namespace {
14
14
15 using DataContainer = std::vector<double>;
15 using DataContainer = std::vector<double>;
16
16
17 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
17 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
18 const DataContainer &valuesData)
18 const DataContainer &valuesData)
19 {
19 {
20 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
20 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
21 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
21 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
22 QVERIFY(std::equal(
22 QVERIFY(std::equal(
23 first, last, valuesData.cbegin(), valuesData.cend(),
23 first, last, valuesData.cbegin(), valuesData.cend(),
24 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
24 [](const auto &it, const auto &expectedVal) { return it.value() == expectedVal; }));
25 }
25 }
26
26
27 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
27 void validateRange(DataSeriesIterator first, DataSeriesIterator last, const DataContainer &xData,
28 const std::vector<DataContainer> &valuesData)
28 const std::vector<DataContainer> &valuesData)
29 {
29 {
30 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
30 QVERIFY(std::equal(first, last, xData.cbegin(), xData.cend(),
31 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
31 [](const auto &it, const auto &expectedX) { return it.x() == expectedX; }));
32 for (auto i = 0; i < valuesData.size(); ++i) {
32 for (auto i = 0; i < valuesData.size(); ++i) {
33 auto componentData = valuesData.at(i);
33 auto componentData = valuesData.at(i);
34
34
35 QVERIFY(std::equal(
35 QVERIFY(std::equal(
36 first, last, componentData.cbegin(), componentData.cend(),
36 first, last, componentData.cbegin(), componentData.cend(),
37 [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; }));
37 [i](const auto &it, const auto &expectedVal) { return it.value(i) == expectedVal; }));
38 }
38 }
39 }
39 }
40
40
41 } // namespace
41 } // namespace
42
42
43 class TestDataSeries : public QObject {
43 class TestDataSeries : public QObject {
44 Q_OBJECT
44 Q_OBJECT
45 private:
45 private:
46 template <typename T>
46 template <typename T>
47 void testValuesBoundsStructure()
47 void testValuesBoundsStructure()
48 {
48 {
49 // ////////////// //
49 // ////////////// //
50 // Test structure //
50 // Test structure //
51 // ////////////// //
51 // ////////////// //
52
52
53 // Data series to get values bounds
53 // Data series to get values bounds
54 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
54 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
55
55
56 // x-axis range
56 // x-axis range
57 QTest::addColumn<double>("minXAxis");
57 QTest::addColumn<double>("minXAxis");
58 QTest::addColumn<double>("maxXAxis");
58 QTest::addColumn<double>("maxXAxis");
59
59
60 // Expected results
60 // Expected results
61 QTest::addColumn<bool>(
61 QTest::addColumn<bool>(
62 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
62 "expectedOK"); // Test is expected to be ok (i.e. method doesn't return end iterators)
63 QTest::addColumn<double>("expectedMinValue");
63 QTest::addColumn<double>("expectedMinValue");
64 QTest::addColumn<double>("expectedMaxValue");
64 QTest::addColumn<double>("expectedMaxValue");
65 }
65 }
66
66
67 template <typename T>
67 template <typename T>
68 void testValuesBounds()
68 void testValuesBounds()
69 {
69 {
70 QFETCH(std::shared_ptr<T>, dataSeries);
70 QFETCH(std::shared_ptr<T>, dataSeries);
71 QFETCH(double, minXAxis);
71 QFETCH(double, minXAxis);
72 QFETCH(double, maxXAxis);
72 QFETCH(double, maxXAxis);
73
73
74 QFETCH(bool, expectedOK);
74 QFETCH(bool, expectedOK);
75 QFETCH(double, expectedMinValue);
75 QFETCH(double, expectedMinValue);
76 QFETCH(double, expectedMaxValue);
76 QFETCH(double, expectedMaxValue);
77
77
78 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
78 auto minMaxIts = dataSeries->valuesBounds(minXAxis, maxXAxis);
79 auto end = dataSeries->cend();
79 auto end = dataSeries->cend();
80
80
81 // Checks iterators with expected result
81 // Checks iterators with expected result
82 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
82 QCOMPARE(expectedOK, minMaxIts.first != end && minMaxIts.second != end);
83
83
84 if (expectedOK) {
84 if (expectedOK) {
85 auto compare = [](const auto &v1, const auto &v2) {
85 auto compare = [](const auto &v1, const auto &v2) {
86 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
86 return (std::isnan(v1) && std::isnan(v2)) || v1 == v2;
87 };
87 };
88
88
89 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
89 QVERIFY(compare(expectedMinValue, minMaxIts.first->minValue()));
90 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
90 QVERIFY(compare(expectedMaxValue, minMaxIts.second->maxValue()));
91 }
91 }
92 }
92 }
93
93
94 template <typename T>
94 template <typename T>
95 void testPurgeStructure()
95 void testPurgeStructure()
96 {
96 {
97 // ////////////// //
97 // ////////////// //
98 // Test structure //
98 // Test structure //
99 // ////////////// //
99 // ////////////// //
100
100
101 // Data series to purge
101 // Data series to purge
102 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
102 QTest::addColumn<std::shared_ptr<T> >("dataSeries");
103 QTest::addColumn<double>("min");
103 QTest::addColumn<double>("min");
104 QTest::addColumn<double>("max");
104 QTest::addColumn<double>("max");
105
105
106 // Expected values after purge
106 // Expected values after purge
107 QTest::addColumn<DataContainer>("expectedXAxisData");
107 QTest::addColumn<DataContainer>("expectedXAxisData");
108 QTest::addColumn<std::vector<DataContainer> >("expectedValuesData");
108 QTest::addColumn<std::vector<DataContainer> >("expectedValuesData");
109 }
109 }
110
110
111 template <typename T>
111 template <typename T>
112 void testPurge()
112 void testPurge()
113 {
113 {
114 QFETCH(std::shared_ptr<T>, dataSeries);
114 QFETCH(std::shared_ptr<T>, dataSeries);
115 QFETCH(double, min);
115 QFETCH(double, min);
116 QFETCH(double, max);
116 QFETCH(double, max);
117
117
118 dataSeries->purge(min, max);
118 dataSeries->purge(min, max);
119
119
120 // Validates results
120 // Validates results
121 QFETCH(DataContainer, expectedXAxisData);
121 QFETCH(DataContainer, expectedXAxisData);
122 QFETCH(std::vector<DataContainer>, expectedValuesData);
122 QFETCH(std::vector<DataContainer>, expectedValuesData);
123
123
124 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData,
124 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData,
125 expectedValuesData);
125 expectedValuesData);
126 }
126 }
127
127
128 template <typename SourceType, typename DestType>
129 void testMergeDifferentTypesStructure()
130 {
131 // ////////////// //
132 // Test structure //
133 // ////////////// //
134
135 // Data series to merge
136 QTest::addColumn<std::shared_ptr<DestType> >("dest");
137 QTest::addColumn<std::shared_ptr<SourceType> >("source");
138
139 // Expected values in the dest data series after merge
140 QTest::addColumn<DataContainer>("expectedXAxisData");
141 QTest::addColumn<DataContainer>("expectedValuesData");
142 }
143
144 template <typename SourceType, typename DestType>
145 void testMergeDifferentTypes()
146 {
147 // Merges series
148 QFETCH(std::shared_ptr<SourceType>, source);
149 QFETCH(std::shared_ptr<DestType>, dest);
150
151 dest->merge(source.get());
152
153 // Validates results : we check that the merge is valid and the data series is sorted on its
154 // x-axis data
155 QFETCH(DataContainer, expectedXAxisData);
156 QFETCH(DataContainer, expectedValuesData);
157
158 validateRange(dest->cbegin(), dest->cend(), expectedXAxisData, expectedValuesData);
159 }
160
128 private slots:
161 private slots:
129
162
130 /// Input test data
163 /// Input test data
131 /// @sa testCtor()
164 /// @sa testCtor()
132 void testCtor_data();
165 void testCtor_data();
133
166
134 /// Tests construction of a data series
167 /// Tests construction of a data series
135 void testCtor();
168 void testCtor();
136
169
137 /// Input test data
170 /// Input test data
138 /// @sa testMerge()
171 /// @sa testMerge()
139 void testMerge_data();
172 void testMerge_data();
140
173
141 /// Tests merge of two data series
174 /// Tests merge of two data series
142 void testMerge();
175 void testMerge();
143
176
144 /// Input test data
177 /// Input test data
178 /// @sa testMergeVectorInScalar()
179 void testMergeVectorInScalar_data();
180
181 /// Tests merge of vector series in scalar series
182 void testMergeVectorInScalar();
183
184 /// Input test data
145 /// @sa testPurgeScalar()
185 /// @sa testPurgeScalar()
146 void testPurgeScalar_data();
186 void testPurgeScalar_data();
147
187
148 /// Tests purge of a scalar series
188 /// Tests purge of a scalar series
149 void testPurgeScalar();
189 void testPurgeScalar();
150
190
151 /// Input test data
191 /// Input test data
152 /// @sa testPurgeVector()
192 /// @sa testPurgeVector()
153 void testPurgeVector_data();
193 void testPurgeVector_data();
154
194
155 /// Tests purge of a vector series
195 /// Tests purge of a vector series
156 void testPurgeVector();
196 void testPurgeVector();
157
197
158 /// Input test data
198 /// Input test data
159 /// @sa testMinXAxisData()
199 /// @sa testMinXAxisData()
160 void testMinXAxisData_data();
200 void testMinXAxisData_data();
161
201
162 /// Tests get min x-axis data of a data series
202 /// Tests get min x-axis data of a data series
163 void testMinXAxisData();
203 void testMinXAxisData();
164
204
165 /// Input test data
205 /// Input test data
166 /// @sa testMaxXAxisData()
206 /// @sa testMaxXAxisData()
167 void testMaxXAxisData_data();
207 void testMaxXAxisData_data();
168
208
169 /// Tests get max x-axis data of a data series
209 /// Tests get max x-axis data of a data series
170 void testMaxXAxisData();
210 void testMaxXAxisData();
171
211
172 /// Input test data
212 /// Input test data
173 /// @sa testXAxisRange()
213 /// @sa testXAxisRange()
174 void testXAxisRange_data();
214 void testXAxisRange_data();
175
215
176 /// Tests get x-axis range of a data series
216 /// Tests get x-axis range of a data series
177 void testXAxisRange();
217 void testXAxisRange();
178
218
179 /// Input test data
219 /// Input test data
180 /// @sa testValuesBoundsScalar()
220 /// @sa testValuesBoundsScalar()
181 void testValuesBoundsScalar_data();
221 void testValuesBoundsScalar_data();
182
222
183 /// Tests get values bounds of a scalar series
223 /// Tests get values bounds of a scalar series
184 void testValuesBoundsScalar();
224 void testValuesBoundsScalar();
185
225
186 /// Input test data
226 /// Input test data
187 /// @sa testValuesBoundsVector()
227 /// @sa testValuesBoundsVector()
188 void testValuesBoundsVector_data();
228 void testValuesBoundsVector_data();
189
229
190 /// Tests get values bounds of a vector series
230 /// Tests get values bounds of a vector series
191 void testValuesBoundsVector();
231 void testValuesBoundsVector();
192 };
232 };
193
233
194 void TestDataSeries::testCtor_data()
234 void TestDataSeries::testCtor_data()
195 {
235 {
196 // ////////////// //
236 // ////////////// //
197 // Test structure //
237 // Test structure //
198 // ////////////// //
238 // ////////////// //
199
239
200 // x-axis data
240 // x-axis data
201 QTest::addColumn<DataContainer>("xAxisData");
241 QTest::addColumn<DataContainer>("xAxisData");
202 // values data
242 // values data
203 QTest::addColumn<DataContainer>("valuesData");
243 QTest::addColumn<DataContainer>("valuesData");
204
244
205 // expected x-axis data
245 // expected x-axis data
206 QTest::addColumn<DataContainer>("expectedXAxisData");
246 QTest::addColumn<DataContainer>("expectedXAxisData");
207 // expected values data
247 // expected values data
208 QTest::addColumn<DataContainer>("expectedValuesData");
248 QTest::addColumn<DataContainer>("expectedValuesData");
209
249
210 // ////////// //
250 // ////////// //
211 // Test cases //
251 // Test cases //
212 // ////////// //
252 // ////////// //
213
253
214 QTest::newRow("invalidData (different sizes of vectors)")
254 QTest::newRow("invalidData (different sizes of vectors)")
215 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << DataContainer{}
255 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300.} << DataContainer{}
216 << DataContainer{};
256 << DataContainer{};
217
257
218 QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.}
258 QTest::newRow("sortedData") << DataContainer{1., 2., 3., 4., 5.}
219 << DataContainer{100., 200., 300., 400., 500.}
259 << DataContainer{100., 200., 300., 400., 500.}
220 << DataContainer{1., 2., 3., 4., 5.}
260 << DataContainer{1., 2., 3., 4., 5.}
221 << DataContainer{100., 200., 300., 400., 500.};
261 << DataContainer{100., 200., 300., 400., 500.};
222
262
223 QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.}
263 QTest::newRow("unsortedData") << DataContainer{5., 4., 3., 2., 1.}
224 << DataContainer{100., 200., 300., 400., 500.}
264 << DataContainer{100., 200., 300., 400., 500.}
225 << DataContainer{1., 2., 3., 4., 5.}
265 << DataContainer{1., 2., 3., 4., 5.}
226 << DataContainer{500., 400., 300., 200., 100.};
266 << DataContainer{500., 400., 300., 200., 100.};
227
267
228 QTest::newRow("unsortedData2")
268 QTest::newRow("unsortedData2")
229 << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.}
269 << DataContainer{1., 4., 3., 5., 2.} << DataContainer{100., 200., 300., 400., 500.}
230 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.};
270 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 500., 300., 200., 400.};
231 }
271 }
232
272
233 void TestDataSeries::testCtor()
273 void TestDataSeries::testCtor()
234 {
274 {
235 // Creates series
275 // Creates series
236 QFETCH(DataContainer, xAxisData);
276 QFETCH(DataContainer, xAxisData);
237 QFETCH(DataContainer, valuesData);
277 QFETCH(DataContainer, valuesData);
238
278
239 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
279 auto series = std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
240 Unit{}, Unit{});
280 Unit{}, Unit{});
241
281
242 // Validates results : we check that the data series is sorted on its x-axis data
282 // Validates results : we check that the data series is sorted on its x-axis data
243 QFETCH(DataContainer, expectedXAxisData);
283 QFETCH(DataContainer, expectedXAxisData);
244 QFETCH(DataContainer, expectedValuesData);
284 QFETCH(DataContainer, expectedValuesData);
245
285
246 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
286 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedValuesData);
247 }
287 }
248
288
249 namespace {
289 namespace {
250
290
251 std::shared_ptr<ScalarSeries> createScalarSeries(DataContainer xAxisData, DataContainer valuesData)
291 std::shared_ptr<ScalarSeries> createScalarSeries(DataContainer xAxisData, DataContainer valuesData)
252 {
292 {
253 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
293 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
254 Unit{});
294 Unit{});
255 }
295 }
256
296
257 std::shared_ptr<VectorSeries> createVectorSeries(DataContainer xAxisData, DataContainer xValuesData,
297 std::shared_ptr<VectorSeries> createVectorSeries(DataContainer xAxisData, DataContainer xValuesData,
258 DataContainer yValuesData,
298 DataContainer yValuesData,
259 DataContainer zValuesData)
299 DataContainer zValuesData)
260 {
300 {
261 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
301 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(xValuesData),
262 std::move(yValuesData), std::move(zValuesData), Unit{},
302 std::move(yValuesData), std::move(zValuesData), Unit{},
263 Unit{});
303 Unit{});
264 }
304 }
265
305
266 } // namespace
306 } // namespace
267
307
268 void TestDataSeries::testMerge_data()
308 void TestDataSeries::testMerge_data()
269 {
309 {
270 // ////////////// //
310 // ////////////// //
271 // Test structure //
311 // Test structure //
272 // ////////////// //
312 // ////////////// //
273
313
274 // Data series to merge
314 // Data series to merge
275 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
315 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
276 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
316 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries2");
277
317
278 // Expected values in the first data series after merge
318 // Expected values in the first data series after merge
279 QTest::addColumn<DataContainer>("expectedXAxisData");
319 QTest::addColumn<DataContainer>("expectedXAxisData");
280 QTest::addColumn<DataContainer>("expectedValuesData");
320 QTest::addColumn<DataContainer>("expectedValuesData");
281
321
282 // ////////// //
322 // ////////// //
283 // Test cases //
323 // Test cases //
284 // ////////// //
324 // ////////// //
285
325
286 QTest::newRow("sortedMerge")
326 QTest::newRow("sortedMerge")
287 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
327 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
288 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
328 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
289 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
329 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
290 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
330 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
291
331
292 QTest::newRow("unsortedMerge")
332 QTest::newRow("unsortedMerge")
293 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
333 << createScalarSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.})
294 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
334 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
295 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
335 << DataContainer{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.}
296 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
336 << DataContainer{100., 200., 300., 400., 500., 600., 700., 800., 900., 1000.};
297
337
298 QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)")
338 QTest::newRow("unsortedMerge2 (merge not made because source is in the bounds of dest)")
299 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 800., 900., 1000.})
339 << createScalarSeries({1., 2., 8., 9., 10}, {100., 200., 800., 900., 1000.})
300 << createScalarSeries({3., 4., 5., 6., 7.}, {300., 400., 500., 600., 700.})
340 << createScalarSeries({3., 4., 5., 6., 7.}, {300., 400., 500., 600., 700.})
301 << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.};
341 << DataContainer{1., 2., 8., 9., 10.} << DataContainer{100., 200., 800., 900., 1000.};
302
342
303 QTest::newRow("unsortedMerge3")
343 QTest::newRow("unsortedMerge3")
304 << createScalarSeries({3., 4., 5., 7., 8}, {300., 400., 500., 700., 800.})
344 << createScalarSeries({3., 4., 5., 7., 8}, {300., 400., 500., 700., 800.})
305 << createScalarSeries({1., 2., 3., 7., 10.}, {100., 200., 333., 777., 1000.})
345 << createScalarSeries({1., 2., 3., 7., 10.}, {100., 200., 333., 777., 1000.})
306 << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.}
346 << DataContainer{1., 2., 3., 4., 5., 7., 8., 10.}
307 << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.};
347 << DataContainer{100., 200., 300., 400., 500., 700., 800., 1000.};
348
349 QTest::newRow("emptySource") << createScalarSeries({3., 4., 5., 7., 8},
350 {300., 400., 500., 700., 800.})
351 << createScalarSeries({}, {}) << DataContainer{3., 4., 5., 7., 8.}
352 << DataContainer{300., 400., 500., 700., 800.};
308 }
353 }
309
354
310 void TestDataSeries::testMerge()
355 void TestDataSeries::testMerge()
311 {
356 {
312 // Merges series
357 // Merges series
313 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
358 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
314 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
359 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries2);
315
360
316 dataSeries->merge(dataSeries2.get());
361 dataSeries->merge(dataSeries2.get());
317
362
318 // Validates results : we check that the merge is valid and the data series is sorted on its
363 // Validates results : we check that the merge is valid and the data series is sorted on its
319 // x-axis data
364 // x-axis data
320 QFETCH(DataContainer, expectedXAxisData);
365 QFETCH(DataContainer, expectedXAxisData);
321 QFETCH(DataContainer, expectedValuesData);
366 QFETCH(DataContainer, expectedValuesData);
322
367
323 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData);
368 validateRange(dataSeries->cbegin(), dataSeries->cend(), expectedXAxisData, expectedValuesData);
324 }
369 }
325
370
371 void TestDataSeries::testMergeVectorInScalar_data()
372 {
373 testMergeDifferentTypesStructure<VectorSeries, ScalarSeries>();
374
375 // ////////// //
376 // Test cases //
377 // ////////// //
378
379 QTest::newRow("purgeVectorInScalar")
380 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.})
381 << createVectorSeries({6., 7., 8., 9., 10.}, {600., 700., 800., 900., 1000.},
382 {610., 710., 810., 910., 1010.}, {620., 720., 820., 920., 1020.})
383 << DataContainer{1., 2., 3., 4., 5.} << DataContainer{100., 200., 300., 400., 500.};
384 }
385
386 void TestDataSeries::testMergeVectorInScalar()
387 {
388 testMergeDifferentTypes<VectorSeries, ScalarSeries>();
389 }
390
326 void TestDataSeries::testPurgeScalar_data()
391 void TestDataSeries::testPurgeScalar_data()
327 {
392 {
328 testPurgeStructure<ScalarSeries>();
393 testPurgeStructure<ScalarSeries>();
329
394
330 // ////////// //
395 // ////////// //
331 // Test cases //
396 // Test cases //
332 // ////////// //
397 // ////////// //
333
398
334 QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.},
399 QTest::newRow("purgeScalar") << createScalarSeries({1., 2., 3., 4., 5.},
335 {100., 200., 300., 400., 500.})
400 {100., 200., 300., 400., 500.})
336 << 2. << 4. << DataContainer{2., 3., 4.}
401 << 2. << 4. << DataContainer{2., 3., 4.}
337 << std::vector<DataContainer>{{200., 300., 400.}};
402 << std::vector<DataContainer>{{200., 300., 400.}};
403 QTest::newRow("purgeScalar1 (min/max swap)")
404 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 4. << 2.
405 << DataContainer{2., 3., 4.} << std::vector<DataContainer>{{200., 300., 400.}};
338 QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.},
406 QTest::newRow("purgeScalar2") << createScalarSeries({1., 2., 3., 4., 5.},
339 {100., 200., 300., 400., 500.})
407 {100., 200., 300., 400., 500.})
340 << 0. << 2.5 << DataContainer{1., 2.}
408 << 0. << 2.5 << DataContainer{1., 2.}
341 << std::vector<DataContainer>{{100., 200.}};
409 << std::vector<DataContainer>{{100., 200.}};
342 QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.},
410 QTest::newRow("purgeScalar3") << createScalarSeries({1., 2., 3., 4., 5.},
343 {100., 200., 300., 400., 500.})
411 {100., 200., 300., 400., 500.})
344 << 3.5 << 7. << DataContainer{4., 5.}
412 << 3.5 << 7. << DataContainer{4., 5.}
345 << std::vector<DataContainer>{{400., 500.}};
413 << std::vector<DataContainer>{{400., 500.}};
346 QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.},
414 QTest::newRow("purgeScalar4") << createScalarSeries({1., 2., 3., 4., 5.},
347 {100., 200., 300., 400., 500.})
415 {100., 200., 300., 400., 500.})
348 << 0. << 7. << DataContainer{1., 2., 3., 4., 5.}
416 << 0. << 7. << DataContainer{1., 2., 3., 4., 5.}
349 << std::vector<DataContainer>{{100., 200., 300., 400., 500.}};
417 << std::vector<DataContainer>{{100., 200., 300., 400., 500.}};
350 QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.},
418 QTest::newRow("purgeScalar5") << createScalarSeries({1., 2., 3., 4., 5.},
351 {100., 200., 300., 400., 500.})
419 {100., 200., 300., 400., 500.})
352 << 5.5 << 7. << DataContainer{} << std::vector<DataContainer>{{}};
420 << 5.5 << 7. << DataContainer{} << std::vector<DataContainer>{{}};
353 }
421 }
354
422
355 void TestDataSeries::testPurgeScalar()
423 void TestDataSeries::testPurgeScalar()
356 {
424 {
357 testPurge<ScalarSeries>();
425 testPurge<ScalarSeries>();
358 }
426 }
359
427
360 void TestDataSeries::testPurgeVector_data()
428 void TestDataSeries::testPurgeVector_data()
361 {
429 {
362 testPurgeStructure<VectorSeries>();
430 testPurgeStructure<VectorSeries>();
363
431
364 // ////////// //
432 // ////////// //
365 // Test cases //
433 // Test cases //
366 // ////////// //
434 // ////////// //
367
435
368 QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.},
436 QTest::newRow("purgeVector") << createVectorSeries({1., 2., 3., 4., 5.}, {6., 7., 8., 9., 10.},
369 {11., 12., 13., 14., 15.},
437 {11., 12., 13., 14., 15.},
370 {16., 17., 18., 19., 20.})
438 {16., 17., 18., 19., 20.})
371 << 2. << 4. << DataContainer{2., 3., 4.}
439 << 2. << 4. << DataContainer{2., 3., 4.}
372 << std::vector<DataContainer>{
440 << std::vector<DataContainer>{
373 {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}};
441 {7., 8., 9.}, {12., 13., 14.}, {17., 18., 19.}};
374 }
442 }
375
443
376 void TestDataSeries::testPurgeVector()
444 void TestDataSeries::testPurgeVector()
377 {
445 {
378 testPurge<VectorSeries>();
446 testPurge<VectorSeries>();
379 }
447 }
380
448
381 void TestDataSeries::testMinXAxisData_data()
449 void TestDataSeries::testMinXAxisData_data()
382 {
450 {
383 // ////////////// //
451 // ////////////// //
384 // Test structure //
452 // Test structure //
385 // ////////////// //
453 // ////////////// //
386
454
387 // Data series to get min data
455 // Data series to get min data
388 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
456 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
389
457
390 // Min data
458 // Min data
391 QTest::addColumn<double>("min");
459 QTest::addColumn<double>("min");
392
460
393 // Expected results
461 // Expected results
394 QTest::addColumn<bool>(
462 QTest::addColumn<bool>(
395 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
463 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
396 QTest::addColumn<double>(
464 QTest::addColumn<double>(
397 "expectedMin"); // Expected value when method doesn't return end iterator
465 "expectedMin"); // Expected value when method doesn't return end iterator
398
466
399 // ////////// //
467 // ////////// //
400 // Test cases //
468 // Test cases //
401 // ////////// //
469 // ////////// //
402
470
403 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
471 QTest::newRow("minData1") << createScalarSeries({1., 2., 3., 4., 5.},
404 {100., 200., 300., 400., 500.})
472 {100., 200., 300., 400., 500.})
405 << 0. << true << 1.;
473 << 0. << true << 1.;
406 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
474 QTest::newRow("minData2") << createScalarSeries({1., 2., 3., 4., 5.},
407 {100., 200., 300., 400., 500.})
475 {100., 200., 300., 400., 500.})
408 << 1. << true << 1.;
476 << 1. << true << 1.;
409 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
477 QTest::newRow("minData3") << createScalarSeries({1., 2., 3., 4., 5.},
410 {100., 200., 300., 400., 500.})
478 {100., 200., 300., 400., 500.})
411 << 1.1 << true << 2.;
479 << 1.1 << true << 2.;
412 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
480 QTest::newRow("minData4") << createScalarSeries({1., 2., 3., 4., 5.},
413 {100., 200., 300., 400., 500.})
481 {100., 200., 300., 400., 500.})
414 << 5. << true << 5.;
482 << 5. << true << 5.;
415 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
483 QTest::newRow("minData5") << createScalarSeries({1., 2., 3., 4., 5.},
416 {100., 200., 300., 400., 500.})
484 {100., 200., 300., 400., 500.})
417 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
485 << 5.1 << false << std::numeric_limits<double>::quiet_NaN();
418 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
486 QTest::newRow("minData6") << createScalarSeries({}, {}) << 1.1 << false
419 << std::numeric_limits<double>::quiet_NaN();
487 << std::numeric_limits<double>::quiet_NaN();
420 }
488 }
421
489
422 void TestDataSeries::testMinXAxisData()
490 void TestDataSeries::testMinXAxisData()
423 {
491 {
424 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
492 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
425 QFETCH(double, min);
493 QFETCH(double, min);
426
494
427 QFETCH(bool, expectedOK);
495 QFETCH(bool, expectedOK);
428 QFETCH(double, expectedMin);
496 QFETCH(double, expectedMin);
429
497
430 auto it = dataSeries->minXAxisData(min);
498 auto it = dataSeries->minXAxisData(min);
431
499
432 QCOMPARE(expectedOK, it != dataSeries->cend());
500 QCOMPARE(expectedOK, it != dataSeries->cend());
433
501
434 // If the method doesn't return a end iterator, checks with expected value
502 // If the method doesn't return a end iterator, checks with expected value
435 if (expectedOK) {
503 if (expectedOK) {
436 QCOMPARE(expectedMin, it->x());
504 QCOMPARE(expectedMin, it->x());
437 }
505 }
438 }
506 }
439
507
440 void TestDataSeries::testMaxXAxisData_data()
508 void TestDataSeries::testMaxXAxisData_data()
441 {
509 {
442 // ////////////// //
510 // ////////////// //
443 // Test structure //
511 // Test structure //
444 // ////////////// //
512 // ////////////// //
445
513
446 // Data series to get max data
514 // Data series to get max data
447 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
515 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
448
516
449 // Max data
517 // Max data
450 QTest::addColumn<double>("max");
518 QTest::addColumn<double>("max");
451
519
452 // Expected results
520 // Expected results
453 QTest::addColumn<bool>(
521 QTest::addColumn<bool>(
454 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
522 "expectedOK"); // if true, expects to have a result (i.e. the iterator != end iterator)
455 QTest::addColumn<double>(
523 QTest::addColumn<double>(
456 "expectedMax"); // Expected value when method doesn't return end iterator
524 "expectedMax"); // Expected value when method doesn't return end iterator
457
525
458 // ////////// //
526 // ////////// //
459 // Test cases //
527 // Test cases //
460 // ////////// //
528 // ////////// //
461
529
462 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
530 QTest::newRow("maxData1") << createScalarSeries({1., 2., 3., 4., 5.},
463 {100., 200., 300., 400., 500.})
531 {100., 200., 300., 400., 500.})
464 << 6. << true << 5.;
532 << 6. << true << 5.;
465 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
533 QTest::newRow("maxData2") << createScalarSeries({1., 2., 3., 4., 5.},
466 {100., 200., 300., 400., 500.})
534 {100., 200., 300., 400., 500.})
467 << 5. << true << 5.;
535 << 5. << true << 5.;
468 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
536 QTest::newRow("maxData3") << createScalarSeries({1., 2., 3., 4., 5.},
469 {100., 200., 300., 400., 500.})
537 {100., 200., 300., 400., 500.})
470 << 4.9 << true << 4.;
538 << 4.9 << true << 4.;
471 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
539 QTest::newRow("maxData4") << createScalarSeries({1., 2., 3., 4., 5.},
472 {100., 200., 300., 400., 500.})
540 {100., 200., 300., 400., 500.})
473 << 1.1 << true << 1.;
541 << 1.1 << true << 1.;
474 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
542 QTest::newRow("maxData5") << createScalarSeries({1., 2., 3., 4., 5.},
475 {100., 200., 300., 400., 500.})
543 {100., 200., 300., 400., 500.})
476 << 1. << true << 1.;
544 << 1. << true << 1.;
477 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
545 QTest::newRow("maxData6") << createScalarSeries({}, {}) << 1.1 << false
478 << std::numeric_limits<double>::quiet_NaN();
546 << std::numeric_limits<double>::quiet_NaN();
479 }
547 }
480
548
481 void TestDataSeries::testMaxXAxisData()
549 void TestDataSeries::testMaxXAxisData()
482 {
550 {
483 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
551 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
484 QFETCH(double, max);
552 QFETCH(double, max);
485
553
486 QFETCH(bool, expectedOK);
554 QFETCH(bool, expectedOK);
487 QFETCH(double, expectedMax);
555 QFETCH(double, expectedMax);
488
556
489 auto it = dataSeries->maxXAxisData(max);
557 auto it = dataSeries->maxXAxisData(max);
490
558
491 QCOMPARE(expectedOK, it != dataSeries->cend());
559 QCOMPARE(expectedOK, it != dataSeries->cend());
492
560
493 // If the method doesn't return a end iterator, checks with expected value
561 // If the method doesn't return a end iterator, checks with expected value
494 if (expectedOK) {
562 if (expectedOK) {
495 QCOMPARE(expectedMax, it->x());
563 QCOMPARE(expectedMax, it->x());
496 }
564 }
497 }
565 }
498
566
499 void TestDataSeries::testXAxisRange_data()
567 void TestDataSeries::testXAxisRange_data()
500 {
568 {
501 // ////////////// //
569 // ////////////// //
502 // Test structure //
570 // Test structure //
503 // ////////////// //
571 // ////////////// //
504
572
505 // Data series to get x-axis range
573 // Data series to get x-axis range
506 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
574 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
507
575
508 // Min/max values
576 // Min/max values
509 QTest::addColumn<double>("min");
577 QTest::addColumn<double>("min");
510 QTest::addColumn<double>("max");
578 QTest::addColumn<double>("max");
511
579
512 // Expected values
580 // Expected values
513 QTest::addColumn<DataContainer>("expectedXAxisData");
581 QTest::addColumn<DataContainer>("expectedXAxisData");
514 QTest::addColumn<DataContainer>("expectedValuesData");
582 QTest::addColumn<DataContainer>("expectedValuesData");
515
583
516 // ////////// //
584 // ////////// //
517 // Test cases //
585 // Test cases //
518 // ////////// //
586 // ////////// //
519
587
520 QTest::newRow("xAxisRange1") << createScalarSeries({1., 2., 3., 4., 5.},
588 QTest::newRow("xAxisRange") << createScalarSeries({1., 2., 3., 4., 5.},
521 {100., 200., 300., 400., 500.})
589 {100., 200., 300., 400., 500.})
522 << -1. << 3.2 << DataContainer{1., 2., 3.}
590 << -1. << 3.2 << DataContainer{1., 2., 3.}
523 << DataContainer{100., 200., 300.};
591 << DataContainer{100., 200., 300.};
592 QTest::newRow("xAxisRange1 (min/max swap)")
593 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 3.2 << -1.
594 << DataContainer{1., 2., 3.} << DataContainer{100., 200., 300.};
524 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
595 QTest::newRow("xAxisRange2") << createScalarSeries({1., 2., 3., 4., 5.},
525 {100., 200., 300., 400., 500.})
596 {100., 200., 300., 400., 500.})
526 << 1. << 4. << DataContainer{1., 2., 3., 4.}
597 << 1. << 4. << DataContainer{1., 2., 3., 4.}
527 << DataContainer{100., 200., 300., 400.};
598 << DataContainer{100., 200., 300., 400.};
528 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
599 QTest::newRow("xAxisRange3") << createScalarSeries({1., 2., 3., 4., 5.},
529 {100., 200., 300., 400., 500.})
600 {100., 200., 300., 400., 500.})
530 << 1. << 3.9 << DataContainer{1., 2., 3.}
601 << 1. << 3.9 << DataContainer{1., 2., 3.}
531 << DataContainer{100., 200., 300.};
602 << DataContainer{100., 200., 300.};
532 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
603 QTest::newRow("xAxisRange4") << createScalarSeries({1., 2., 3., 4., 5.},
533 {100., 200., 300., 400., 500.})
604 {100., 200., 300., 400., 500.})
534 << 0. << 0.9 << DataContainer{} << DataContainer{};
605 << 0. << 0.9 << DataContainer{} << DataContainer{};
535 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
606 QTest::newRow("xAxisRange5") << createScalarSeries({1., 2., 3., 4., 5.},
536 {100., 200., 300., 400., 500.})
607 {100., 200., 300., 400., 500.})
537 << 0. << 1. << DataContainer{1.} << DataContainer{100.};
608 << 0. << 1. << DataContainer{1.} << DataContainer{100.};
538 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
609 QTest::newRow("xAxisRange6") << createScalarSeries({1., 2., 3., 4., 5.},
539 {100., 200., 300., 400., 500.})
610 {100., 200., 300., 400., 500.})
540 << 2.1 << 6. << DataContainer{3., 4., 5.}
611 << 2.1 << 6. << DataContainer{3., 4., 5.}
541 << DataContainer{300., 400., 500.};
612 << DataContainer{300., 400., 500.};
542 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
613 QTest::newRow("xAxisRange7") << createScalarSeries({1., 2., 3., 4., 5.},
543 {100., 200., 300., 400., 500.})
614 {100., 200., 300., 400., 500.})
544 << 6. << 9. << DataContainer{} << DataContainer{};
615 << 6. << 9. << DataContainer{} << DataContainer{};
545 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
616 QTest::newRow("xAxisRange8") << createScalarSeries({1., 2., 3., 4., 5.},
546 {100., 200., 300., 400., 500.})
617 {100., 200., 300., 400., 500.})
547 << 5. << 9. << DataContainer{5.} << DataContainer{500.};
618 << 5. << 9. << DataContainer{5.} << DataContainer{500.};
548 }
619 }
549
620
550 void TestDataSeries::testXAxisRange()
621 void TestDataSeries::testXAxisRange()
551 {
622 {
552 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
623 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
553 QFETCH(double, min);
624 QFETCH(double, min);
554 QFETCH(double, max);
625 QFETCH(double, max);
555
626
556 QFETCH(DataContainer, expectedXAxisData);
627 QFETCH(DataContainer, expectedXAxisData);
557 QFETCH(DataContainer, expectedValuesData);
628 QFETCH(DataContainer, expectedValuesData);
558
629
559 auto bounds = dataSeries->xAxisRange(min, max);
630 auto bounds = dataSeries->xAxisRange(min, max);
560 validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData);
631 validateRange(bounds.first, bounds.second, expectedXAxisData, expectedValuesData);
561 }
632 }
562
633
563 void TestDataSeries::testValuesBoundsScalar_data()
634 void TestDataSeries::testValuesBoundsScalar_data()
564 {
635 {
565 testValuesBoundsStructure<ScalarSeries>();
636 testValuesBoundsStructure<ScalarSeries>();
566
637
567 // ////////// //
638 // ////////// //
568 // Test cases //
639 // Test cases //
569 // ////////// //
640 // ////////// //
570 auto nan = std::numeric_limits<double>::quiet_NaN();
641 auto nan = std::numeric_limits<double>::quiet_NaN();
571
642
572 QTest::newRow("scalarBounds1")
643 QTest::newRow("scalarBounds1")
573 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
644 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 6.
574 << true << 100. << 500.;
645 << true << 100. << 500.;
575 QTest::newRow("scalarBounds2")
646 QTest::newRow("scalarBounds2")
576 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
647 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 2. << 4.
577 << true << 200. << 400.;
648 << true << 200. << 400.;
578 QTest::newRow("scalarBounds3")
649 QTest::newRow("scalarBounds3")
579 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
650 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 0. << 0.5
580 << false << nan << nan;
651 << false << nan << nan;
581 QTest::newRow("scalarBounds4")
652 QTest::newRow("scalarBounds4")
582 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
653 << createScalarSeries({1., 2., 3., 4., 5.}, {100., 200., 300., 400., 500.}) << 5.1 << 6.
583 << false << nan << nan;
654 << false << nan << nan;
584 QTest::newRow("scalarBounds5") << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100.
655 QTest::newRow("scalarBounds5")
585 << 100.;
656 << createScalarSeries({1.}, {100.}) << 0. << 2. << true << 100. << 100.;
586 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
657 QTest::newRow("scalarBounds6") << createScalarSeries({}, {}) << 0. << 2. << false << nan << nan;
587
658
588 // Tests with NaN values: NaN values are not included in min/max search
659 // Tests with NaN values: NaN values are not included in min/max search
589 QTest::newRow("scalarBounds7")
660 QTest::newRow("scalarBounds7")
590 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
661 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, 200., 300., 400., nan}) << 0. << 6.
591 << true << 200. << 400.;
662 << true << 200. << 400.;
592 QTest::newRow("scalarBounds8")
663 QTest::newRow("scalarBounds8")
593 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
664 << createScalarSeries({1., 2., 3., 4., 5.}, {nan, nan, nan, nan, nan}) << 0. << 6. << true
594 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
665 << std::numeric_limits<double>::quiet_NaN() << std::numeric_limits<double>::quiet_NaN();
595 }
666 }
596
667
597 void TestDataSeries::testValuesBoundsScalar()
668 void TestDataSeries::testValuesBoundsScalar()
598 {
669 {
599 testValuesBounds<ScalarSeries>();
670 testValuesBounds<ScalarSeries>();
600 }
671 }
601
672
602 void TestDataSeries::testValuesBoundsVector_data()
673 void TestDataSeries::testValuesBoundsVector_data()
603 {
674 {
604 testValuesBoundsStructure<VectorSeries>();
675 testValuesBoundsStructure<VectorSeries>();
605
676
606 // ////////// //
677 // ////////// //
607 // Test cases //
678 // Test cases //
608 // ////////// //
679 // ////////// //
609 auto nan = std::numeric_limits<double>::quiet_NaN();
680 auto nan = std::numeric_limits<double>::quiet_NaN();
610
681
611 QTest::newRow("vectorBounds1")
682 QTest::newRow("vectorBounds1")
612 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
683 << createVectorSeries({1., 2., 3., 4., 5.}, {10., 15., 20., 13., 12.},
613 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
684 {35., 24., 10., 9., 0.3}, {13., 14., 12., 9., 24.})
614 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
685 << 0. << 6. << true << 0.3 << 35.; // min/max in same component
615 QTest::newRow("vectorBounds2")
686 QTest::newRow("vectorBounds2")
616 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
687 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
617 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
688 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
618 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
689 << 0. << 6. << true << 2.3 << 35.; // min/max in same entry
619 QTest::newRow("vectorBounds3")
690 QTest::newRow("vectorBounds3")
620 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
691 << createVectorSeries({1., 2., 3., 4., 5.}, {2.3, 15., 20., 13., 12.},
621 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
692 {35., 24., 10., 9., 4.}, {13., 14., 12., 9., 24.})
622 << 2. << 3. << true << 10. << 24.;
693 << 2. << 3. << true << 10. << 24.;
623
694
624 // Tests with NaN values: NaN values are not included in min/max search
695 // Tests with NaN values: NaN values are not included in min/max search
625 QTest::newRow("vectorBounds4")
696 QTest::newRow("vectorBounds4")
626 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
697 << createVectorSeries({1., 2.}, {nan, nan}, {nan, nan}, {nan, nan}) << 0. << 6. << true
627 << nan << nan;
698 << nan << nan;
628 }
699 }
629
700
630 void TestDataSeries::testValuesBoundsVector()
701 void TestDataSeries::testValuesBoundsVector()
631 {
702 {
632 testValuesBounds<VectorSeries>();
703 testValuesBounds<VectorSeries>();
633 }
704 }
634
705
635 QTEST_MAIN(TestDataSeries)
706 QTEST_MAIN(TestDataSeries)
636 #include "TestDataSeries.moc"
707 #include "TestDataSeries.moc"
@@ -1,177 +1,409
1 #include <Variable/Variable.h>
1 #include <Variable/Variable.h>
2
2
3 #include <Data/ScalarSeries.h>
4
3 #include <QObject>
5 #include <QObject>
4 #include <QtTest>
6 #include <QtTest>
5
7
6 #include <memory>
8 #include <memory>
7
9
10 namespace {
11
12 /// Generates a date in double
13 auto date = [](int year, int month, int day, int hours, int minutes, int seconds) {
14 return DateUtils::secondsSinceEpoch(
15 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
16 };
17
18 /// Generates a series of test data for a range
19 std::shared_ptr<ScalarSeries> dataSeries(const SqpRange &range)
20 {
21 auto xAxisData = std::vector<double>{};
22 auto valuesData = std::vector<double>{};
23
24 auto value = 0;
25 for (auto x = range.m_TStart; x <= range.m_TEnd; ++x, ++value) {
26 xAxisData.push_back(x);
27 valuesData.push_back(value);
28 }
29
30 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData), Unit{},
31 Unit{});
32 }
33
34 } // namespace
35
36 Q_DECLARE_METATYPE(std::shared_ptr<ScalarSeries>)
37
8 class TestVariable : public QObject {
38 class TestVariable : public QObject {
9 Q_OBJECT
39 Q_OBJECT
10
40
11 private slots:
41 private slots:
12 void testNotInCacheRangeList();
42 void testClone_data();
43 void testClone();
13
44
45 void testNotInCacheRangeList();
14 void testInCacheRangeList();
46 void testInCacheRangeList();
47
48 void testNbPoints_data();
49 void testNbPoints();
50
51 void testRealRange_data();
52 void testRealRange();
15 };
53 };
16
54
55 void TestVariable::testClone_data()
56 {
57 // ////////////// //
58 // Test structure //
59 // ////////////// //
60
61 QTest::addColumn<QString>("name");
62 QTest::addColumn<QVariantHash>("metadata");
63 QTest::addColumn<SqpRange>("range");
64 QTest::addColumn<SqpRange>("cacheRange");
65 QTest::addColumn<std::shared_ptr<ScalarSeries> >("dataSeries");
66
67 // ////////// //
68 // Test cases //
69 // ////////// //
70
71 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)};
72 QTest::newRow("clone1") << QStringLiteral("var1")
73 << QVariantHash{{"data1", 1}, {"data2", "abc"}}
74 << SqpRange{date(2017, 1, 1, 12, 30, 0), (date(2017, 1, 1, 12, 45, 0))}
75 << cacheRange << dataSeries(cacheRange);
76 }
77
78 void TestVariable::testClone()
79 {
80 // Creates variable
81 QFETCH(QString, name);
82 QFETCH(QVariantHash, metadata);
83 QFETCH(SqpRange, range);
84 QFETCH(SqpRange, cacheRange);
85 QFETCH(std::shared_ptr<ScalarSeries>, dataSeries);
86
87 Variable variable{name, metadata};
88 variable.setRange(range);
89 variable.setCacheRange(cacheRange);
90 variable.mergeDataSeries(dataSeries);
91
92 // Clones variable
93 auto clone = variable.clone();
94
95 // Checks cloned variable's state
96 QCOMPARE(clone->name(), name);
97 QCOMPARE(clone->metadata(), metadata);
98 QCOMPARE(clone->range(), range);
99 QCOMPARE(clone->cacheRange(), cacheRange);
100
101 // Compares data series
102 if (dataSeries != nullptr) {
103 QVERIFY(clone->dataSeries() != nullptr);
104 QVERIFY(std::equal(dataSeries->cbegin(), dataSeries->cend(), clone->dataSeries()->cbegin(),
105 clone->dataSeries()->cend(), [](const auto &it1, const auto &it2) {
106 return it1.x() == it2.x() && it1.value() == it2.value();
107 }));
108 }
109 else {
110 QVERIFY(clone->dataSeries() == nullptr);
111 }
112 }
17
113
18 void TestVariable::testNotInCacheRangeList()
114 void TestVariable::testNotInCacheRangeList()
19 {
115 {
20 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
116 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
21 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
117 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
22
118
23 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
119 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
24
120
25 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
121 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
26 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
122 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
27
123
28 auto sqpCR
124 auto sqpCR
29 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
125 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
30
126
31 Variable var{"Var test"};
127 Variable var{"Var test"};
32 var.setRange(sqpR);
128 var.setRange(sqpR);
33 var.setCacheRange(sqpCR);
129 var.setCacheRange(sqpCR);
34
130
35 // 1: [ts,te] < varTS
131 // 1: [ts,te] < varTS
36 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
132 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
37 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
133 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
38 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
134 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
39
135
40 auto notInCach = var.provideNotInCacheRangeList(sqp);
136 auto notInCach = var.provideNotInCacheRangeList(sqp);
41
137
42 QCOMPARE(notInCach.size(), 1);
138 QCOMPARE(notInCach.size(), 1);
43
139
44 auto notInCachRange = notInCach.first();
140 auto notInCachRange = notInCach.first();
45
141
46 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
142 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
47 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
143 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
48
144
49 // 2: ts < varTS < te < varTE
145 // 2: ts < varTS < te < varTE
50 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
146 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
51 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
147 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
52 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
148 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
53 notInCach = var.provideNotInCacheRangeList(sqp);
149 notInCach = var.provideNotInCacheRangeList(sqp);
54 QCOMPARE(notInCach.size(), 1);
150 QCOMPARE(notInCach.size(), 1);
55 notInCachRange = notInCach.first();
151 notInCachRange = notInCach.first();
56 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
152 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
57 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
153 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
58
154
59 // 3: varTS < ts < te < varTE
155 // 3: varTS < ts < te < varTE
60 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
156 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
61 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
157 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
62 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
158 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
63 notInCach = var.provideNotInCacheRangeList(sqp);
159 notInCach = var.provideNotInCacheRangeList(sqp);
64 QCOMPARE(notInCach.size(), 0);
160 QCOMPARE(notInCach.size(), 0);
65
161
66
162
67 // 4: varTS < ts < varTE < te
163 // 4: varTS < ts < varTE < te
68 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
164 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
69 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
165 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
70 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
166 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
71 notInCach = var.provideNotInCacheRangeList(sqp);
167 notInCach = var.provideNotInCacheRangeList(sqp);
72 QCOMPARE(notInCach.size(), 1);
168 QCOMPARE(notInCach.size(), 1);
73 notInCachRange = notInCach.first();
169 notInCachRange = notInCach.first();
74 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
170 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
75 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
171 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
76
172
77 // 5: varTS < varTE < ts < te
173 // 5: varTS < varTE < ts < te
78 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
174 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
79 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
175 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
80 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
176 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
81 notInCach = var.provideNotInCacheRangeList(sqp);
177 notInCach = var.provideNotInCacheRangeList(sqp);
82 QCOMPARE(notInCach.size(), 1);
178 QCOMPARE(notInCach.size(), 1);
83 notInCachRange = notInCach.first();
179 notInCachRange = notInCach.first();
84 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
180 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
85 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
181 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
86
182
87 // 6: ts <varTS < varTE < te
183 // 6: ts <varTS < varTE < te
88 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
184 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
89 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
185 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
90 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
186 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
91 notInCach = var.provideNotInCacheRangeList(sqp);
187 notInCach = var.provideNotInCacheRangeList(sqp);
92 QCOMPARE(notInCach.size(), 2);
188 QCOMPARE(notInCach.size(), 2);
93 notInCachRange = notInCach.first();
189 notInCachRange = notInCach.first();
94 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
190 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
95 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
191 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRS));
96 notInCachRange = notInCach[1];
192 notInCachRange = notInCach[1];
97 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
193 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRE));
98 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
194 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
99 }
195 }
100
196
101
197
102 void TestVariable::testInCacheRangeList()
198 void TestVariable::testInCacheRangeList()
103 {
199 {
104 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
200 auto varRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
105 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
201 auto varRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 40, 0}};
106
202
107 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
203 auto sqpR = SqpRange{DateUtils::secondsSinceEpoch(varRS), DateUtils::secondsSinceEpoch(varRE)};
108
204
109 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
205 auto varCRS = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 0, 0}};
110 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
206 auto varCRE = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 0, 0}};
111 auto sqpCR
207 auto sqpCR
112 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
208 = SqpRange{DateUtils::secondsSinceEpoch(varCRS), DateUtils::secondsSinceEpoch(varCRE)};
113
209
114 Variable var{"Var test"};
210 Variable var{"Var test"};
115 var.setRange(sqpR);
211 var.setRange(sqpR);
116 var.setCacheRange(sqpCR);
212 var.setCacheRange(sqpCR);
117
213
118 // 1: [ts,te] < varTS
214 // 1: [ts,te] < varTS
119 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
215 auto ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
120 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
216 auto te = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
121 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
217 auto sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
122
218
123 auto notInCach = var.provideInCacheRangeList(sqp);
219 auto notInCach = var.provideInCacheRangeList(sqp);
124
220
125 QCOMPARE(notInCach.size(), 0);
221 QCOMPARE(notInCach.size(), 0);
126
222
127 // 2: ts < varTS < te < varTE
223 // 2: ts < varTS < te < varTE
128 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
224 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 0, 0, 0}};
129 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
225 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
130 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
226 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
131 notInCach = var.provideInCacheRangeList(sqp);
227 notInCach = var.provideInCacheRangeList(sqp);
132 QCOMPARE(notInCach.size(), 1);
228 QCOMPARE(notInCach.size(), 1);
133 auto notInCachRange = notInCach.first();
229 auto notInCachRange = notInCach.first();
134 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
230 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
135 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
231 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
136
232
137 // 3: varTS < ts < te < varTE
233 // 3: varTS < ts < te < varTE
138 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
234 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
139 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
235 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 30, 0}};
140 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
236 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
141 notInCach = var.provideInCacheRangeList(sqp);
237 notInCach = var.provideInCacheRangeList(sqp);
142 QCOMPARE(notInCach.size(), 1);
238 QCOMPARE(notInCach.size(), 1);
143 notInCachRange = notInCach.first();
239 notInCachRange = notInCach.first();
144 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
240 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
145 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
241 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(te));
146
242
147 // 4: varTS < ts < varTE < te
243 // 4: varTS < ts < varTE < te
148 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
244 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 3, 20, 0}};
149 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
245 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
150 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
246 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
151 notInCach = var.provideInCacheRangeList(sqp);
247 notInCach = var.provideInCacheRangeList(sqp);
152 QCOMPARE(notInCach.size(), 1);
248 QCOMPARE(notInCach.size(), 1);
153 notInCachRange = notInCach.first();
249 notInCachRange = notInCach.first();
154 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
250 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(ts));
155 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
251 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
156
252
157 // 5: varTS < varTE < ts < te
253 // 5: varTS < varTE < ts < te
158 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
254 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 4, 20, 0}};
159 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
255 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
160 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
256 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
161 notInCach = var.provideInCacheRangeList(sqp);
257 notInCach = var.provideInCacheRangeList(sqp);
162 QCOMPARE(notInCach.size(), 0);
258 QCOMPARE(notInCach.size(), 0);
163
259
164 // 6: ts <varTS < varTE < te
260 // 6: ts <varTS < varTE < te
165 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
261 ts = QDateTime{QDate{2017, 01, 01}, QTime{2, 1, 0, 0}};
166 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
262 te = QDateTime{QDate{2017, 01, 01}, QTime{2, 5, 0, 0}};
167 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
263 sqp = SqpRange{DateUtils::secondsSinceEpoch(ts), DateUtils::secondsSinceEpoch(te)};
168 notInCach = var.provideInCacheRangeList(sqp);
264 notInCach = var.provideInCacheRangeList(sqp);
169 QCOMPARE(notInCach.size(), 1);
265 QCOMPARE(notInCach.size(), 1);
170 notInCachRange = notInCach.first();
266 notInCachRange = notInCach.first();
171 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
267 QCOMPARE(notInCachRange.m_TStart, DateUtils::secondsSinceEpoch(varCRS));
172 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
268 QCOMPARE(notInCachRange.m_TEnd, DateUtils::secondsSinceEpoch(varCRE));
173 }
269 }
174
270
271 namespace {
272
273 /// Struct used to represent an operation for @sa TestVariable::testNbPoints()
274 struct NbPointsOperation {
275 SqpRange m_CacheRange; /// Range to set for the variable
276 std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable
277 int m_ExpectedNbPoints; /// Number of points in the variable expected after operation
278 };
279
280 using NbPointsOperations = std::vector<NbPointsOperation>;
281
282 } // namespace
283
284 Q_DECLARE_METATYPE(NbPointsOperations)
285
286 void TestVariable::testNbPoints_data()
287 {
288 // ////////////// //
289 // Test structure //
290 // ////////////// //
291
292 QTest::addColumn<NbPointsOperations>("operations");
293
294 // ////////// //
295 // Test cases //
296 // ////////// //
297 NbPointsOperations operations{};
298
299 // Sets cache range (expected nb points = series xAxis data + series values data)
300 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 9)};
301 operations.push_back({cacheRange, dataSeries(cacheRange), 20});
302
303 // Doubles cache but don't add data series (expected nb points don't change)
304 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)};
305 operations.push_back({cacheRange, nullptr, 20});
306
307 // Doubles cache and data series (expected nb points change)
308 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 12, 0, 19)};
309 operations.push_back({cacheRange, dataSeries(cacheRange), 40});
310
311 // Decreases cache (expected nb points decreases as the series is purged)
312 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 5), date(2017, 1, 1, 12, 0, 9)};
313 operations.push_back({cacheRange, nullptr, 10});
314
315 QTest::newRow("nbPoints1") << operations;
316 }
317
318 void TestVariable::testNbPoints()
319 {
320 // Creates variable
321 Variable variable{"var"};
322 QCOMPARE(variable.nbPoints(), 0);
323
324 QFETCH(NbPointsOperations, operations);
325 for (const auto &operation : operations) {
326 // Sets cache range and merge data series
327 variable.setCacheRange(operation.m_CacheRange);
328 if (operation.m_DataSeries != nullptr) {
329 variable.mergeDataSeries(operation.m_DataSeries);
330 }
331
332 // Checks nb points
333 QCOMPARE(variable.nbPoints(), operation.m_ExpectedNbPoints);
334 }
335 }
336
337 namespace {
338
339 /// Struct used to represent a range operation on a variable
340 /// @sa TestVariable::testRealRange()
341 struct RangeOperation {
342 SqpRange m_CacheRange; /// Range to set for the variable
343 std::shared_ptr<ScalarSeries> m_DataSeries; /// Series to merge in the variable
344 SqpRange m_ExpectedRealRange; /// Real Range expected after operation on the variable
345 };
346
347 using RangeOperations = std::vector<RangeOperation>;
348
349 } // namespace
350
351 Q_DECLARE_METATYPE(RangeOperations)
352
353 void TestVariable::testRealRange_data()
354 {
355 // ////////////// //
356 // Test structure //
357 // ////////////// //
358
359 QTest::addColumn<RangeOperations>("operations");
360
361 // ////////// //
362 // Test cases //
363 // ////////// //
364 RangeOperations operations{};
365
366 // Inits cache range and data series (expected real range = cache range)
367 auto cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 13, 0, 0)};
368 operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange});
369
370 // Changes cache range and updates data series (expected real range = cache range)
371 cacheRange = SqpRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)};
372 operations.push_back({cacheRange, dataSeries(cacheRange), cacheRange});
373
374 // Changes cache range and update data series but with a lower range (expected real range =
375 // data series range)
376 cacheRange = SqpRange{date(2017, 1, 1, 12, 0, 0), date(2017, 1, 1, 16, 0, 0)};
377 auto dataSeriesRange = SqpRange{date(2017, 1, 1, 14, 0, 0), date(2017, 1, 1, 15, 0, 0)};
378 operations.push_back({cacheRange, dataSeries(dataSeriesRange), dataSeriesRange});
379
380 // Changes cache range but DON'T update data series (expected real range = cache range
381 // before operation)
382 cacheRange = SqpRange{date(2017, 1, 1, 10, 0, 0), date(2017, 1, 1, 17, 0, 0)};
383 operations.push_back({cacheRange, nullptr, dataSeriesRange});
384
385 QTest::newRow("realRange1") << operations;
386 }
387
388 void TestVariable::testRealRange()
389 {
390 // Creates variable (real range is invalid)
391 Variable variable{"var"};
392 QCOMPARE(variable.realRange(), INVALID_RANGE);
393
394 QFETCH(RangeOperations, operations);
395 for (const auto &operation : operations) {
396 // Sets cache range and merge data series
397 variable.setCacheRange(operation.m_CacheRange);
398 if (operation.m_DataSeries != nullptr) {
399 variable.mergeDataSeries(operation.m_DataSeries);
400 }
401
402 // Checks real range
403 QCOMPARE(variable.realRange(), operation.m_ExpectedRealRange);
404 }
405 }
406
175
407
176 QTEST_MAIN(TestVariable)
408 QTEST_MAIN(TestVariable)
177 #include "TestVariable.moc"
409 #include "TestVariable.moc"
General Comments 0
You need to be logged in to leave comments. Login now