##// END OF EJS Templates
Introduces NaN and zero values in data of the mock spectrogram...
Alexandre Leroux -
r922:e65d7f08d776
parent child
Show More
@@ -1,336 +1,345
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
5 #include <Data/SpectrogramSeries.h>
5 #include <Data/SpectrogramSeries.h>
6 #include <Data/VectorSeries.h>
6 #include <Data/VectorSeries.h>
7
7
8 #include <Variable/Variable.h>
8 #include <Variable/Variable.h>
9
9
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11
11
12 namespace {
12 namespace {
13
13
14 class SqpDataContainer : public QCPGraphDataContainer {
14 class SqpDataContainer : public QCPGraphDataContainer {
15 public:
15 public:
16 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
16 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
17 };
17 };
18
18
19 /**
19 /**
20 * Struct used to create plottables, depending on the type of the data series from which to create
20 * Struct used to create plottables, depending on the type of the data series from which to create
21 * them
21 * them
22 * @tparam T the data series' type
22 * @tparam T the data series' type
23 * @remarks Default implementation can't create plottables
23 * @remarks Default implementation can't create plottables
24 */
24 */
25 template <typename T, typename Enabled = void>
25 template <typename T, typename Enabled = void>
26 struct PlottablesCreator {
26 struct PlottablesCreator {
27 static PlottablesMap createPlottables(T &, QCustomPlot &)
27 static PlottablesMap createPlottables(T &, QCustomPlot &)
28 {
28 {
29 qCCritical(LOG_DataSeries())
29 qCCritical(LOG_DataSeries())
30 << QObject::tr("Can't create plottables: unmanaged data series type");
30 << QObject::tr("Can't create plottables: unmanaged data series type");
31 return {};
31 return {};
32 }
32 }
33 };
33 };
34
34
35 /**
35 /**
36 * Specialization of PlottablesCreator for scalars and vectors
36 * Specialization of PlottablesCreator for scalars and vectors
37 * @sa ScalarSeries
37 * @sa ScalarSeries
38 * @sa VectorSeries
38 * @sa VectorSeries
39 */
39 */
40 template <typename T>
40 template <typename T>
41 struct PlottablesCreator<T,
41 struct PlottablesCreator<T,
42 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
42 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
43 or std::is_base_of<VectorSeries, T>::value> > {
43 or std::is_base_of<VectorSeries, T>::value> > {
44 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
44 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
45 {
45 {
46 PlottablesMap result{};
46 PlottablesMap result{};
47
47
48 // Gets the number of components of the data series
48 // Gets the number of components of the data series
49 dataSeries.lockRead();
49 dataSeries.lockRead();
50 auto componentCount = dataSeries.valuesData()->componentCount();
50 auto componentCount = dataSeries.valuesData()->componentCount();
51 dataSeries.unlock();
51 dataSeries.unlock();
52
52
53 // For each component of the data series, creates a QCPGraph to add to the plot
53 // For each component of the data series, creates a QCPGraph to add to the plot
54 for (auto i = 0; i < componentCount; ++i) {
54 for (auto i = 0; i < componentCount; ++i) {
55 auto graph = plot.addGraph();
55 auto graph = plot.addGraph();
56 result.insert({i, graph});
56 result.insert({i, graph});
57 }
57 }
58
58
59 plot.replot();
59 plot.replot();
60
60
61 return result;
61 return result;
62 }
62 }
63 };
63 };
64
64
65 /**
65 /**
66 * Specialization of PlottablesCreator for spectrograms
66 * Specialization of PlottablesCreator for spectrograms
67 * @sa SpectrogramSeries
67 * @sa SpectrogramSeries
68 */
68 */
69 template <typename T>
69 template <typename T>
70 struct PlottablesCreator<T,
70 struct PlottablesCreator<T,
71 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
71 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
72 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
72 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
73 {
73 {
74 PlottablesMap result{};
74 PlottablesMap result{};
75 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
75 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
76
76
77 plot.replot();
77 plot.replot();
78
78
79 return result;
79 return result;
80 }
80 }
81 };
81 };
82
82
83 /**
83 /**
84 * Struct used to update plottables, depending on the type of the data series from which to update
84 * Struct used to update plottables, depending on the type of the data series from which to update
85 * them
85 * them
86 * @tparam T the data series' type
86 * @tparam T the data series' type
87 * @remarks Default implementation can't update plottables
87 * @remarks Default implementation can't update plottables
88 */
88 */
89 template <typename T, typename Enabled = void>
89 template <typename T, typename Enabled = void>
90 struct PlottablesUpdater {
90 struct PlottablesUpdater {
91 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
91 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
92 {
92 {
93 qCCritical(LOG_VisualizationGraphHelper())
93 qCCritical(LOG_VisualizationGraphHelper())
94 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
94 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
95 }
95 }
96
96
97 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
97 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
98 {
98 {
99 qCCritical(LOG_VisualizationGraphHelper())
99 qCCritical(LOG_VisualizationGraphHelper())
100 << QObject::tr("Can't update plottables: unmanaged data series type");
100 << QObject::tr("Can't update plottables: unmanaged data series type");
101 }
101 }
102 };
102 };
103
103
104 /**
104 /**
105 * Specialization of PlottablesUpdater for scalars and vectors
105 * Specialization of PlottablesUpdater for scalars and vectors
106 * @sa ScalarSeries
106 * @sa ScalarSeries
107 * @sa VectorSeries
107 * @sa VectorSeries
108 */
108 */
109 template <typename T>
109 template <typename T>
110 struct PlottablesUpdater<T,
110 struct PlottablesUpdater<T,
111 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
111 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
112 or std::is_base_of<VectorSeries, T>::value> > {
112 or std::is_base_of<VectorSeries, T>::value> > {
113 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
113 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
114 {
114 {
115 auto minValue = 0., maxValue = 0.;
115 auto minValue = 0., maxValue = 0.;
116
116
117 dataSeries.lockRead();
117 dataSeries.lockRead();
118 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
118 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
119 auto end = dataSeries.cend();
119 auto end = dataSeries.cend();
120 if (valuesBounds.first != end && valuesBounds.second != end) {
120 if (valuesBounds.first != end && valuesBounds.second != end) {
121 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
121 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
122
122
123 minValue = rangeValue(valuesBounds.first->minValue());
123 minValue = rangeValue(valuesBounds.first->minValue());
124 maxValue = rangeValue(valuesBounds.second->maxValue());
124 maxValue = rangeValue(valuesBounds.second->maxValue());
125 }
125 }
126 dataSeries.unlock();
126 dataSeries.unlock();
127
127
128 plot.yAxis->setRange(QCPRange{minValue, maxValue});
128 plot.yAxis->setRange(QCPRange{minValue, maxValue});
129 }
129 }
130
130
131 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
131 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
132 bool rescaleAxes)
132 bool rescaleAxes)
133 {
133 {
134
134
135 // For each plottable to update, resets its data
135 // For each plottable to update, resets its data
136 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
136 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
137 for (const auto &plottable : plottables) {
137 for (const auto &plottable : plottables) {
138 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
138 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
139 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
139 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
140 graph->setData(dataContainer);
140 graph->setData(dataContainer);
141
141
142 dataContainers.insert({plottable.first, dataContainer});
142 dataContainers.insert({plottable.first, dataContainer});
143 }
143 }
144 }
144 }
145 dataSeries.lockRead();
145 dataSeries.lockRead();
146
146
147 // - Gets the data of the series included in the current range
147 // - Gets the data of the series included in the current range
148 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
148 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
149 // and value data. The correct value is retrieved according to the index of the component
149 // and value data. The correct value is retrieved according to the index of the component
150 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
150 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
151 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
151 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
152 for (const auto &dataContainer : dataContainers) {
152 for (const auto &dataContainer : dataContainers) {
153 auto componentIndex = dataContainer.first;
153 auto componentIndex = dataContainer.first;
154 dataContainer.second->appendGraphData(
154 dataContainer.second->appendGraphData(
155 QCPGraphData(it->x(), it->value(componentIndex)));
155 QCPGraphData(it->x(), it->value(componentIndex)));
156 }
156 }
157 }
157 }
158
158
159 dataSeries.unlock();
159 dataSeries.unlock();
160
160
161 if (!plottables.empty()) {
161 if (!plottables.empty()) {
162 auto plot = plottables.begin()->second->parentPlot();
162 auto plot = plottables.begin()->second->parentPlot();
163
163
164 if (rescaleAxes) {
164 if (rescaleAxes) {
165 plot->rescaleAxes();
165 plot->rescaleAxes();
166 }
166 }
167
167
168 plot->replot();
168 plot->replot();
169 }
169 }
170 }
170 }
171 };
171 };
172
172
173 /**
173 /**
174 * Specialization of PlottablesUpdater for spectrograms
174 * Specialization of PlottablesUpdater for spectrograms
175 * @sa SpectrogramSeries
175 * @sa SpectrogramSeries
176 */
176 */
177 template <typename T>
177 template <typename T>
178 struct PlottablesUpdater<T,
178 struct PlottablesUpdater<T,
179 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
179 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
180 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
180 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
181 {
181 {
182 double min, max;
182 double min, max;
183 /// @todo ALX: use iterators here
183 /// @todo ALX: use iterators here
184 std::tie(min, max) = dataSeries.yAxis().bounds();
184 std::tie(min, max) = dataSeries.yAxis().bounds();
185
185
186 if (!std::isnan(min) && !std::isnan(max)) {
186 if (!std::isnan(min) && !std::isnan(max)) {
187 plot.yAxis->setRange(QCPRange{min, max});
187 plot.yAxis->setRange(QCPRange{min, max});
188 }
188 }
189 }
189 }
190
190
191 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
191 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
192 bool rescaleAxes)
192 bool rescaleAxes)
193 {
193 {
194 if (plottables.empty()) {
194 if (plottables.empty()) {
195 qCDebug(LOG_VisualizationGraphHelper())
195 qCDebug(LOG_VisualizationGraphHelper())
196 << QObject::tr("Can't update spectrogram: no colormap has been associated");
196 << QObject::tr("Can't update spectrogram: no colormap has been associated");
197 return;
197 return;
198 }
198 }
199
199
200 // Gets the colormap to update (normally there is only one colormap)
200 // Gets the colormap to update (normally there is only one colormap)
201 Q_ASSERT(plottables.size() == 1);
201 Q_ASSERT(plottables.size() == 1);
202 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
202 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
203 Q_ASSERT(colormap != nullptr);
203 Q_ASSERT(colormap != nullptr);
204
204
205 dataSeries.lockRead();
205 dataSeries.lockRead();
206
206
207 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
207 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
208 /// @todo ALX: use iterators here
208 /// @todo ALX: use iterators here
209 auto yAxis = dataSeries.yAxis();
209 auto yAxis = dataSeries.yAxis();
210
210
211 // Gets properties of x-axis and y-axis to set size and range of the colormap
211 // Gets properties of x-axis and y-axis to set size and range of the colormap
212 auto nbX = std::distance(its.first, its.second);
212 auto nbX = std::distance(its.first, its.second);
213 auto xMin = nbX != 0 ? its.first->x() : 0.;
213 auto xMin = nbX != 0 ? its.first->x() : 0.;
214 auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.;
214 auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.;
215
215
216 auto nbY = yAxis.size();
216 auto nbY = yAxis.size();
217 auto yMin = 0., yMax = 0.;
217 auto yMin = 0., yMax = 0.;
218 if (nbY != 0) {
218 if (nbY != 0) {
219 std::tie(yMin, yMax) = yAxis.bounds();
219 std::tie(yMin, yMax) = yAxis.bounds();
220 }
220 }
221
221
222 colormap->data()->setSize(nbX, nbY);
222 colormap->data()->setSize(nbX, nbY);
223 colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax});
223 colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax});
224
224
225 // Sets values
225 // Sets values
226 auto xIndex = 0;
226 auto xIndex = 0;
227 for (auto it = its.first; it != its.second; ++it, ++xIndex) {
227 for (auto it = its.first; it != its.second; ++it, ++xIndex) {
228 for (auto yIndex = 0; yIndex < nbY; ++yIndex) {
228 for (auto yIndex = 0; yIndex < nbY; ++yIndex) {
229 colormap->data()->setCell(xIndex, yIndex, it->value(yIndex));
229 auto value = it->value(yIndex);
230
231 colormap->data()->setCell(xIndex, yIndex, value);
232
233 // Processing spectrogram data for display in QCustomPlot
234 /// For the moment, we just make the NaN values to be transparent in the colormap
235 /// @todo ALX: complete treatments (mesh generation, etc.)
236 if (std::isnan(value)) {
237 colormap->data()->setAlpha(xIndex, yIndex, 0);
238 }
230 }
239 }
231 }
240 }
232
241
233 dataSeries.unlock();
242 dataSeries.unlock();
234
243
235 // Rescales axes
244 // Rescales axes
236 auto plot = colormap->parentPlot();
245 auto plot = colormap->parentPlot();
237
246
238 if (rescaleAxes) {
247 if (rescaleAxes) {
239 plot->rescaleAxes();
248 plot->rescaleAxes();
240 }
249 }
241
250
242 plot->replot();
251 plot->replot();
243 }
252 }
244 };
253 };
245
254
246 /**
255 /**
247 * Helper used to create/update plottables
256 * Helper used to create/update plottables
248 */
257 */
249 struct IPlottablesHelper {
258 struct IPlottablesHelper {
250 virtual ~IPlottablesHelper() noexcept = default;
259 virtual ~IPlottablesHelper() noexcept = default;
251 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
260 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
252 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
261 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
253 virtual void update(PlottablesMap &plottables, const SqpRange &range,
262 virtual void update(PlottablesMap &plottables, const SqpRange &range,
254 bool rescaleAxes = false) const = 0;
263 bool rescaleAxes = false) const = 0;
255 };
264 };
256
265
257 /**
266 /**
258 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
267 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
259 * @tparam T the data series' type
268 * @tparam T the data series' type
260 */
269 */
261 template <typename T>
270 template <typename T>
262 struct PlottablesHelper : public IPlottablesHelper {
271 struct PlottablesHelper : public IPlottablesHelper {
263 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
272 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
264
273
265 PlottablesMap create(QCustomPlot &plot) const override
274 PlottablesMap create(QCustomPlot &plot) const override
266 {
275 {
267 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
276 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
268 }
277 }
269
278
270 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
279 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
271 {
280 {
272 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
281 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
273 }
282 }
274
283
275 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
284 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
276 {
285 {
277 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
286 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
278 }
287 }
279
288
280 T &m_DataSeries;
289 T &m_DataSeries;
281 };
290 };
282
291
283 /// Creates IPlottablesHelper according to a data series
292 /// Creates IPlottablesHelper according to a data series
284 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
293 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
285 {
294 {
286 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
295 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
287 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
296 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
288 }
297 }
289 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
298 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
290 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
299 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
291 }
300 }
292 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
301 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
293 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
302 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
294 }
303 }
295 else {
304 else {
296 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
305 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
297 }
306 }
298 }
307 }
299
308
300 } // namespace
309 } // namespace
301
310
302 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
311 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
303 QCustomPlot &plot) noexcept
312 QCustomPlot &plot) noexcept
304 {
313 {
305 if (variable) {
314 if (variable) {
306 auto helper = createHelper(variable->dataSeries());
315 auto helper = createHelper(variable->dataSeries());
307 auto plottables = helper->create(plot);
316 auto plottables = helper->create(plot);
308 return plottables;
317 return plottables;
309 }
318 }
310 else {
319 else {
311 qCDebug(LOG_VisualizationGraphHelper())
320 qCDebug(LOG_VisualizationGraphHelper())
312 << QObject::tr("Can't create graph plottables : the variable is null");
321 << QObject::tr("Can't create graph plottables : the variable is null");
313 return PlottablesMap{};
322 return PlottablesMap{};
314 }
323 }
315 }
324 }
316
325
317 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
326 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
318 QCustomPlot &plot) noexcept
327 QCustomPlot &plot) noexcept
319 {
328 {
320 if (variable) {
329 if (variable) {
321 auto helper = createHelper(variable->dataSeries());
330 auto helper = createHelper(variable->dataSeries());
322 helper->setYAxisRange(variable->range(), plot);
331 helper->setYAxisRange(variable->range(), plot);
323 }
332 }
324 else {
333 else {
325 qCDebug(LOG_VisualizationGraphHelper())
334 qCDebug(LOG_VisualizationGraphHelper())
326 << QObject::tr("Can't set y-axis range of plot: the variable is null");
335 << QObject::tr("Can't set y-axis range of plot: the variable is null");
327 }
336 }
328 }
337 }
329
338
330 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
339 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
331 std::shared_ptr<IDataSeries> dataSeries,
340 std::shared_ptr<IDataSeries> dataSeries,
332 const SqpRange &dateTime)
341 const SqpRange &dateTime)
333 {
342 {
334 auto helper = createHelper(dataSeries);
343 auto helper = createHelper(dataSeries);
335 helper->update(plottables, dateTime);
344 helper->update(plottables, dateTime);
336 }
345 }
@@ -1,272 +1,291
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <cmath>
9 #include <cmath>
10 #include <set>
10
11
11 #include <QFuture>
12 #include <QFuture>
12 #include <QThread>
13 #include <QThread>
13 #include <QtConcurrent/QtConcurrent>
14 #include <QtConcurrent/QtConcurrent>
14
15
15 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
16 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
16
17
17 namespace {
18 namespace {
18
19
19 /// Number of bands generated for a spectrogram
20 /// Number of bands generated for a spectrogram
20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21
22
23 /// Bands for which to generate NaN values for a spectrogram
24 const auto SPECTROGRAM_NAN_BANDS = std::set<int>{1, 3, 10, 20};
25
26 /// Bands for which to generate zeros for a spectrogram
27 const auto SPECTROGRAM_ZERO_BANDS = std::set<int>{2, 15, 19, 29};
28
22 /// Abstract cosinus type
29 /// Abstract cosinus type
23 struct ICosinusType {
30 struct ICosinusType {
24 virtual ~ICosinusType() = default;
31 virtual ~ICosinusType() = default;
25 /// @return the number of components generated for the type
32 /// @return the number of components generated for the type
26 virtual int componentCount() const = 0;
33 virtual int componentCount() const = 0;
27 /// @return the data series created for the type
34 /// @return the data series created for the type
28 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
35 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
29 std::vector<double> valuesData) const = 0;
36 std::vector<double> valuesData) const = 0;
30 /// Generates values (one value per component)
37 /// Generates values (one value per component)
31 /// @param x the x-axis data used to generate values
38 /// @param x the x-axis data used to generate values
32 /// @param values the vector in which to insert the generated values
39 /// @param values the vector in which to insert the generated values
33 /// @param dataIndex the index of insertion of the generated values
40 /// @param dataIndex the index of insertion of the generated values
34 ///
41 ///
35 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
42 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
36 };
43 };
37
44
38 struct ScalarCosinus : public ICosinusType {
45 struct ScalarCosinus : public ICosinusType {
39 int componentCount() const override { return 1; }
46 int componentCount() const override { return 1; }
40
47
41 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
48 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
42 std::vector<double> valuesData) const override
49 std::vector<double> valuesData) const override
43 {
50 {
44 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
51 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
45 Unit{QStringLiteral("t"), true}, Unit{});
52 Unit{QStringLiteral("t"), true}, Unit{});
46 }
53 }
47
54
48 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
55 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
49 {
56 {
50 values[dataIndex] = std::cos(x);
57 values[dataIndex] = std::cos(x);
51 }
58 }
52 };
59 };
53
60
54 struct SpectrogramCosinus : public ICosinusType {
61 struct SpectrogramCosinus : public ICosinusType {
55 /// Ctor with y-axis
62 /// Ctor with y-axis
56 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit, Unit valuesUnit)
63 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit, Unit valuesUnit)
57 : m_YAxisData{std::move(yAxisData)},
64 : m_YAxisData{std::move(yAxisData)},
58 m_YAxisUnit{std::move(yAxisUnit)},
65 m_YAxisUnit{std::move(yAxisUnit)},
59 m_ValuesUnit{std::move(valuesUnit)}
66 m_ValuesUnit{std::move(valuesUnit)}
60 {
67 {
61 }
68 }
62
69
63 int componentCount() const override { return m_YAxisData.size(); }
70 int componentCount() const override { return m_YAxisData.size(); }
64
71
65 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
72 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
66 std::vector<double> valuesData) const override
73 std::vector<double> valuesData) const override
67 {
74 {
68 return std::make_shared<SpectrogramSeries>(
75 return std::make_shared<SpectrogramSeries>(
69 std::move(xAxisData), m_YAxisData, std::move(valuesData),
76 std::move(xAxisData), m_YAxisData, std::move(valuesData),
70 Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit);
77 Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit);
71 }
78 }
72
79
73 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
80 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
74 {
81 {
75 auto componentCount = this->componentCount();
82 auto componentCount = this->componentCount();
76 for (int i = 0; i < componentCount; ++i) {
83 for (int i = 0; i < componentCount; ++i) {
77 auto y = m_YAxisData[i];
84 auto y = m_YAxisData[i];
78 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
85
79 auto value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
86 double value;
87
88 if (SPECTROGRAM_ZERO_BANDS.find(y) != SPECTROGRAM_ZERO_BANDS.end()) {
89 value = 0.;
90 }
91 else if (SPECTROGRAM_NAN_BANDS.find(y) != SPECTROGRAM_NAN_BANDS.end()) {
92 value = std::numeric_limits<double>::quiet_NaN();
93 }
94 else {
95 // Generates value for non NaN/zero bands
96 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
97 value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
98 }
80
99
81 values[componentCount * dataIndex + i] = value;
100 values[componentCount * dataIndex + i] = value;
82 }
101 }
83 }
102 }
84
103
85 std::vector<double> m_YAxisData;
104 std::vector<double> m_YAxisData;
86 Unit m_YAxisUnit;
105 Unit m_YAxisUnit;
87 Unit m_ValuesUnit;
106 Unit m_ValuesUnit;
88 };
107 };
89
108
90 struct VectorCosinus : public ICosinusType {
109 struct VectorCosinus : public ICosinusType {
91 int componentCount() const override { return 3; }
110 int componentCount() const override { return 3; }
92
111
93 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
112 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
94 std::vector<double> valuesData) const override
113 std::vector<double> valuesData) const override
95 {
114 {
96 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
115 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
97 Unit{QStringLiteral("t"), true}, Unit{});
116 Unit{QStringLiteral("t"), true}, Unit{});
98 }
117 }
99
118
100 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
119 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
101 {
120 {
102 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
121 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
103 auto xValue = std::cos(x);
122 auto xValue = std::cos(x);
104 auto componentCount = this->componentCount();
123 auto componentCount = this->componentCount();
105 for (auto i = 0; i < componentCount; ++i) {
124 for (auto i = 0; i < componentCount; ++i) {
106 values[componentCount * dataIndex + i] = xValue / (i + 1);
125 values[componentCount * dataIndex + i] = xValue / (i + 1);
107 }
126 }
108 }
127 }
109 };
128 };
110
129
111 /// Converts string to cosinus type
130 /// Converts string to cosinus type
112 /// @return the cosinus type if the string could be converted, nullptr otherwise
131 /// @return the cosinus type if the string could be converted, nullptr otherwise
113 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
132 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
114 {
133 {
115 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
134 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
116 return std::make_unique<ScalarCosinus>();
135 return std::make_unique<ScalarCosinus>();
117 }
136 }
118 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
137 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
119 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
138 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
120 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
139 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
121 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
140 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
122
141
123 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"},
142 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"},
124 Unit{"eV/(cm^2-s-sr-eV)"});
143 Unit{"eV/(cm^2-s-sr-eV)"});
125 }
144 }
126 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
145 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
127 return std::make_unique<VectorCosinus>();
146 return std::make_unique<VectorCosinus>();
128 }
147 }
129 else {
148 else {
130 return nullptr;
149 return nullptr;
131 }
150 }
132 }
151 }
133
152
134 } // namespace
153 } // namespace
135
154
136 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
155 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
137 {
156 {
138 // No copy is made in clone
157 // No copy is made in clone
139 return std::make_shared<CosinusProvider>();
158 return std::make_shared<CosinusProvider>();
140 }
159 }
141
160
142 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
161 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
143 const SqpRange &dataRangeRequested,
162 const SqpRange &dataRangeRequested,
144 const QVariantHash &data)
163 const QVariantHash &data)
145 {
164 {
146 // TODO: Add Mutex
165 // TODO: Add Mutex
147 auto dataIndex = 0;
166 auto dataIndex = 0;
148
167
149 // Retrieves cosinus type
168 // Retrieves cosinus type
150 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
169 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
151 if (!typeVariant.canConvert<QString>()) {
170 if (!typeVariant.canConvert<QString>()) {
152 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
171 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
153 return nullptr;
172 return nullptr;
154 }
173 }
155
174
156 auto type = cosinusType(typeVariant.toString());
175 auto type = cosinusType(typeVariant.toString());
157 if (!type) {
176 if (!type) {
158 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
177 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
159 return nullptr;
178 return nullptr;
160 }
179 }
161
180
162 // Retrieves frequency
181 // Retrieves frequency
163 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
182 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
164 if (!freqVariant.canConvert<double>()) {
183 if (!freqVariant.canConvert<double>()) {
165 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
184 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
166 return nullptr;
185 return nullptr;
167 }
186 }
168
187
169 // Gets the timerange from the parameters
188 // Gets the timerange from the parameters
170 double freq = freqVariant.toDouble();
189 double freq = freqVariant.toDouble();
171 double start = std::ceil(dataRangeRequested.m_TStart * freq);
190 double start = std::ceil(dataRangeRequested.m_TStart * freq);
172 double end = std::floor(dataRangeRequested.m_TEnd * freq);
191 double end = std::floor(dataRangeRequested.m_TEnd * freq);
173
192
174 // We assure that timerange is valid
193 // We assure that timerange is valid
175 if (end < start) {
194 if (end < start) {
176 std::swap(start, end);
195 std::swap(start, end);
177 }
196 }
178
197
179 // Generates scalar series containing cosinus values (one value per second, end value is
198 // Generates scalar series containing cosinus values (one value per second, end value is
180 // included)
199 // included)
181 auto dataCount = end - start + 1;
200 auto dataCount = end - start + 1;
182
201
183 // Number of components (depending on the cosinus type)
202 // Number of components (depending on the cosinus type)
184 auto componentCount = type->componentCount();
203 auto componentCount = type->componentCount();
185
204
186 auto xAxisData = std::vector<double>{};
205 auto xAxisData = std::vector<double>{};
187 xAxisData.resize(dataCount);
206 xAxisData.resize(dataCount);
188
207
189 auto valuesData = std::vector<double>{};
208 auto valuesData = std::vector<double>{};
190 valuesData.resize(dataCount * componentCount);
209 valuesData.resize(dataCount * componentCount);
191
210
192 int progress = 0;
211 int progress = 0;
193 auto progressEnd = dataCount;
212 auto progressEnd = dataCount;
194 for (auto time = start; time <= end; ++time, ++dataIndex) {
213 for (auto time = start; time <= end; ++time, ++dataIndex) {
195 auto it = m_VariableToEnableProvider.find(acqIdentifier);
214 auto it = m_VariableToEnableProvider.find(acqIdentifier);
196 if (it != m_VariableToEnableProvider.end() && it.value()) {
215 if (it != m_VariableToEnableProvider.end() && it.value()) {
197 const auto x = time / freq;
216 const auto x = time / freq;
198
217
199 xAxisData[dataIndex] = x;
218 xAxisData[dataIndex] = x;
200
219
201 // Generates values (depending on the type)
220 // Generates values (depending on the type)
202 type->generateValues(x, valuesData, dataIndex);
221 type->generateValues(x, valuesData, dataIndex);
203
222
204 // progression
223 // progression
205 int currentProgress = (time - start) * 100.0 / progressEnd;
224 int currentProgress = (time - start) * 100.0 / progressEnd;
206 if (currentProgress != progress) {
225 if (currentProgress != progress) {
207 progress = currentProgress;
226 progress = currentProgress;
208
227
209 emit dataProvidedProgress(acqIdentifier, progress);
228 emit dataProvidedProgress(acqIdentifier, progress);
210 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
229 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
211 << QThread::currentThread()->objectName()
230 << QThread::currentThread()->objectName()
212 << progress;
231 << progress;
213 // NOTE: Try to use multithread if possible
232 // NOTE: Try to use multithread if possible
214 }
233 }
215 }
234 }
216 else {
235 else {
217 if (!it.value()) {
236 if (!it.value()) {
218 qCDebug(LOG_CosinusProvider())
237 qCDebug(LOG_CosinusProvider())
219 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
238 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
220 << end - time;
239 << end - time;
221 }
240 }
222 }
241 }
223 }
242 }
224 if (progress != 100) {
243 if (progress != 100) {
225 // We can close progression beacause all data has been retrieved
244 // We can close progression beacause all data has been retrieved
226 emit dataProvidedProgress(acqIdentifier, 100);
245 emit dataProvidedProgress(acqIdentifier, 100);
227 }
246 }
228 return type->createDataSeries(std::move(xAxisData), std::move(valuesData));
247 return type->createDataSeries(std::move(xAxisData), std::move(valuesData));
229 }
248 }
230
249
231 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
250 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
232 const DataProviderParameters &parameters)
251 const DataProviderParameters &parameters)
233 {
252 {
234 // TODO: Add Mutex
253 // TODO: Add Mutex
235 m_VariableToEnableProvider[acqIdentifier] = true;
254 m_VariableToEnableProvider[acqIdentifier] = true;
236 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
255 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
237 << QThread::currentThread()->objectName();
256 << QThread::currentThread()->objectName();
238 // NOTE: Try to use multithread if possible
257 // NOTE: Try to use multithread if possible
239 const auto times = parameters.m_Times;
258 const auto times = parameters.m_Times;
240
259
241 for (const auto &dateTime : qAsConst(times)) {
260 for (const auto &dateTime : qAsConst(times)) {
242 if (m_VariableToEnableProvider[acqIdentifier]) {
261 if (m_VariableToEnableProvider[acqIdentifier]) {
243 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
262 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
244 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
263 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
245 }
264 }
246 }
265 }
247 }
266 }
248
267
249 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
268 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
250 {
269 {
251 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
270 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
252 << QThread::currentThread()->objectName();
271 << QThread::currentThread()->objectName();
253 auto it = m_VariableToEnableProvider.find(acqIdentifier);
272 auto it = m_VariableToEnableProvider.find(acqIdentifier);
254 if (it != m_VariableToEnableProvider.end()) {
273 if (it != m_VariableToEnableProvider.end()) {
255 it.value() = false;
274 it.value() = false;
256 }
275 }
257 else {
276 else {
258 qCDebug(LOG_CosinusProvider())
277 qCDebug(LOG_CosinusProvider())
259 << tr("Aborting progression of inexistant identifier detected !!!");
278 << tr("Aborting progression of inexistant identifier detected !!!");
260 }
279 }
261 }
280 }
262
281
263 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
282 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
264 const QVariantHash &data)
283 const QVariantHash &data)
265 {
284 {
266 auto uid = QUuid::createUuid();
285 auto uid = QUuid::createUuid();
267 m_VariableToEnableProvider[uid] = true;
286 m_VariableToEnableProvider[uid] = true;
268 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
287 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
269
288
270 m_VariableToEnableProvider.remove(uid);
289 m_VariableToEnableProvider.remove(uid);
271 return dataSeries;
290 return dataSeries;
272 }
291 }
General Comments 0
You need to be logged in to leave comments. Login now