##// END OF EJS Templates
Merge branch 'feature/DataSeriesIterator' into develop
Alexandre Leroux -
r559:575b804cd7dd merge
parent child
Show More
@@ -1,230 +1,298
1 1 #ifndef SCIQLOP_ARRAYDATA_H
2 2 #define SCIQLOP_ARRAYDATA_H
3 3
4 4 #include <Common/SortUtils.h>
5 5
6 6 #include <QReadLocker>
7 7 #include <QReadWriteLock>
8 8 #include <QVector>
9 9
10 10 #include <memory>
11 11
12 12 template <int Dim>
13 13 class ArrayData;
14 14
15 15 using DataContainer = QVector<QVector<double> >;
16 16
17 17 namespace arraydata_detail {
18 18
19 19 /// Struct used to sort ArrayData
20 20 template <int Dim>
21 21 struct Sort {
22 22 static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data,
23 23 const std::vector<int> &sortPermutation)
24 24 {
25 25 auto nbComponents = data.size();
26 26 auto sortedData = DataContainer(nbComponents);
27 27
28 28 for (auto i = 0; i < nbComponents; ++i) {
29 29 sortedData[i] = SortUtils::sort(data.at(i), sortPermutation);
30 30 }
31 31
32 32 return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
33 33 }
34 34 };
35 35
36 36 /// Specialization for uni-dimensional ArrayData
37 37 template <>
38 38 struct Sort<1> {
39 39 static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data,
40 40 const std::vector<int> &sortPermutation)
41 41 {
42 42 return std::make_shared<ArrayData<1> >(SortUtils::sort(data.at(0), sortPermutation));
43 43 }
44 44 };
45 45
46 46 } // namespace arraydata_detail
47 47
48 48 /**
49 49 * @brief The ArrayData class represents a dataset for a data series.
50 50 *
51 51 * A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
52 52 * template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
53 53 * number of values
54 54 *
55 55 * @tparam Dim the dimension of the ArrayData (one or two)
56 56 * @sa IDataSeries
57 57 */
58 58 template <int Dim>
59 59 class ArrayData {
60 60 public:
61 class IteratorValue {
62 public:
63 explicit IteratorValue(const DataContainer &container, bool begin) : m_Its{}
64 {
65 for (auto i = 0; i < container.size(); ++i) {
66 m_Its.push_back(begin ? container.at(i).cbegin() : container.at(i).cend());
67 }
68 }
69
70 double at(int index) const { return *m_Its.at(index); }
71 double first() const { return *m_Its.front(); }
72
73 void next()
74 {
75 for (auto &it : m_Its) {
76 ++it;
77 }
78 }
79
80 bool operator==(const IteratorValue &other) const { return m_Its == other.m_Its; }
81
82 private:
83 std::vector<DataContainer::value_type::const_iterator> m_Its;
84 };
85
86 class Iterator {
87 public:
88 using iterator_category = std::forward_iterator_tag;
89 using value_type = const IteratorValue;
90 using difference_type = std::ptrdiff_t;
91 using pointer = value_type *;
92 using reference = value_type &;
93
94 Iterator(const DataContainer &container, bool begin) : m_CurrentValue{container, begin} {}
95
96 virtual ~Iterator() noexcept = default;
97 Iterator(const Iterator &) = default;
98 Iterator(Iterator &&) = default;
99 Iterator &operator=(const Iterator &) = default;
100 Iterator &operator=(Iterator &&) = default;
101
102 Iterator &operator++()
103 {
104 m_CurrentValue.next();
105 return *this;
106 }
107
108 pointer operator->() const { return &m_CurrentValue; }
109 reference operator*() const { return m_CurrentValue; }
110
111 bool operator==(const Iterator &other) const
112 {
113 return m_CurrentValue == other.m_CurrentValue;
114 }
115
116 bool operator!=(const Iterator &other) const { return !(*this == other); }
117
118 private:
119 IteratorValue m_CurrentValue;
120 };
121
61 122 // ///// //
62 123 // Ctors //
63 124 // ///// //
64 125
65 126 /**
66 127 * Ctor for a unidimensional ArrayData
67 128 * @param data the data the ArrayData will hold
68 129 */
69 130 template <int D = Dim, typename = std::enable_if_t<D == 1> >
70 131 explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
71 132 {
72 133 m_Data[0] = std::move(data);
73 134 }
74 135
75 136 /**
76 137 * Ctor for a two-dimensional ArrayData. The number of components (number of vectors) must be
77 138 * greater than 2 and each component must have the same number of values
78 139 * @param data the data the ArrayData will hold
79 140 * @throws std::invalid_argument if the number of components is less than 2
80 141 * @remarks if the number of values is not the same for each component, no value is set
81 142 */
82 143 template <int D = Dim, typename = std::enable_if_t<D == 2> >
83 144 explicit ArrayData(DataContainer data)
84 145 {
85 146 auto nbComponents = data.size();
86 147 if (nbComponents < 2) {
87 148 throw std::invalid_argument{
88 149 QString{"A multidimensional ArrayData must have at least 2 components (found: %1"}
89 150 .arg(data.size())
90 151 .toStdString()};
91 152 }
92 153
93 154 auto nbValues = data.front().size();
94 155 if (std::all_of(data.cbegin(), data.cend(), [nbValues](const auto &component) {
95 156 return component.size() == nbValues;
96 157 })) {
97 158 m_Data = std::move(data);
98 159 }
99 160 else {
100 161 m_Data = DataContainer{nbComponents, QVector<double>{}};
101 162 }
102 163 }
103 164
104 165 /// Copy ctor
105 166 explicit ArrayData(const ArrayData &other)
106 167 {
107 168 QReadLocker otherLocker{&other.m_Lock};
108 169 m_Data = other.m_Data;
109 170 }
110 171
111 172 // /////////////// //
112 173 // General methods //
113 174 // /////////////// //
114 175
115 176 /**
116 177 * Merges into the array data an other array data. The two array datas must have the same number
117 178 * of components so the merge can be done
118 179 * @param other the array data to merge with
119 180 * @param prepend if true, the other array data is inserted at the beginning, otherwise it is
120 181 * inserted at the end
121 182 */
122 183 void add(const ArrayData<Dim> &other, bool prepend = false)
123 184 {
124 185 QWriteLocker locker{&m_Lock};
125 186 QReadLocker otherLocker{&other.m_Lock};
126 187
127 188 auto nbComponents = m_Data.size();
128 189 if (nbComponents != other.m_Data.size()) {
129 190 return;
130 191 }
131 192
132 193 for (auto componentIndex = 0; componentIndex < nbComponents; ++componentIndex) {
133 194 if (prepend) {
134 195 const auto &otherData = other.data(componentIndex);
135 196 const auto otherDataSize = otherData.size();
136 197
137 198 auto &data = m_Data[componentIndex];
138 199 data.insert(data.begin(), otherDataSize, 0.);
139 200
140 201 for (auto i = 0; i < otherDataSize; ++i) {
141 202 data.replace(i, otherData.at(i));
142 203 }
143 204 }
144 205 else {
145 206 m_Data[componentIndex] += other.data(componentIndex);
146 207 }
147 208 }
148 209 }
149 210
150 211 void clear()
151 212 {
152 213 QWriteLocker locker{&m_Lock};
153 214
154 215 auto nbComponents = m_Data.size();
155 216 for (auto i = 0; i < nbComponents; ++i) {
156 217 m_Data[i].clear();
157 218 }
158 219 }
159 220
160 221 /**
161 222 * @return the data of a component
162 223 * @param componentIndex the index of the component to retrieve the data
163 224 * @return the component's data, empty vector if the index is invalid
164 225 */
165 226 QVector<double> data(int componentIndex) const noexcept
166 227 {
167 228 QReadLocker locker{&m_Lock};
168 229
169 230 return (componentIndex >= 0 && componentIndex < m_Data.size()) ? m_Data.at(componentIndex)
170 231 : QVector<double>{};
171 232 }
172 233
173 234 /// @return the size (i.e. number of values) of a single component
174 235 /// @remarks in a case of a two-dimensional ArrayData, each component has the same size
175 236 int size() const
176 237 {
177 238 QReadLocker locker{&m_Lock};
178 239 return m_Data[0].size();
179 240 }
180 241
181 242 std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
182 243 {
183 244 QReadLocker locker{&m_Lock};
184 245 return arraydata_detail::Sort<Dim>::sort(m_Data, sortPermutation);
185 246 }
186 247
248 // ///////// //
249 // Iterators //
250 // ///////// //
251
252 Iterator cbegin() const { return Iterator{m_Data, true}; }
253 Iterator cend() const { return Iterator{m_Data, false}; }
254
187 255 // ///////////// //
188 256 // 1-dim methods //
189 257 // ///////////// //
190 258
191 259 /**
192 260 * @return the data at a specified index
193 261 * @remarks index must be a valid position
194 262 * @remarks this method is only available for a unidimensional ArrayData
195 263 */
196 264 template <int D = Dim, typename = std::enable_if_t<D == 1> >
197 265 double at(int index) const noexcept
198 266 {
199 267 QReadLocker locker{&m_Lock};
200 268 return m_Data[0].at(index);
201 269 }
202 270
203 271 /**
204 272 * @return the data as a vector, as a const reference
205 273 * @remarks this method is only available for a unidimensional ArrayData
206 274 */
207 275 template <int D = Dim, typename = std::enable_if_t<D == 1> >
208 276 const QVector<double> &cdata() const noexcept
209 277 {
210 278 QReadLocker locker{&m_Lock};
211 279 return m_Data.at(0);
212 280 }
213 281
214 282 /**
215 283 * @return the data as a vector
216 284 * @remarks this method is only available for a unidimensional ArrayData
217 285 */
218 286 template <int D = Dim, typename = std::enable_if_t<D == 1> >
219 287 QVector<double> data() const noexcept
220 288 {
221 289 QReadLocker locker{&m_Lock};
222 290 return m_Data[0];
223 291 }
224 292
225 293 private:
226 294 DataContainer m_Data;
227 295 mutable QReadWriteLock m_Lock;
228 296 };
229 297
230 298 #endif // SCIQLOP_ARRAYDATA_H
@@ -1,190 +1,288
1 1 #ifndef SCIQLOP_DATASERIES_H
2 2 #define SCIQLOP_DATASERIES_H
3 3
4 4 #include <Common/SortUtils.h>
5 5
6 6 #include <Data/ArrayData.h>
7 7 #include <Data/IDataSeries.h>
8 8
9 9 #include <QLoggingCategory>
10 10
11 11 #include <QReadLocker>
12 12 #include <QReadWriteLock>
13 13 #include <memory>
14 14
15 15 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeries)
16 16 Q_LOGGING_CATEGORY(LOG_DataSeries, "DataSeries")
17 17
18 18
19 19 /**
20 20 * @brief The DataSeries class is the base (abstract) implementation of IDataSeries.
21 21 *
22 22 * It proposes to set a dimension for the values ​​data.
23 23 *
24 24 * A DataSeries is always sorted on its x-axis data.
25 25 *
26 26 * @tparam Dim The dimension of the values data
27 27 *
28 28 */
29 29 template <int Dim>
30 30 class DataSeries : public IDataSeries {
31 31 public:
32 class IteratorValue {
33 public:
34 explicit IteratorValue(const DataSeries &dataSeries, bool begin)
35 : m_XIt(begin ? dataSeries.xAxisData()->cbegin() : dataSeries.xAxisData()->cend()),
36 m_ValuesIt(begin ? dataSeries.valuesData()->cbegin()
37 : dataSeries.valuesData()->cend())
38 {
39 }
40
41 double x() const { return m_XIt->at(0); }
42 double value() const { return m_ValuesIt->at(0); }
43 double value(int componentIndex) const { return m_ValuesIt->at(componentIndex); }
44
45 void next()
46 {
47 ++m_XIt;
48 ++m_ValuesIt;
49 }
50
51 bool operator==(const IteratorValue &other) const
52 {
53 return std::tie(m_XIt, m_ValuesIt) == std::tie(other.m_XIt, other.m_ValuesIt);
54 }
55
56 private:
57 ArrayData<1>::Iterator m_XIt;
58 typename ArrayData<Dim>::Iterator m_ValuesIt;
59 };
60
61 class Iterator {
62 public:
63 using iterator_category = std::forward_iterator_tag;
64 using value_type = const IteratorValue;
65 using difference_type = std::ptrdiff_t;
66 using pointer = value_type *;
67 using reference = value_type &;
68
69 Iterator(const DataSeries &dataSeries, bool begin) : m_CurrentValue{dataSeries, begin} {}
70 virtual ~Iterator() noexcept = default;
71 Iterator(const Iterator &) = default;
72 Iterator(Iterator &&) = default;
73 Iterator &operator=(const Iterator &) = default;
74 Iterator &operator=(Iterator &&) = default;
75
76 Iterator &operator++()
77 {
78 m_CurrentValue.next();
79 return *this;
80 }
81
82 pointer operator->() const { return &m_CurrentValue; }
83
84 reference operator*() const { return m_CurrentValue; }
85
86 bool operator==(const Iterator &other) const
87 {
88 return m_CurrentValue == other.m_CurrentValue;
89 }
90
91 bool operator!=(const Iterator &other) const { return !(*this == other); }
92
93 private:
94 IteratorValue m_CurrentValue;
95 };
96
32 97 /// @sa IDataSeries::xAxisData()
33 98 std::shared_ptr<ArrayData<1> > xAxisData() override { return m_XAxisData; }
34 99 const std::shared_ptr<ArrayData<1> > xAxisData() const { return m_XAxisData; }
35 100
36 101 /// @sa IDataSeries::xAxisUnit()
37 102 Unit xAxisUnit() const override { return m_XAxisUnit; }
38 103
39 104 /// @return the values dataset
40 105 std::shared_ptr<ArrayData<Dim> > valuesData() { return m_ValuesData; }
41 106 const std::shared_ptr<ArrayData<Dim> > valuesData() const { return m_ValuesData; }
42 107
43 108 /// @sa IDataSeries::valuesUnit()
44 109 Unit valuesUnit() const override { return m_ValuesUnit; }
45 110
46 111
47 112 SqpRange range() const override
48 113 {
49 114 if (!m_XAxisData->cdata().isEmpty()) {
50 115 return SqpRange{m_XAxisData->cdata().first(), m_XAxisData->cdata().last()};
51 116 }
52 117
53 118 return SqpRange{};
54 119 }
55 120
56 121 void clear()
57 122 {
58 123 m_XAxisData->clear();
59 124 m_ValuesData->clear();
60 125 }
61 126
62 127 /// Merges into the data series an other data series
63 128 /// @remarks the data series to merge with is cleared after the operation
64 129 void merge(IDataSeries *dataSeries) override
65 130 {
66 131 dataSeries->lockWrite();
67 132 lockWrite();
68 133
69 134 if (auto other = dynamic_cast<DataSeries<Dim> *>(dataSeries)) {
70 135 const auto &otherXAxisData = other->xAxisData()->cdata();
71 136 const auto &xAxisData = m_XAxisData->cdata();
72 137
73 138 // As data series are sorted, we can improve performances of merge, by call the sort
74 139 // method only if the two data series overlap.
75 140 if (!otherXAxisData.empty()) {
76 141 auto firstValue = otherXAxisData.front();
77 142 auto lastValue = otherXAxisData.back();
78 143
79 144 auto xAxisDataBegin = xAxisData.cbegin();
80 145 auto xAxisDataEnd = xAxisData.cend();
81 146
82 147 bool prepend;
83 148 bool sortNeeded;
84 149
85 150 if (std::lower_bound(xAxisDataBegin, xAxisDataEnd, firstValue) == xAxisDataEnd) {
86 151 // Other data series if after data series
87 152 prepend = false;
88 153 sortNeeded = false;
89 154 }
90 155 else if (std::upper_bound(xAxisDataBegin, xAxisDataEnd, lastValue)
91 156 == xAxisDataBegin) {
92 157 // Other data series if before data series
93 158 prepend = true;
94 159 sortNeeded = false;
95 160 }
96 161 else {
97 162 // The two data series overlap
98 163 prepend = false;
99 164 sortNeeded = true;
100 165 }
101 166
102 167 // Makes the merge
103 168 m_XAxisData->add(*other->xAxisData(), prepend);
104 169 m_ValuesData->add(*other->valuesData(), prepend);
105 170
106 171 if (sortNeeded) {
107 172 sort();
108 173 }
109 174 }
110 175
111 176 // Clears the other data series
112 177 other->clear();
113 178 }
114 179 else {
115 180 qCWarning(LOG_DataSeries())
116 181 << QObject::tr("Detection of a type of IDataSeries we cannot merge with !");
117 182 }
118 183 unlock();
119 184 dataSeries->unlock();
120 185 }
121 186
187 // ///////// //
188 // Iterators //
189 // ///////// //
190
191 Iterator cbegin() const { return Iterator{*this, true}; }
192
193 Iterator cend() const { return Iterator{*this, false}; }
194
195 std::pair<Iterator, Iterator> subData(double min, double max) const
196 {
197 if (min > max) {
198 std::swap(min, max);
199 }
200
201 auto begin = cbegin();
202 auto end = cend();
203
204 auto lowerIt
205 = std::lower_bound(begin, end, min, [](const auto &itValue, const auto &value) {
206 return itValue.x() == value;
207 });
208 auto upperIt
209 = std::upper_bound(begin, end, max, [](const auto &value, const auto &itValue) {
210 return itValue.x() == value;
211 });
212
213 return std::make_pair(lowerIt, upperIt);
214 }
215
216 // /////// //
217 // Mutexes //
218 // /////// //
219
122 220 virtual void lockRead() { m_Lock.lockForRead(); }
123 221 virtual void lockWrite() { m_Lock.lockForWrite(); }
124 222 virtual void unlock() { m_Lock.unlock(); }
125 223
126 224 protected:
127 225 /// Protected ctor (DataSeries is abstract). The vectors must have the same size, otherwise a
128 226 /// DataSeries with no values will be created.
129 227 /// @remarks data series is automatically sorted on its x-axis data
130 228 explicit DataSeries(std::shared_ptr<ArrayData<1> > xAxisData, const Unit &xAxisUnit,
131 229 std::shared_ptr<ArrayData<Dim> > valuesData, const Unit &valuesUnit)
132 230 : m_XAxisData{xAxisData},
133 231 m_XAxisUnit{xAxisUnit},
134 232 m_ValuesData{valuesData},
135 233 m_ValuesUnit{valuesUnit}
136 234 {
137 235 if (m_XAxisData->size() != m_ValuesData->size()) {
138 236 clear();
139 237 }
140 238
141 239 // Sorts data if it's not the case
142 240 const auto &xAxisCData = m_XAxisData->cdata();
143 241 if (!std::is_sorted(xAxisCData.cbegin(), xAxisCData.cend())) {
144 242 sort();
145 243 }
146 244 }
147 245
148 246 /// Copy ctor
149 247 explicit DataSeries(const DataSeries<Dim> &other)
150 248 : m_XAxisData{std::make_shared<ArrayData<1> >(*other.m_XAxisData)},
151 249 m_XAxisUnit{other.m_XAxisUnit},
152 250 m_ValuesData{std::make_shared<ArrayData<Dim> >(*other.m_ValuesData)},
153 251 m_ValuesUnit{other.m_ValuesUnit}
154 252 {
155 253 // Since a series is ordered from its construction and is always ordered, it is not
156 254 // necessary to call the sort method here ('other' is sorted)
157 255 }
158 256
159 257 /// Assignment operator
160 258 template <int D>
161 259 DataSeries &operator=(DataSeries<D> other)
162 260 {
163 261 std::swap(m_XAxisData, other.m_XAxisData);
164 262 std::swap(m_XAxisUnit, other.m_XAxisUnit);
165 263 std::swap(m_ValuesData, other.m_ValuesData);
166 264 std::swap(m_ValuesUnit, other.m_ValuesUnit);
167 265
168 266 return *this;
169 267 }
170 268
171 269 private:
172 270 /**
173 271 * Sorts data series on its x-axis data
174 272 */
175 273 void sort() noexcept
176 274 {
177 275 auto permutation = SortUtils::sortPermutation(*m_XAxisData, std::less<double>());
178 276 m_XAxisData = m_XAxisData->sort(permutation);
179 277 m_ValuesData = m_ValuesData->sort(permutation);
180 278 }
181 279
182 280 std::shared_ptr<ArrayData<1> > m_XAxisData;
183 281 Unit m_XAxisUnit;
184 282 std::shared_ptr<ArrayData<Dim> > m_ValuesData;
185 283 Unit m_ValuesUnit;
186 284
187 285 QReadWriteLock m_Lock;
188 286 };
189 287
190 288 #endif // SCIQLOP_DATASERIES_H
@@ -1,72 +1,73
1 1 #ifndef SCIQLOP_IDATASERIES_H
2 2 #define SCIQLOP_IDATASERIES_H
3 3
4 4 #include <Common/MetaTypes.h>
5 5 #include <Data/SqpRange.h>
6 6
7 7 #include <memory>
8 8
9 9 #include <QString>
10 10
11 11 template <int Dim>
12 12 class ArrayData;
13 13
14 14 struct Unit {
15 15 explicit Unit(const QString &name = {}, bool timeUnit = false)
16 16 : m_Name{name}, m_TimeUnit{timeUnit}
17 17 {
18 18 }
19 19
20 20 inline bool operator==(const Unit &other) const
21 21 {
22 22 return std::tie(m_Name, m_TimeUnit) == std::tie(other.m_Name, other.m_TimeUnit);
23 23 }
24 24 inline bool operator!=(const Unit &other) const { return !(*this == other); }
25 25
26 26 QString m_Name; ///< Unit name
27 27 bool m_TimeUnit; ///< The unit is a unit of time (UTC)
28 28 };
29 29
30 30 /**
31 31 * @brief The IDataSeries aims to declare a data series.
32 32 *
33 33 * A data series is an entity that contains at least :
34 34 * - one dataset representing the x-axis
35 35 * - one dataset representing the values
36 36 *
37 37 * Each dataset is represented by an ArrayData, and is associated with a unit.
38 38 *
39 39 * An ArrayData can be unidimensional or two-dimensional, depending on the implementation of the
40 40 * IDataSeries. The x-axis dataset is always unidimensional.
41 41 *
42 42 * @sa ArrayData
43 43 */
44 44 class IDataSeries {
45 45 public:
46 46 virtual ~IDataSeries() noexcept = default;
47 47
48 48 /// Returns the x-axis dataset
49 49 virtual std::shared_ptr<ArrayData<1> > xAxisData() = 0;
50 50
51 51 /// Returns the x-axis dataset (as const)
52 52 virtual const std::shared_ptr<ArrayData<1> > xAxisData() const = 0;
53 53
54 54 virtual Unit xAxisUnit() const = 0;
55 55
56 56 virtual Unit valuesUnit() const = 0;
57 57
58 58 virtual void merge(IDataSeries *dataSeries) = 0;
59 virtual std::shared_ptr<IDataSeries> subData(const SqpRange &range) = 0;
59 /// @todo Review the name and signature of this method
60 virtual std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) = 0;
60 61
61 62 virtual std::unique_ptr<IDataSeries> clone() const = 0;
62 63 virtual SqpRange range() const = 0;
63 64
64 65 virtual void lockRead() = 0;
65 66 virtual void lockWrite() = 0;
66 67 virtual void unlock() = 0;
67 68 };
68 69
69 70 // Required for using shared_ptr in signals/slots
70 71 SCIQLOP_REGISTER_META_TYPE(IDATASERIES_PTR_REGISTRY, std::shared_ptr<IDataSeries>)
71 72
72 73 #endif // SCIQLOP_IDATASERIES_H
@@ -1,27 +1,27
1 1 #ifndef SCIQLOP_SCALARSERIES_H
2 2 #define SCIQLOP_SCALARSERIES_H
3 3
4 4 #include "CoreGlobal.h"
5 5
6 6 #include <Data/DataSeries.h>
7 7
8 8 /**
9 9 * @brief The ScalarSeries class is the implementation for a data series representing a scalar.
10 10 */
11 11 class SCIQLOP_CORE_EXPORT ScalarSeries : public DataSeries<1> {
12 12 public:
13 13 /**
14 14 * Ctor with two vectors. The vectors must have the same size, otherwise a ScalarSeries with no
15 15 * values will be created.
16 16 * @param xAxisData x-axis data
17 17 * @param valuesData values data
18 18 */
19 19 explicit ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
20 20 const Unit &xAxisUnit, const Unit &valuesUnit);
21 21
22 22 std::unique_ptr<IDataSeries> clone() const override;
23 23
24 std::shared_ptr<IDataSeries> subData(const SqpRange &range) override;
24 std::shared_ptr<IDataSeries> subDataSeries(const SqpRange &range) override;
25 25 };
26 26
27 27 #endif // SCIQLOP_SCALARSERIES_H
@@ -1,41 +1,41
1 1 #include <Data/ScalarSeries.h>
2 2
3 3 ScalarSeries::ScalarSeries(QVector<double> xAxisData, QVector<double> valuesData,
4 4 const Unit &xAxisUnit, const Unit &valuesUnit)
5 5 : DataSeries{std::make_shared<ArrayData<1> >(std::move(xAxisData)), xAxisUnit,
6 6 std::make_shared<ArrayData<1> >(std::move(valuesData)), valuesUnit}
7 7 {
8 8 }
9 9
10 10 std::unique_ptr<IDataSeries> ScalarSeries::clone() const
11 11 {
12 12 return std::make_unique<ScalarSeries>(*this);
13 13 }
14 14
15 std::shared_ptr<IDataSeries> ScalarSeries::subData(const SqpRange &range)
15 std::shared_ptr<IDataSeries> ScalarSeries::subDataSeries(const SqpRange &range)
16 16 {
17 17 auto subXAxisData = QVector<double>();
18 18 auto subValuesData = QVector<double>();
19 19 this->lockRead();
20 20 {
21 21 const auto &currentXData = this->xAxisData()->cdata();
22 22 const auto &currentValuesData = this->valuesData()->cdata();
23 23
24 24 auto xDataBegin = currentXData.cbegin();
25 25 auto xDataEnd = currentXData.cend();
26 26
27 27 auto lowerIt = std::lower_bound(xDataBegin, xDataEnd, range.m_TStart);
28 28 auto upperIt = std::upper_bound(xDataBegin, xDataEnd, range.m_TEnd);
29 29 auto distance = std::distance(xDataBegin, lowerIt);
30 30
31 31 auto valuesDataIt = currentValuesData.cbegin() + distance;
32 32 for (auto xAxisDataIt = lowerIt; xAxisDataIt != upperIt; ++xAxisDataIt, ++valuesDataIt) {
33 33 subXAxisData.append(*xAxisDataIt);
34 34 subValuesData.append(*valuesDataIt);
35 35 }
36 36 }
37 37 this->unlock();
38 38
39 39 return std::make_shared<ScalarSeries>(subXAxisData, subValuesData, this->xAxisUnit(),
40 40 this->valuesUnit());
41 41 }
@@ -1,211 +1,211
1 1 #include "Variable/Variable.h"
2 2
3 3 #include <Data/IDataSeries.h>
4 4 #include <Data/SqpRange.h>
5 5
6 6 #include <QMutex>
7 7 #include <QReadWriteLock>
8 8 #include <QThread>
9 9
10 10 Q_LOGGING_CATEGORY(LOG_Variable, "Variable")
11 11
12 12 struct Variable::VariablePrivate {
13 13 explicit VariablePrivate(const QString &name, const SqpRange &dateTime,
14 14 const QVariantHash &metadata)
15 15 : m_Name{name}, m_Range{dateTime}, m_Metadata{metadata}, m_DataSeries{nullptr}
16 16 {
17 17 }
18 18
19 19 void lockRead() { m_Lock.lockForRead(); }
20 20 void lockWrite() { m_Lock.lockForWrite(); }
21 21 void unlock() { m_Lock.unlock(); }
22 22
23 23 QString m_Name;
24 24
25 25 SqpRange m_Range;
26 26 SqpRange m_CacheRange;
27 27 QVariantHash m_Metadata;
28 28 std::shared_ptr<IDataSeries> m_DataSeries;
29 29
30 30 QReadWriteLock m_Lock;
31 31 };
32 32
33 33 Variable::Variable(const QString &name, const SqpRange &dateTime, const QVariantHash &metadata)
34 34 : impl{spimpl::make_unique_impl<VariablePrivate>(name, dateTime, metadata)}
35 35 {
36 36 }
37 37
38 38 QString Variable::name() const noexcept
39 39 {
40 40 impl->lockRead();
41 41 auto name = impl->m_Name;
42 42 impl->unlock();
43 43 return name;
44 44 }
45 45
46 46 SqpRange Variable::range() const noexcept
47 47 {
48 48 impl->lockRead();
49 49 auto range = impl->m_Range;
50 50 impl->unlock();
51 51 return range;
52 52 }
53 53
54 54 void Variable::setRange(const SqpRange &range) noexcept
55 55 {
56 56 impl->lockWrite();
57 57 impl->m_Range = range;
58 58 impl->unlock();
59 59 }
60 60
61 61 SqpRange Variable::cacheRange() const noexcept
62 62 {
63 63 impl->lockRead();
64 64 auto cacheRange = impl->m_CacheRange;
65 65 impl->unlock();
66 66 return cacheRange;
67 67 }
68 68
69 69 void Variable::setCacheRange(const SqpRange &cacheRange) noexcept
70 70 {
71 71 impl->lockWrite();
72 72 impl->m_CacheRange = cacheRange;
73 73 impl->unlock();
74 74 }
75 75
76 76 void Variable::setDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
77 77 {
78 78 qCDebug(LOG_Variable()) << "TORM Variable::setDataSeries"
79 79 << QThread::currentThread()->objectName();
80 80 if (!dataSeries) {
81 81 /// @todo ALX : log
82 82 return;
83 83 }
84 84 impl->lockWrite();
85 85 impl->m_DataSeries = dataSeries->clone();
86 86 impl->unlock();
87 87 }
88 88
89 89 void Variable::mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept
90 90 {
91 91 qCDebug(LOG_Variable()) << "TORM Variable::mergeDataSeries"
92 92 << QThread::currentThread()->objectName();
93 93 if (!dataSeries) {
94 94 /// @todo ALX : log
95 95 return;
96 96 }
97 97
98 98 // Add or merge the data
99 99 // Inits the data series of the variable
100 100 impl->lockWrite();
101 101 if (!impl->m_DataSeries) {
102 102 impl->m_DataSeries = dataSeries->clone();
103 103 }
104 104 else {
105 105 impl->m_DataSeries->merge(dataSeries.get());
106 106 }
107 107 impl->unlock();
108 108
109 109 // sub the data
110 auto subData = this->dataSeries()->subData(this->cacheRange());
110 auto subData = this->dataSeries()->subDataSeries(this->cacheRange());
111 111 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries sub" << subData->range();
112 112 this->setDataSeries(subData);
113 113 qCDebug(LOG_Variable()) << "TORM: Variable::mergeDataSeries set" << this->dataSeries()->range();
114 114 }
115 115
116 116 std::shared_ptr<IDataSeries> Variable::dataSeries() const noexcept
117 117 {
118 118 impl->lockRead();
119 119 auto dataSeries = impl->m_DataSeries;
120 120 impl->unlock();
121 121
122 122 return dataSeries;
123 123 }
124 124
125 125 QVariantHash Variable::metadata() const noexcept
126 126 {
127 127 impl->lockRead();
128 128 auto metadata = impl->m_Metadata;
129 129 impl->unlock();
130 130 return metadata;
131 131 }
132 132
133 133 bool Variable::contains(const SqpRange &range) const noexcept
134 134 {
135 135 impl->lockRead();
136 136 auto res = impl->m_Range.contains(range);
137 137 impl->unlock();
138 138 return res;
139 139 }
140 140
141 141 bool Variable::intersect(const SqpRange &range) const noexcept
142 142 {
143 143
144 144 impl->lockRead();
145 145 auto res = impl->m_Range.intersect(range);
146 146 impl->unlock();
147 147 return res;
148 148 }
149 149
150 150 bool Variable::isInside(const SqpRange &range) const noexcept
151 151 {
152 152 impl->lockRead();
153 153 auto res = range.contains(SqpRange{impl->m_Range.m_TStart, impl->m_Range.m_TEnd});
154 154 impl->unlock();
155 155 return res;
156 156 }
157 157
158 158 bool Variable::cacheContains(const SqpRange &range) const noexcept
159 159 {
160 160 impl->lockRead();
161 161 auto res = impl->m_CacheRange.contains(range);
162 162 impl->unlock();
163 163 return res;
164 164 }
165 165
166 166 bool Variable::cacheIntersect(const SqpRange &range) const noexcept
167 167 {
168 168 impl->lockRead();
169 169 auto res = impl->m_CacheRange.intersect(range);
170 170 impl->unlock();
171 171 return res;
172 172 }
173 173
174 174 bool Variable::cacheIsInside(const SqpRange &range) const noexcept
175 175 {
176 176 impl->lockRead();
177 177 auto res = range.contains(SqpRange{impl->m_CacheRange.m_TStart, impl->m_CacheRange.m_TEnd});
178 178 impl->unlock();
179 179 return res;
180 180 }
181 181
182 182
183 183 QVector<SqpRange> Variable::provideNotInCacheRangeList(const SqpRange &range) const noexcept
184 184 {
185 185 auto notInCache = QVector<SqpRange>{};
186 186
187 187 if (!this->cacheContains(range)) {
188 188 if (range.m_TEnd <= impl->m_CacheRange.m_TStart
189 189 || range.m_TStart >= impl->m_CacheRange.m_TEnd) {
190 190 notInCache << range;
191 191 }
192 192 else if (range.m_TStart < impl->m_CacheRange.m_TStart
193 193 && range.m_TEnd <= impl->m_CacheRange.m_TEnd) {
194 194 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart};
195 195 }
196 196 else if (range.m_TStart < impl->m_CacheRange.m_TStart
197 197 && range.m_TEnd > impl->m_CacheRange.m_TEnd) {
198 198 notInCache << SqpRange{range.m_TStart, impl->m_CacheRange.m_TStart}
199 199 << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
200 200 }
201 201 else if (range.m_TStart < impl->m_CacheRange.m_TEnd) {
202 202 notInCache << SqpRange{impl->m_CacheRange.m_TEnd, range.m_TEnd};
203 203 }
204 204 else {
205 205 qCCritical(LOG_Variable()) << tr("Detection of unknown case.")
206 206 << QThread::currentThread();
207 207 }
208 208 }
209 209
210 210 return notInCache;
211 211 }
@@ -1,541 +1,541
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheController.h>
4 4 #include <Variable/VariableCacheStrategy.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Time/TimeController.h>
13 13
14 14 #include <QMutex>
15 15 #include <QThread>
16 16 #include <QUuid>
17 17 #include <QtCore/QItemSelectionModel>
18 18
19 19 #include <set>
20 20 #include <unordered_map>
21 21
22 22 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
23 23
24 24 namespace {
25 25
26 26 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
27 27 const SqpRange &oldGraphRange)
28 28 {
29 29 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
30 30
31 31 auto varRangeRequested = varRange;
32 32 switch (zoomType) {
33 33 case AcquisitionZoomType::ZoomIn: {
34 34 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
35 35 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
36 36 varRangeRequested.m_TStart += deltaLeft;
37 37 varRangeRequested.m_TEnd -= deltaRight;
38 38 break;
39 39 }
40 40
41 41 case AcquisitionZoomType::ZoomOut: {
42 42 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
43 43 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
44 44 varRangeRequested.m_TStart -= deltaLeft;
45 45 varRangeRequested.m_TEnd += deltaRight;
46 46 break;
47 47 }
48 48 case AcquisitionZoomType::PanRight: {
49 49 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
50 50 varRangeRequested.m_TStart += deltaRight;
51 51 varRangeRequested.m_TEnd += deltaRight;
52 52 break;
53 53 }
54 54 case AcquisitionZoomType::PanLeft: {
55 55 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
56 56 varRangeRequested.m_TStart -= deltaLeft;
57 57 varRangeRequested.m_TEnd -= deltaLeft;
58 58 break;
59 59 }
60 60 case AcquisitionZoomType::Unknown: {
61 61 qCCritical(LOG_VariableController())
62 62 << VariableController::tr("Impossible to synchronize: zoom type unknown");
63 63 break;
64 64 }
65 65 default:
66 66 qCCritical(LOG_VariableController()) << VariableController::tr(
67 67 "Impossible to synchronize: zoom type not take into account");
68 68 // No action
69 69 break;
70 70 }
71 71
72 72 return varRangeRequested;
73 73 }
74 74 }
75 75
76 76 struct VariableController::VariableControllerPrivate {
77 77 explicit VariableControllerPrivate(VariableController *parent)
78 78 : m_WorkingMutex{},
79 79 m_VariableModel{new VariableModel{parent}},
80 80 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
81 81 m_VariableCacheController{std::make_unique<VariableCacheController>()},
82 82 m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
83 83 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()}
84 84 {
85 85
86 86 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
87 87 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
88 88 }
89 89
90 90
91 91 virtual ~VariableControllerPrivate()
92 92 {
93 93 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
94 94 m_VariableAcquisitionWorkerThread.quit();
95 95 m_VariableAcquisitionWorkerThread.wait();
96 96 }
97 97
98 98
99 99 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested);
100 100
101 101 QVector<SqpRange> provideNotInCacheDateTimeList(std::shared_ptr<Variable> variable,
102 102 const SqpRange &dateTime);
103 103
104 104 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
105 105 std::shared_ptr<IDataSeries>
106 106 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
107 107
108 108 void registerProvider(std::shared_ptr<IDataProvider> provider);
109 109
110 110 QMutex m_WorkingMutex;
111 111 /// Variable model. The VariableController has the ownership
112 112 VariableModel *m_VariableModel;
113 113 QItemSelectionModel *m_VariableSelectionModel;
114 114
115 115
116 116 TimeController *m_TimeController{nullptr};
117 117 std::unique_ptr<VariableCacheController> m_VariableCacheController;
118 118 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
119 119 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
120 120 QThread m_VariableAcquisitionWorkerThread;
121 121
122 122 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
123 123 m_VariableToProviderMap;
124 124 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
125 125 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
126 126 m_GroupIdToVariableSynchronizationGroupMap;
127 127 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
128 128 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
129 129 };
130 130
131 131
132 132 VariableController::VariableController(QObject *parent)
133 133 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
134 134 {
135 135 qCDebug(LOG_VariableController()) << tr("VariableController construction")
136 136 << QThread::currentThread();
137 137
138 138 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
139 139 &VariableController::onAbortProgressRequested);
140 140
141 141 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
142 142 &VariableController::onDataProvided);
143 143 connect(impl->m_VariableAcquisitionWorker.get(),
144 144 &VariableAcquisitionWorker::variableRequestInProgress, this,
145 145 &VariableController::onVariableRetrieveDataInProgress);
146 146
147 147 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
148 148 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
149 149 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
150 150 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
151 151
152 152
153 153 impl->m_VariableAcquisitionWorkerThread.start();
154 154 }
155 155
156 156 VariableController::~VariableController()
157 157 {
158 158 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
159 159 << QThread::currentThread();
160 160 this->waitForFinish();
161 161 }
162 162
163 163 VariableModel *VariableController::variableModel() noexcept
164 164 {
165 165 return impl->m_VariableModel;
166 166 }
167 167
168 168 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
169 169 {
170 170 return impl->m_VariableSelectionModel;
171 171 }
172 172
173 173 void VariableController::setTimeController(TimeController *timeController) noexcept
174 174 {
175 175 impl->m_TimeController = timeController;
176 176 }
177 177
178 178 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
179 179 {
180 180 if (!variable) {
181 181 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
182 182 return;
183 183 }
184 184
185 185 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
186 186 // make some treatments before the deletion
187 187 emit variableAboutToBeDeleted(variable);
188 188
189 189 // Deletes identifier
190 190 impl->m_VariableToIdentifierMap.erase(variable);
191 191
192 192 // Deletes provider
193 193 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
194 194 qCDebug(LOG_VariableController())
195 195 << tr("Number of providers deleted for variable %1: %2")
196 196 .arg(variable->name(), QString::number(nbProvidersDeleted));
197 197
198 198 // Clears cache
199 199 impl->m_VariableCacheController->clear(variable);
200 200
201 201 // Deletes from model
202 202 impl->m_VariableModel->deleteVariable(variable);
203 203 }
204 204
205 205 void VariableController::deleteVariables(
206 206 const QVector<std::shared_ptr<Variable> > &variables) noexcept
207 207 {
208 208 for (auto variable : qAsConst(variables)) {
209 209 deleteVariable(variable);
210 210 }
211 211 }
212 212
213 213 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
214 214 {
215 215 }
216 216
217 217 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
218 218 std::shared_ptr<IDataProvider> provider) noexcept
219 219 {
220 220
221 221 if (!impl->m_TimeController) {
222 222 qCCritical(LOG_VariableController())
223 223 << tr("Impossible to create variable: The time controller is null");
224 224 return;
225 225 }
226 226
227 227 auto range = impl->m_TimeController->dateTime();
228 228
229 229 if (auto newVariable = impl->m_VariableModel->createVariable(name, range, metadata)) {
230 230 auto identifier = QUuid::createUuid();
231 231
232 232 // store the provider
233 233 impl->registerProvider(provider);
234 234
235 235 // Associate the provider
236 236 impl->m_VariableToProviderMap[newVariable] = provider;
237 237 impl->m_VariableToIdentifierMap[newVariable] = identifier;
238 238
239 239
240 240 impl->processRequest(newVariable, range);
241 241 }
242 242 }
243 243
244 244 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
245 245 {
246 246 // TODO check synchronisation
247 247 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
248 248 << QThread::currentThread()->objectName();
249 249 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
250 250
251 251 for (const auto &selectedRow : qAsConst(selectedRows)) {
252 252 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
253 253 selectedVariable->setRange(dateTime);
254 254 impl->processRequest(selectedVariable, dateTime);
255 255
256 256 // notify that rescale operation has to be done
257 257 emit rangeChanged(selectedVariable, dateTime);
258 258 }
259 259 }
260 260 }
261 261
262 262 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
263 263 const SqpRange &cacheRangeRequested,
264 264 QVector<AcquisitionDataPacket> dataAcquired)
265 265 {
266 266 if (auto var = impl->findVariable(vIdentifier)) {
267 267 var->setRange(rangeRequested);
268 268 var->setCacheRange(cacheRangeRequested);
269 269 qCDebug(LOG_VariableController()) << tr("1: onDataProvided") << rangeRequested;
270 270 qCDebug(LOG_VariableController()) << tr("2: onDataProvided") << cacheRangeRequested;
271 271
272 272 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
273 273 qCDebug(LOG_VariableController()) << tr("3: onDataProvided")
274 274 << retrievedDataSeries->range();
275 275 var->mergeDataSeries(retrievedDataSeries);
276 276 qCDebug(LOG_VariableController()) << tr("4: onDataProvided");
277 277 emit var->updated();
278 278 }
279 279 else {
280 280 qCCritical(LOG_VariableController()) << tr("Impossible to provide data to a null variable");
281 281 }
282 282 }
283 283
284 284 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
285 285 {
286 286 if (auto var = impl->findVariable(identifier)) {
287 287 impl->m_VariableModel->setDataProgress(var, progress);
288 288 }
289 289 else {
290 290 qCCritical(LOG_VariableController())
291 291 << tr("Impossible to notify progression of a null variable");
292 292 }
293 293 }
294 294
295 295 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
296 296 {
297 297 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
298 298 << QThread::currentThread()->objectName();
299 299
300 300 auto it = impl->m_VariableToIdentifierMap.find(variable);
301 301 if (it != impl->m_VariableToIdentifierMap.cend()) {
302 302 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
303 303 }
304 304 else {
305 305 qCWarning(LOG_VariableController())
306 306 << tr("Aborting progression of inexistant variable detected !!!")
307 307 << QThread::currentThread()->objectName();
308 308 }
309 309 }
310 310
311 311 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
312 312 {
313 313 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
314 314 << QThread::currentThread()->objectName()
315 315 << synchronizationGroupId;
316 316 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
317 317 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
318 318 std::make_pair(synchronizationGroupId, vSynchroGroup));
319 319 }
320 320
321 321 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
322 322 {
323 323 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
324 324 }
325 325
326 326 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
327 327 QUuid synchronizationGroupId)
328 328
329 329 {
330 330 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
331 331 << synchronizationGroupId;
332 332 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
333 333 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
334 334 auto groupIdToVSGIt
335 335 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
336 336 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
337 337 impl->m_VariableIdGroupIdMap.insert(
338 338 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
339 339 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
340 340 }
341 341 else {
342 342 qCCritical(LOG_VariableController())
343 343 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
344 344 << variable->name();
345 345 }
346 346 }
347 347 else {
348 348 qCCritical(LOG_VariableController())
349 349 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
350 350 }
351 351 }
352 352
353 353
354 354 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
355 355 const SqpRange &range, const SqpRange &oldRange,
356 356 bool synchronise)
357 357 {
358 358 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
359 359
360 360 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
361 361 << QThread::currentThread()->objectName();
362 362 // we want to load data of the variable for the dateTime.
363 363 // First we check if the cache contains some of them.
364 364 // For the other, we ask the provider to give them.
365 365
366 366 for (const auto &var : variables) {
367 367 qCDebug(LOG_VariableController()) << "processRequest for" << var->name();
368 368 impl->processRequest(var, range);
369 369 }
370 370
371 371 if (synchronise) {
372 372 // Get the group ids
373 373 qCDebug(LOG_VariableController())
374 374 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
375 375 auto groupIds = std::set<QUuid>();
376 376 for (const auto &var : variables) {
377 377 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
378 378 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
379 379 auto vId = varToVarIdIt->second;
380 380 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
381 381 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
382 382 auto gId = varIdToGroupIdIt->second;
383 383 if (groupIds.find(gId) == groupIds.cend()) {
384 384 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
385 385 groupIds.insert(gId);
386 386 }
387 387 }
388 388 }
389 389 }
390 390
391 391 // We assume here all group ids exist
392 392 for (const auto &gId : groupIds) {
393 393 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
394 394 auto vSyncIds = vSynchronizationGroup->getIds();
395 395 qCDebug(LOG_VariableController()) << "Var in synchro group ";
396 396 for (auto vId : vSyncIds) {
397 397 auto var = impl->findVariable(vId);
398 398
399 399 // Don't process already processed var
400 400 if (!variables.contains(var)) {
401 401 if (var != nullptr) {
402 402 qCDebug(LOG_VariableController()) << "processRequest synchro for"
403 403 << var->name();
404 404 auto vSyncRangeRequested
405 405 = computeSynchroRangeRequested(var->range(), range, oldRange);
406 406 impl->processRequest(var, vSyncRangeRequested);
407 407 }
408 408 else {
409 409 qCCritical(LOG_VariableController())
410 410
411 411 << tr("Impossible to synchronize a null variable");
412 412 }
413 413 }
414 414 }
415 415 }
416 416 }
417 417 }
418 418
419 419
420 420 void VariableController::initialize()
421 421 {
422 422 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
423 423 impl->m_WorkingMutex.lock();
424 424 qCDebug(LOG_VariableController()) << tr("VariableController init END");
425 425 }
426 426
427 427 void VariableController::finalize()
428 428 {
429 429 impl->m_WorkingMutex.unlock();
430 430 }
431 431
432 432 void VariableController::waitForFinish()
433 433 {
434 434 QMutexLocker locker{&impl->m_WorkingMutex};
435 435 }
436 436
437 437 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
438 438 {
439 439 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
440 440 auto zoomType = AcquisitionZoomType::Unknown;
441 441 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
442 442 zoomType = AcquisitionZoomType::ZoomOut;
443 443 }
444 444 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
445 445 zoomType = AcquisitionZoomType::PanRight;
446 446 }
447 447 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
448 448 zoomType = AcquisitionZoomType::PanLeft;
449 449 }
450 450 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
451 451 zoomType = AcquisitionZoomType::ZoomIn;
452 452 }
453 453 else {
454 454 qCCritical(LOG_VariableController()) << "getZoomType: Unknown type detected";
455 455 }
456 456 return zoomType;
457 457 }
458 458
459 459 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
460 460 const SqpRange &rangeRequested)
461 461 {
462 462
463 463 auto varRangesRequested
464 464 = m_VariableCacheStrategy->computeCacheRange(var->range(), rangeRequested);
465 465 auto notInCacheRangeList = var->provideNotInCacheRangeList(varRangesRequested.second);
466 466
467 467 if (!notInCacheRangeList.empty()) {
468 468 auto identifier = m_VariableToIdentifierMap.at(var);
469 469 auto varProvider = m_VariableToProviderMap.at(var);
470 470 if (varProvider != nullptr) {
471 471 m_VariableAcquisitionWorker->pushVariableRequest(
472 472 identifier, varRangesRequested.first, varRangesRequested.second,
473 473 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
474 474 varProvider);
475 475 }
476 476 else {
477 477 qCCritical(LOG_VariableController())
478 478 << "Impossible to provide data with a null provider";
479 479 }
480 480 }
481 481 else {
482 482 var->setRange(rangeRequested);
483 483 var->setCacheRange(varRangesRequested.second);
484 var->setDataSeries(var->dataSeries()->subData(varRangesRequested.second));
484 var->setDataSeries(var->dataSeries()->subDataSeries(varRangesRequested.second));
485 485 emit var->updated();
486 486 }
487 487 }
488 488
489 489 std::shared_ptr<Variable>
490 490 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
491 491 {
492 492 std::shared_ptr<Variable> var;
493 493 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
494 494
495 495 auto end = m_VariableToIdentifierMap.cend();
496 496 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
497 497 if (it != end) {
498 498 var = it->first;
499 499 }
500 500 else {
501 501 qCCritical(LOG_VariableController())
502 502 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
503 503 }
504 504
505 505 return var;
506 506 }
507 507
508 508 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
509 509 const QVector<AcquisitionDataPacket> acqDataPacketVector)
510 510 {
511 511 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
512 512 << acqDataPacketVector.size();
513 513 std::shared_ptr<IDataSeries> dataSeries;
514 514 if (!acqDataPacketVector.isEmpty()) {
515 515 dataSeries = acqDataPacketVector[0].m_DateSeries;
516 516 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
517 517 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
518 518 }
519 519 }
520 520 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
521 521 << acqDataPacketVector.size();
522 522 return dataSeries;
523 523 }
524 524
525 525 void VariableController::VariableControllerPrivate::registerProvider(
526 526 std::shared_ptr<IDataProvider> provider)
527 527 {
528 528 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
529 529 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
530 530 << provider->objectName();
531 531 m_ProviderSet.insert(provider);
532 532 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
533 533 &VariableAcquisitionWorker::onVariableDataAcquired);
534 534 connect(provider.get(), &IDataProvider::dataProvidedProgress,
535 535 m_VariableAcquisitionWorker.get(),
536 536 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
537 537 }
538 538 else {
539 539 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
540 540 }
541 541 }
@@ -1,18 +1,44
1 1 # On ignore toutes les règles vera++ pour le fichier spimpl
2 2 Common/spimpl\.h:\d+:.*
3 3
4 4 # Ignore false positive relative to two class definitions in a same file
5 5 DataSourceItem\.h:\d+:.*IPSIS_S01.*
6 6
7 7 # Ignore false positive relative to a template class
8 8 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (D)
9 9 ArrayData\.h:\d+:.*IPSIS_S04_NAMESPACE.*found: (arraydata_detail)
10 10 ArrayData\.h:\d+:.*IPSIS_S06.*found: (D)
11 11 ArrayData\.h:\d+:.*IPSIS_S06.*found: (Dim)
12 12 DataSeries\.h:\d+:.*IPSIS_S04_VARIABLE.*
13 13
14 # Ignore false positive relative to iterators
15 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (forward_iterator_tag)
16 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (IteratorValue)
17 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (ptrdiff_t)
18 ArrayData\.h:\d+:.*IPSIS_S04_VARIABLE.*found: (value_type)
19 ArrayData\.h:\d+:.*IPSIS_S05.*
20 ArrayData\.h:\d+:.*IPSIS_S06.*found: (iterator_category)
21 ArrayData\.h:\d+:.*IPSIS_S06.*found: (forward_iterator_tag)
22 ArrayData\.h:\d+:.*IPSIS_S06.*found: (value_type)
23 ArrayData\.h:\d+:.*IPSIS_S06.*found: (IteratorValue)
24 ArrayData\.h:\d+:.*IPSIS_S06.*found: (difference_type)
25 ArrayData\.h:\d+:.*IPSIS_S06.*found: (ptrdiff_t)
26 ArrayData\.h:\d+:.*IPSIS_S06.*found: (pointer)
27 ArrayData\.h:\d+:.*IPSIS_S06.*found: (reference)
28 ArrayData\.h:\d+:.*IPSIS_S06.*found: (value_type)
29 DataSeries\.h:\d+:.*IPSIS_S05.*
30 DataSeries\.h:\d+:.*IPSIS_S06.*found: (iterator_category)
31 DataSeries\.h:\d+:.*IPSIS_S06.*found: (forward_iterator_tag)
32 DataSeries\.h:\d+:.*IPSIS_S06.*found: (value_type)
33 DataSeries\.h:\d+:.*IPSIS_S06.*found: (IteratorValue)
34 DataSeries\.h:\d+:.*IPSIS_S06.*found: (difference_type)
35 DataSeries\.h:\d+:.*IPSIS_S06.*found: (ptrdiff_t)
36 DataSeries\.h:\d+:.*IPSIS_S06.*found: (pointer)
37 DataSeries\.h:\d+:.*IPSIS_S06.*found: (reference)
38 DataSeries\.h:\d+:.*IPSIS_S06.*found: (value_type)
39
14 40 # Ignore false positive relative to an alias
15 41 DataSourceItemAction\.h:\d+:.*IPSIS_S06.*found: (ExecuteFunction)
16 42
17 43 # Ignore false positive relative to unnamed namespace
18 44 VariableController\.cpp:\d+:.*IPSIS_F13.*
General Comments 0
You need to be logged in to leave comments. Login now