##// END OF EJS Templates
Handles y-axis in DataSeries....
Alexandre Leroux -
r867:da8b6df7cbcf
parent child
Show More
@@ -1,391 +1,429
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 #include <Data/OptionalAxis.h>
11
12
12 #include <QLoggingCategory>
13 #include <QLoggingCategory>
13 #include <QReadLocker>
14 #include <QReadLocker>
14 #include <QReadWriteLock>
15 #include <QReadWriteLock>
15 #include <memory>
16 #include <memory>
16
17
17 // We don't use the Qt macro since the log is used in the header file, which causes multiple log
18 // 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
19 // definitions with inheritance. Inline method is used instead
19 inline const QLoggingCategory &LOG_DataSeries()
20 inline const QLoggingCategory &LOG_DataSeries()
20 {
21 {
21 static const QLoggingCategory category{"DataSeries"};
22 static const QLoggingCategory category{"DataSeries"};
22 return category;
23 return category;
23 }
24 }
24
25
25 template <int Dim>
26 template <int Dim>
26 class DataSeries;
27 class DataSeries;
27
28
28 namespace dataseries_detail {
29 namespace dataseries_detail {
29
30
30 template <int Dim, bool IsConst>
31 template <int Dim, bool IsConst>
31 class IteratorValue : public DataSeriesIteratorValue::Impl {
32 class IteratorValue : public DataSeriesIteratorValue::Impl {
32 public:
33 public:
33 friend class DataSeries<Dim>;
34 friend class DataSeries<Dim>;
34
35
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
36 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
37 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
38 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
39 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
39 {
40 {
40 }
41 }
41
42
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
43 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
44 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
45 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
46 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
46 : dataSeries.valuesData()->cend())
47 : dataSeries.valuesData()->cend())
47 {
48 {
48 }
49 }
49
50
50 IteratorValue(const IteratorValue &other) = default;
51 IteratorValue(const IteratorValue &other) = default;
51
52
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
53 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
53 {
54 {
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
55 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
55 }
56 }
56
57
57 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
58 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
59 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
59 return m_XIt->distance(*otherImpl.m_XIt);
60 return m_XIt->distance(*otherImpl.m_XIt);
60 }
61 }
61 catch (const std::bad_cast &) {
62 catch (const std::bad_cast &) {
62 return 0;
63 return 0;
63 }
64 }
64
65
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
66 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
67 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
67 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
68 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
68 }
69 }
69 catch (const std::bad_cast &) {
70 catch (const std::bad_cast &) {
70 return false;
71 return false;
71 }
72 }
72
73
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
74 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
75 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
76 return m_XIt->lowerThan(*otherImpl.m_XIt);
76 }
77 }
77 catch (const std::bad_cast &) {
78 catch (const std::bad_cast &) {
78 return false;
79 return false;
79 }
80 }
80
81
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
82 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
82 {
83 {
83 auto result = clone();
84 auto result = clone();
84 result->next(offset);
85 result->next(offset);
85 return result;
86 return result;
86 }
87 }
87
88
88 void next(int offset) override
89 void next(int offset) override
89 {
90 {
90 m_XIt->next(offset);
91 m_XIt->next(offset);
91 m_ValuesIt->next(offset);
92 m_ValuesIt->next(offset);
92 }
93 }
93
94
94 void prev() override
95 void prev() override
95 {
96 {
96 --m_XIt;
97 --m_XIt;
97 --m_ValuesIt;
98 --m_ValuesIt;
98 }
99 }
99
100
100 double x() const override { return m_XIt->at(0); }
101 double x() const override { return m_XIt->at(0); }
101 double value() const override { return m_ValuesIt->at(0); }
102 double value() const override { return m_ValuesIt->at(0); }
102 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
103 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
103 double minValue() const override { return m_ValuesIt->min(); }
104 double minValue() const override { return m_ValuesIt->min(); }
104 double maxValue() const override { return m_ValuesIt->max(); }
105 double maxValue() const override { return m_ValuesIt->max(); }
105 QVector<double> values() const override { return m_ValuesIt->values(); }
106 QVector<double> values() const override { return m_ValuesIt->values(); }
106
107
107 void swap(DataSeriesIteratorValue::Impl &other) override
108 void swap(DataSeriesIteratorValue::Impl &other) override
108 {
109 {
109 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
110 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
110 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
111 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
111 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
112 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
112 }
113 }
113
114
114 private:
115 private:
115 ArrayDataIterator m_XIt;
116 ArrayDataIterator m_XIt;
116 ArrayDataIterator m_ValuesIt;
117 ArrayDataIterator m_ValuesIt;
117 };
118 };
118 } // namespace dataseries_detail
119 } // namespace dataseries_detail
119
120
120 /**
121 /**
121 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
122 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
122 *
123 *
123 * It proposes to set a dimension for the values ​​data.
124 * It proposes to set a dimension for the values ​​data.
124 *
125 *
125 * A DataSeries is always sorted on its x-axis data.
126 * A DataSeries is always sorted on its x-axis data.
126 *
127 *
127 * @tparam Dim The dimension of the values data
128 * @tparam Dim The dimension of the values data
128 *
129 *
129 */
130 */
130 template <int Dim>
131 template <int Dim>
131 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
132 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
132 friend class DataSeriesMergeHelper;
133 friend class DataSeriesMergeHelper;
133
134
134 public:
135 public:
135 /// @sa IDataSeries::xAxisData()
136 /// @sa IDataSeries::xAxisData()
136 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
137 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
137 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
138 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
138
139
139 /// @sa IDataSeries::xAxisUnit()
140 /// @sa IDataSeries::xAxisUnit()
140 Unit xAxisUnit() const override { return m_XAxisUnit; }
141 Unit xAxisUnit() const override { return m_XAxisUnit; }
141
142
142 /// @return the values dataset
143 /// @return the values dataset
143 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
144 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
144 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
145 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
145
146
146 /// @sa IDataSeries::valuesUnit()
147 /// @sa IDataSeries::valuesUnit()
147 Unit valuesUnit() const override { return m_ValuesUnit; }
148 Unit valuesUnit() const override { return m_ValuesUnit; }
148
149
149 int nbPoints() const override { return m_ValuesData->totalSize(); }
150 int nbPoints() const override { return m_ValuesData->totalSize(); }
150
151
151 void clear()
152 void clear()
152 {
153 {
153 m_XAxisData->clear();
154 m_XAxisData->clear();
154 m_ValuesData->clear();
155 m_ValuesData->clear();
155 }
156 }
156
157
157 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
158 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
158
159
159 /// Merges into the data series an other data series
160 /// Merges into the data series an other data series.
161 ///
162 /// The two dataseries:
163 /// - must be of the same dimension
164 /// - must have the same y-axis (if defined)
165 ///
166 /// If the prerequisites are not valid, the method does nothing
167 ///
160 /// @remarks the data series to merge with is cleared after the operation
168 /// @remarks the data series to merge with is cleared after the operation
161 void merge(IDataSeries *dataSeries) override
169 void merge(IDataSeries *dataSeries) override
162 {
170 {
163 dataSeries->lockWrite();
171 dataSeries->lockWrite();
164 lockWrite();
172 lockWrite();
165
173
166 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
174 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
167 DataSeriesMergeHelper::merge(*other, *this);
175 if (m_YAxis == other->m_YAxis) {
176 DataSeriesMergeHelper::merge(*other, *this);
177 }
178 else {
179 qCWarning(LOG_DataSeries())
180 << QObject::tr("Can't merge data series that have not the same y-axis");
181 }
168 }
182 }
169 else {
183 else {
170 qCWarning(LOG_DataSeries())
184 qCWarning(LOG_DataSeries())
171 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
185 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
172 }
186 }
173 unlock();
187 unlock();
174 dataSeries->unlock();
188 dataSeries->unlock();
175 }
189 }
176
190
177 void purge(double min, double max) override
191 void purge(double min, double max) override
178 {
192 {
179 // Nothing to purge if series is empty
193 // Nothing to purge if series is empty
180 if (isEmpty()) {
194 if (isEmpty()) {
181 return;
195 return;
182 }
196 }
183
197
184 if (min > max) {
198 if (min > max) {
185 std::swap(min, max);
199 std::swap(min, max);
186 }
200 }
187
201
188 // Nothing to purge if series min/max are inside purge range
202 // Nothing to purge if series min/max are inside purge range
189 auto xMin = cbegin()->x();
203 auto xMin = cbegin()->x();
190 auto xMax = (--cend())->x();
204 auto xMax = (--cend())->x();
191 if (xMin >= min && xMax <= max) {
205 if (xMin >= min && xMax <= max) {
192 return;
206 return;
193 }
207 }
194
208
195 auto lowerIt = std::lower_bound(
209 auto lowerIt = std::lower_bound(
196 begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; });
210 begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; });
197 erase(begin(), lowerIt);
211 erase(begin(), lowerIt);
198 auto upperIt = std::upper_bound(
212 auto upperIt = std::upper_bound(
199 begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); });
213 begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); });
200 erase(upperIt, end());
214 erase(upperIt, end());
201 }
215 }
202
216
203 // ///////// //
217 // ///////// //
204 // Iterators //
218 // Iterators //
205 // ///////// //
219 // ///////// //
206
220
207 DataSeriesIterator begin() override
221 DataSeriesIterator begin() override
208 {
222 {
209 return DataSeriesIterator{DataSeriesIteratorValue{
223 return DataSeriesIterator{DataSeriesIteratorValue{
210 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
224 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
211 }
225 }
212
226
213 DataSeriesIterator end() override
227 DataSeriesIterator end() override
214 {
228 {
215 return DataSeriesIterator{DataSeriesIteratorValue{
229 return DataSeriesIterator{DataSeriesIteratorValue{
216 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
230 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
217 }
231 }
218
232
219 DataSeriesIterator cbegin() const override
233 DataSeriesIterator cbegin() const override
220 {
234 {
221 return DataSeriesIterator{DataSeriesIteratorValue{
235 return DataSeriesIterator{DataSeriesIteratorValue{
222 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
236 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
223 }
237 }
224
238
225 DataSeriesIterator cend() const override
239 DataSeriesIterator cend() const override
226 {
240 {
227 return DataSeriesIterator{DataSeriesIteratorValue{
241 return DataSeriesIterator{DataSeriesIteratorValue{
228 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
242 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
229 }
243 }
230
244
231 void erase(DataSeriesIterator first, DataSeriesIterator last)
245 void erase(DataSeriesIterator first, DataSeriesIterator last)
232 {
246 {
233 auto firstImpl
247 auto firstImpl
234 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
248 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
235 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
249 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
236
250
237 if (firstImpl && lastImpl) {
251 if (firstImpl && lastImpl) {
238 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
252 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
239 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
253 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
240 }
254 }
241 }
255 }
242
256
243 void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false)
257 void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false)
244 {
258 {
245 auto firstImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(first->impl());
259 auto firstImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(first->impl());
246 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(last->impl());
260 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(last->impl());
247
261
248 if (firstImpl && lastImpl) {
262 if (firstImpl && lastImpl) {
249 m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend);
263 m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend);
250 m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend);
264 m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend);
251 }
265 }
252 }
266 }
253
267
254 /// @sa IDataSeries::minXAxisData()
268 /// @sa IDataSeries::minXAxisData()
255 DataSeriesIterator minXAxisData(double minXAxisData) const override
269 DataSeriesIterator minXAxisData(double minXAxisData) const override
256 {
270 {
257 return std::lower_bound(
271 return std::lower_bound(
258 cbegin(), cend(), minXAxisData,
272 cbegin(), cend(), minXAxisData,
259 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
273 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
260 }
274 }
261
275
262 /// @sa IDataSeries::maxXAxisData()
276 /// @sa IDataSeries::maxXAxisData()
263 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
277 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
264 {
278 {
265 // Gets the first element that greater than max value
279 // Gets the first element that greater than max value
266 auto it = std::upper_bound(
280 auto it = std::upper_bound(
267 cbegin(), cend(), maxXAxisData,
281 cbegin(), cend(), maxXAxisData,
268 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
282 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
269
283
270 return it == cbegin() ? cend() : --it;
284 return it == cbegin() ? cend() : --it;
271 }
285 }
272
286
273 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
287 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
274 double maxXAxisData) const override
288 double maxXAxisData) const override
275 {
289 {
276 if (minXAxisData > maxXAxisData) {
290 if (minXAxisData > maxXAxisData) {
277 std::swap(minXAxisData, maxXAxisData);
291 std::swap(minXAxisData, maxXAxisData);
278 }
292 }
279
293
280 auto begin = cbegin();
294 auto begin = cbegin();
281 auto end = cend();
295 auto end = cend();
282
296
283 auto lowerIt = std::lower_bound(
297 auto lowerIt = std::lower_bound(
284 begin, end, minXAxisData,
298 begin, end, minXAxisData,
285 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
299 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
286 auto upperIt = std::upper_bound(
300 auto upperIt = std::upper_bound(
287 lowerIt, end, maxXAxisData,
301 lowerIt, end, maxXAxisData,
288 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
302 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
289
303
290 return std::make_pair(lowerIt, upperIt);
304 return std::make_pair(lowerIt, upperIt);
291 }
305 }
292
306
293 std::pair<DataSeriesIterator, DataSeriesIterator>
307 std::pair<DataSeriesIterator, DataSeriesIterator>
294 valuesBounds(double minXAxisData, double maxXAxisData) const override
308 valuesBounds(double minXAxisData, double maxXAxisData) const override
295 {
309 {
296 // Places iterators to the correct x-axis range
310 // Places iterators to the correct x-axis range
297 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
311 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
298
312
299 // Returns end iterators if the range is empty
313 // Returns end iterators if the range is empty
300 if (xAxisRangeIts.first == xAxisRangeIts.second) {
314 if (xAxisRangeIts.first == xAxisRangeIts.second) {
301 return std::make_pair(cend(), cend());
315 return std::make_pair(cend(), cend());
302 }
316 }
303
317
304 // Gets the iterator on the min of all values data
318 // Gets the iterator on the min of all values data
305 auto minIt = std::min_element(
319 auto minIt = std::min_element(
306 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
320 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
307 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
321 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
308 });
322 });
309
323
310 // Gets the iterator on the max of all values data
324 // Gets the iterator on the max of all values data
311 auto maxIt = std::max_element(
325 auto maxIt = std::max_element(
312 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
326 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
313 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
327 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
314 });
328 });
315
329
316 return std::make_pair(minIt, maxIt);
330 return std::make_pair(minIt, maxIt);
317 }
331 }
318
332
319 // /////// //
333 // /////// //
320 // Mutexes //
334 // Mutexes //
321 // /////// //
335 // /////// //
322
336
323 virtual void lockRead() { m_Lock.lockForRead(); }
337 virtual void lockRead() { m_Lock.lockForRead(); }
324 virtual void lockWrite() { m_Lock.lockForWrite(); }
338 virtual void lockWrite() { m_Lock.lockForWrite(); }
325 virtual void unlock() { m_Lock.unlock(); }
339 virtual void unlock() { m_Lock.unlock(); }
326
340
327 protected:
341 protected:
328 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
342 /// Protected ctor (DataSeries is abstract).
329 /// DataSeries with no values will be created.
343 ///
344 /// Data vectors must be consistent with each other, otherwise an exception will be thrown (@sa
345 /// class description for consistent rules)
330 /// @remarks data series is automatically sorted on its x-axis data
346 /// @remarks data series is automatically sorted on its x-axis data
347 /// @throws std::invalid_argument if the data are inconsistent with each other
331 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
348 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
332 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
349 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit,
350 OptionalAxis yAxis = OptionalAxis{})
333 : m_XAxisData{xAxisData},
351 : m_XAxisData{xAxisData},
334 m_XAxisUnit{xAxisUnit},
352 m_XAxisUnit{xAxisUnit},
335 m_ValuesData{valuesData},
353 m_ValuesData{valuesData},
336 m_ValuesUnit{valuesUnit}
354 m_ValuesUnit{valuesUnit},
355 m_YAxis{std::move(yAxis)}
337 {
356 {
338 if (m_XAxisData->size() != m_ValuesData->size()) {
357 if (m_XAxisData->size() != m_ValuesData->size()) {
339 clear();
358 throw std::invalid_argument{
note

Why an exception? A simple clear() on the data and maybe a method isValid() might be enough.

359 "The number of values by component must be equal to the number of x-axis data"};
360 }
361
362 // Validates y-axis (if defined)
363 if (yAxis.isDefined() && (yAxis.size() != m_ValuesData->componentCount())) {
364 throw std::invalid_argument{
365 "As the y-axis is defined, the number of value components must be equal to the "
366 "number of y-axis data"};
340 }
367 }
341
368
342 // Sorts data if it's not the case
369 // Sorts data if it's not the case
343 const auto &xAxisCData = m_XAxisData->cdata();
370 const auto &xAxisCData = m_XAxisData->cdata();
344 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
371 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
345 sort();
372 sort();
346 }
373 }
347 }
374 }
348
375
349 /// Copy ctor
376 /// Copy ctor
350 explicit DataSeries(const DataSeries<Dim> &other)
377 explicit DataSeries(const DataSeries<Dim> &other)
351 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
378 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
352 m_XAxisUnit{other.m_XAxisUnit},
379 m_XAxisUnit{other.m_XAxisUnit},
353 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
380 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
354 m_ValuesUnit{other.m_ValuesUnit}
381 m_ValuesUnit{other.m_ValuesUnit},
382 m_YAxis{other.m_YAxis}
355 {
383 {
356 // Since a series is ordered from its construction and is always ordered, it is not
384 // Since a series is ordered from its construction and is always ordered, it is not
357 // necessary to call the sort method here ('other' is sorted)
385 // necessary to call the sort method here ('other' is sorted)
358 }
386 }
359
387
388 /// @return the y-axis associated to the data series
389 OptionalAxis yAxis() const { return m_YAxis; }
390
360 /// Assignment operator
391 /// Assignment operator
361 template <int D>
392 template <int D>
362 DataSeries &operator=(DataSeries<D> other)
393 DataSeries &operator=(DataSeries<D> other)
363 {
394 {
364 std::swap(m_XAxisData, other.m_XAxisData);
395 std::swap(m_XAxisData, other.m_XAxisData);
365 std::swap(m_XAxisUnit, other.m_XAxisUnit);
396 std::swap(m_XAxisUnit, other.m_XAxisUnit);
366 std::swap(m_ValuesData, other.m_ValuesData);
397 std::swap(m_ValuesData, other.m_ValuesData);
367 std::swap(m_ValuesUnit, other.m_ValuesUnit);
398 std::swap(m_ValuesUnit, other.m_ValuesUnit);
399 std::swap(m_YAxis, other.m_YAxis);
368
400
369 return *this;
401 return *this;
370 }
402 }
371
403
372 private:
404 private:
373 /**
405 /**
374 * Sorts data series on its x-axis data
406 * Sorts data series on its x-axis data
375 */
407 */
376 void sort() noexcept
408 void sort() noexcept
377 {
409 {
378 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
410 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
379 m_XAxisData = m_XAxisData->sort(permutation);
411 m_XAxisData = m_XAxisData->sort(permutation);
380 m_ValuesData = m_ValuesData->sort(permutation);
412 m_ValuesData = m_ValuesData->sort(permutation);
381 }
413 }
382
414
415 // x-axis
383 std::shared_ptr<ArrayData<1> > m_XAxisData;
416 std::shared_ptr<ArrayData<1> > m_XAxisData;
384 Unit m_XAxisUnit;
417 Unit m_XAxisUnit;
418
419 // values
385 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
420 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
386 Unit m_ValuesUnit;
421 Unit m_ValuesUnit;
387
422
423 // y-axis (optional)
424 OptionalAxis m_YAxis;
425
388 QReadWriteLock m_Lock;
426 QReadWriteLock m_Lock;
389 };
427 };
390
428
391 #endif // SCIQLOP_DATASERIES_H
429 #endif // SCIQLOP_DATASERIES_H
General Comments 0
You need to be logged in to leave comments. Login now