##// END OF EJS Templates
Restored Spectrograms plots...
jeandet -
r43:54e194b00c35
parent child
Show More
@@ -1,510 +1,510
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 #include <Data/OptionalAxis.h>
12
12
13 #include <QLoggingCategory>
13 #include <QLoggingCategory>
14 #include <QReadLocker>
14 #include <QReadLocker>
15 #include <QReadWriteLock>
15 #include <QReadWriteLock>
16 #include <memory>
16 #include <memory>
17
17
18 // 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
19 // definitions with inheritance. Inline method is used instead
19 // definitions with inheritance. Inline method is used instead
20 inline const QLoggingCategory &LOG_DataSeries()
20 inline const QLoggingCategory &LOG_DataSeries()
21 {
21 {
22 static const QLoggingCategory category{"DataSeries"};
22 static const QLoggingCategory category{"DataSeries"};
23 return category;
23 return category;
24 }
24 }
25
25
26 template <int Dim>
26 template <int Dim>
27 class DataSeries;
27 class DataSeries;
28
28
29 namespace dataseries_detail {
29 namespace dataseries_detail {
30
30
31 template <int Dim, bool IsConst>
31 template <int Dim, bool IsConst>
32 class IteratorValue : public DataSeriesIteratorValue::Impl {
32 class IteratorValue : public DataSeriesIteratorValue::Impl {
33 public:
33 public:
34 friend class DataSeries<Dim>;
34 friend class DataSeries<Dim>;
35
35
36 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
36 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
37 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
37 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
38 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
38 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
39 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end()),
39 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end()),
40 m_YItBegin{dataSeries.yAxis().begin()},
40 m_YItBegin{dataSeries.yAxis().begin()},
41 m_YItEnd{dataSeries.yAxis().end()}
41 m_YItEnd{dataSeries.yAxis().end()}
42 {
42 {
43 }
43 }
44
44
45 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
45 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
46 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
46 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
47 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
47 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
48 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
48 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
49 : dataSeries.valuesData()->cend()),
49 : dataSeries.valuesData()->cend()),
50 m_YItBegin{dataSeries.yAxis().cbegin()},
50 m_YItBegin{dataSeries.yAxis().cbegin()},
51 m_YItEnd{dataSeries.yAxis().cend()}
51 m_YItEnd{dataSeries.yAxis().cend()}
52 {
52 {
53 }
53 }
54
54
55 IteratorValue(const IteratorValue &other) = default;
55 IteratorValue(const IteratorValue &other) = default;
56
56
57 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
57 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
58 {
58 {
59 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
59 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
60 }
60 }
61
61
62 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
62 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
63 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
63 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
64 return m_XIt->distance(*otherImpl.m_XIt);
64 return m_XIt->distance(*otherImpl.m_XIt);
65 }
65 }
66 catch (const std::bad_cast &) {
66 catch (const std::bad_cast &) {
67 return 0;
67 return 0;
68 }
68 }
69
69
70 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
70 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
71 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
71 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
72 return std::tie(m_XIt, m_ValuesIt, m_YItBegin, m_YItEnd)
72 return std::tie(m_XIt, m_ValuesIt, m_YItBegin, m_YItEnd)
73 == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt, otherImpl.m_YItBegin,
73 == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt, otherImpl.m_YItBegin,
74 otherImpl.m_YItEnd);
74 otherImpl.m_YItEnd);
75 }
75 }
76 catch (const std::bad_cast &) {
76 catch (const std::bad_cast &) {
77 return false;
77 return false;
78 }
78 }
79
79
80 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
80 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
81 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
81 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
82 return m_XIt->lowerThan(*otherImpl.m_XIt);
82 return m_XIt->lowerThan(*otherImpl.m_XIt);
83 }
83 }
84 catch (const std::bad_cast &) {
84 catch (const std::bad_cast &) {
85 return false;
85 return false;
86 }
86 }
87
87
88 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
88 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
89 {
89 {
90 auto result = clone();
90 auto result = clone();
91 result->next(offset);
91 result->next(offset);
92 return result;
92 return result;
93 }
93 }
94
94
95 void next(int offset) override
95 void next(int offset) override
96 {
96 {
97 m_XIt->next(offset);
97 m_XIt->next(offset);
98 m_ValuesIt->next(offset);
98 m_ValuesIt->next(offset);
99 }
99 }
100
100
101 void prev() override
101 void prev() override
102 {
102 {
103 --m_XIt;
103 --m_XIt;
104 --m_ValuesIt;
104 --m_ValuesIt;
105 }
105 }
106
106
107 double x() const override { return m_XIt->at(0); }
107 double x() const override { return m_XIt->at(0); }
108 std::vector<double> y() const override
108 std::vector<double> y() const override
109 {
109 {
110 std::vector<double> result{};
110 std::vector<double> result{};
111 std::transform(m_YItBegin, m_YItEnd, std::back_inserter(result),
111 std::transform(m_YItBegin, m_YItEnd, std::back_inserter(result),
112 [](const auto &it) { return it.first(); });
112 [](const auto &it) { return it.first(); });
113
113
114 return result;
114 return result;
115 }
115 }
116
116
117 double value() const override { return m_ValuesIt->at(0); }
117 double value() const override { return m_ValuesIt->at(0); }
118 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
118 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
119 double minValue() const override { return m_ValuesIt->min(); }
119 double minValue() const override { return m_ValuesIt->min(); }
120 double maxValue() const override { return m_ValuesIt->max(); }
120 double maxValue() const override { return m_ValuesIt->max(); }
121 QVector<double> values() const override { return m_ValuesIt->values(); }
121 QVector<double> values() const override { return m_ValuesIt->values(); }
122
122
123 void swap(DataSeriesIteratorValue::Impl &other) override
123 void swap(DataSeriesIteratorValue::Impl &other) override
124 {
124 {
125 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
125 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
126 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
126 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
127 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
127 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
128 m_YItBegin->impl()->swap(*otherImpl.m_YItBegin->impl());
128 m_YItBegin->impl()->swap(*otherImpl.m_YItBegin->impl());
129 m_YItEnd->impl()->swap(*otherImpl.m_YItEnd->impl());
129 m_YItEnd->impl()->swap(*otherImpl.m_YItEnd->impl());
130 }
130 }
131
131
132 private:
132 private:
133 ArrayDataIterator m_XIt;
133 ArrayDataIterator m_XIt;
134 ArrayDataIterator m_ValuesIt;
134 ArrayDataIterator m_ValuesIt;
135 ArrayDataIterator m_YItBegin;
135 ArrayDataIterator m_YItBegin;
136 ArrayDataIterator m_YItEnd;
136 ArrayDataIterator m_YItEnd;
137 };
137 };
138 } // namespace dataseries_detail
138 } // namespace dataseries_detail
139
139
140 /**
140 /**
141 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
141 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
142 *
142 *
143 * The DataSeries represents values on one or two axes, according to these rules:
143 * The DataSeries represents values on one or two axes, according to these rules:
144 * - the x-axis is always defined
144 * - the x-axis is always defined
145 * - an y-axis can be defined or not. If set, additional consistency checks apply to the values (see
145 * - an y-axis can be defined or not. If set, additional consistency checks apply to the values (see
146 * below)
146 * below)
147 * - the values are defined on one or two dimensions. In the case of 2-dim values, the data is
147 * - the values are defined on one or two dimensions. In the case of 2-dim values, the data is
148 * distributed into components (for example, a vector defines three components)
148 * distributed into components (for example, a vector defines three components)
149 * - New values can be added to the series, on the x-axis.
149 * - New values can be added to the series, on the x-axis.
150 * - Once initialized to the series creation, the y-axis (if defined) is no longer modifiable
150 * - Once initialized to the series creation, the y-axis (if defined) is no longer modifiable
151 * - Data representing values and axes are associated with a unit
151 * - Data representing values and axes are associated with a unit
152 * - The data series is always sorted in ascending order on the x-axis.
152 * - The data series is always sorted in ascending order on the x-axis.
153 *
153 *
154 * Consistency checks are carried out between the axes and the values. These controls are provided
154 * Consistency checks are carried out between the axes and the values. These controls are provided
155 * throughout the DataSeries lifecycle:
155 * throughout the DataSeries lifecycle:
156 * - the number of data on the x-axis must be equal to the number of values (in the case of
156 * - the number of data on the x-axis must be equal to the number of values (in the case of
157 * 2-dim ArrayData for values, the test is performed on the number of values per component)
157 * 2-dim ArrayData for values, the test is performed on the number of values per component)
158 * - if the y-axis is defined, the number of components of the ArrayData for values must equal the
158 * - if the y-axis is defined, the number of components of the ArrayData for values must equal the
159 * number of data on the y-axis.
159 * number of data on the y-axis.
160 *
160 *
161 * Examples:
161 * Examples:
162 * 1)
162 * 1)
163 * - x-axis: [1 ; 2 ; 3]
163 * - x-axis: [1 ; 2 ; 3]
164 * - y-axis: not defined
164 * - y-axis: not defined
165 * - values: [10 ; 20 ; 30] (1-dim ArrayData)
165 * - values: [10 ; 20 ; 30] (1-dim ArrayData)
166 * => the DataSeries is valid, as x-axis and values have the same number of data
166 * => the DataSeries is valid, as x-axis and values have the same number of data
167 *
167 *
168 * 2)
168 * 2)
169 * - x-axis: [1 ; 2 ; 3]
169 * - x-axis: [1 ; 2 ; 3]
170 * - y-axis: not defined
170 * - y-axis: not defined
171 * - values: [10 ; 20 ; 30 ; 40] (1-dim ArrayData)
171 * - values: [10 ; 20 ; 30 ; 40] (1-dim ArrayData)
172 * => the DataSeries is invalid, as x-axis and values haven't the same number of data
172 * => the DataSeries is invalid, as x-axis and values haven't the same number of data
173 *
173 *
174 * 3)
174 * 3)
175 * - x-axis: [1 ; 2 ; 3]
175 * - x-axis: [1 ; 2 ; 3]
176 * - y-axis: not defined
176 * - y-axis: not defined
177 * - values: [10 ; 20 ; 30
177 * - values: [10 ; 20 ; 30
178 * 40 ; 50 ; 60] (2-dim ArrayData)
178 * 40 ; 50 ; 60] (2-dim ArrayData)
179 * => the DataSeries is valid, as x-axis has 3 data and values contains 2 components with 3
179 * => the DataSeries is valid, as x-axis has 3 data and values contains 2 components with 3
180 * data each
180 * data each
181 *
181 *
182 * 4)
182 * 4)
183 * - x-axis: [1 ; 2 ; 3]
183 * - x-axis: [1 ; 2 ; 3]
184 * - y-axis: [1 ; 2]
184 * - y-axis: [1 ; 2]
185 * - values: [10 ; 20 ; 30
185 * - values: [10 ; 20 ; 30
186 * 40 ; 50 ; 60] (2-dim ArrayData)
186 * 40 ; 50 ; 60] (2-dim ArrayData)
187 * => the DataSeries is valid, as:
187 * => the DataSeries is valid, as:
188 * - x-axis has 3 data and values contains 2 components with 3 data each AND
188 * - x-axis has 3 data and values contains 2 components with 3 data each AND
189 * - y-axis has 2 data and values contains 2 components
189 * - y-axis has 2 data and values contains 2 components
190 *
190 *
191 * 5)
191 * 5)
192 * - x-axis: [1 ; 2 ; 3]
192 * - x-axis: [1 ; 2 ; 3]
193 * - y-axis: [1 ; 2 ; 3]
193 * - y-axis: [1 ; 2 ; 3]
194 * - values: [10 ; 20 ; 30
194 * - values: [10 ; 20 ; 30
195 * 40 ; 50 ; 60] (2-dim ArrayData)
195 * 40 ; 50 ; 60] (2-dim ArrayData)
196 * => the DataSeries is invalid, as:
196 * => the DataSeries is invalid, as:
197 * - x-axis has 3 data and values contains 2 components with 3 data each BUT
197 * - x-axis has 3 data and values contains 2 components with 3 data each BUT
198 * - y-axis has 3 data and values contains only 2 components
198 * - y-axis has 3 data and values contains only 2 components
199 *
199 *
200 * @tparam Dim The dimension of the values data
200 * @tparam Dim The dimension of the values data
201 *
201 *
202 */
202 */
203 template <int Dim>
203 template <int Dim>
204 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
204 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
205 friend class DataSeriesMergeHelper;
205 friend class DataSeriesMergeHelper;
206
206
207 public:
207 public:
208 /// @sa IDataSeries::xAxisData()
208 /// @sa IDataSeries::xAxisData()
209 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
209 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
210 const std::shared_ptr<ArrayData<1> > xAxisData() const override { return m_XAxisData; }
210 const std::shared_ptr<ArrayData<1> > xAxisData() const override { return m_XAxisData; }
211
211
212 /// @sa IDataSeries::xAxisUnit()
212 /// @sa IDataSeries::xAxisUnit()
213 Unit xAxisUnit() const override { return m_XAxisUnit; }
213 Unit xAxisUnit() const override { return m_XAxisUnit; }
214
214
215 /// @sa IDataSeries::yAxisUnit()
215 /// @sa IDataSeries::yAxisUnit()
216 Unit yAxisUnit() const override { return m_YAxis.unit(); }
216 Unit yAxisUnit() const override { return m_YAxis.unit(); }
217
217
218 /// @return the values dataset
218 /// @return the values dataset
219 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
219 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
220 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
220 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
221
221
222 /// @sa IDataSeries::valuesUnit()
222 /// @sa IDataSeries::valuesUnit()
223 Unit valuesUnit() const override { return m_ValuesUnit; }
223 Unit valuesUnit() const override { return m_ValuesUnit; }
224
224
225 int nbPoints() const override { return m_ValuesData->totalSize(); }
225 int nbPoints() const override { return m_ValuesData->totalSize(); }
226
226
227 std::pair<double, double> yBounds() const override { return m_YAxis.bounds(); }
227 std::pair<double, double> yBounds() const override { return m_YAxis.bounds(); }
228
228
229 void clear()
229 void clear()
230 {
230 {
231 m_XAxisData->clear();
231 m_XAxisData->clear();
232 m_ValuesData->clear();
232 m_ValuesData->clear();
233 }
233 }
234
234
235 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
235 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
236
236
237 /// Merges into the data series an other data series.
237 /// Merges into the data series an other data series.
238 ///
238 ///
239 /// The two dataseries:
239 /// The two dataseries:
240 /// - must be of the same dimension
240 /// - must be of the same dimension
241 /// - must have the same y-axis (if defined)
241 /// - must have the same y-axis (if defined)
242 ///
242 ///
243 /// If the prerequisites are not valid, the method does nothing
243 /// If the prerequisites are not valid, the method does nothing
244 ///
244 ///
245 /// @remarks the data series to merge with is cleared after the operation
245 /// @remarks the data series to merge with is cleared after the operation
246 void merge(IDataSeries *dataSeries) override
246 void merge(IDataSeries *dataSeries) override
247 {
247 {
248 dataSeries->lockWrite();
248 dataSeries->lockWrite();
249 lockWrite();
249 lockWrite();
250
250
251 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
251 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
252 if (m_YAxis == other->m_YAxis) {
252 if (m_YAxis == other->m_YAxis) {
253 DataSeriesMergeHelper::merge(*other, *this);
253 DataSeriesMergeHelper::merge(*other, *this);
254 }
254 }
255 else {
255 else {
256 qCWarning(LOG_DataSeries())
256 qCWarning(LOG_DataSeries())
257 << QObject::tr("Can't merge data series that have not the same y-axis");
257 << QObject::tr("Can't merge data series that have not the same y-axis");
258 }
258 }
259 }
259 }
260 else {
260 else {
261 qCWarning(LOG_DataSeries())
261 qCWarning(LOG_DataSeries())
262 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
262 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
263 }
263 }
264 unlock();
264 unlock();
265 dataSeries->unlock();
265 dataSeries->unlock();
266 }
266 }
267
267
268 void purge(double min, double max) override
268 void purge(double min, double max) override
269 {
269 {
270 // Nothing to purge if series is empty
270 // Nothing to purge if series is empty
271 if (isEmpty()) {
271 if (isEmpty()) {
272 return;
272 return;
273 }
273 }
274
274
275 if (min > max) {
275 if (min > max) {
276 std::swap(min, max);
276 std::swap(min, max);
277 }
277 }
278
278
279 // Nothing to purge if series min/max are inside purge range
279 // Nothing to purge if series min/max are inside purge range
280 auto xMin = cbegin()->x();
280 auto xMin = cbegin()->x();
281 auto xMax = (--cend())->x();
281 auto xMax = (--cend())->x();
282 if (xMin >= min && xMax <= max) {
282 if (xMin >= min && xMax <= max) {
283 return;
283 return;
284 }
284 }
285
285
286 auto lowerIt = std::lower_bound(
286 auto lowerIt = std::lower_bound(
287 begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; });
287 begin(), end(), min, [](const auto &it, const auto &val) { return it.x() < val; });
288 erase(begin(), lowerIt);
288 erase(begin(), lowerIt);
289 auto upperIt = std::upper_bound(
289 auto upperIt = std::upper_bound(
290 begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); });
290 begin(), end(), max, [](const auto &val, const auto &it) { return val < it.x(); });
291 erase(upperIt, end());
291 erase(upperIt, end());
292 }
292 }
293
293
294 // ///////// //
294 // ///////// //
295 // Iterators //
295 // Iterators //
296 // ///////// //
296 // ///////// //
297
297
298 DataSeriesIterator begin() override
298 DataSeriesIterator begin() override
299 {
299 {
300 return DataSeriesIterator{DataSeriesIteratorValue{
300 return DataSeriesIterator{DataSeriesIteratorValue{
301 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
301 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
302 }
302 }
303
303
304 DataSeriesIterator end() override
304 DataSeriesIterator end() override
305 {
305 {
306 return DataSeriesIterator{DataSeriesIteratorValue{
306 return DataSeriesIterator{DataSeriesIteratorValue{
307 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
307 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
308 }
308 }
309
309
310 DataSeriesIterator cbegin() const override
310 DataSeriesIterator cbegin() const override
311 {
311 {
312 return DataSeriesIterator{DataSeriesIteratorValue{
312 return DataSeriesIterator{DataSeriesIteratorValue{
313 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
313 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
314 }
314 }
315
315
316 DataSeriesIterator cend() const override
316 DataSeriesIterator cend() const override
317 {
317 {
318 return DataSeriesIterator{DataSeriesIteratorValue{
318 return DataSeriesIterator{DataSeriesIteratorValue{
319 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
319 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
320 }
320 }
321
321
322 void erase(DataSeriesIterator first, DataSeriesIterator last)
322 virtual void erase(DataSeriesIterator first, DataSeriesIterator last)
323 {
323 {
324 auto firstImpl
324 auto firstImpl
325 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
325 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
326 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
326 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
327
327
328 if (firstImpl && lastImpl) {
328 if (firstImpl && lastImpl) {
329 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
329 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
330 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
330 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
331 }
331 }
332 }
332 }
333
333
334 void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false)
334 virtual void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false)
335 {
335 {
336 auto firstImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(first->impl());
336 auto firstImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(first->impl());
337 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(last->impl());
337 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, true> *>(last->impl());
338
338
339 if (firstImpl && lastImpl) {
339 if (firstImpl && lastImpl) {
340 m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend);
340 m_XAxisData->insert(firstImpl->m_XIt, lastImpl->m_XIt, prepend);
341 m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend);
341 m_ValuesData->insert(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt, prepend);
342 }
342 }
343 }
343 }
344
344
345 /// @sa IDataSeries::minXAxisData()
345 /// @sa IDataSeries::minXAxisData()
346 DataSeriesIterator minXAxisData(double minXAxisData) const override
346 DataSeriesIterator minXAxisData(double minXAxisData) const override
347 {
347 {
348 return std::lower_bound(
348 return std::lower_bound(
349 cbegin(), cend(), minXAxisData,
349 cbegin(), cend(), minXAxisData,
350 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
350 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
351 }
351 }
352
352
353 /// @sa IDataSeries::maxXAxisData()
353 /// @sa IDataSeries::maxXAxisData()
354 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
354 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
355 {
355 {
356 // Gets the first element that greater than max value
356 // Gets the first element that greater than max value
357 auto it = std::upper_bound(
357 auto it = std::upper_bound(
358 cbegin(), cend(), maxXAxisData,
358 cbegin(), cend(), maxXAxisData,
359 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
359 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
360
360
361 return it == cbegin() ? cend() : --it;
361 return it == cbegin() ? cend() : --it;
362 }
362 }
363
363
364 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
364 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
365 double maxXAxisData) const override
365 double maxXAxisData) const override
366 {
366 {
367 if (minXAxisData > maxXAxisData) {
367 if (minXAxisData > maxXAxisData) {
368 std::swap(minXAxisData, maxXAxisData);
368 std::swap(minXAxisData, maxXAxisData);
369 }
369 }
370
370
371 auto begin = cbegin();
371 auto begin = cbegin();
372 auto end = cend();
372 auto end = cend();
373
373
374 auto lowerIt = std::lower_bound(
374 auto lowerIt = std::lower_bound(
375 begin, end, minXAxisData,
375 begin, end, minXAxisData,
376 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
376 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
377 auto upperIt = std::upper_bound(
377 auto upperIt = std::upper_bound(
378 lowerIt, end, maxXAxisData,
378 lowerIt, end, maxXAxisData,
379 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
379 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
380
380
381 return std::make_pair(lowerIt, upperIt);
381 return std::make_pair(lowerIt, upperIt);
382 }
382 }
383
383
384 std::pair<DataSeriesIterator, DataSeriesIterator>
384 std::pair<DataSeriesIterator, DataSeriesIterator>
385 valuesBounds(double minXAxisData, double maxXAxisData) const override
385 valuesBounds(double minXAxisData, double maxXAxisData) const override
386 {
386 {
387 // Places iterators to the correct x-axis range
387 // Places iterators to the correct x-axis range
388 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
388 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
389
389
390 // Returns end iterators if the range is empty
390 // Returns end iterators if the range is empty
391 if (xAxisRangeIts.first == xAxisRangeIts.second) {
391 if (xAxisRangeIts.first == xAxisRangeIts.second) {
392 return std::make_pair(cend(), cend());
392 return std::make_pair(cend(), cend());
393 }
393 }
394
394
395 // Gets the iterator on the min of all values data
395 // Gets the iterator on the min of all values data
396 auto minIt = std::min_element(
396 auto minIt = std::min_element(
397 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
397 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
398 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
398 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
399 });
399 });
400
400
401 // Gets the iterator on the max of all values data
401 // Gets the iterator on the max of all values data
402 auto maxIt = std::max_element(
402 auto maxIt = std::max_element(
403 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
403 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
404 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
404 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
405 });
405 });
406
406
407 return std::make_pair(minIt, maxIt);
407 return std::make_pair(minIt, maxIt);
408 }
408 }
409
409
410 /// @return the y-axis associated to the data series
410 /// @return the y-axis associated to the data series
411 const OptionalAxis &yAxis() const { return m_YAxis; }
411 const OptionalAxis &yAxis() const { return m_YAxis; }
412 OptionalAxis &yAxis() { return m_YAxis; }
412 OptionalAxis &yAxis() { return m_YAxis; }
413
413
414 // /////// //
414 // /////// //
415 // Mutexes //
415 // Mutexes //
416 // /////// //
416 // /////// //
417
417
418 virtual QReadLocker getReadLock() override { return QReadLocker{&m_Lock}; }
418 virtual QReadLocker getReadLock() override { return QReadLocker{&m_Lock}; }
419 virtual QWriteLocker getWriteLock() override { return QWriteLocker{&m_Lock}; }
419 virtual QWriteLocker getWriteLock() override { return QWriteLocker{&m_Lock}; }
420
420
421 virtual void lockRead() override { m_Lock.lockForRead(); }
421 virtual void lockRead() override { m_Lock.lockForRead(); }
422 virtual void lockWrite() override { m_Lock.lockForWrite(); }
422 virtual void lockWrite() override { m_Lock.lockForWrite(); }
423 virtual void unlock() override { m_Lock.unlock(); }
423 virtual void unlock() override { m_Lock.unlock(); }
424
424
425 protected:
425 protected:
426 /// Protected ctor (DataSeries is abstract).
426 /// Protected ctor (DataSeries is abstract).
427 ///
427 ///
428 /// Data vectors must be consistent with each other, otherwise an exception will be thrown (@sa
428 /// Data vectors must be consistent with each other, otherwise an exception will be thrown (@sa
429 /// class description for consistent rules)
429 /// class description for consistent rules)
430 /// @remarks data series is automatically sorted on its x-axis data
430 /// @remarks data series is automatically sorted on its x-axis data
431 /// @throws std::invalid_argument if the data are inconsistent with each other
431 /// @throws std::invalid_argument if the data are inconsistent with each other
432 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
432 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
433 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit,
433 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit,
434 OptionalAxis yAxis = OptionalAxis{})
434 OptionalAxis yAxis = OptionalAxis{})
435 : m_XAxisData{xAxisData},
435 : m_XAxisData{xAxisData},
436 m_XAxisUnit{xAxisUnit},
436 m_XAxisUnit{xAxisUnit},
437 m_ValuesData{valuesData},
437 m_ValuesData{valuesData},
438 m_ValuesUnit{valuesUnit},
438 m_ValuesUnit{valuesUnit},
439 m_YAxis{std::move(yAxis)}
439 m_YAxis{std::move(yAxis)}
440 {
440 {
441 if (m_XAxisData->size() != m_ValuesData->size()) {
441 if (m_XAxisData->size() != m_ValuesData->size()) {
442 throw std::invalid_argument{
442 throw std::invalid_argument{
443 "The number of values by component must be equal to the number of x-axis data"};
443 "The number of values by component must be equal to the number of x-axis data"};
444 }
444 }
445
445
446 // Validates y-axis (if defined)
446 // Validates y-axis (if defined)
447 if (yAxis.isDefined() && (yAxis.size() != m_ValuesData->componentCount())) {
447 if (yAxis.isDefined() && (yAxis.size() != m_ValuesData->componentCount())) {
448 throw std::invalid_argument{
448 throw std::invalid_argument{
449 "As the y-axis is defined, the number of value components must be equal to the "
449 "As the y-axis is defined, the number of value components must be equal to the "
450 "number of y-axis data"};
450 "number of y-axis data"};
451 }
451 }
452
452
453 // Sorts data if it's not the case
453 // Sorts data if it's not the case
454 const auto &xAxisCData = m_XAxisData->cdata();
454 const auto &xAxisCData = m_XAxisData->cdata();
455 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
455 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
456 sort();
456 sort();
457 }
457 }
458 }
458 }
459
459
460 /// Copy ctor
460 /// Copy ctor
461 explicit DataSeries(const DataSeries<Dim> &other)
461 explicit DataSeries(const DataSeries<Dim> &other)
462 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
462 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
463 m_XAxisUnit{other.m_XAxisUnit},
463 m_XAxisUnit{other.m_XAxisUnit},
464 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
464 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
465 m_ValuesUnit{other.m_ValuesUnit},
465 m_ValuesUnit{other.m_ValuesUnit},
466 m_YAxis{other.m_YAxis}
466 m_YAxis{other.m_YAxis}
467 {
467 {
468 // Since a series is ordered from its construction and is always ordered, it is not
468 // Since a series is ordered from its construction and is always ordered, it is not
469 // necessary to call the sort method here ('other' is sorted)
469 // necessary to call the sort method here ('other' is sorted)
470 }
470 }
471
471
472 /// Assignment operator
472 /// Assignment operator
473 template <int D>
473 template <int D>
474 DataSeries &operator=(DataSeries<D> other)
474 DataSeries &operator=(DataSeries<D> other)
475 {
475 {
476 std::swap(m_XAxisData, other.m_XAxisData);
476 std::swap(m_XAxisData, other.m_XAxisData);
477 std::swap(m_XAxisUnit, other.m_XAxisUnit);
477 std::swap(m_XAxisUnit, other.m_XAxisUnit);
478 std::swap(m_ValuesData, other.m_ValuesData);
478 std::swap(m_ValuesData, other.m_ValuesData);
479 std::swap(m_ValuesUnit, other.m_ValuesUnit);
479 std::swap(m_ValuesUnit, other.m_ValuesUnit);
480 std::swap(m_YAxis, other.m_YAxis);
480 std::swap(m_YAxis, other.m_YAxis);
481
481
482 return *this;
482 return *this;
483 }
483 }
484
484
485 private:
485 private:
486 /**
486 /**
487 * Sorts data series on its x-axis data
487 * Sorts data series on its x-axis data
488 */
488 */
489 void sort() noexcept
489 void sort() noexcept
490 {
490 {
491 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
491 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
492 m_XAxisData = m_XAxisData->sort(permutation);
492 m_XAxisData = m_XAxisData->sort(permutation);
493 m_ValuesData = m_ValuesData->sort(permutation);
493 m_ValuesData = m_ValuesData->sort(permutation);
494 }
494 }
495
495
496 // x-axis
496 // x-axis
497 std::shared_ptr<ArrayData<1> > m_XAxisData;
497 std::shared_ptr<ArrayData<1> > m_XAxisData;
498 Unit m_XAxisUnit;
498 Unit m_XAxisUnit;
499
499
500 // values
500 // values
501 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
501 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
502 Unit m_ValuesUnit;
502 Unit m_ValuesUnit;
503
503
504 // y-axis (optional)
504 // y-axis (optional)
505 OptionalAxis m_YAxis;
505 OptionalAxis m_YAxis;
506
506
507 QReadWriteLock m_Lock;
507 QReadWriteLock m_Lock;
508 };
508 };
509
509
510 #endif // SCIQLOP_DATASERIES_H
510 #endif // SCIQLOP_DATASERIES_H
@@ -1,40 +1,59
1 #ifndef SCIQLOP_SPECTROGRAMSERIES_H
1 #ifndef SCIQLOP_SPECTROGRAMSERIES_H
2 #define SCIQLOP_SPECTROGRAMSERIES_H
2 #define SCIQLOP_SPECTROGRAMSERIES_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Data/DataSeries.h>
6 #include <Data/DataSeries.h>
7
7
8 /**
8 /**
9 * @brief The SpectrogramSeries class is the implementation for a data series representing a
9 * @brief The SpectrogramSeries class is the implementation for a data series representing a
10 * spectrogram.
10 * spectrogram.
11 *
11 *
12 * It defines values on a x-axis and a y-axis.
12 * It defines values on a x-axis and a y-axis.
13 */
13 */
14 class SCIQLOP_CORE_EXPORT SpectrogramSeries : public DataSeries<2> {
14 class SCIQLOP_CORE_EXPORT SpectrogramSeries : public DataSeries<2> {
15 public:
15 public:
16 /// Ctor
16 /// Ctor
17 explicit SpectrogramSeries(std::vector<double> xAxisData, std::vector<double> yAxisData,
17 explicit SpectrogramSeries(std::vector<double> xAxisData, std::vector<double> yAxisData,
18 std::vector<double> valuesData, const Unit &xAxisUnit,
18 std::vector<double> valuesData, const Unit &xAxisUnit,
19 const Unit &yAxisUnit, const Unit &valuesUnit,
19 const Unit &yAxisUnit, const Unit &valuesUnit,
20 double xResolution = std::numeric_limits<double>::quiet_NaN());
20 double xResolution = std::numeric_limits<double>::quiet_NaN());
21
21
22 /// Ctor directly with the y-axis
22 /// Ctor directly with the y-axis
23 explicit SpectrogramSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
23 explicit SpectrogramSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
24 std::shared_ptr<ArrayData<2> > valuesData, const Unit &valuesUnit,
24 std::shared_ptr<ArrayData<2> > valuesData, const Unit &valuesUnit,
25 OptionalAxis yAxis,
25 OptionalAxis yAxis,
26 double xResolution = std::numeric_limits<double>::quiet_NaN());
26 double xResolution = std::numeric_limits<double>::quiet_NaN());
27
27
28 /// @sa DataSeries::clone()
28 /// @sa DataSeries::clone()
29 std::unique_ptr<IDataSeries> clone() const override;
29 std::unique_ptr<IDataSeries> clone() const override;
30
30
31 /// @sa DataSeries::subDataSeries()
31 /// @sa DataSeries::subDataSeries()
32 std::shared_ptr<IDataSeries> subDataSeries(const DateTimeRange &range) override;
32 std::shared_ptr<IDataSeries> subDataSeries(const DateTimeRange &range) override;
33
33
34 inline double xResolution() const noexcept { return m_XResolution; }
34 inline double xResolution() const noexcept { return m_XResolution; }
35
35
36 void erase(DataSeriesIterator first, DataSeriesIterator last) override
37 {
38 DataSeries<2>::erase(first,last);
39 updateResolution();
40 }
41
42 void insert(DataSeriesIterator first, DataSeriesIterator last, bool prepend = false) override
43 {
44 DataSeries<2>::insert(first,last, prepend);
45 updateResolution();
46 }
47
48 void merge(IDataSeries *dataSeries) override
49 {
50 DataSeries<2>::merge(dataSeries);
51 updateResolution();
52 }
53
36 private:
54 private:
55 void updateResolution();
37 double m_XResolution; ///< Resolution used on x-axis to build the spectrogram
56 double m_XResolution; ///< Resolution used on x-axis to build the spectrogram
38 };
57 };
39
58
40 #endif // SCIQLOP_SPECTROGRAMSERIES_H
59 #endif // SCIQLOP_SPECTROGRAMSERIES_H
@@ -1,55 +1,61
1 #include <Data/SpectrogramSeries.h>
1 #include <Data/SpectrogramSeries.h>
2 #include <Data/DataSeriesUtils.h>
2 #include <Data/DataSeriesUtils.h>
3
3
4 SpectrogramSeries::SpectrogramSeries(std::vector<double> xAxisData, std::vector<double> yAxisData,
4 SpectrogramSeries::SpectrogramSeries(std::vector<double> xAxisData, std::vector<double> yAxisData,
5 std::vector<double> valuesData, const Unit &xAxisUnit,
5 std::vector<double> valuesData, const Unit &xAxisUnit,
6 const Unit &yAxisUnit, const Unit &valuesUnit,
6 const Unit &yAxisUnit, const Unit &valuesUnit,
7 double resolution)
7 double resolution)
8 : SpectrogramSeries{
8 : SpectrogramSeries{
9 std::make_shared<ArrayData<1> >(std::move(xAxisData)),
9 std::make_shared<ArrayData<1> >(std::move(xAxisData)),
10 xAxisUnit,
10 xAxisUnit,
11 std::make_shared<ArrayData<2> >(std::move(valuesData), yAxisData.size()),
11 std::make_shared<ArrayData<2> >(std::move(valuesData), yAxisData.size()),
12 valuesUnit,
12 valuesUnit,
13 OptionalAxis{std::make_shared<ArrayData<1> >(std::move(yAxisData)), yAxisUnit},
13 OptionalAxis{std::make_shared<ArrayData<1> >(std::move(yAxisData)), yAxisUnit},
14 resolution}
14 resolution}
15 {
15 {
16 }
16 }
17
17
18 SpectrogramSeries::SpectrogramSeries(std::shared_ptr<ArrayData<1> > xAxisData,
18 SpectrogramSeries::SpectrogramSeries(std::shared_ptr<ArrayData<1> > xAxisData,
19 const Unit &xAxisUnit,
19 const Unit &xAxisUnit,
20 std::shared_ptr<ArrayData<2> > valuesData,
20 std::shared_ptr<ArrayData<2> > valuesData,
21 const Unit &valuesUnit, OptionalAxis yAxis, double resolution)
21 const Unit &valuesUnit, OptionalAxis yAxis, double resolution)
22 : DataSeries{std::move(xAxisData), xAxisUnit, std::move(valuesData), valuesUnit,
22 : DataSeries{std::move(xAxisData), xAxisUnit, std::move(valuesData), valuesUnit,
23 std::move(yAxis)},
23 std::move(yAxis)},
24 m_XResolution{resolution}
24 m_XResolution{resolution}
25 {
25 {
26 if(std::isnan(m_XResolution))
26 if(std::isnan(m_XResolution))
27 {
27 {
28 //m_XResolution = DataSeriesUtils::resolution(xAxisData->begin(), xAxisData->end()).m_Val;
28 updateResolution();
29 }
29 }
30 }
30 }
31
31
32 std::unique_ptr<IDataSeries> SpectrogramSeries::clone() const
32 std::unique_ptr<IDataSeries> SpectrogramSeries::clone() const
33 {
33 {
34 return std::make_unique<SpectrogramSeries>(*this);
34 return std::make_unique<SpectrogramSeries>(*this);
35 }
35 }
36
36
37 std::shared_ptr<IDataSeries> SpectrogramSeries::subDataSeries(const DateTimeRange &range)
37 std::shared_ptr<IDataSeries> SpectrogramSeries::subDataSeries(const DateTimeRange &range)
38 {
38 {
39 auto subXAxisData = std::vector<double>();
39 auto subXAxisData = std::vector<double>();
40 auto subValuesData = QVector<double>(); // Uses QVector to append easily values to it
40 auto subValuesData = QVector<double>(); // Uses QVector to append easily values to it
41 this->lockRead();
41 this->lockRead();
42 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
42 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
43 for (auto it = bounds.first; it != bounds.second; ++it) {
43 for (auto it = bounds.first; it != bounds.second; ++it) {
44 subXAxisData.push_back(it->x());
44 subXAxisData.push_back(it->x());
45 subValuesData.append(it->values());
45 subValuesData.append(it->values());
46 }
46 }
47
47
48 auto yAxis = this->yAxis();
48 auto yAxis = this->yAxis();
49 this->unlock();
49 this->unlock();
50
50
51 return std::make_shared<SpectrogramSeries>(
51 return std::make_shared<SpectrogramSeries>(
52 std::make_shared<ArrayData<1> >(std::move(subXAxisData)), this->xAxisUnit(),
52 std::make_shared<ArrayData<1> >(std::move(subXAxisData)), this->xAxisUnit(),
53 std::make_shared<ArrayData<2> >(subValuesData.toStdVector(), yAxis.size()),
53 std::make_shared<ArrayData<2> >(subValuesData.toStdVector(), yAxis.size()),
54 this->valuesUnit(), std::move(yAxis));
54 this->valuesUnit(), std::move(yAxis));
55 }
55 }
56
57 void SpectrogramSeries::updateResolution()
58 {
59 auto xAxisData = this->xAxisData()->cdata();
60 m_XResolution = DataSeriesUtils::resolution(xAxisData.begin(), xAxisData.end()).m_Val;
61 }
@@ -1,152 +1,157
1 #include <pybind11/pybind11.h>
1 #include <pybind11/pybind11.h>
2 #include <pybind11/operators.h>
2 #include <pybind11/operators.h>
3 #include <pybind11/embed.h>
3 #include <pybind11/embed.h>
4 #include <pybind11/numpy.h>
4 #include <pybind11/numpy.h>
5 #include <pybind11/chrono.h>
5 #include <pybind11/chrono.h>
6 #include <pybind11/functional.h>
6 #include <pybind11/functional.h>
7 #include <pybind11/stl.h>
7 #include <pybind11/stl.h>
8
8
9
9
10 #include <string>
10 #include <string>
11 #include <sstream>
11 #include <sstream>
12
12
13 #include "pywrappers_common.h"
13 #include "pywrappers_common.h"
14 #include "CoreWrappers.h"
14 #include "CoreWrappers.h"
15
15
16 #include <Data/DataSeriesType.h>
16 #include <Data/DataSeriesType.h>
17 #include <Data/ScalarSeries.h>
17 #include <Data/ScalarSeries.h>
18 #include <Data/VectorSeries.h>
18 #include <Data/VectorSeries.h>
19 #include <Data/SpectrogramSeries.h>
19 #include <Data/SpectrogramSeries.h>
20 #include <Data/Unit.h>
20 #include <Data/Unit.h>
21 #include <Data/OptionalAxis.h>
21 #include <Data/OptionalAxis.h>
22 #include <Data/IDataProvider.h>
22 #include <Data/IDataProvider.h>
23
23
24 #include <Variable/VariableController2.h>
24 #include <Variable/VariableController2.h>
25
25
26 #include <Time/TimeController.h>
26 #include <Time/TimeController.h>
27
27
28 #include <Network/Downloader.h>
28 #include <Network/Downloader.h>
29
29
30
30
31
31
32 namespace py = pybind11;
32 namespace py = pybind11;
33 using namespace std::chrono;
33 using namespace std::chrono;
34
34
35 PYBIND11_MODULE(pysciqlopcore,m){
35 PYBIND11_MODULE(pysciqlopcore,m){
36
36
37 py::enum_<DataSeriesType>(m, "DataSeriesType")
37 py::enum_<DataSeriesType>(m, "DataSeriesType")
38 .value("SCALAR", DataSeriesType::SCALAR)
38 .value("SCALAR", DataSeriesType::SCALAR)
39 .value("SPECTROGRAM", DataSeriesType::SPECTROGRAM)
39 .value("SPECTROGRAM", DataSeriesType::SPECTROGRAM)
40 .value("VECTOR", DataSeriesType::VECTOR)
40 .value("VECTOR", DataSeriesType::VECTOR)
41 .value("UNKNOWN", DataSeriesType::UNKNOWN)
41 .value("UNKNOWN", DataSeriesType::UNKNOWN)
42 .export_values();
42 .export_values();
43
43
44 py::class_<Unit>(m, "Unit")
44 py::class_<Unit>(m, "Unit")
45 .def_readwrite("name", &Unit::m_Name)
45 .def_readwrite("name", &Unit::m_Name)
46 .def_readwrite("time_unit", &Unit::m_TimeUnit)
46 .def_readwrite("time_unit", &Unit::m_TimeUnit)
47 .def(py::self == py::self)
47 .def(py::self == py::self)
48 .def(py::self != py::self)
48 .def(py::self != py::self)
49 .def("__repr__",__repr__<Unit>);
49 .def("__repr__",__repr__<Unit>);
50
50
51 py::class_<Response>(m,"Response")
51 py::class_<Response>(m,"Response")
52 .def("status_code", &Response::status_code);
52 .def("status_code", &Response::status_code);
53
53
54 py::class_<Downloader>(m,"Downloader")
54 py::class_<Downloader>(m,"Downloader")
55 .def_static("get", Downloader::get)
55 .def_static("get", Downloader::get)
56 .def_static("getAsync", Downloader::getAsync)
56 .def_static("getAsync", Downloader::getAsync)
57 .def_static("downloadFinished", Downloader::downloadFinished);
57 .def_static("downloadFinished", Downloader::downloadFinished);
58
58
59 py::class_<ArrayDataIteratorValue>(m, "ArrayDataIteratorValue")
59 py::class_<ArrayDataIteratorValue>(m, "ArrayDataIteratorValue")
60 .def_property_readonly("value", &ArrayDataIteratorValue::first);
60 .def_property_readonly("value", &ArrayDataIteratorValue::first);
61
61
62 py::class_<OptionalAxis>(m, "OptionalAxis")
62 py::class_<OptionalAxis>(m, "OptionalAxis")
63 .def("__len__", &OptionalAxis::size)
63 .def("__len__", &OptionalAxis::size)
64 .def_property_readonly("size", &OptionalAxis::size)
64 .def_property_readonly("size", &OptionalAxis::size)
65 .def("__getitem__", [](OptionalAxis& ax, int key) {
65 .def("__getitem__", [](OptionalAxis& ax, int key) {
66 return (*(ax.begin()+key)).first();
66 return (*(ax.begin()+key)).first();
67 }, py::is_operator())
67 }, py::is_operator())
68 .def("__iter__", [](OptionalAxis& ax) {
68 .def("__iter__", [](OptionalAxis& ax) {
69 return py::make_iterator(ax.begin(), ax.end());
69 return py::make_iterator(ax.begin(), ax.end());
70 }, py::keep_alive<0, 1>());
70 }, py::keep_alive<0, 1>());
71
71
72 py::class_<DataSeriesIteratorValue>(m,"DataSeriesIteratorValue")
72 py::class_<DataSeriesIteratorValue>(m,"DataSeriesIteratorValue")
73 .def_property_readonly("x", &DataSeriesIteratorValue::x)
73 .def_property_readonly("x", &DataSeriesIteratorValue::x)
74 .def_property_readonly("y", &DataSeriesIteratorValue::y)
74 .def_property_readonly("y", &DataSeriesIteratorValue::y)
75 .def("value", py::overload_cast<>(&DataSeriesIteratorValue::value, py::const_))
75 .def("value", py::overload_cast<>(&DataSeriesIteratorValue::value, py::const_))
76 .def("value", py::overload_cast<int>(&DataSeriesIteratorValue::value, py::const_))
76 .def("value", py::overload_cast<int>(&DataSeriesIteratorValue::value, py::const_))
77 .def("values", &DataSeriesIteratorValue::values);
77 .def("values", &DataSeriesIteratorValue::values);
78
78
79 py::class_<IDataSeries, std::shared_ptr<IDataSeries>>(m, "IDataSeries")
79 py::class_<IDataSeries, std::shared_ptr<IDataSeries>>(m, "IDataSeries")
80 .def("nbPoints", &IDataSeries::nbPoints)
80 .def("nbPoints", &IDataSeries::nbPoints)
81 .def_property_readonly("xAxisUnit", &IDataSeries::xAxisUnit)
81 .def_property_readonly("xAxisUnit", &IDataSeries::xAxisUnit)
82 .def_property_readonly("yAxisUnit", &IDataSeries::yAxisUnit)
82 .def_property_readonly("yAxisUnit", &IDataSeries::yAxisUnit)
83 .def_property_readonly("valuesUnit", &IDataSeries::valuesUnit)
83 .def_property_readonly("valuesUnit", &IDataSeries::valuesUnit)
84 .def("__getitem__", [](IDataSeries& serie, int key) {
84 .def("__getitem__", [](IDataSeries& serie, int key) {
85 return *(serie.begin()+key);
85 return *(serie.begin()+key);
86 }, py::is_operator())
86 }, py::is_operator())
87 .def("__len__", &IDataSeries::nbPoints)
87 .def("__len__", &IDataSeries::nbPoints)
88 .def("__iter__", [](IDataSeries& serie) {
88 .def("__iter__", [](IDataSeries& serie) {
89 return py::make_iterator(serie.begin(), serie.end());
89 return py::make_iterator(serie.begin(), serie.end());
90 }, py::keep_alive<0, 1>())
90 }, py::keep_alive<0, 1>())
91 .def("__repr__",__repr__<IDataSeries>);
91 .def("__repr__",__repr__<IDataSeries>);
92
92
93 py::class_<ArrayData<1>, std::shared_ptr<ArrayData<1>> >(m,"ArrayData1d")
94 .def("cdata", [](ArrayData<1>& array) {return array.cdata();});
95
93 py::class_<ScalarSeries, std::shared_ptr<ScalarSeries>, IDataSeries>(m, "ScalarSeries")
96 py::class_<ScalarSeries, std::shared_ptr<ScalarSeries>, IDataSeries>(m, "ScalarSeries")
94 .def("nbPoints", &ScalarSeries::nbPoints);
97 .def("nbPoints", &ScalarSeries::nbPoints);
95
98
96 py::class_<VectorSeries, std::shared_ptr<VectorSeries>, IDataSeries>(m, "VectorSeries")
99 py::class_<VectorSeries, std::shared_ptr<VectorSeries>, IDataSeries>(m, "VectorSeries")
97 .def("nbPoints", &VectorSeries::nbPoints);
100 .def("nbPoints", &VectorSeries::nbPoints);
98
101
99 py::class_<DataSeries<2>, std::shared_ptr<DataSeries<2>>, IDataSeries>(m,"DataSeries2d")
102 py::class_<DataSeries<2>, std::shared_ptr<DataSeries<2>>, IDataSeries>(m,"DataSeries2d")
103 .def_property_readonly("xAxis", py::overload_cast<>(&DataSeries<2>::xAxisData, py::const_))
100 .def_property_readonly("yAxis", py::overload_cast<>(&DataSeries<2>::yAxis, py::const_));
104 .def_property_readonly("yAxis", py::overload_cast<>(&DataSeries<2>::yAxis, py::const_));
101
105
102 py::class_<SpectrogramSeries, std::shared_ptr<SpectrogramSeries>, DataSeries<2>>(m, "SpectrogramSeries")
106 py::class_<SpectrogramSeries, std::shared_ptr<SpectrogramSeries>, DataSeries<2>>(m, "SpectrogramSeries")
103 .def("nbPoints", &SpectrogramSeries::nbPoints);
107 .def("nbPoints", &SpectrogramSeries::nbPoints)
108 .def("xRes", &SpectrogramSeries::xResolution);
104
109
105
110
106 py::class_<IDataProvider, std::shared_ptr<IDataProvider>>(m, "IDataProvider");
111 py::class_<IDataProvider, std::shared_ptr<IDataProvider>>(m, "IDataProvider");
107
112
108
113
109 py::class_<Variable,std::shared_ptr<Variable>>(m, "Variable")
114 py::class_<Variable,std::shared_ptr<Variable>>(m, "Variable")
110 .def(py::init<const QString&>())
115 .def(py::init<const QString&>())
111 .def_property("name", &Variable::name, &Variable::setName)
116 .def_property("name", &Variable::name, &Variable::setName)
112 .def_property("range", &Variable::range, &Variable::setRange)
117 .def_property("range", &Variable::range, &Variable::setRange)
113 .def_property("cacheRange", &Variable::cacheRange, &Variable::setCacheRange)
118 .def_property("cacheRange", &Variable::cacheRange, &Variable::setCacheRange)
114 .def_property_readonly("nbPoints", &Variable::nbPoints)
119 .def_property_readonly("nbPoints", &Variable::nbPoints)
115 .def_property_readonly("dataSeries", &Variable::dataSeries)
120 .def_property_readonly("dataSeries", &Variable::dataSeries)
116 .def("__len__", [](Variable& variable) {
121 .def("__len__", [](Variable& variable) {
117 auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd);
122 auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd);
118 return std::distance(rng.first,rng.second);
123 return std::distance(rng.first,rng.second);
119 })
124 })
120 .def("__iter__", [](Variable& variable) {
125 .def("__iter__", [](Variable& variable) {
121 auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd);
126 auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd);
122 return py::make_iterator(rng.first, rng.second);
127 return py::make_iterator(rng.first, rng.second);
123 }, py::keep_alive<0, 1>())
128 }, py::keep_alive<0, 1>())
124 .def("__getitem__", [](Variable& variable, int key) {
129 .def("__getitem__", [](Variable& variable, int key) {
125 //insane and slow!
130 //insane and slow!
126 auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd);
131 auto rng = variable.dataSeries()->xAxisRange(variable.range().m_TStart,variable.range().m_TEnd);
127 if(key<0)
132 if(key<0)
128 return *(rng.second+key);
133 return *(rng.second+key);
129 else
134 else
130 return *(rng.first+key);
135 return *(rng.first+key);
131 })
136 })
132 .def("__repr__",__repr__<Variable>);
137 .def("__repr__",__repr__<Variable>);
133
138
134
139
135 py::class_<DateTimeRange>(m,"SqpRange")
140 py::class_<DateTimeRange>(m,"SqpRange")
136 //.def("fromDateTime", &DateTimeRange::fromDateTime, py::return_value_policy::move)
141 //.def("fromDateTime", &DateTimeRange::fromDateTime, py::return_value_policy::move)
137 .def(py::init([](double start, double stop){return DateTimeRange{start, stop};}))
142 .def(py::init([](double start, double stop){return DateTimeRange{start, stop};}))
138 .def(py::init([](system_clock::time_point start, system_clock::time_point stop)
143 .def(py::init([](system_clock::time_point start, system_clock::time_point stop)
139 {
144 {
140 double start_ = 0.001 * duration_cast<milliseconds>(start.time_since_epoch()).count();
145 double start_ = 0.001 * duration_cast<milliseconds>(start.time_since_epoch()).count();
141 double stop_ = 0.001 * duration_cast<milliseconds>(stop.time_since_epoch()).count();
146 double stop_ = 0.001 * duration_cast<milliseconds>(stop.time_since_epoch()).count();
142 return DateTimeRange{start_, stop_};
147 return DateTimeRange{start_, stop_};
143 }))
148 }))
144 .def_property_readonly("start", [](const DateTimeRange& range){
149 .def_property_readonly("start", [](const DateTimeRange& range){
145 return system_clock::from_time_t(range.m_TStart);
150 return system_clock::from_time_t(range.m_TStart);
146 })
151 })
147 .def_property_readonly("stop", [](const DateTimeRange& range){
152 .def_property_readonly("stop", [](const DateTimeRange& range){
148 return system_clock::from_time_t(range.m_TEnd);
153 return system_clock::from_time_t(range.m_TEnd);
149 })
154 })
150 .def("__repr__", __repr__<DateTimeRange>);
155 .def("__repr__", __repr__<DateTimeRange>);
151
156
152 }
157 }
General Comments 0
You need to be logged in to leave comments. Login now