##// END OF EJS Templates
Uses std::vector instead of QVector in ArrayData (1)...
Alexandre Leroux -
r644:c050c224f3de
parent child
Show More
@@ -1,139 +1,139
1 #ifndef SCIQLOP_SORTUTILS_H
1 #ifndef SCIQLOP_SORTUTILS_H
2 #define SCIQLOP_SORTUTILS_H
2 #define SCIQLOP_SORTUTILS_H
3
3
4 #include <algorithm>
4 #include <algorithm>
5 #include <cmath>
5 #include <cmath>
6 #include <numeric>
6 #include <numeric>
7 #include <vector>
7 #include <vector>
8
8
9 /**
9 /**
10 * Utility class with methods for sorting data
10 * Utility class with methods for sorting data
11 */
11 */
12 struct SortUtils {
12 struct SortUtils {
13 /**
13 /**
14 * Generates a vector representing the index of insertion of each data of a container if this
14 * Generates a vector representing the index of insertion of each data of a container if this
15 * one had to be sorted according to a comparison function.
15 * one had to be sorted according to a comparison function.
16 *
16 *
17 * For example:
17 * For example:
18 * If the container is a vector {1; 4; 2; 5; 3} and the comparison function is std::less, the
18 * If the container is a vector {1; 4; 2; 5; 3} and the comparison function is std::less, the
19 * result would be : {0; 3; 1; 4; 2}
19 * result would be : {0; 3; 1; 4; 2}
20 *
20 *
21 * @tparam Container the type of the container.
21 * @tparam Container the type of the container.
22 * @tparam Compare the type of the comparison function
22 * @tparam Compare the type of the comparison function
23 * @param container the container from which to generate the result. The container must have a
23 * @param container the container from which to generate the result. The container must have a
24 * at() method that returns a value associated to an index
24 * at() method that returns a value associated to an index
25 * @param compare the comparison function
25 * @param compare the comparison function
26 */
26 */
27 template <typename Container, typename Compare>
27 template <typename Container, typename Compare>
28 static std::vector<int> sortPermutation(const Container &container, const Compare &compare)
28 static std::vector<int> sortPermutation(const Container &container, const Compare &compare)
29 {
29 {
30 auto permutation = std::vector<int>{};
30 auto permutation = std::vector<int>{};
31 permutation.resize(container.size());
31 permutation.resize(container.size());
32
32
33 std::iota(permutation.begin(), permutation.end(), 0);
33 std::iota(permutation.begin(), permutation.end(), 0);
34 std::sort(permutation.begin(), permutation.end(),
34 std::sort(permutation.begin(), permutation.end(),
35 [&](int i, int j) { return compare(container.at(i), container.at(j)); });
35 [&](int i, int j) { return compare(container.at(i), container.at(j)); });
36 return permutation;
36 return permutation;
37 }
37 }
38
38
39 /**
39 /**
40 * Sorts a container according to indices passed in parameter. The number of data in the
40 * Sorts a container according to indices passed in parameter. The number of data in the
41 * container must be a multiple of the number of indices used to sort the container.
41 * container must be a multiple of the number of indices used to sort the container.
42 *
42 *
43 * Example 1:
43 * Example 1:
44 * container: {1, 2, 3, 4, 5, 6}
44 * container: {1, 2, 3, 4, 5, 6}
45 * sortPermutation: {1, 0}
45 * sortPermutation: {1, 0}
46 *
46 *
47 * Values will be sorted three by three, and the result will be:
47 * Values will be sorted three by three, and the result will be:
48 * {4, 5, 6, 1, 2, 3}
48 * {4, 5, 6, 1, 2, 3}
49 *
49 *
50 * Example 2:
50 * Example 2:
51 * container: {1, 2, 3, 4, 5, 6}
51 * container: {1, 2, 3, 4, 5, 6}
52 * sortPermutation: {2, 0, 1}
52 * sortPermutation: {2, 0, 1}
53 *
53 *
54 * Values will be sorted two by two, and the result will be:
54 * Values will be sorted two by two, and the result will be:
55 * {5, 6, 1, 2, 3, 4}
55 * {5, 6, 1, 2, 3, 4}
56 *
56 *
57 * @param container the container sorted
57 * @param container the container sorted
58 * @param sortPermutation the indices used to sort the container
58 * @param sortPermutation the indices used to sort the container
59 * @return the container sorted
59 * @return the container sorted
60 * @warning no verification is made on validity of sortPermutation (i.e. the vector has unique
60 * @warning no verification is made on validity of sortPermutation (i.e. the vector has unique
61 * indices and its range is [0 ; vector.size()[ )
61 * indices and its range is [0 ; vector.size()[ )
62 */
62 */
63 template <typename Container>
63 template <typename Container>
64 static Container sort(const Container &container, int nbValues,
64 static Container sort(const Container &container, int nbValues,
65 const std::vector<int> &sortPermutation)
65 const std::vector<int> &sortPermutation)
66 {
66 {
67 auto containerSize = container.size();
67 auto containerSize = container.size();
68 if (containerSize % nbValues != 0
68 if (containerSize % nbValues != 0
69 || ((containerSize / nbValues) != sortPermutation.size())) {
69 || ((containerSize / nbValues) != sortPermutation.size())) {
70 return Container{};
70 return Container{};
71 }
71 }
72
72
73 // Inits result
73 // Inits result
74 auto sortedData = Container{};
74 auto sortedData = Container{};
75 sortedData.reserve(containerSize);
75 sortedData.reserve(containerSize);
76
76
77 for (auto i = 0, componentIndex = 0, permutationIndex = 0; i < containerSize;
77 for (auto i = 0, componentIndex = 0, permutationIndex = 0; i < containerSize;
78 ++i, componentIndex = i % nbValues, permutationIndex = i / nbValues) {
78 ++i, componentIndex = i % nbValues, permutationIndex = i / nbValues) {
79 auto insertIndex = sortPermutation.at(permutationIndex) * nbValues + componentIndex;
79 auto insertIndex = sortPermutation.at(permutationIndex) * nbValues + componentIndex;
80 sortedData.append(container.at(insertIndex));
80 sortedData.push_back(container.at(insertIndex));
81 }
81 }
82
82
83 return sortedData;
83 return sortedData;
84 }
84 }
85
85
86 /**
86 /**
87 * Compares two values that can be NaN. This method is intended to be used as a compare function
87 * Compares two values that can be NaN. This method is intended to be used as a compare function
88 * for searching min value by excluding NaN values.
88 * for searching min value by excluding NaN values.
89 *
89 *
90 * Examples of use:
90 * Examples of use:
91 * - f({1, 3, 2, 4, 5}) will return 1
91 * - f({1, 3, 2, 4, 5}) will return 1
92 * - f({NaN, 3, 2, 4, 5}) will return 2 (NaN is excluded)
92 * - f({NaN, 3, 2, 4, 5}) will return 2 (NaN is excluded)
93 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
93 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
94 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
94 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
95 *
95 *
96 * @param v1 first value
96 * @param v1 first value
97 * @param v2 second value
97 * @param v2 second value
98 * @return true if v1 < v2, false otherwise
98 * @return true if v1 < v2, false otherwise
99 * @sa std::min_element
99 * @sa std::min_element
100 */
100 */
101 template <typename T>
101 template <typename T>
102 static bool minCompareWithNaN(const T &v1, const T &v2)
102 static bool minCompareWithNaN(const T &v1, const T &v2)
103 {
103 {
104 // Table used with NaN values:
104 // Table used with NaN values:
105 // NaN < v2 -> false
105 // NaN < v2 -> false
106 // v1 < NaN -> true
106 // v1 < NaN -> true
107 // NaN < NaN -> false
107 // NaN < NaN -> false
108 // v1 < v2 -> v1 < v2
108 // v1 < v2 -> v1 < v2
109 return std::isnan(v1) ? false : std::isnan(v2) || (v1 < v2);
109 return std::isnan(v1) ? false : std::isnan(v2) || (v1 < v2);
110 }
110 }
111
111
112 /**
112 /**
113 * Compares two values that can be NaN. This method is intended to be used as a compare function
113 * Compares two values that can be NaN. This method is intended to be used as a compare function
114 * for searching max value by excluding NaN values.
114 * for searching max value by excluding NaN values.
115 *
115 *
116 * Examples of use:
116 * Examples of use:
117 * - f({1, 3, 2, 4, 5}) will return 5
117 * - f({1, 3, 2, 4, 5}) will return 5
118 * - f({1, 3, 2, 4, NaN}) will return 4 (NaN is excluded)
118 * - f({1, 3, 2, 4, NaN}) will return 4 (NaN is excluded)
119 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
119 * - f({NaN, NaN, 3, NaN, NaN}) will return 3 (NaN are excluded)
120 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
120 * - f({NaN, NaN, NaN, NaN, NaN}) will return NaN (no existing value)
121 *
121 *
122 * @param v1 first value
122 * @param v1 first value
123 * @param v2 second value
123 * @param v2 second value
124 * @return true if v1 < v2, false otherwise
124 * @return true if v1 < v2, false otherwise
125 * @sa std::max_element
125 * @sa std::max_element
126 */
126 */
127 template <typename T>
127 template <typename T>
128 static bool maxCompareWithNaN(const T &v1, const T &v2)
128 static bool maxCompareWithNaN(const T &v1, const T &v2)
129 {
129 {
130 // Table used with NaN values:
130 // Table used with NaN values:
131 // NaN < v2 -> true
131 // NaN < v2 -> true
132 // v1 < NaN -> false
132 // v1 < NaN -> false
133 // NaN < NaN -> false
133 // NaN < NaN -> false
134 // v1 < v2 -> v1 < v2
134 // v1 < v2 -> v1 < v2
135 return std::isnan(v1) ? true : !std::isnan(v2) && (v1 < v2);
135 return std::isnan(v1) ? true : !std::isnan(v2) && (v1 < v2);
136 }
136 }
137 };
137 };
138
138
139 #endif // SCIQLOP_SORTUTILS_H
139 #endif // SCIQLOP_SORTUTILS_H
@@ -1,379 +1,378
1 #ifndef SCIQLOP_ARRAYDATA_H
1 #ifndef SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
2 #define SCIQLOP_ARRAYDATA_H
3
3
4 #include "Data/ArrayDataIterator.h"
4 #include "Data/ArrayDataIterator.h"
5 #include <Common/SortUtils.h>
5 #include <Common/SortUtils.h>
6
6
7 #include <QReadLocker>
7 #include <QReadLocker>
8 #include <QReadWriteLock>
8 #include <QReadWriteLock>
9 #include <QVector>
9 #include <QVector>
10
10
11 #include <memory>
11 #include <memory>
12
12
13 template <int Dim>
13 template <int Dim>
14 class ArrayData;
14 class ArrayData;
15
15
16 using DataContainer = QVector<double>;
16 using DataContainer = std::vector<double>;
17
17
18 namespace arraydata_detail {
18 namespace arraydata_detail {
19
19
20 /// Struct used to sort ArrayData
20 /// Struct used to sort ArrayData
21 template <int Dim>
21 template <int Dim>
22 struct Sort {
22 struct Sort {
23 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data, int nbComponents,
23 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data, int nbComponents,
24 const std::vector<int> &sortPermutation)
24 const std::vector<int> &sortPermutation)
25 {
25 {
26 return std::make_shared<ArrayData<Dim> >(
26 return std::make_shared<ArrayData<Dim> >(
27 SortUtils::sort(data, nbComponents, sortPermutation), nbComponents);
27 SortUtils::sort(data, nbComponents, sortPermutation), nbComponents);
28 }
28 }
29 };
29 };
30
30
31 /// Specialization for uni-dimensional ArrayData
31 /// Specialization for uni-dimensional ArrayData
32 template <>
32 template <>
33 struct Sort<1> {
33 struct Sort<1> {
34 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data, int nbComponents,
34 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data, int nbComponents,
35 const std::vector<int> &sortPermutation)
35 const std::vector<int> &sortPermutation)
36 {
36 {
37 Q_UNUSED(nbComponents)
37 Q_UNUSED(nbComponents)
38 return std::make_shared<ArrayData<1> >(SortUtils::sort(data, 1, sortPermutation));
38 return std::make_shared<ArrayData<1> >(SortUtils::sort(data, 1, sortPermutation));
39 }
39 }
40 };
40 };
41
41
42 template <int Dim, bool IsConst>
42 template <int Dim, bool IsConst>
43 class IteratorValue;
43 class IteratorValue;
44
44
45 template <int Dim, bool IsConst>
45 template <int Dim, bool IsConst>
46 struct IteratorValueBuilder {
46 struct IteratorValueBuilder {
47 };
47 };
48
48
49 template <int Dim>
49 template <int Dim>
50 struct IteratorValueBuilder<Dim, true> {
50 struct IteratorValueBuilder<Dim, true> {
51 using DataContainerIterator = DataContainer::const_iterator;
51 using DataContainerIterator = DataContainer::const_iterator;
52
52
53 static void swap(IteratorValue<Dim, true> &o1, IteratorValue<Dim, true> &o2) {}
53 static void swap(IteratorValue<Dim, true> &o1, IteratorValue<Dim, true> &o2) {}
54 };
54 };
55
55
56 template <int Dim>
56 template <int Dim>
57 struct IteratorValueBuilder<Dim, false> {
57 struct IteratorValueBuilder<Dim, false> {
58 using DataContainerIterator = DataContainer::iterator;
58 using DataContainerIterator = DataContainer::iterator;
59
59
60 static void swap(IteratorValue<Dim, false> &o1, IteratorValue<Dim, false> &o2)
60 static void swap(IteratorValue<Dim, false> &o1, IteratorValue<Dim, false> &o2)
61 {
61 {
62 for (auto i = 0; i < o1.m_NbComponents; ++i) {
62 for (auto i = 0; i < o1.m_NbComponents; ++i) {
63 std::iter_swap(o1.m_It + i, o2.m_It + i);
63 std::iter_swap(o1.m_It + i, o2.m_It + i);
64 }
64 }
65 }
65 }
66 };
66 };
67
67
68 template <int Dim, bool IsConst>
68 template <int Dim, bool IsConst>
69 class IteratorValue : public ArrayDataIteratorValue::Impl {
69 class IteratorValue : public ArrayDataIteratorValue::Impl {
70 public:
70 public:
71 friend class ArrayData<Dim>;
71 friend class ArrayData<Dim>;
72 friend class IteratorValueBuilder<Dim, IsConst>;
72 friend class IteratorValueBuilder<Dim, IsConst>;
73
73
74 using DataContainerIterator =
74 using DataContainerIterator =
75 typename IteratorValueBuilder<Dim, IsConst>::DataContainerIterator;
75 typename IteratorValueBuilder<Dim, IsConst>::DataContainerIterator;
76
76
77 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
77 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
78 explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin)
78 explicit IteratorValue(const DataContainer &container, int nbComponents, bool begin)
79 : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents}
79 : m_It{begin ? container.cbegin() : container.cend()}, m_NbComponents{nbComponents}
80 {
80 {
81 }
81 }
82
82
83 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
83 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
84 explicit IteratorValue(DataContainer &container, int nbComponents, bool begin)
84 explicit IteratorValue(DataContainer &container, int nbComponents, bool begin)
85 : m_It{begin ? container.begin() : container.end()}, m_NbComponents{nbComponents}
85 : m_It{begin ? container.begin() : container.end()}, m_NbComponents{nbComponents}
86 {
86 {
87 }
87 }
88
88
89 IteratorValue(const IteratorValue &other) = default;
89 IteratorValue(const IteratorValue &other) = default;
90
90
91 std::unique_ptr<ArrayDataIteratorValue::Impl> clone() const override
91 std::unique_ptr<ArrayDataIteratorValue::Impl> clone() const override
92 {
92 {
93 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
93 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
94 }
94 }
95
95
96 int distance(const ArrayDataIteratorValue::Impl &other) const override try {
96 int distance(const ArrayDataIteratorValue::Impl &other) const override try {
97 /// @todo ALX : validate
97 /// @todo ALX : validate
98 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
98 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
99 return std::distance(otherImpl.m_It, m_It) / m_NbComponents;
99 return std::distance(otherImpl.m_It, m_It) / m_NbComponents;
100 }
100 }
101 catch (const std::bad_cast &) {
101 catch (const std::bad_cast &) {
102 return 0;
102 return 0;
103 }
103 }
104
104
105 bool equals(const ArrayDataIteratorValue::Impl &other) const override try {
105 bool equals(const ArrayDataIteratorValue::Impl &other) const override try {
106 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
106 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
107 return std::tie(m_It, m_NbComponents) == std::tie(otherImpl.m_It, otherImpl.m_NbComponents);
107 return std::tie(m_It, m_NbComponents) == std::tie(otherImpl.m_It, otherImpl.m_NbComponents);
108 }
108 }
109 catch (const std::bad_cast &) {
109 catch (const std::bad_cast &) {
110 return false;
110 return false;
111 }
111 }
112
112
113 bool lowerThan(const ArrayDataIteratorValue::Impl &other) const override try {
113 bool lowerThan(const ArrayDataIteratorValue::Impl &other) const override try {
114 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
114 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
115 return m_It < otherImpl.m_It;
115 return m_It < otherImpl.m_It;
116 }
116 }
117 catch (const std::bad_cast &) {
117 catch (const std::bad_cast &) {
118 return false;
118 return false;
119 }
119 }
120
120
121 std::unique_ptr<ArrayDataIteratorValue::Impl> advance(int offset) const override
121 std::unique_ptr<ArrayDataIteratorValue::Impl> advance(int offset) const override
122 {
122 {
123 auto result = clone();
123 auto result = clone();
124 while (offset--) {
124 while (offset--) {
125 result->next();
125 result->next();
126 }
126 }
127 return result;
127 return result;
128 }
128 }
129
129
130 void next() override { std::advance(m_It, m_NbComponents); }
130 void next() override { std::advance(m_It, m_NbComponents); }
131 void prev() override { std::advance(m_It, -m_NbComponents); }
131 void prev() override { std::advance(m_It, -m_NbComponents); }
132
132
133 double at(int componentIndex) const override { return *(m_It + componentIndex); }
133 double at(int componentIndex) const override { return *(m_It + componentIndex); }
134 double first() const override { return *m_It; }
134 double first() const override { return *m_It; }
135 double min() const override
135 double min() const override
136 {
136 {
137 auto values = this->values();
137 auto values = this->values();
138 auto end = values.cend();
138 auto end = values.cend();
139 auto it = std::min_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
139 auto it = std::min_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
140 return SortUtils::minCompareWithNaN(v1, v2);
140 return SortUtils::minCompareWithNaN(v1, v2);
141 });
141 });
142
142
143 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
143 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
144 }
144 }
145 double max() const override
145 double max() const override
146 {
146 {
147 auto values = this->values();
147 auto values = this->values();
148 auto end = values.cend();
148 auto end = values.cend();
149 auto it = std::max_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
149 auto it = std::max_element(values.cbegin(), end, [](const auto &v1, const auto &v2) {
150 return SortUtils::maxCompareWithNaN(v1, v2);
150 return SortUtils::maxCompareWithNaN(v1, v2);
151 });
151 });
152 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
152 return it != end ? *it : std::numeric_limits<double>::quiet_NaN();
153 }
153 }
154
154
155 QVector<double> values() const override
155 QVector<double> values() const override
156 {
156 {
157 auto result = QVector<double>{};
157 auto result = QVector<double>{};
158 for (auto i = 0; i < m_NbComponents; ++i) {
158 for (auto i = 0; i < m_NbComponents; ++i) {
159 result.push_back(*(m_It + i));
159 result.push_back(*(m_It + i));
160 }
160 }
161
161
162 return result;
162 return result;
163 }
163 }
164
164
165 void swap(ArrayDataIteratorValue::Impl &other) override
165 void swap(ArrayDataIteratorValue::Impl &other) override
166 {
166 {
167 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
167 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
168 IteratorValueBuilder<Dim, IsConst>::swap(*this, otherImpl);
168 IteratorValueBuilder<Dim, IsConst>::swap(*this, otherImpl);
169 }
169 }
170
170
171 private:
171 private:
172 DataContainerIterator m_It;
172 DataContainerIterator m_It;
173 int m_NbComponents;
173 int m_NbComponents;
174 };
174 };
175
175
176 } // namespace arraydata_detail
176 } // namespace arraydata_detail
177
177
178 /**
178 /**
179 * @brief The ArrayData class represents a dataset for a data series.
179 * @brief The ArrayData class represents a dataset for a data series.
180 *
180 *
181 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
181 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
182 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
182 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
183 * number of values
183 * number of values
184 *
184 *
185 * @tparam Dim the dimension of the ArrayData (one or two)
185 * @tparam Dim the dimension of the ArrayData (one or two)
186 * @sa IDataSeries
186 * @sa IDataSeries
187 */
187 */
188 template <int Dim>
188 template <int Dim>
189 class ArrayData {
189 class ArrayData {
190 public:
190 public:
191 // ///// //
191 // ///// //
192 // Ctors //
192 // Ctors //
193 // ///// //
193 // ///// //
194
194
195 /**
195 /**
196 * Ctor for a unidimensional ArrayData
196 * Ctor for a unidimensional ArrayData
197 * @param data the data the ArrayData will hold
197 * @param data the data the ArrayData will hold
198 */
198 */
199 template <int D = Dim, typename = std::enable_if_t<D == 1> >
199 template <int D = Dim, typename = std::enable_if_t<D == 1> >
200 explicit ArrayData(DataContainer data) : m_Data{std::move(data)}, m_NbComponents{1}
200 explicit ArrayData(DataContainer data) : m_Data{std::move(data)}, m_NbComponents{1}
201 {
201 {
202 }
202 }
203
203
204 /**
204 /**
205 * Ctor for a two-dimensional ArrayData. The number of components (number of lines) must be
205 * Ctor for a two-dimensional ArrayData. The number of components (number of lines) must be
206 * greater than 2 and must be a divisor of the total number of data in the vector
206 * greater than 2 and must be a divisor of the total number of data in the vector
207 * @param data the data the ArrayData will hold
207 * @param data the data the ArrayData will hold
208 * @param nbComponents the number of components
208 * @param nbComponents the number of components
209 * @throws std::invalid_argument if the number of components is less than 2 or is not a divisor
209 * @throws std::invalid_argument if the number of components is less than 2 or is not a divisor
210 * of the size of the data
210 * of the size of the data
211 */
211 */
212 template <int D = Dim, typename = std::enable_if_t<D == 2> >
212 template <int D = Dim, typename = std::enable_if_t<D == 2> >
213 explicit ArrayData(DataContainer data, int nbComponents)
213 explicit ArrayData(DataContainer data, int nbComponents)
214 : m_Data{std::move(data)}, m_NbComponents{nbComponents}
214 : m_Data{std::move(data)}, m_NbComponents{nbComponents}
215 {
215 {
216 if (nbComponents < 2) {
216 if (nbComponents < 2) {
217 throw std::invalid_argument{
217 throw std::invalid_argument{
218 QString{"A multidimensional ArrayData must have at least 2 components (found: %1)"}
218 QString{"A multidimensional ArrayData must have at least 2 components (found: %1)"}
219 .arg(nbComponents)
219 .arg(nbComponents)
220 .toStdString()};
220 .toStdString()};
221 }
221 }
222
222
223 if (m_Data.size() % m_NbComponents != 0) {
223 if (m_Data.size() % m_NbComponents != 0) {
224 throw std::invalid_argument{QString{
224 throw std::invalid_argument{QString{
225 "The number of components (%1) is inconsistent with the total number of data (%2)"}
225 "The number of components (%1) is inconsistent with the total number of data (%2)"}
226 .arg(m_Data.size(), nbComponents)
226 .arg(m_Data.size(), nbComponents)
227 .toStdString()};
227 .toStdString()};
228 }
228 }
229 }
229 }
230
230
231 /// Copy ctor
231 /// Copy ctor
232 explicit ArrayData(const ArrayData &other)
232 explicit ArrayData(const ArrayData &other)
233 {
233 {
234 QReadLocker otherLocker{&other.m_Lock};
234 QReadLocker otherLocker{&other.m_Lock};
235 m_Data = other.m_Data;
235 m_Data = other.m_Data;
236 m_NbComponents = other.m_NbComponents;
236 m_NbComponents = other.m_NbComponents;
237 }
237 }
238
238
239 // /////////////// //
239 // /////////////// //
240 // General methods //
240 // General methods //
241 // /////////////// //
241 // /////////////// //
242
242
243 /**
243 /**
244 * Merges into the array data an other array data. The two array datas must have the same number
244 * Merges into the array data an other array data. The two array datas must have the same number
245 * of components so the merge can be done
245 * of components so the merge can be done
246 * @param other the array data to merge with
246 * @param other the array data to merge with
247 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
247 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
248 * inserted at the end
248 * inserted at the end
249 */
249 */
250 void add(const ArrayData<Dim> &other, bool prepend = false)
250 void add(const ArrayData<Dim> &other, bool prepend = false)
251 {
251 {
252 QWriteLocker locker{&m_Lock};
252 QWriteLocker locker{&m_Lock};
253 QReadLocker otherLocker{&other.m_Lock};
253 QReadLocker otherLocker{&other.m_Lock};
254
254
255 if (m_NbComponents != other.componentCount()) {
255 if (m_NbComponents != other.componentCount()) {
256 return;
256 return;
257 }
257 }
258
258
259 if (prepend) {
259 if (prepend) {
260 auto otherDataSize = other.m_Data.size();
260 auto otherDataSize = other.m_Data.size();
261 m_Data.insert(m_Data.begin(), otherDataSize, 0.);
261 m_Data.insert(m_Data.begin(), otherDataSize, 0.);
262 for (auto i = 0; i < otherDataSize; ++i) {
262 for (auto i = 0; i < otherDataSize; ++i) {
263 m_Data.replace(i, other.m_Data.at(i));
263 m_Data.replace(i, other.m_Data.at(i));
264 }
264 }
265 }
265 }
266 else {
266 else {
267 m_Data.append(other.m_Data);
267 m_Data.append(other.m_Data);
268 }
268 }
269 }
269 }
270
270
271 void clear()
271 void clear()
272 {
272 {
273 QWriteLocker locker{&m_Lock};
273 QWriteLocker locker{&m_Lock};
274 m_Data.clear();
274 m_Data.clear();
275 }
275 }
276
276
277 int componentCount() const noexcept { return m_NbComponents; }
277 int componentCount() const noexcept { return m_NbComponents; }
278
278
279 /// @return the size (i.e. number of values) of a single component
279 /// @return the size (i.e. number of values) of a single component
280 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
280 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
281 int size() const
281 int size() const
282 {
282 {
283 QReadLocker locker{&m_Lock};
283 QReadLocker locker{&m_Lock};
284 return m_Data.size() / m_NbComponents;
284 return m_Data.size() / m_NbComponents;
285 }
285 }
286
286
287 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
287 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
288 {
288 {
289 QReadLocker locker{&m_Lock};
289 QReadLocker locker{&m_Lock};
290 return arraydata_detail::Sort<Dim>::sort(m_Data, m_NbComponents, sortPermutation);
290 return arraydata_detail::Sort<Dim>::sort(m_Data, m_NbComponents, sortPermutation);
291 }
291 }
292
292
293 // ///////// //
293 // ///////// //
294 // Iterators //
294 // Iterators //
295 // ///////// //
295 // ///////// //
296
296
297 ArrayDataIterator begin()
297 ArrayDataIterator begin()
298 {
298 {
299 return ArrayDataIterator{
299 return ArrayDataIterator{
300 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
300 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
301 m_Data, m_NbComponents, true)}};
301 m_Data, m_NbComponents, true)}};
302 }
302 }
303
303
304 ArrayDataIterator end()
304 ArrayDataIterator end()
305 {
305 {
306 return ArrayDataIterator{
306 return ArrayDataIterator{
307 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
307 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, false> >(
308 m_Data, m_NbComponents, false)}};
308 m_Data, m_NbComponents, false)}};
309 }
309 }
310
310
311 ArrayDataIterator cbegin() const
311 ArrayDataIterator cbegin() const
312 {
312 {
313 return ArrayDataIterator{
313 return ArrayDataIterator{
314 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
314 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
315 m_Data, m_NbComponents, true)}};
315 m_Data, m_NbComponents, true)}};
316 }
316 }
317
317
318 ArrayDataIterator cend() const
318 ArrayDataIterator cend() const
319 {
319 {
320 return ArrayDataIterator{
320 return ArrayDataIterator{
321 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
321 ArrayDataIteratorValue{std::make_unique<arraydata_detail::IteratorValue<Dim, true> >(
322 m_Data, m_NbComponents, false)}};
322 m_Data, m_NbComponents, false)}};
323 }
323 }
324
324
325 void erase(ArrayDataIterator first, ArrayDataIterator last)
325 void erase(ArrayDataIterator first, ArrayDataIterator last)
326 {
326 {
327 auto firstImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(first->impl());
327 auto firstImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(first->impl());
328 auto lastImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(last->impl());
328 auto lastImpl = dynamic_cast<arraydata_detail::IteratorValue<Dim, false> *>(last->impl());
329
329
330 if (firstImpl && lastImpl) {
330 if (firstImpl && lastImpl) {
331 m_Data.erase(firstImpl->m_It, lastImpl->m_It);
331 m_Data.erase(firstImpl->m_It, lastImpl->m_It);
332 }
332 }
333 }
333 }
334
334
335 /// Inserts at the end of the array data the values passed as a parameter. This
335 /// Inserts at the end of the array data the values passed as a parameter. This
336 /// method is intended to be used in the context of generating a back insert iterator, or only
336 /// method is intended to be used in the context of generating a back insert iterator, or only
337 /// if it's ensured that the total size of the vector is consistent with the number of
337 /// if it's ensured that the total size of the vector is consistent with the number of
338 /// components of the array data
338 /// components of the array data
339 /// @param values the values to insert
339 /// @param values the values to insert
340 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
340 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
341 void push_back(const QVector<double> &values)
341 void push_back(const QVector<double> &values)
342 {
342 {
343 Q_ASSERT(values.size() % m_NbComponents == 0);
343 Q_ASSERT(values.size() % m_NbComponents == 0);
344 m_Data.append(values);
344 m_Data.append(values);
345 }
345 }
346
346
347 /**
347 /**
348 * @return the data at a specified index
348 * @return the data at a specified index
349 * @remarks index must be a valid position
349 * @remarks index must be a valid position
350 */
350 */
351 double at(int index) const noexcept
351 double at(int index) const noexcept
352 {
352 {
353 QReadLocker locker{&m_Lock};
353 QReadLocker locker{&m_Lock};
354 return m_Data.at(index);
354 return m_Data.at(index);
355 }
355 }
356
356
357 // ///////////// //
357 // ///////////// //
358 // 1-dim methods //
358 // 1-dim methods //
359 // ///////////// //
359 // ///////////// //
360
360
361 /**
361 /**
362 * @return the data as a vector, as a const reference
362 * @return the data as a vector, as a const reference
363 * @remarks this method is only available for a unidimensional ArrayData
363 * @remarks this method is only available for a unidimensional ArrayData
364 */
364 */
365 template <int D = Dim, typename = std::enable_if_t<D == 1> >
365 template <int D = Dim, typename = std::enable_if_t<D == 1> >
366 const QVector<double> &cdata() const noexcept
366 DataContainer cdata() const noexcept
367 {
367 {
368 QReadLocker locker{&m_Lock};
369 return m_Data;
368 return m_Data;
370 }
369 }
371
370
372 private:
371 private:
373 DataContainer m_Data;
372 DataContainer m_Data;
374 /// Number of components (lines). Is always 1 in a 1-dim ArrayData
373 /// Number of components (lines). Is always 1 in a 1-dim ArrayData
375 int m_NbComponents;
374 int m_NbComponents;
376 mutable QReadWriteLock m_Lock;
375 mutable QReadWriteLock m_Lock;
377 };
376 };
378
377
379 #endif // SCIQLOP_ARRAYDATA_H
378 #endif // SCIQLOP_ARRAYDATA_H
@@ -1,410 +1,410
1 #ifndef SCIQLOP_DATASERIES_H
1 #ifndef SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
2 #define SCIQLOP_DATASERIES_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Common/SortUtils.h>
6 #include <Common/SortUtils.h>
7
7
8 #include <Data/ArrayData.h>
8 #include <Data/ArrayData.h>
9 #include <Data/DataSeriesMergeHelper.h>
9 #include <Data/DataSeriesMergeHelper.h>
10 #include <Data/IDataSeries.h>
10 #include <Data/IDataSeries.h>
11
11
12 #include <QLoggingCategory>
12 #include <QLoggingCategory>
13 #include <QReadLocker>
13 #include <QReadLocker>
14 #include <QReadWriteLock>
14 #include <QReadWriteLock>
15 #include <memory>
15 #include <memory>
16
16
17 // We don't use the Qt macro since the log is used in the header file, which causes multiple log
17 // We don't use the Qt macro since the log is used in the header file, which causes multiple log
18 // definitions with inheritance. Inline method is used instead
18 // definitions with inheritance. Inline method is used instead
19 inline const QLoggingCategory &LOG_DataSeries()
19 inline const QLoggingCategory &LOG_DataSeries()
20 {
20 {
21 static const QLoggingCategory category{"DataSeries"};
21 static const QLoggingCategory category{"DataSeries"};
22 return category;
22 return category;
23 }
23 }
24
24
25 template <int Dim>
25 template <int Dim>
26 class DataSeries;
26 class DataSeries;
27
27
28 namespace dataseries_detail {
28 namespace dataseries_detail {
29
29
30 template <int Dim, bool IsConst>
30 template <int Dim, bool IsConst>
31 class IteratorValue : public DataSeriesIteratorValue::Impl {
31 class IteratorValue : public DataSeriesIteratorValue::Impl {
32 public:
32 public:
33 friend class DataSeries<Dim>;
33 friend class DataSeries<Dim>;
34
34
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
35 template <bool IC = IsConst, typename = std::enable_if_t<IC == false> >
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
36 explicit IteratorValue(DataSeries<Dim> &dataSeries, bool begin)
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
37 : m_XIt(begin ? dataSeries.xAxisData()->begin() : dataSeries.xAxisData()->end()),
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
38 m_ValuesIt(begin ? dataSeries.valuesData()->begin() : dataSeries.valuesData()->end())
39 {
39 {
40 }
40 }
41
41
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
42 template <bool IC = IsConst, typename = std::enable_if_t<IC == true> >
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
43 explicit IteratorValue(const DataSeries<Dim> &dataSeries, bool begin)
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
44 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
45 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
46 : dataSeries.valuesData()->cend())
46 : dataSeries.valuesData()->cend())
47 {
47 {
48 }
48 }
49
49
50 IteratorValue(const IteratorValue &other) = default;
50 IteratorValue(const IteratorValue &other) = default;
51
51
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
52 std::unique_ptr<DataSeriesIteratorValue::Impl> clone() const override
53 {
53 {
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
54 return std::make_unique<IteratorValue<Dim, IsConst> >(*this);
55 }
55 }
56
56
57 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
57 int distance(const DataSeriesIteratorValue::Impl &other) const override try {
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
58 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
59 return m_XIt->distance(*otherImpl.m_XIt);
59 return m_XIt->distance(*otherImpl.m_XIt);
60 }
60 }
61 catch (const std::bad_cast &) {
61 catch (const std::bad_cast &) {
62 return 0;
62 return 0;
63 }
63 }
64
64
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
65 bool equals(const DataSeriesIteratorValue::Impl &other) const override try {
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
66 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
67 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
67 return std::tie(m_XIt, m_ValuesIt) == std::tie(otherImpl.m_XIt, otherImpl.m_ValuesIt);
68 }
68 }
69 catch (const std::bad_cast &) {
69 catch (const std::bad_cast &) {
70 return false;
70 return false;
71 }
71 }
72
72
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
73 bool lowerThan(const DataSeriesIteratorValue::Impl &other) const override try {
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
74 const auto &otherImpl = dynamic_cast<const IteratorValue &>(other);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
75 return m_XIt->lowerThan(*otherImpl.m_XIt);
76 }
76 }
77 catch (const std::bad_cast &) {
77 catch (const std::bad_cast &) {
78 return false;
78 return false;
79 }
79 }
80
80
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
81 std::unique_ptr<DataSeriesIteratorValue::Impl> advance(int offset) const override
82 {
82 {
83 auto result = clone();
83 auto result = clone();
84 while (offset--) {
84 while (offset--) {
85 result->next();
85 result->next();
86 }
86 }
87 return result;
87 return result;
88 }
88 }
89
89
90 void next() override
90 void next() override
91 {
91 {
92 ++m_XIt;
92 ++m_XIt;
93 ++m_ValuesIt;
93 ++m_ValuesIt;
94 }
94 }
95
95
96 void prev() override
96 void prev() override
97 {
97 {
98 --m_XIt;
98 --m_XIt;
99 --m_ValuesIt;
99 --m_ValuesIt;
100 }
100 }
101
101
102 double x() const override { return m_XIt->at(0); }
102 double x() const override { return m_XIt->at(0); }
103 double value() const override { return m_ValuesIt->at(0); }
103 double value() const override { return m_ValuesIt->at(0); }
104 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
104 double value(int componentIndex) const override { return m_ValuesIt->at(componentIndex); }
105 double minValue() const override { return m_ValuesIt->min(); }
105 double minValue() const override { return m_ValuesIt->min(); }
106 double maxValue() const override { return m_ValuesIt->max(); }
106 double maxValue() const override { return m_ValuesIt->max(); }
107 QVector<double> values() const override { return m_ValuesIt->values(); }
107 QVector<double> values() const override { return m_ValuesIt->values(); }
108
108
109 void swap(DataSeriesIteratorValue::Impl &other) override
109 void swap(DataSeriesIteratorValue::Impl &other) override
110 {
110 {
111 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
111 auto &otherImpl = dynamic_cast<IteratorValue &>(other);
112 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
112 m_XIt->impl()->swap(*otherImpl.m_XIt->impl());
113 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
113 m_ValuesIt->impl()->swap(*otherImpl.m_ValuesIt->impl());
114 }
114 }
115
115
116 private:
116 private:
117 ArrayDataIterator m_XIt;
117 ArrayDataIterator m_XIt;
118 ArrayDataIterator m_ValuesIt;
118 ArrayDataIterator m_ValuesIt;
119 };
119 };
120 } // namespace dataseries_detail
120 } // namespace dataseries_detail
121
121
122 /**
122 /**
123 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
123 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
124 *
124 *
125 * It proposes to set a dimension for the values ​​data.
125 * It proposes to set a dimension for the values ​​data.
126 *
126 *
127 * A DataSeries is always sorted on its x-axis data.
127 * A DataSeries is always sorted on its x-axis data.
128 *
128 *
129 * @tparam Dim The dimension of the values data
129 * @tparam Dim The dimension of the values data
130 *
130 *
131 */
131 */
132 template <int Dim>
132 template <int Dim>
133 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
133 class SCIQLOP_CORE_EXPORT DataSeries : public IDataSeries {
134 friend class DataSeriesMergeHelper;
134 friend class DataSeriesMergeHelper;
135
135
136 public:
136 public:
137 /// Tag needed to define the push_back() method
137 /// Tag needed to define the push_back() method
138 /// @sa push_back()
138 /// @sa push_back()
139 using value_type = DataSeriesIteratorValue;
139 using value_type = DataSeriesIteratorValue;
140
140
141 /// @sa IDataSeries::xAxisData()
141 /// @sa IDataSeries::xAxisData()
142 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
142 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
143 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
143 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
144
144
145 /// @sa IDataSeries::xAxisUnit()
145 /// @sa IDataSeries::xAxisUnit()
146 Unit xAxisUnit() const override { return m_XAxisUnit; }
146 Unit xAxisUnit() const override { return m_XAxisUnit; }
147
147
148 /// @return the values dataset
148 /// @return the values dataset
149 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
149 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
150 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
150 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
151
151
152 /// @sa IDataSeries::valuesUnit()
152 /// @sa IDataSeries::valuesUnit()
153 Unit valuesUnit() const override { return m_ValuesUnit; }
153 Unit valuesUnit() const override { return m_ValuesUnit; }
154
154
155
155
156 SqpRange range() const override
156 SqpRange range() const override
157 {
157 {
158 if (!m_XAxisData->cdata().isEmpty()) {
158 if (!m_XAxisData->cdata().empty()) {
159 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
159 return SqpRange{m_XAxisData->cdata().front(), m_XAxisData->cdata().back()};
160 }
160 }
161
161
162 return SqpRange{};
162 return SqpRange{};
163 }
163 }
164
164
165 void clear()
165 void clear()
166 {
166 {
167 m_XAxisData->clear();
167 m_XAxisData->clear();
168 m_ValuesData->clear();
168 m_ValuesData->clear();
169 }
169 }
170
170
171 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
171 bool isEmpty() const noexcept { return m_XAxisData->size() == 0; }
172
172
173 /// Merges into the data series an other data series
173 /// Merges into the data series an other data series
174 /// @remarks the data series to merge with is cleared after the operation
174 /// @remarks the data series to merge with is cleared after the operation
175 void merge(IDataSeries *dataSeries) override
175 void merge(IDataSeries *dataSeries) override
176 {
176 {
177 dataSeries->lockWrite();
177 dataSeries->lockWrite();
178 lockWrite();
178 lockWrite();
179
179
180 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
180 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
181 DataSeriesMergeHelper::merge(*other, *this);
181 DataSeriesMergeHelper::merge(*other, *this);
182 }
182 }
183 else {
183 else {
184 qCWarning(LOG_DataSeries())
184 qCWarning(LOG_DataSeries())
185 << 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 !");
186 }
186 }
187 unlock();
187 unlock();
188 dataSeries->unlock();
188 dataSeries->unlock();
189 }
189 }
190
190
191 void purge(double min, double max) override
191 void purge(double min, double max) override
192 {
192 {
193 // Nothing to purge if series is empty
193 // Nothing to purge if series is empty
194 if (isEmpty()) {
194 if (isEmpty()) {
195 return;
195 return;
196 }
196 }
197
197
198 if (min > max) {
198 if (min > max) {
199 std::swap(min, max);
199 std::swap(min, max);
200 }
200 }
201
201
202 // Nothing to purge if series min/max are inside purge range
202 // Nothing to purge if series min/max are inside purge range
203 auto xMin = cbegin()->x();
203 auto xMin = cbegin()->x();
204 auto xMax = (--cend())->x();
204 auto xMax = (--cend())->x();
205 if (xMin >= min && xMax <= max) {
205 if (xMin >= min && xMax <= max) {
206 return;
206 return;
207 }
207 }
208
208
209 auto lowerIt = std::lower_bound(
209 auto lowerIt = std::lower_bound(
210 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; });
211 erase(begin(), lowerIt);
211 erase(begin(), lowerIt);
212 auto upperIt = std::upper_bound(
212 auto upperIt = std::upper_bound(
213 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(); });
214 erase(upperIt, end());
214 erase(upperIt, end());
215 }
215 }
216
216
217 // ///////// //
217 // ///////// //
218 // Iterators //
218 // Iterators //
219 // ///////// //
219 // ///////// //
220
220
221 DataSeriesIterator begin() override
221 DataSeriesIterator begin() override
222 {
222 {
223 return DataSeriesIterator{DataSeriesIteratorValue{
223 return DataSeriesIterator{DataSeriesIteratorValue{
224 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
224 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, true)}};
225 }
225 }
226
226
227 DataSeriesIterator end() override
227 DataSeriesIterator end() override
228 {
228 {
229 return DataSeriesIterator{DataSeriesIteratorValue{
229 return DataSeriesIterator{DataSeriesIteratorValue{
230 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
230 std::make_unique<dataseries_detail::IteratorValue<Dim, false> >(*this, false)}};
231 }
231 }
232
232
233 DataSeriesIterator cbegin() const override
233 DataSeriesIterator cbegin() const override
234 {
234 {
235 return DataSeriesIterator{DataSeriesIteratorValue{
235 return DataSeriesIterator{DataSeriesIteratorValue{
236 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
236 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, true)}};
237 }
237 }
238
238
239 DataSeriesIterator cend() const override
239 DataSeriesIterator cend() const override
240 {
240 {
241 return DataSeriesIterator{DataSeriesIteratorValue{
241 return DataSeriesIterator{DataSeriesIteratorValue{
242 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
242 std::make_unique<dataseries_detail::IteratorValue<Dim, true> >(*this, false)}};
243 }
243 }
244
244
245 void erase(DataSeriesIterator first, DataSeriesIterator last)
245 void erase(DataSeriesIterator first, DataSeriesIterator last)
246 {
246 {
247 auto firstImpl
247 auto firstImpl
248 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
248 = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(first->impl());
249 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
249 auto lastImpl = dynamic_cast<dataseries_detail::IteratorValue<Dim, false> *>(last->impl());
250
250
251 if (firstImpl && lastImpl) {
251 if (firstImpl && lastImpl) {
252 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
252 m_XAxisData->erase(firstImpl->m_XIt, lastImpl->m_XIt);
253 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
253 m_ValuesData->erase(firstImpl->m_ValuesIt, lastImpl->m_ValuesIt);
254 }
254 }
255 }
255 }
256
256
257 /// @sa IDataSeries::minXAxisData()
257 /// @sa IDataSeries::minXAxisData()
258 DataSeriesIterator minXAxisData(double minXAxisData) const override
258 DataSeriesIterator minXAxisData(double minXAxisData) const override
259 {
259 {
260 return std::lower_bound(
260 return std::lower_bound(
261 cbegin(), cend(), minXAxisData,
261 cbegin(), cend(), minXAxisData,
262 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
262 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
263 }
263 }
264
264
265 /// @sa IDataSeries::maxXAxisData()
265 /// @sa IDataSeries::maxXAxisData()
266 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
266 DataSeriesIterator maxXAxisData(double maxXAxisData) const override
267 {
267 {
268 // Gets the first element that greater than max value
268 // Gets the first element that greater than max value
269 auto it = std::upper_bound(
269 auto it = std::upper_bound(
270 cbegin(), cend(), maxXAxisData,
270 cbegin(), cend(), maxXAxisData,
271 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
271 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
272
272
273 return it == cbegin() ? cend() : --it;
273 return it == cbegin() ? cend() : --it;
274 }
274 }
275
275
276 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
276 std::pair<DataSeriesIterator, DataSeriesIterator> xAxisRange(double minXAxisData,
277 double maxXAxisData) const override
277 double maxXAxisData) const override
278 {
278 {
279 if (minXAxisData > maxXAxisData) {
279 if (minXAxisData > maxXAxisData) {
280 std::swap(minXAxisData, maxXAxisData);
280 std::swap(minXAxisData, maxXAxisData);
281 }
281 }
282
282
283 auto begin = cbegin();
283 auto begin = cbegin();
284 auto end = cend();
284 auto end = cend();
285
285
286 auto lowerIt = std::lower_bound(
286 auto lowerIt = std::lower_bound(
287 begin, end, minXAxisData,
287 begin, end, minXAxisData,
288 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
288 [](const auto &itValue, const auto &value) { return itValue.x() < value; });
289 auto upperIt = std::upper_bound(
289 auto upperIt = std::upper_bound(
290 begin, end, maxXAxisData,
290 begin, end, maxXAxisData,
291 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
291 [](const auto &value, const auto &itValue) { return value < itValue.x(); });
292
292
293 return std::make_pair(lowerIt, upperIt);
293 return std::make_pair(lowerIt, upperIt);
294 }
294 }
295
295
296 std::pair<DataSeriesIterator, DataSeriesIterator>
296 std::pair<DataSeriesIterator, DataSeriesIterator>
297 valuesBounds(double minXAxisData, double maxXAxisData) const override
297 valuesBounds(double minXAxisData, double maxXAxisData) const override
298 {
298 {
299 // Places iterators to the correct x-axis range
299 // Places iterators to the correct x-axis range
300 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
300 auto xAxisRangeIts = xAxisRange(minXAxisData, maxXAxisData);
301
301
302 // Returns end iterators if the range is empty
302 // Returns end iterators if the range is empty
303 if (xAxisRangeIts.first == xAxisRangeIts.second) {
303 if (xAxisRangeIts.first == xAxisRangeIts.second) {
304 return std::make_pair(cend(), cend());
304 return std::make_pair(cend(), cend());
305 }
305 }
306
306
307 // Gets the iterator on the min of all values data
307 // Gets the iterator on the min of all values data
308 auto minIt = std::min_element(
308 auto minIt = std::min_element(
309 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
309 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
310 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
310 return SortUtils::minCompareWithNaN(it1.minValue(), it2.minValue());
311 });
311 });
312
312
313 // Gets the iterator on the max of all values data
313 // Gets the iterator on the max of all values data
314 auto maxIt = std::max_element(
314 auto maxIt = std::max_element(
315 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
315 xAxisRangeIts.first, xAxisRangeIts.second, [](const auto &it1, const auto &it2) {
316 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
316 return SortUtils::maxCompareWithNaN(it1.maxValue(), it2.maxValue());
317 });
317 });
318
318
319 return std::make_pair(minIt, maxIt);
319 return std::make_pair(minIt, maxIt);
320 }
320 }
321
321
322 // /////// //
322 // /////// //
323 // Mutexes //
323 // Mutexes //
324 // /////// //
324 // /////// //
325
325
326 virtual void lockRead() { m_Lock.lockForRead(); }
326 virtual void lockRead() { m_Lock.lockForRead(); }
327 virtual void lockWrite() { m_Lock.lockForWrite(); }
327 virtual void lockWrite() { m_Lock.lockForWrite(); }
328 virtual void unlock() { m_Lock.unlock(); }
328 virtual void unlock() { m_Lock.unlock(); }
329
329
330 // ///// //
330 // ///// //
331 // Other //
331 // Other //
332 // ///// //
332 // ///// //
333
333
334 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
334 /// Inserts at the end of the data series the value of the iterator passed as a parameter. This
335 /// method is intended to be used in the context of generating a back insert iterator
335 /// method is intended to be used in the context of generating a back insert iterator
336 /// @param iteratorValue the iterator value containing the values to insert
336 /// @param iteratorValue the iterator value containing the values to insert
337 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
337 /// @sa http://en.cppreference.com/w/cpp/iterator/back_inserter
338 /// @sa merge()
338 /// @sa merge()
339 /// @sa value_type
339 /// @sa value_type
340 void push_back(const value_type &iteratorValue)
340 void push_back(const value_type &iteratorValue)
341 {
341 {
342 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
342 m_XAxisData->push_back(QVector<double>{iteratorValue.x()});
343 m_ValuesData->push_back(iteratorValue.values());
343 m_ValuesData->push_back(iteratorValue.values());
344 }
344 }
345
345
346 protected:
346 protected:
347 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
347 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
348 /// DataSeries with no values will be created.
348 /// DataSeries with no values will be created.
349 /// @remarks data series is automatically sorted on its x-axis data
349 /// @remarks data series is automatically sorted on its x-axis data
350 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
350 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
351 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
351 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
352 : m_XAxisData{xAxisData},
352 : m_XAxisData{xAxisData},
353 m_XAxisUnit{xAxisUnit},
353 m_XAxisUnit{xAxisUnit},
354 m_ValuesData{valuesData},
354 m_ValuesData{valuesData},
355 m_ValuesUnit{valuesUnit}
355 m_ValuesUnit{valuesUnit}
356 {
356 {
357 if (m_XAxisData->size() != m_ValuesData->size()) {
357 if (m_XAxisData->size() != m_ValuesData->size()) {
358 clear();
358 clear();
359 }
359 }
360
360
361 // Sorts data if it's not the case
361 // Sorts data if it's not the case
362 const auto &xAxisCData = m_XAxisData->cdata();
362 const auto &xAxisCData = m_XAxisData->cdata();
363 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
363 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
364 sort();
364 sort();
365 }
365 }
366 }
366 }
367
367
368 /// Copy ctor
368 /// Copy ctor
369 explicit DataSeries(const DataSeries<Dim> &other)
369 explicit DataSeries(const DataSeries<Dim> &other)
370 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
370 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
371 m_XAxisUnit{other.m_XAxisUnit},
371 m_XAxisUnit{other.m_XAxisUnit},
372 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
372 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
373 m_ValuesUnit{other.m_ValuesUnit}
373 m_ValuesUnit{other.m_ValuesUnit}
374 {
374 {
375 // Since a series is ordered from its construction and is always ordered, it is not
375 // Since a series is ordered from its construction and is always ordered, it is not
376 // necessary to call the sort method here ('other' is sorted)
376 // necessary to call the sort method here ('other' is sorted)
377 }
377 }
378
378
379 /// Assignment operator
379 /// Assignment operator
380 template <int D>
380 template <int D>
381 DataSeries &operator=(DataSeries<D> other)
381 DataSeries &operator=(DataSeries<D> other)
382 {
382 {
383 std::swap(m_XAxisData, other.m_XAxisData);
383 std::swap(m_XAxisData, other.m_XAxisData);
384 std::swap(m_XAxisUnit, other.m_XAxisUnit);
384 std::swap(m_XAxisUnit, other.m_XAxisUnit);
385 std::swap(m_ValuesData, other.m_ValuesData);
385 std::swap(m_ValuesData, other.m_ValuesData);
386 std::swap(m_ValuesUnit, other.m_ValuesUnit);
386 std::swap(m_ValuesUnit, other.m_ValuesUnit);
387
387
388 return *this;
388 return *this;
389 }
389 }
390
390
391 private:
391 private:
392 /**
392 /**
393 * Sorts data series on its x-axis data
393 * Sorts data series on its x-axis data
394 */
394 */
395 void sort() noexcept
395 void sort() noexcept
396 {
396 {
397 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
397 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
398 m_XAxisData = m_XAxisData->sort(permutation);
398 m_XAxisData = m_XAxisData->sort(permutation);
399 m_ValuesData = m_ValuesData->sort(permutation);
399 m_ValuesData = m_ValuesData->sort(permutation);
400 }
400 }
401
401
402 std::shared_ptr<ArrayData<1> > m_XAxisData;
402 std::shared_ptr<ArrayData<1> > m_XAxisData;
403 Unit m_XAxisUnit;
403 Unit m_XAxisUnit;
404 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
404 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
405 Unit m_ValuesUnit;
405 Unit m_ValuesUnit;
406
406
407 QReadWriteLock m_Lock;
407 QReadWriteLock m_Lock;
408 };
408 };
409
409
410 #endif // SCIQLOP_DATASERIES_H
410 #endif // SCIQLOP_DATASERIES_H
@@ -1,27 +1,27
1 #ifndef SCIQLOP_SCALARSERIES_H
1 #ifndef SCIQLOP_SCALARSERIES_H
2 #define SCIQLOP_SCALARSERIES_H
2 #define SCIQLOP_SCALARSERIES_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 ScalarSeries class is the implementation for a data series representing a scalar.
9 * @brief The ScalarSeries class is the implementation for a data series representing a scalar.
10 */
10 */
11 class SCIQLOP_CORE_EXPORT ScalarSeries : public DataSeries<1> {
11 class SCIQLOP_CORE_EXPORT ScalarSeries : public DataSeries<1> {
12 public:
12 public:
13 /**
13 /**
14 * Ctor with two vectors. The vectors must have the same size, otherwise a ScalarSeries with no
14 * Ctor with two vectors. The vectors must have the same size, otherwise a ScalarSeries with no
15 * values will be created.
15 * values will be created.
16 * @param xAxisData x-axis data
16 * @param xAxisData x-axis data
17 * @param valuesData values data
17 * @param valuesData values data
18 */
18 */
19 explicit ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
19 explicit ScalarSeries(std::vector<double> xAxisData, std::vector<double> valuesData,
20 const Unit &xAxisUnit, const Unit &valuesUnit);
20 const Unit &xAxisUnit, const Unit &valuesUnit);
21
21
22 std::unique_ptr<IDataSeries> clone() const override;
22 std::unique_ptr<IDataSeries> clone() const override;
23
23
24 std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) override;
24 std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) override;
25 };
25 };
26
26
27 #endif // SCIQLOP_SCALARSERIES_H
27 #endif // SCIQLOP_SCALARSERIES_H
@@ -1,34 +1,34
1 #ifndef SCIQLOP_VECTORSERIES_H
1 #ifndef SCIQLOP_VECTORSERIES_H
2 #define SCIQLOP_VECTORSERIES_H
2 #define SCIQLOP_VECTORSERIES_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 VectorSeries class is the implementation for a data series representing a vector.
9 * @brief The VectorSeries class is the implementation for a data series representing a vector.
10 */
10 */
11 class SCIQLOP_CORE_EXPORT VectorSeries : public DataSeries<2> {
11 class SCIQLOP_CORE_EXPORT VectorSeries : public DataSeries<2> {
12 public:
12 public:
13 /**
13 /**
14 * Ctor with three vectors (one per component). The vectors must have the same size, otherwise a
14 * Ctor with three vectors (one per component). The vectors must have the same size, otherwise a
15 * ScalarSeries with no values will be created.
15 * ScalarSeries with no values will be created.
16 * @param xAxisData x-axis data
16 * @param xAxisData x-axis data
17 * @param xvaluesData x-values data
17 * @param xvaluesData x-values data
18 * @param yvaluesData y-values data
18 * @param yvaluesData y-values data
19 * @param zvaluesData z-values data
19 * @param zvaluesData z-values data
20 */
20 */
21 explicit VectorSeries(QVector<double> xAxisData, QVector<double> xValuesData,
21 explicit VectorSeries(std::vector<double> xAxisData, std::vector<double> xValuesData,
22 QVector<double> yValuesData, QVector<double> zValuesData,
22 std::vector<double> yValuesData, std::vector<double> zValuesData,
23 const Unit &xAxisUnit, const Unit &valuesUnit);
23 const Unit &xAxisUnit, const Unit &valuesUnit);
24
24
25 /// Default Ctor
25 /// Default Ctor
26 explicit VectorSeries(QVector<double> xAxisData, QVector<double> valuesData,
26 explicit VectorSeries(std::vector<double> xAxisData, std::vector<double> valuesData,
27 const Unit &xAxisUnit, const Unit &valuesUnit);
27 const Unit &xAxisUnit, const Unit &valuesUnit);
28
28
29 std::unique_ptr<IDataSeries> clone() const;
29 std::unique_ptr<IDataSeries> clone() const;
30
30
31 std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) override;
31 std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) override;
32 };
32 };
33
33
34 #endif // SCIQLOP_VECTORSERIES_H
34 #endif // SCIQLOP_VECTORSERIES_H
@@ -1,31 +1,31
1 #include <Data/ScalarSeries.h>
1 #include <Data/ScalarSeries.h>
2
2
3 ScalarSeries::ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
3 ScalarSeries::ScalarSeries(std::vector<double> xAxisData, std::vector<double> valuesData,
4 const Unit &xAxisUnit, const Unit &valuesUnit)
4 const Unit &xAxisUnit, const Unit &valuesUnit)
5 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
5 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
6 std::make_shared<ArrayData<1> >(std::move(valuesData)), valuesUnit}
6 std::make_shared<ArrayData<1> >(std::move(valuesData)), valuesUnit}
7 {
7 {
8 }
8 }
9
9
10 std::unique_ptr<IDataSeries> ScalarSeries::clone() const
10 std::unique_ptr<IDataSeries> ScalarSeries::clone() const
11 {
11 {
12 return std::make_unique<ScalarSeries>(*this);
12 return std::make_unique<ScalarSeries>(*this);
13 }
13 }
14
14
15 std::shared_ptr<IDataSeries> ScalarSeries::subDataSeries(const SqpRange &range)
15 std::shared_ptr<IDataSeries> ScalarSeries::subDataSeries(const SqpRange &range)
16 {
16 {
17 auto subXAxisData = QVector<double>();
17 auto subXAxisData = std::vector<double>();
18 auto subValuesData = QVector<double>();
18 auto subValuesData = std::vector<double>();
19 this->lockRead();
19 this->lockRead();
20 {
20 {
21 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
21 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
22 for (auto it = bounds.first; it != bounds.second; ++it) {
22 for (auto it = bounds.first; it != bounds.second; ++it) {
23 subXAxisData.append(it->x());
23 subXAxisData.push_back(it->x());
24 subValuesData.append(it->value());
24 subValuesData.push_back(it->value());
25 }
25 }
26 }
26 }
27 this->unlock();
27 this->unlock();
28
28
29 return std::make_shared<ScalarSeries>(subXAxisData, subValuesData, this->xAxisUnit(),
29 return std::make_shared<ScalarSeries>(std::move(subXAxisData), std::move(subValuesData),
30 this->valuesUnit());
30 this->xAxisUnit(), this->valuesUnit());
31 }
31 }
@@ -1,83 +1,88
1 #include "Data/VectorSeries.h"
1 #include "Data/VectorSeries.h"
2
2
3 namespace {
3 namespace {
4
4
5 /**
5 /**
6 * Flatten the three components of a vector to a single QVector that can be passed to an ArrayData
6 * Flatten the three components of a vector to a single QVector that can be passed to an ArrayData
7 *
7 *
8 * Example:
8 * Example:
9 * xValues = {1, 2, 3}
9 * xValues = {1, 2, 3}
10 * yValues = {4, 5, 6}
10 * yValues = {4, 5, 6}
11 * zValues = {7, 8, 9}
11 * zValues = {7, 8, 9}
12 *
12 *
13 * result = {1, 4, 7, 2, 5, 8, 3, 6, 9}
13 * result = {1, 4, 7, 2, 5, 8, 3, 6, 9}
14 *
14 *
15 * @param xValues the x-component values of the vector
15 * @param xValues the x-component values of the vector
16 * @param yValues the y-component values of the vector
16 * @param yValues the y-component values of the vector
17 * @param zValues the z-component values of the vector
17 * @param zValues the z-component values of the vector
18 * @return the single QVector
18 * @return the single QVector
19 * @remarks the three components are consumed
19 * @remarks the three components are consumed
20 * @sa ArrayData
20 * @sa ArrayData
21 */
21 */
22 QVector<double> flatten(QVector<double> xValues, QVector<double> yValues, QVector<double> zValues)
22 std::vector<double> flatten(std::vector<double> xValues, std::vector<double> yValues,
23 std::vector<double> zValues)
23 {
24 {
24 if (xValues.size() != yValues.size() || xValues.size() != zValues.size()) {
25 if (xValues.size() != yValues.size() || xValues.size() != zValues.size()) {
25 /// @todo ALX : log
26 /// @todo ALX : log
26 return {};
27 return {};
27 }
28 }
28
29
29 auto result = QVector<double>{};
30 auto result = std::vector<double>();
30 result.reserve(xValues.size() * 3);
31 result.reserve(xValues.size() * 3);
31
32
32 while (!xValues.isEmpty()) {
33 while (!xValues.empty()) {
33 result.append({xValues.takeFirst(), yValues.takeFirst(), zValues.takeFirst()});
34 result.insert(result.cend(), {xValues.front(), yValues.front(), zValues.front()});
35 xValues.erase(xValues.begin());
36 yValues.erase(yValues.begin());
37 zValues.erase(zValues.begin());
34 }
38 }
35
39
36 return result;
40 return result;
37 }
41 }
38
42
39 } // namespace
43 } // namespace
40
44
41 VectorSeries::VectorSeries(QVector<double> xAxisData, QVector<double> xValuesData,
45 VectorSeries::VectorSeries(std::vector<double> xAxisData, std::vector<double> xValuesData,
42 QVector<double> yValuesData, QVector<double> zValuesData,
46 std::vector<double> yValuesData, std::vector<double> zValuesData,
43 const Unit &xAxisUnit, const Unit &valuesUnit)
47 const Unit &xAxisUnit, const Unit &valuesUnit)
44 : VectorSeries{std::move(xAxisData), flatten(std::move(xValuesData), std::move(yValuesData),
48 : VectorSeries{std::move(xAxisData), flatten(std::move(xValuesData), std::move(yValuesData),
45 std::move(zValuesData)),
49 std::move(zValuesData)),
46 xAxisUnit, valuesUnit}
50 xAxisUnit, valuesUnit}
47 {
51 {
48 }
52 }
49
53
50 VectorSeries::VectorSeries(QVector<double> xAxisData, QVector<double> valuesData,
54 VectorSeries::VectorSeries(std::vector<double> xAxisData, std::vector<double> valuesData,
51 const Unit &xAxisUnit, const Unit &valuesUnit)
55 const Unit &xAxisUnit, const Unit &valuesUnit)
52 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
56 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
53 std::make_shared<ArrayData<2> >(std::move(valuesData), 3), valuesUnit}
57 std::make_shared<ArrayData<2> >(std::move(valuesData), 3), valuesUnit}
54 {
58 {
55 }
59 }
56
60
57 std::unique_ptr<IDataSeries> VectorSeries::clone() const
61 std::unique_ptr<IDataSeries> VectorSeries::clone() const
58 {
62 {
59 return std::make_unique<VectorSeries>(*this);
63 return std::make_unique<VectorSeries>(*this);
60 }
64 }
61
65
62 std::shared_ptr<IDataSeries> VectorSeries::subDataSeries(const SqpRange &range)
66 std::shared_ptr<IDataSeries> VectorSeries::subDataSeries(const SqpRange &range)
63 {
67 {
64 auto subXAxisData = QVector<double>();
68 auto subXAxisData = std::vector<double>();
65 auto subXValuesData = QVector<double>();
69 auto subXValuesData = std::vector<double>();
66 auto subYValuesData = QVector<double>();
70 auto subYValuesData = std::vector<double>();
67 auto subZValuesData = QVector<double>();
71 auto subZValuesData = std::vector<double>();
68
72
69 this->lockRead();
73 this->lockRead();
70 {
74 {
71 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
75 auto bounds = xAxisRange(range.m_TStart, range.m_TEnd);
72 for (auto it = bounds.first; it != bounds.second; ++it) {
76 for (auto it = bounds.first; it != bounds.second; ++it) {
73 subXAxisData.append(it->x());
77 subXAxisData.push_back(it->x());
74 subXValuesData.append(it->value(0));
78 subXValuesData.push_back(it->value(0));
75 subYValuesData.append(it->value(1));
79 subYValuesData.push_back(it->value(1));
76 subZValuesData.append(it->value(2));
80 subZValuesData.push_back(it->value(2));
77 }
81 }
78 }
82 }
79 this->unlock();
83 this->unlock();
80
84
81 return std::make_shared<VectorSeries>(subXAxisData, subXValuesData, subYValuesData,
85 return std::make_shared<VectorSeries>(std::move(subXAxisData), std::move(subXValuesData),
82 subZValuesData, this->xAxisUnit(), this->valuesUnit());
86 std::move(subYValuesData), std::move(subZValuesData),
87 this->xAxisUnit(), this->valuesUnit());
83 }
88 }
@@ -1,216 +1,217
1 #include "AmdaResultParser.h"
1 #include "AmdaResultParser.h"
2
2
3 #include <Common/DateUtils.h>
3 #include <Common/DateUtils.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5 #include <Data/VectorSeries.h>
5 #include <Data/VectorSeries.h>
6
6
7 #include <QDateTime>
7 #include <QDateTime>
8 #include <QFile>
8 #include <QFile>
9 #include <QRegularExpression>
9 #include <QRegularExpression>
10
10
11 #include <cmath>
11 #include <cmath>
12
12
13 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
13 Q_LOGGING_CATEGORY(LOG_AmdaResultParser, "AmdaResultParser")
14
14
15 namespace {
15 namespace {
16
16
17 /// Message in result file when the file was not found on server
17 /// Message in result file when the file was not found on server
18 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
18 const auto FILE_NOT_FOUND_MESSAGE = QStringLiteral("Not Found");
19
19
20 /// Format for dates in result files
20 /// Format for dates in result files
21 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
21 const auto DATE_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss.zzz");
22
22
23 /// Separator between values in a result line
23 /// Separator between values in a result line
24 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
24 const auto RESULT_LINE_SEPARATOR = QRegularExpression{QStringLiteral("\\s+")};
25
25
26 /// Regex to find unit in a line. Examples of valid lines:
26 /// Regex to find unit in a line. Examples of valid lines:
27 /// ... - Units : nT - ...
27 /// ... - Units : nT - ...
28 /// ... -Units:nT- ...
28 /// ... -Units:nT- ...
29 /// ... -Units: mΒ²- ...
29 /// ... -Units: mΒ²- ...
30 /// ... - Units : m/s - ...
30 /// ... - Units : m/s - ...
31 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
31 const auto UNIT_REGEX = QRegularExpression{QStringLiteral("-\\s*Units\\s*:\\s*(.+?)\\s*-")};
32
32
33 /// Converts a string date to a double date
33 /// Converts a string date to a double date
34 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
34 /// @return a double that represents the date in seconds, NaN if the string date can't be converted
35 double doubleDate(const QString &stringDate) noexcept
35 double doubleDate(const QString &stringDate) noexcept
36 {
36 {
37 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
37 auto dateTime = QDateTime::fromString(stringDate, DATE_FORMAT);
38 dateTime.setTimeSpec(Qt::UTC);
38 dateTime.setTimeSpec(Qt::UTC);
39 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
39 return dateTime.isValid() ? DateUtils::secondsSinceEpoch(dateTime)
40 : std::numeric_limits<double>::quiet_NaN();
40 : std::numeric_limits<double>::quiet_NaN();
41 }
41 }
42
42
43 /// Checks if a line is a comment line
43 /// Checks if a line is a comment line
44 bool isCommentLine(const QString &line)
44 bool isCommentLine(const QString &line)
45 {
45 {
46 return line.startsWith("#");
46 return line.startsWith("#");
47 }
47 }
48
48
49 /// @return the number of lines to be read depending on the type of value passed in parameter
49 /// @return the number of lines to be read depending on the type of value passed in parameter
50 int nbValues(AmdaResultParser::ValueType valueType) noexcept
50 int nbValues(AmdaResultParser::ValueType valueType) noexcept
51 {
51 {
52 switch (valueType) {
52 switch (valueType) {
53 case AmdaResultParser::ValueType::SCALAR:
53 case AmdaResultParser::ValueType::SCALAR:
54 return 1;
54 return 1;
55 case AmdaResultParser::ValueType::VECTOR:
55 case AmdaResultParser::ValueType::VECTOR:
56 return 3;
56 return 3;
57 case AmdaResultParser::ValueType::UNKNOWN:
57 case AmdaResultParser::ValueType::UNKNOWN:
58 // Invalid case
58 // Invalid case
59 break;
59 break;
60 }
60 }
61
61
62 // Invalid cases
62 // Invalid cases
63 qCCritical(LOG_AmdaResultParser())
63 qCCritical(LOG_AmdaResultParser())
64 << QObject::tr("Can't get the number of values to read: unsupported type");
64 << QObject::tr("Can't get the number of values to read: unsupported type");
65 return 0;
65 return 0;
66 }
66 }
67
67
68 /**
68 /**
69 * Reads stream to retrieve x-axis unit
69 * Reads stream to retrieve x-axis unit
70 * @param stream the stream to read
70 * @param stream the stream to read
71 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
71 * @return the unit that has been read in the stream, a default unit (time unit with no label) if an
72 * error occured during reading
72 * error occured during reading
73 */
73 */
74 Unit readXAxisUnit(QTextStream &stream)
74 Unit readXAxisUnit(QTextStream &stream)
75 {
75 {
76 QString line{};
76 QString line{};
77
77
78 // Searches unit in the comment lines
78 // Searches unit in the comment lines
79 while (stream.readLineInto(&line) && isCommentLine(line)) {
79 while (stream.readLineInto(&line) && isCommentLine(line)) {
80 auto match = UNIT_REGEX.match(line);
80 auto match = UNIT_REGEX.match(line);
81 if (match.hasMatch()) {
81 if (match.hasMatch()) {
82 return Unit{match.captured(1), true};
82 return Unit{match.captured(1), true};
83 }
83 }
84 }
84 }
85
85
86 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
86 qCWarning(LOG_AmdaResultParser()) << QObject::tr("The unit could not be found in the file");
87
87
88 // Error cases
88 // Error cases
89 return Unit{{}, true};
89 return Unit{{}, true};
90 }
90 }
91
91
92 /**
92 /**
93 * Reads stream to retrieve results
93 * Reads stream to retrieve results
94 * @param stream the stream to read
94 * @param stream the stream to read
95 * @return the pair of vectors x-axis data/values data that has been read in the stream
95 * @return the pair of vectors x-axis data/values data that has been read in the stream
96 */
96 */
97 QPair<QVector<double>, QVector<QVector<double> > >
97 QPair<QVector<double>, QVector<QVector<double> > >
98 readResults(QTextStream &stream, AmdaResultParser::ValueType valueType)
98 readResults(QTextStream &stream, AmdaResultParser::ValueType valueType)
99 {
99 {
100 auto expectedNbValues = nbValues(valueType);
100 auto expectedNbValues = nbValues(valueType);
101
101
102 auto xData = QVector<double>{};
102 auto xData = QVector<double>{};
103 auto valuesData = QVector<QVector<double> >(expectedNbValues);
103 auto valuesData = QVector<QVector<double> >(expectedNbValues);
104
104
105 QString line{};
105 QString line{};
106
106
107 while (stream.readLineInto(&line)) {
107 while (stream.readLineInto(&line)) {
108 // Ignore comment lines
108 // Ignore comment lines
109 if (!isCommentLine(line)) {
109 if (!isCommentLine(line)) {
110 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
110 auto lineData = line.split(RESULT_LINE_SEPARATOR, QString::SkipEmptyParts);
111 if (lineData.size() == expectedNbValues + 1) {
111 if (lineData.size() == expectedNbValues + 1) {
112 // X : the data is converted from date to double (in secs)
112 // X : the data is converted from date to double (in secs)
113 auto x = doubleDate(lineData.at(0));
113 auto x = doubleDate(lineData.at(0));
114
114
115 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
115 // Adds result only if x is valid. Then, if value is invalid, it is set to NaN
116 if (!std::isnan(x)) {
116 if (!std::isnan(x)) {
117 xData.push_back(x);
117 xData.push_back(x);
118
118
119 // Values
119 // Values
120 for (auto valueIndex = 0; valueIndex < expectedNbValues; ++valueIndex) {
120 for (auto valueIndex = 0; valueIndex < expectedNbValues; ++valueIndex) {
121 auto column = valueIndex + 1;
121 auto column = valueIndex + 1;
122
122
123 bool valueOk;
123 bool valueOk;
124 auto value = lineData.at(column).toDouble(&valueOk);
124 auto value = lineData.at(column).toDouble(&valueOk);
125
125
126 if (!valueOk) {
126 if (!valueOk) {
127 qCWarning(LOG_AmdaResultParser())
127 qCWarning(LOG_AmdaResultParser())
128 << QObject::tr(
128 << QObject::tr(
129 "Value from (line %1, column %2) is invalid and will be "
129 "Value from (line %1, column %2) is invalid and will be "
130 "converted to NaN")
130 "converted to NaN")
131 .arg(line, column);
131 .arg(line, column);
132 value = std::numeric_limits<double>::quiet_NaN();
132 value = std::numeric_limits<double>::quiet_NaN();
133 }
133 }
134 valuesData[valueIndex].append(value);
134 valuesData[valueIndex].append(value);
135 }
135 }
136 }
136 }
137 else {
137 else {
138 qCWarning(LOG_AmdaResultParser())
138 qCWarning(LOG_AmdaResultParser())
139 << QObject::tr("Can't retrieve results from line %1: x is invalid")
139 << QObject::tr("Can't retrieve results from line %1: x is invalid")
140 .arg(line);
140 .arg(line);
141 }
141 }
142 }
142 }
143 else {
143 else {
144 qCWarning(LOG_AmdaResultParser())
144 qCWarning(LOG_AmdaResultParser())
145 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
145 << QObject::tr("Can't retrieve results from line %1: invalid line").arg(line);
146 }
146 }
147 }
147 }
148 }
148 }
149
149
150 return qMakePair(std::move(xData), std::move(valuesData));
150 return qMakePair(std::move(xData), std::move(valuesData));
151 }
151 }
152
152
153 } // namespace
153 } // namespace
154
154
155 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
155 std::shared_ptr<IDataSeries> AmdaResultParser::readTxt(const QString &filePath,
156 ValueType valueType) noexcept
156 ValueType valueType) noexcept
157 {
157 {
158 if (valueType == ValueType::UNKNOWN) {
158 if (valueType == ValueType::UNKNOWN) {
159 qCCritical(LOG_AmdaResultParser())
159 qCCritical(LOG_AmdaResultParser())
160 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
160 << QObject::tr("Can't retrieve AMDA data: the type of values to be read is unknown");
161 return nullptr;
161 return nullptr;
162 }
162 }
163
163
164 QFile file{filePath};
164 QFile file{filePath};
165
165
166 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
166 if (!file.open(QFile::ReadOnly | QIODevice::Text)) {
167 qCCritical(LOG_AmdaResultParser())
167 qCCritical(LOG_AmdaResultParser())
168 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
168 << QObject::tr("Can't retrieve AMDA data from file %1: %2")
169 .arg(filePath, file.errorString());
169 .arg(filePath, file.errorString());
170 return nullptr;
170 return nullptr;
171 }
171 }
172
172
173 QTextStream stream{&file};
173 QTextStream stream{&file};
174
174
175 // Checks if the file was found on the server
175 // Checks if the file was found on the server
176 auto firstLine = stream.readLine();
176 auto firstLine = stream.readLine();
177 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
177 if (firstLine.compare(FILE_NOT_FOUND_MESSAGE) == 0) {
178 qCCritical(LOG_AmdaResultParser())
178 qCCritical(LOG_AmdaResultParser())
179 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
179 << QObject::tr("Can't retrieve AMDA data from file %1: file was not found on server")
180 .arg(filePath);
180 .arg(filePath);
181 return nullptr;
181 return nullptr;
182 }
182 }
183
183
184 // Reads x-axis unit
184 // Reads x-axis unit
185 stream.seek(0); // returns to the beginning of the file
185 stream.seek(0); // returns to the beginning of the file
186 auto xAxisUnit = readXAxisUnit(stream);
186 auto xAxisUnit = readXAxisUnit(stream);
187
187
188 // Reads results
188 // Reads results
189 stream.seek(0); // returns to the beginning of the file
189 stream.seek(0); // returns to the beginning of the file
190 auto results = readResults(stream, valueType);
190 auto results = readResults(stream, valueType);
191
191
192 // Creates data series
192 // Creates data series
193 switch (valueType) {
193 switch (valueType) {
194 case ValueType::SCALAR:
194 case ValueType::SCALAR:
195 Q_ASSERT(results.second.size() == 1);
195 Q_ASSERT(results.second.size() == 1);
196 return std::make_shared<ScalarSeries>(
196 return std::make_shared<ScalarSeries>(
197 std::move(results.first), std::move(results.second.takeFirst()), xAxisUnit, Unit{});
197 std::move(results.first.toStdVector()),
198 std::move(results.second.takeFirst().toStdVector()), xAxisUnit, Unit{});
198 case ValueType::VECTOR: {
199 case ValueType::VECTOR: {
199 Q_ASSERT(results.second.size() == 3);
200 Q_ASSERT(results.second.size() == 3);
200 auto xValues = results.second.takeFirst();
201 auto xValues = results.second.takeFirst().toStdVector();
201 auto yValues = results.second.takeFirst();
202 auto yValues = results.second.takeFirst().toStdVector();
202 auto zValues = results.second.takeFirst();
203 auto zValues = results.second.takeFirst().toStdVector();
203 return std::make_shared<VectorSeries>(std::move(results.first), std::move(xValues),
204 return std::make_shared<VectorSeries>(std::move(results.first.toStdVector()),
204 std::move(yValues), std::move(zValues), xAxisUnit,
205 std::move(xValues), std::move(yValues),
205 Unit{});
206 std::move(zValues), xAxisUnit, Unit{});
206 }
207 }
207 case ValueType::UNKNOWN:
208 case ValueType::UNKNOWN:
208 // Invalid case
209 // Invalid case
209 break;
210 break;
210 }
211 }
211
212
212 // Invalid cases
213 // Invalid cases
213 qCCritical(LOG_AmdaResultParser())
214 qCCritical(LOG_AmdaResultParser())
214 << QObject::tr("Can't create data series: unsupported value type");
215 << QObject::tr("Can't create data series: unsupported value type");
215 return nullptr;
216 return nullptr;
216 }
217 }
@@ -1,103 +1,103
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2
2
3 #include <Data/DataProviderParameters.h>
3 #include <Data/DataProviderParameters.h>
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5
5
6 #include <cmath>
6 #include <cmath>
7
7
8 #include <QFuture>
8 #include <QFuture>
9 #include <QThread>
9 #include <QThread>
10 #include <QtConcurrent/QtConcurrent>
10 #include <QtConcurrent/QtConcurrent>
11
11
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
12 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
13
13
14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
14 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
15 const SqpRange &dataRangeRequested)
15 const SqpRange &dataRangeRequested)
16 {
16 {
17 // TODO: Add Mutex
17 // TODO: Add Mutex
18 auto dataIndex = 0;
18 auto dataIndex = 0;
19
19
20 // Gets the timerange from the parameters
20 // Gets the timerange from the parameters
21 double freq = 1.0;
21 double freq = 100.0;
22 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
22 double start = std::ceil(dataRangeRequested.m_TStart * freq); // 100 htz
23 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
23 double end = std::floor(dataRangeRequested.m_TEnd * freq); // 100 htz
24
24
25 // We assure that timerange is valid
25 // We assure that timerange is valid
26 if (end < start) {
26 if (end < start) {
27 std::swap(start, end);
27 std::swap(start, end);
28 }
28 }
29
29
30 // Generates scalar series containing cosinus values (one value per second)
30 // Generates scalar series containing cosinus values (one value per second)
31 auto dataCount = end - start;
31 auto dataCount = end - start;
32
32
33 auto xAxisData = QVector<double>{};
33 auto xAxisData = std::vector<double>{};
34 xAxisData.resize(dataCount);
34 xAxisData.resize(dataCount);
35
35
36 auto valuesData = QVector<double>{};
36 auto valuesData = std::vector<double>{};
37 valuesData.resize(dataCount);
37 valuesData.resize(dataCount);
38
38
39 int progress = 0;
39 int progress = 0;
40 auto progressEnd = dataCount;
40 auto progressEnd = dataCount;
41 for (auto time = start; time < end; ++time, ++dataIndex) {
41 for (auto time = start; time < end; ++time, ++dataIndex) {
42 auto it = m_VariableToEnableProvider.find(acqIdentifier);
42 auto it = m_VariableToEnableProvider.find(acqIdentifier);
43 if (it != m_VariableToEnableProvider.end() && it.value()) {
43 if (it != m_VariableToEnableProvider.end() && it.value()) {
44 const auto timeOnFreq = time / freq;
44 const auto timeOnFreq = time / freq;
45
45
46 xAxisData.replace(dataIndex, timeOnFreq);
46 xAxisData[dataIndex] = timeOnFreq;
47 valuesData.replace(dataIndex, std::cos(timeOnFreq));
47 valuesData[dataIndex] = std::cos(timeOnFreq);
48
48
49 // progression
49 // progression
50 int currentProgress = (time - start) * 100.0 / progressEnd;
50 int currentProgress = (time - start) * 100.0 / progressEnd;
51 if (currentProgress != progress) {
51 if (currentProgress != progress) {
52 progress = currentProgress;
52 progress = currentProgress;
53
53
54 emit dataProvidedProgress(acqIdentifier, progress);
54 emit dataProvidedProgress(acqIdentifier, progress);
55 }
55 }
56 }
56 }
57 else {
57 else {
58 if (!it.value()) {
58 if (!it.value()) {
59 qCDebug(LOG_CosinusProvider())
59 qCDebug(LOG_CosinusProvider())
60 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
60 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
61 << end - time;
61 << end - time;
62 }
62 }
63 }
63 }
64 }
64 }
65 emit dataProvidedProgress(acqIdentifier, 0.0);
65 emit dataProvidedProgress(acqIdentifier, 0.0);
66
66
67 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
67 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
68 Unit{QStringLiteral("t"), true}, Unit{});
68 Unit{QStringLiteral("t"), true}, Unit{});
69 }
69 }
70
70
71 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
71 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
72 const DataProviderParameters &parameters)
72 const DataProviderParameters &parameters)
73 {
73 {
74 // TODO: Add Mutex
74 // TODO: Add Mutex
75 m_VariableToEnableProvider[acqIdentifier] = true;
75 m_VariableToEnableProvider[acqIdentifier] = true;
76 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
76 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
77 << QThread::currentThread()->objectName();
77 << QThread::currentThread()->objectName();
78 // NOTE: Try to use multithread if possible
78 // NOTE: Try to use multithread if possible
79 const auto times = parameters.m_Times;
79 const auto times = parameters.m_Times;
80
80
81 for (const auto &dateTime : qAsConst(times)) {
81 for (const auto &dateTime : qAsConst(times)) {
82 if (m_VariableToEnableProvider[acqIdentifier]) {
82 if (m_VariableToEnableProvider[acqIdentifier]) {
83 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
83 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime);
84 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
84 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::dataProvided";
85 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
85 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
86 }
86 }
87 }
87 }
88 }
88 }
89
89
90 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
90 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
91 {
91 {
92 // TODO: Add Mutex
92 // TODO: Add Mutex
93 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
93 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
94 << QThread::currentThread()->objectName();
94 << QThread::currentThread()->objectName();
95 auto it = m_VariableToEnableProvider.find(acqIdentifier);
95 auto it = m_VariableToEnableProvider.find(acqIdentifier);
96 if (it != m_VariableToEnableProvider.end()) {
96 if (it != m_VariableToEnableProvider.end()) {
97 it.value() = false;
97 it.value() = false;
98 }
98 }
99 else {
99 else {
100 qCWarning(LOG_CosinusProvider())
100 qCWarning(LOG_CosinusProvider())
101 << tr("Aborting progression of inexistant identifier detected !!!");
101 << tr("Aborting progression of inexistant identifier detected !!!");
102 }
102 }
103 }
103 }
General Comments 0
You need to be logged in to leave comments. Login now