##// END OF EJS Templates
Adds subData() method
Alexandre Leroux -
r557:8d58d9ce4f09
parent child
Show More
@@ -1,267 +1,288
1 #ifndef SCIQLOP_DATASERIES_H
1 #ifndef SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
3
3
4 #include <Common/SortUtils.h>
4 #include <Common/SortUtils.h>
5
5
6 #include <Data/ArrayData.h>
6 #include <Data/ArrayData.h>
7 #include <Data/IDataSeries.h>
7 #include <Data/IDataSeries.h>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10
10
11 #include <QReadLocker>
11 #include <QReadLocker>
12 #include <QReadWriteLock>
12 #include <QReadWriteLock>
13 #include <memory>
13 #include <memory>
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
17
17
18
18
19 /**
19 /**
20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
21 *
21 *
22 * It proposes to set a dimension for the values ​​data.
22 * It proposes to set a dimension for the values ​​data.
23 *
23 *
24 * A DataSeries is always sorted on its x-axis data.
24 * A DataSeries is always sorted on its x-axis data.
25 *
25 *
26 * @tparam Dim The dimension of the values data
26 * @tparam Dim The dimension of the values data
27 *
27 *
28 */
28 */
29 template <int Dim>
29 template <int Dim>
30 class DataSeries : public IDataSeries {
30 class DataSeries : public IDataSeries {
31 public:
31 public:
32 class IteratorValue {
32 class IteratorValue {
33 public:
33 public:
34 explicit IteratorValue(const DataSeries &dataSeries, bool begin)
34 explicit IteratorValue(const DataSeries &dataSeries, bool begin)
35 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
35 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
36 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
36 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
37 : dataSeries.valuesData()->cend())
37 : dataSeries.valuesData()->cend())
38 {
38 {
39 }
39 }
40
40
41 double x() const { return m_XIt->at(0); }
41 double x() const { return m_XIt->at(0); }
42 double value() const { return m_ValuesIt->at(0); }
42 double value() const { return m_ValuesIt->at(0); }
43 double value(int componentIndex) const { return m_ValuesIt->at(componentIndex); }
43 double value(int componentIndex) const { return m_ValuesIt->at(componentIndex); }
44
44
45 void next()
45 void next()
46 {
46 {
47 ++m_XIt;
47 ++m_XIt;
48 ++m_ValuesIt;
48 ++m_ValuesIt;
49 }
49 }
50
50
51 bool operator==(const IteratorValue &other) const
51 bool operator==(const IteratorValue &other) const
52 {
52 {
53 return std::tie(m_XIt, m_ValuesIt) == std::tie(other.m_XIt, other.m_ValuesIt);
53 return std::tie(m_XIt, m_ValuesIt) == std::tie(other.m_XIt, other.m_ValuesIt);
54 }
54 }
55
55
56 private:
56 private:
57 ArrayData<1>::Iterator m_XIt;
57 ArrayData<1>::Iterator m_XIt;
58 typename ArrayData<Dim>::Iterator m_ValuesIt;
58 typename ArrayData<Dim>::Iterator m_ValuesIt;
59 };
59 };
60
60
61 class Iterator {
61 class Iterator {
62 public:
62 public:
63 using iterator_category = std::forward_iterator_tag;
63 using iterator_category = std::forward_iterator_tag;
64 using value_type = const IteratorValue;
64 using value_type = const IteratorValue;
65 using difference_type = std::ptrdiff_t;
65 using difference_type = std::ptrdiff_t;
66 using pointer = value_type *;
66 using pointer = value_type *;
67 using reference = value_type &;
67 using reference = value_type &;
68
68
69 Iterator(const DataSeries &dataSeries, bool begin) : m_CurrentValue{dataSeries, begin} {}
69 Iterator(const DataSeries &dataSeries, bool begin) : m_CurrentValue{dataSeries, begin} {}
70 virtual ~Iterator() noexcept = default;
70 virtual ~Iterator() noexcept = default;
71 Iterator(const Iterator &) = default;
71 Iterator(const Iterator &) = default;
72 Iterator(Iterator &&) = default;
72 Iterator(Iterator &&) = default;
73 Iterator &operator=(const Iterator &) = default;
73 Iterator &operator=(const Iterator &) = default;
74 Iterator &operator=(Iterator &&) = default;
74 Iterator &operator=(Iterator &&) = default;
75
75
76 Iterator &operator++()
76 Iterator &operator++()
77 {
77 {
78 m_CurrentValue.next();
78 m_CurrentValue.next();
79 return *this;
79 return *this;
80 }
80 }
81
81
82 pointer operator->() const { return &m_CurrentValue; }
82 pointer operator->() const { return &m_CurrentValue; }
83
83
84 reference operator*() const { return m_CurrentValue; }
84 reference operator*() const { return m_CurrentValue; }
85
85
86 bool operator==(const Iterator &other) const
86 bool operator==(const Iterator &other) const
87 {
87 {
88 return m_CurrentValue == other.m_CurrentValue;
88 return m_CurrentValue == other.m_CurrentValue;
89 }
89 }
90
90
91 bool operator!=(const Iterator &other) const { return !(*this == other); }
91 bool operator!=(const Iterator &other) const { return !(*this == other); }
92
92
93 private:
93 private:
94 IteratorValue m_CurrentValue;
94 IteratorValue m_CurrentValue;
95 };
95 };
96
96
97 /// @sa IDataSeries::xAxisData()
97 /// @sa IDataSeries::xAxisData()
98 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
98 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
99 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
99 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
100
100
101 /// @sa IDataSeries::xAxisUnit()
101 /// @sa IDataSeries::xAxisUnit()
102 Unit xAxisUnit() const override { return m_XAxisUnit; }
102 Unit xAxisUnit() const override { return m_XAxisUnit; }
103
103
104 /// @return the values dataset
104 /// @return the values dataset
105 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
105 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
106 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
106 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
107
107
108 /// @sa IDataSeries::valuesUnit()
108 /// @sa IDataSeries::valuesUnit()
109 Unit valuesUnit() const override { return m_ValuesUnit; }
109 Unit valuesUnit() const override { return m_ValuesUnit; }
110
110
111
111
112 SqpRange range() const override
112 SqpRange range() const override
113 {
113 {
114 if (!m_XAxisData->cdata().isEmpty()) {
114 if (!m_XAxisData->cdata().isEmpty()) {
115 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
115 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
116 }
116 }
117
117
118 return SqpRange{};
118 return SqpRange{};
119 }
119 }
120
120
121 void clear()
121 void clear()
122 {
122 {
123 m_XAxisData->clear();
123 m_XAxisData->clear();
124 m_ValuesData->clear();
124 m_ValuesData->clear();
125 }
125 }
126
126
127 /// Merges into the data series an other data series
127 /// Merges into the data series an other data series
128 /// @remarks the data series to merge with is cleared after the operation
128 /// @remarks the data series to merge with is cleared after the operation
129 void merge(IDataSeries *dataSeries) override
129 void merge(IDataSeries *dataSeries) override
130 {
130 {
131 dataSeries->lockWrite();
131 dataSeries->lockWrite();
132 lockWrite();
132 lockWrite();
133
133
134 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
134 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
135 const auto &otherXAxisData = other->xAxisData()->cdata();
135 const auto &otherXAxisData = other->xAxisData()->cdata();
136 const auto &xAxisData = m_XAxisData->cdata();
136 const auto &xAxisData = m_XAxisData->cdata();
137
137
138 // As data series are sorted, we can improve performances of merge, by call the sort
138 // As data series are sorted, we can improve performances of merge, by call the sort
139 // method only if the two data series overlap.
139 // method only if the two data series overlap.
140 if (!otherXAxisData.empty()) {
140 if (!otherXAxisData.empty()) {
141 auto firstValue = otherXAxisData.front();
141 auto firstValue = otherXAxisData.front();
142 auto lastValue = otherXAxisData.back();
142 auto lastValue = otherXAxisData.back();
143
143
144 auto xAxisDataBegin = xAxisData.cbegin();
144 auto xAxisDataBegin = xAxisData.cbegin();
145 auto xAxisDataEnd = xAxisData.cend();
145 auto xAxisDataEnd = xAxisData.cend();
146
146
147 bool prepend;
147 bool prepend;
148 bool sortNeeded;
148 bool sortNeeded;
149
149
150 if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) {
150 if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) {
151 // Other data series if after data series
151 // Other data series if after data series
152 prepend = false;
152 prepend = false;
153 sortNeeded = false;
153 sortNeeded = false;
154 }
154 }
155 else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue)
155 else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue)
156 == xAxisDataBegin) {
156 == xAxisDataBegin) {
157 // Other data series if before data series
157 // Other data series if before data series
158 prepend = true;
158 prepend = true;
159 sortNeeded = false;
159 sortNeeded = false;
160 }
160 }
161 else {
161 else {
162 // The two data series overlap
162 // The two data series overlap
163 prepend = false;
163 prepend = false;
164 sortNeeded = true;
164 sortNeeded = true;
165 }
165 }
166
166
167 // Makes the merge
167 // Makes the merge
168 m_XAxisData->add(*other->xAxisData(), prepend);
168 m_XAxisData->add(*other->xAxisData(), prepend);
169 m_ValuesData->add(*other->valuesData(), prepend);
169 m_ValuesData->add(*other->valuesData(), prepend);
170
170
171 if (sortNeeded) {
171 if (sortNeeded) {
172 sort();
172 sort();
173 }
173 }
174 }
174 }
175
175
176 // Clears the other data series
176 // Clears the other data series
177 other->clear();
177 other->clear();
178 }
178 }
179 else {
179 else {
180 qCWarning(LOG_DataSeries())
180 qCWarning(LOG_DataSeries())
181 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
181 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
182 }
182 }
183 unlock();
183 unlock();
184 dataSeries->unlock();
184 dataSeries->unlock();
185 }
185 }
186
186
187 // ///////// //
187 // ///////// //
188 // Iterators //
188 // Iterators //
189 // ///////// //
189 // ///////// //
190
190
191 Iterator cbegin() const { return Iterator{*this, true}; }
191 Iterator cbegin() const { return Iterator{*this, true}; }
192
192
193 Iterator cend() const { return Iterator{*this, false}; }
193 Iterator cend() const { return Iterator{*this, false}; }
194
194
195 std::pair<Iterator, Iterator> subData(double min, double max) const
196 {
197 if (min > max) {
198 std::swap(min, max);
199 }
200
201 auto begin = cbegin();
202 auto end = cend();
203
204 auto lowerIt
205 = std::lower_bound(begin, end, min, [](const auto &itValue, const auto &value) {
206 return itValue.x() == value;
207 });
208 auto upperIt
209 = std::upper_bound(begin, end, max, [](const auto &value, const auto &itValue) {
210 return itValue.x() == value;
211 });
212
213 return std::make_pair(lowerIt, upperIt);
214 }
215
195 // /////// //
216 // /////// //
196 // Mutexes //
217 // Mutexes //
197 // /////// //
218 // /////// //
198
219
199 virtual void lockRead() { m_Lock.lockForRead(); }
220 virtual void lockRead() { m_Lock.lockForRead(); }
200 virtual void lockWrite() { m_Lock.lockForWrite(); }
221 virtual void lockWrite() { m_Lock.lockForWrite(); }
201 virtual void unlock() { m_Lock.unlock(); }
222 virtual void unlock() { m_Lock.unlock(); }
202
223
203 protected:
224 protected:
204 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
225 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
205 /// DataSeries with no values will be created.
226 /// DataSeries with no values will be created.
206 /// @remarks data series is automatically sorted on its x-axis data
227 /// @remarks data series is automatically sorted on its x-axis data
207 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
228 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
208 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
229 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
209 : m_XAxisData{xAxisData},
230 : m_XAxisData{xAxisData},
210 m_XAxisUnit{xAxisUnit},
231 m_XAxisUnit{xAxisUnit},
211 m_ValuesData{valuesData},
232 m_ValuesData{valuesData},
212 m_ValuesUnit{valuesUnit}
233 m_ValuesUnit{valuesUnit}
213 {
234 {
214 if (m_XAxisData->size() != m_ValuesData->size()) {
235 if (m_XAxisData->size() != m_ValuesData->size()) {
215 clear();
236 clear();
216 }
237 }
217
238
218 // Sorts data if it's not the case
239 // Sorts data if it's not the case
219 const auto &xAxisCData = m_XAxisData->cdata();
240 const auto &xAxisCData = m_XAxisData->cdata();
220 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
241 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
221 sort();
242 sort();
222 }
243 }
223 }
244 }
224
245
225 /// Copy ctor
246 /// Copy ctor
226 explicit DataSeries(const DataSeries<Dim> &other)
247 explicit DataSeries(const DataSeries<Dim> &other)
227 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
248 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
228 m_XAxisUnit{other.m_XAxisUnit},
249 m_XAxisUnit{other.m_XAxisUnit},
229 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
250 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
230 m_ValuesUnit{other.m_ValuesUnit}
251 m_ValuesUnit{other.m_ValuesUnit}
231 {
252 {
232 // Since a series is ordered from its construction and is always ordered, it is not
253 // Since a series is ordered from its construction and is always ordered, it is not
233 // necessary to call the sort method here ('other' is sorted)
254 // necessary to call the sort method here ('other' is sorted)
234 }
255 }
235
256
236 /// Assignment operator
257 /// Assignment operator
237 template <int D>
258 template <int D>
238 DataSeries &operator=(DataSeries<D> other)
259 DataSeries &operator=(DataSeries<D> other)
239 {
260 {
240 std::swap(m_XAxisData, other.m_XAxisData);
261 std::swap(m_XAxisData, other.m_XAxisData);
241 std::swap(m_XAxisUnit, other.m_XAxisUnit);
262 std::swap(m_XAxisUnit, other.m_XAxisUnit);
242 std::swap(m_ValuesData, other.m_ValuesData);
263 std::swap(m_ValuesData, other.m_ValuesData);
243 std::swap(m_ValuesUnit, other.m_ValuesUnit);
264 std::swap(m_ValuesUnit, other.m_ValuesUnit);
244
265
245 return *this;
266 return *this;
246 }
267 }
247
268
248 private:
269 private:
249 /**
270 /**
250 * Sorts data series on its x-axis data
271 * Sorts data series on its x-axis data
251 */
272 */
252 void sort() noexcept
273 void sort() noexcept
253 {
274 {
254 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
275 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
255 m_XAxisData = m_XAxisData->sort(permutation);
276 m_XAxisData = m_XAxisData->sort(permutation);
256 m_ValuesData = m_ValuesData->sort(permutation);
277 m_ValuesData = m_ValuesData->sort(permutation);
257 }
278 }
258
279
259 std::shared_ptr<ArrayData<1> > m_XAxisData;
280 std::shared_ptr<ArrayData<1> > m_XAxisData;
260 Unit m_XAxisUnit;
281 Unit m_XAxisUnit;
261 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
282 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
262 Unit m_ValuesUnit;
283 Unit m_ValuesUnit;
263
284
264 QReadWriteLock m_Lock;
285 QReadWriteLock m_Lock;
265 };
286 };
266
287
267 #endif // SCIQLOP_DATASERIES_H
288 #endif // SCIQLOP_DATASERIES_H
General Comments 0
You need to be logged in to leave comments. Login now