##// END OF EJS Templates
Implements purge() method for DataSeries
Alexandre Leroux -
r629:34ec67ab5cd8
parent child
Show More
@@ -1,359 +1,374
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 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
57 bool equals(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 std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
59 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
60 }
60 }
61 catch (const std::bad_cast &) {
61 catch (const std::bad_cast &) {
62 return false;
62 return false;
63 }
63 }
64
64
65 void next() override
65 void next() override
66 {
66 {
67 ++m_XIt;
67 ++m_XIt;
68 ++m_ValuesIt;
68 ++m_ValuesIt;
69 }
69 }
70
70
71 void prev() override
71 void prev() override
72 {
72 {
73 --m_XIt;
73 --m_XIt;
74 --m_ValuesIt;
74 --m_ValuesIt;
75 }
75 }
76
76
77 double x() const override { return m_XIt->at(0); }
77 double x() const override { return m_XIt->at(0); }
78 double value() const override { return m_ValuesIt->at(0); }
78 double value() const override { return m_ValuesIt->at(0); }
79 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
79 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
80 double minValue() const override { return m_ValuesIt->min(); }
80 double minValue() const override { return m_ValuesIt->min(); }
81 double maxValue() const override { return m_ValuesIt->max(); }
81 double maxValue() const override { return m_ValuesIt->max(); }
82 QVector<double> values() const override { return m_ValuesIt->values(); }
82 QVector<double> values() const override { return m_ValuesIt->values(); }
83
83
84 void swap(DataSeriesIteratorValue::Impl &other) override
84 void swap(DataSeriesIteratorValue::Impl &other) override
85 {
85 {
86 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
86 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
87 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
87 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
88 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
88 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
89 }
89 }
90
90
91 private:
91 private:
92 ArrayDataIterator m_XIt;
92 ArrayDataIterator m_XIt;
93 ArrayDataIterator m_ValuesIt;
93 ArrayDataIterator m_ValuesIt;
94 };
94 };
95 } // namespace dataseries_detail
95 } // namespace dataseries_detail
96
96
97 /**
97 /**
98 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
98 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
99 *
99 *
100 * It proposes to set a dimension for the values ​​data.
100 * It proposes to set a dimension for the values ​​data.
101 *
101 *
102 * A DataSeries is always sorted on its x-axis data.
102 * A DataSeries is always sorted on its x-axis data.
103 *
103 *
104 * @tparam Dim The dimension of the values data
104 * @tparam Dim The dimension of the values data
105 *
105 *
106 */
106 */
107 template <int Dim>
107 template <int Dim>
108 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
108 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
109 friend class DataSeriesMergeHelper;
109 friend class DataSeriesMergeHelper;
110
110
111 public:
111 public:
112 /// Tag needed to define the push_back() method
112 /// Tag needed to define the push_back() method
113 /// @sa push_back()
113 /// @sa push_back()
114 using value_type = DataSeriesIteratorValue;
114 using value_type = DataSeriesIteratorValue;
115
115
116 /// @sa IDataSeries::xAxisData()
116 /// @sa IDataSeries::xAxisData()
117 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
117 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
118 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
118 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
119
119
120 /// @sa IDataSeries::xAxisUnit()
120 /// @sa IDataSeries::xAxisUnit()
121 Unit xAxisUnit() const override { return m_XAxisUnit; }
121 Unit xAxisUnit() const override { return m_XAxisUnit; }
122
122
123 /// @return the values dataset
123 /// @return the values dataset
124 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
124 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
125 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
125 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
126
126
127 /// @sa IDataSeries::valuesUnit()
127 /// @sa IDataSeries::valuesUnit()
128 Unit valuesUnit() const override { return m_ValuesUnit; }
128 Unit valuesUnit() const override { return m_ValuesUnit; }
129
129
130
130
131 SqpRange range() const override
131 SqpRange range() const override
132 {
132 {
133 if (!m_XAxisData->cdata().isEmpty()) {
133 if (!m_XAxisData->cdata().isEmpty()) {
134 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
134 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
135 }
135 }
136
136
137 return SqpRange{};
137 return SqpRange{};
138 }
138 }
139
139
140 void clear()
140 void clear()
141 {
141 {
142 m_XAxisData->clear();
142 m_XAxisData->clear();
143 m_ValuesData->clear();
143 m_ValuesData->clear();
144 }
144 }
145
145
146 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
146 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
147
147
148 /// Merges into the data series an other data series
148 /// Merges into the data series an other data series
149 /// @remarks the data series to merge with is cleared after the operation
149 /// @remarks the data series to merge with is cleared after the operation
150 void merge(IDataSeries *dataSeries) override
150 void merge(IDataSeries *dataSeries) override
151 {
151 {
152 dataSeries->lockWrite();
152 dataSeries->lockWrite();
153 lockWrite();
153 lockWrite();
154
154
155 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
155 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
156 DataSeriesMergeHelper::merge(*other, *this);
156 DataSeriesMergeHelper::merge(*other, *this);
157 }
157 }
158 else {
158 else {
159 qCWarning(LOG_DataSeries())
159 qCWarning(LOG_DataSeries())
160 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
160 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
161 }
161 }
162 unlock();
162 unlock();
163 dataSeries->unlock();
163 dataSeries->unlock();
164 }
164 }
165
165
166 void purge(double min, double max) override
167 {
168 if (min > max) {
169 std::swap(min, max);
170 }
171
172 lockWrite();
173
174 auto it = std::remove_if(
175 begin(), end(), [min, max](const auto &it) { return it.x() < min || it.x() > max; });
176 erase(it, end());
177
178 unlock();
179 }
180
166 // ///////// //
181 // ///////// //
167 // Iterators //
182 // Iterators //
168 // ///////// //
183 // ///////// //
169
184
170 DataSeriesIterator begin() override
185 DataSeriesIterator begin() override
171 {
186 {
172 return DataSeriesIterator{DataSeriesIteratorValue{
187 return DataSeriesIterator{DataSeriesIteratorValue{
173 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
188 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
174 }
189 }
175
190
176 DataSeriesIterator end() override
191 DataSeriesIterator end() override
177 {
192 {
178 return DataSeriesIterator{DataSeriesIteratorValue{
193 return DataSeriesIterator{DataSeriesIteratorValue{
179 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
194 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
180 }
195 }
181
196
182 DataSeriesIterator cbegin() const override
197 DataSeriesIterator cbegin() const override
183 {
198 {
184 return DataSeriesIterator{DataSeriesIteratorValue{
199 return DataSeriesIterator{DataSeriesIteratorValue{
185 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
200 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
186 }
201 }
187
202
188 DataSeriesIterator cend() const override
203 DataSeriesIterator cend() const override
189 {
204 {
190 return DataSeriesIterator{DataSeriesIteratorValue{
205 return DataSeriesIterator{DataSeriesIteratorValue{
191 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
206 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
192 }
207 }
193
208
194 void erase(DataSeriesIterator first, DataSeriesIterator last)
209 void erase(DataSeriesIterator first, DataSeriesIterator last)
195 {
210 {
196 auto firstImpl
211 auto firstImpl
197 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
212 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
198 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
213 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
199
214
200 if (firstImpl && lastImpl) {
215 if (firstImpl && lastImpl) {
201 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
216 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
202 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
217 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
203 }
218 }
204 }
219 }
205
220
206 /// @sa IDataSeries::minXAxisData()
221 /// @sa IDataSeries::minXAxisData()
207 DataSeriesIterator minXAxisData(double minXAxisData) const override
222 DataSeriesIterator minXAxisData(double minXAxisData) const override
208 {
223 {
209 return std::lower_bound(
224 return std::lower_bound(
210 cbegin(), cend(), minXAxisData,
225 cbegin(), cend(), minXAxisData,
211 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
226 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
212 }
227 }
213
228
214 /// @sa IDataSeries::maxXAxisData()
229 /// @sa IDataSeries::maxXAxisData()
215 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
230 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
216 {
231 {
217 // Gets the first element that greater than max value
232 // Gets the first element that greater than max value
218 auto it = std::upper_bound(
233 auto it = std::upper_bound(
219 cbegin(), cend(), maxXAxisData,
234 cbegin(), cend(), maxXAxisData,
220 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
235 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
221
236
222 return it == cbegin() ? cend() : --it;
237 return it == cbegin() ? cend() : --it;
223 }
238 }
224
239
225 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
240 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
226 double maxXAxisData) const override
241 double maxXAxisData) const override
227 {
242 {
228 if (minXAxisData > maxXAxisData) {
243 if (minXAxisData > maxXAxisData) {
229 std::swap(minXAxisData, maxXAxisData);
244 std::swap(minXAxisData, maxXAxisData);
230 }
245 }
231
246
232 auto begin = cbegin();
247 auto begin = cbegin();
233 auto end = cend();
248 auto end = cend();
234
249
235 auto lowerIt = std::lower_bound(
250 auto lowerIt = std::lower_bound(
236 begin, end, minXAxisData,
251 begin, end, minXAxisData,
237 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
252 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
238 auto upperIt = std::upper_bound(
253 auto upperIt = std::upper_bound(
239 begin, end, maxXAxisData,
254 begin, end, maxXAxisData,
240 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
255 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
241
256
242 return std::make_pair(lowerIt, upperIt);
257 return std::make_pair(lowerIt, upperIt);
243 }
258 }
244
259
245 std::pair<DataSeriesIterator, DataSeriesIterator>
260 std::pair<DataSeriesIterator, DataSeriesIterator>
246 valuesBounds(double minXAxisData, double maxXAxisData) const override
261 valuesBounds(double minXAxisData, double maxXAxisData) const override
247 {
262 {
248 // Places iterators to the correct x-axis range
263 // Places iterators to the correct x-axis range
249 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
264 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
250
265
251 // Returns end iterators if the range is empty
266 // Returns end iterators if the range is empty
252 if (xAxisRangeIts.first == xAxisRangeIts.second) {
267 if (xAxisRangeIts.first == xAxisRangeIts.second) {
253 return std::make_pair(cend(), cend());
268 return std::make_pair(cend(), cend());
254 }
269 }
255
270
256 // Gets the iterator on the min of all values data
271 // Gets the iterator on the min of all values data
257 auto minIt = std::min_element(
272 auto minIt = std::min_element(
258 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
273 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
259 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
274 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
260 });
275 });
261
276
262 // Gets the iterator on the max of all values data
277 // Gets the iterator on the max of all values data
263 auto maxIt = std::max_element(
278 auto maxIt = std::max_element(
264 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
279 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
265 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
280 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
266 });
281 });
267
282
268 return std::make_pair(minIt, maxIt);
283 return std::make_pair(minIt, maxIt);
269 }
284 }
270
285
271 // /////// //
286 // /////// //
272 // Mutexes //
287 // Mutexes //
273 // /////// //
288 // /////// //
274
289
275 virtual void lockRead() { m_Lock.lockForRead(); }
290 virtual void lockRead() { m_Lock.lockForRead(); }
276 virtual void lockWrite() { m_Lock.lockForWrite(); }
291 virtual void lockWrite() { m_Lock.lockForWrite(); }
277 virtual void unlock() { m_Lock.unlock(); }
292 virtual void unlock() { m_Lock.unlock(); }
278
293
279 // ///// //
294 // ///// //
280 // Other //
295 // Other //
281 // ///// //
296 // ///// //
282
297
283 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
298 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
284 /// method is intended to be used in the context of generating a back insert iterator
299 /// method is intended to be used in the context of generating a back insert iterator
285 /// @param iteratorValue the iterator value containing the values to insert
300 /// @param iteratorValue the iterator value containing the values to insert
286 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
301 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
287 /// @sa merge()
302 /// @sa merge()
288 /// @sa value_type
303 /// @sa value_type
289 void push_back(const value_type &iteratorValue)
304 void push_back(const value_type &iteratorValue)
290 {
305 {
291 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
306 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
292 m_ValuesData->push_back(iteratorValue.values());
307 m_ValuesData->push_back(iteratorValue.values());
293 }
308 }
294
309
295 protected:
310 protected:
296 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
311 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
297 /// DataSeries with no values will be created.
312 /// DataSeries with no values will be created.
298 /// @remarks data series is automatically sorted on its x-axis data
313 /// @remarks data series is automatically sorted on its x-axis data
299 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
314 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
300 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
315 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
301 : m_XAxisData{xAxisData},
316 : m_XAxisData{xAxisData},
302 m_XAxisUnit{xAxisUnit},
317 m_XAxisUnit{xAxisUnit},
303 m_ValuesData{valuesData},
318 m_ValuesData{valuesData},
304 m_ValuesUnit{valuesUnit}
319 m_ValuesUnit{valuesUnit}
305 {
320 {
306 if (m_XAxisData->size() != m_ValuesData->size()) {
321 if (m_XAxisData->size() != m_ValuesData->size()) {
307 clear();
322 clear();
308 }
323 }
309
324
310 // Sorts data if it's not the case
325 // Sorts data if it's not the case
311 const auto &xAxisCData = m_XAxisData->cdata();
326 const auto &xAxisCData = m_XAxisData->cdata();
312 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
327 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
313 sort();
328 sort();
314 }
329 }
315 }
330 }
316
331
317 /// Copy ctor
332 /// Copy ctor
318 explicit DataSeries(const DataSeries<Dim> &other)
333 explicit DataSeries(const DataSeries<Dim> &other)
319 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
334 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
320 m_XAxisUnit{other.m_XAxisUnit},
335 m_XAxisUnit{other.m_XAxisUnit},
321 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
336 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
322 m_ValuesUnit{other.m_ValuesUnit}
337 m_ValuesUnit{other.m_ValuesUnit}
323 {
338 {
324 // Since a series is ordered from its construction and is always ordered, it is not
339 // Since a series is ordered from its construction and is always ordered, it is not
325 // necessary to call the sort method here ('other' is sorted)
340 // necessary to call the sort method here ('other' is sorted)
326 }
341 }
327
342
328 /// Assignment operator
343 /// Assignment operator
329 template <int D>
344 template <int D>
330 DataSeries &operator=(DataSeries<D> other)
345 DataSeries &operator=(DataSeries<D> other)
331 {
346 {
332 std::swap(m_XAxisData, other.m_XAxisData);
347 std::swap(m_XAxisData, other.m_XAxisData);
333 std::swap(m_XAxisUnit, other.m_XAxisUnit);
348 std::swap(m_XAxisUnit, other.m_XAxisUnit);
334 std::swap(m_ValuesData, other.m_ValuesData);
349 std::swap(m_ValuesData, other.m_ValuesData);
335 std::swap(m_ValuesUnit, other.m_ValuesUnit);
350 std::swap(m_ValuesUnit, other.m_ValuesUnit);
336
351
337 return *this;
352 return *this;
338 }
353 }
339
354
340 private:
355 private:
341 /**
356 /**
342 * Sorts data series on its x-axis data
357 * Sorts data series on its x-axis data
343 */
358 */
344 void sort() noexcept
359 void sort() noexcept
345 {
360 {
346 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
361 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
347 m_XAxisData = m_XAxisData->sort(permutation);
362 m_XAxisData = m_XAxisData->sort(permutation);
348 m_ValuesData = m_ValuesData->sort(permutation);
363 m_ValuesData = m_ValuesData->sort(permutation);
349 }
364 }
350
365
351 std::shared_ptr<ArrayData<1> > m_XAxisData;
366 std::shared_ptr<ArrayData<1> > m_XAxisData;
352 Unit m_XAxisUnit;
367 Unit m_XAxisUnit;
353 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
368 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
354 Unit m_ValuesUnit;
369 Unit m_ValuesUnit;
355
370
356 QReadWriteLock m_Lock;
371 QReadWriteLock m_Lock;
357 };
372 };
358
373
359 #endif // SCIQLOP_DATASERIES_H
374 #endif // SCIQLOP_DATASERIES_H
@@ -1,106 +1,109
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
61 virtual void purge(double min, double max) = 0;
62
60 /// @todo Review the name and signature of this method
63 /// @todo Review the name and signature of this method
61 virtual std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) = 0;
64 virtual std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) = 0;
62
65
63 virtual std::unique_ptr<IDataSeries> clone() const = 0;
66 virtual std::unique_ptr<IDataSeries> clone() const = 0;
64 virtual SqpRange range() const = 0;
67 virtual SqpRange range() const = 0;
65
68
66 // ///////// //
69 // ///////// //
67 // Iterators //
70 // Iterators //
68 // ///////// //
71 // ///////// //
69
72
70 virtual DataSeriesIterator cbegin() const = 0;
73 virtual DataSeriesIterator cbegin() const = 0;
71 virtual DataSeriesIterator cend() const = 0;
74 virtual DataSeriesIterator cend() const = 0;
72 virtual DataSeriesIterator begin() = 0;
75 virtual DataSeriesIterator begin() = 0;
73 virtual DataSeriesIterator end() = 0;
76 virtual DataSeriesIterator end() = 0;
74
77
75 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
78 /// @return the iterator to the first entry of the data series whose x-axis data is greater than
76 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
79 /// or equal to the value passed in parameter, or the end iterator if there is no matching value
77 virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0;
80 virtual DataSeriesIterator minXAxisData(double minXAxisData) const = 0;
78
81
79 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
82 /// @return the iterator to the last entry of the data series whose x-axis data is less than or
80 /// equal to the value passed in parameter, or the end iterator if there is no matching value
83 /// equal to the value passed in parameter, or the end iterator if there is no matching value
81 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
84 virtual DataSeriesIterator maxXAxisData(double maxXAxisData) const = 0;
82
85
83 /// @return the iterators pointing to the range of data whose x-axis values are between min and
86 /// @return the iterators pointing to the range of data whose x-axis values are between min and
84 /// max passed in parameters
87 /// max passed in parameters
85 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
88 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
86 xAxisRange(double minXAxisData, double maxXAxisData) const = 0;
89 xAxisRange(double minXAxisData, double maxXAxisData) const = 0;
87
90
88 /// @return two iterators pointing to the data that have respectively the min and the max value
91 /// @return two iterators pointing to the data that have respectively the min and the max value
89 /// data of a data series' range. The search is performed for a given x-axis range.
92 /// data of a data series' range. The search is performed for a given x-axis range.
90 /// @sa xAxisRange()
93 /// @sa xAxisRange()
91 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
94 virtual std::pair<DataSeriesIterator, DataSeriesIterator>
92 valuesBounds(double minXAxisData, double maxXAxisData) const = 0;
95 valuesBounds(double minXAxisData, double maxXAxisData) const = 0;
93
96
94 // /////// //
97 // /////// //
95 // Mutexes //
98 // Mutexes //
96 // /////// //
99 // /////// //
97
100
98 virtual void lockRead() = 0;
101 virtual void lockRead() = 0;
99 virtual void lockWrite() = 0;
102 virtual void lockWrite() = 0;
100 virtual void unlock() = 0;
103 virtual void unlock() = 0;
101 };
104 };
102
105
103 // Required for using shared_ptr in signals/slots
106 // Required for using shared_ptr in signals/slots
104 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
107 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
105
108
106 #endif // SCIQLOP_IDATASERIES_H
109 #endif // SCIQLOP_IDATASERIES_H
General Comments 0
You need to be logged in to leave comments. Login now