##// END OF EJS Templates
Updates sqp color scale thresholds (2)...
Alexandre Leroux -
r1061:edadf7db2f1e
parent child
Show More
@@ -1,40 +1,42
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5
5
6 #include <Visualization/VisualizationDefs.h>
6 #include <Visualization/VisualizationDefs.h>
7
7
8 class IDataSeries;
8 class IDataSeries;
9 class QCustomPlot;
9 class QCustomPlot;
10 class QMouseEvent;
10 class QMouseEvent;
11 class Unit;
11 class Unit;
12 class VisualizationGraphWidget;
12 class VisualizationGraphWidget;
13
13
14 class VisualizationGraphRenderingDelegate {
14 class VisualizationGraphRenderingDelegate {
15 public:
15 public:
16 /// Ctor
16 /// Ctor
17 /// @param graphWidget the graph widget to which the delegate is associated
17 /// @param graphWidget the graph widget to which the delegate is associated
18 /// @remarks the graph widget must exist throughout the life cycle of the delegate
18 /// @remarks the graph widget must exist throughout the life cycle of the delegate
19 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
19 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
20
20
21 void onMouseDoubleClick(QMouseEvent *event) noexcept;
21 void onMouseDoubleClick(QMouseEvent *event) noexcept;
22 void onMouseMove(QMouseEvent *event) noexcept;
22 void onMouseMove(QMouseEvent *event) noexcept;
23 /// Updates rendering when data of plot changed
24 void onPlotUpdated() noexcept;
23
25
24 /// Sets properties of the plot's axes from the data series passed as parameter
26 /// Sets properties of the plot's axes from the data series passed as parameter
25 void setAxesProperties(std::shared_ptr<IDataSeries> dataSeries) noexcept;
27 void setAxesProperties(std::shared_ptr<IDataSeries> dataSeries) noexcept;
26
28
27 /// Sets rendering properties of the plottables passed as parameter, from the data series that
29 /// Sets rendering properties of the plottables passed as parameter, from the data series that
28 /// generated these
30 /// generated these
29 void setPlottablesProperties(std::shared_ptr<IDataSeries> dataSeries,
31 void setPlottablesProperties(std::shared_ptr<IDataSeries> dataSeries,
30 PlottablesMap &plottables) noexcept;
32 PlottablesMap &plottables) noexcept;
31
33
32 /// Shows or hides graph overlay (name, close button, etc.)
34 /// Shows or hides graph overlay (name, close button, etc.)
33 void showGraphOverlay(bool show) noexcept;
35 void showGraphOverlay(bool show) noexcept;
34
36
35 private:
37 private:
36 class VisualizationGraphRenderingDelegatePrivate;
38 class VisualizationGraphRenderingDelegatePrivate;
37 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
39 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
38 };
40 };
39
41
40 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
42 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
@@ -1,344 +1,340
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/DataSeriesUtils.h>
4 #include <Data/DataSeriesUtils.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 <Variable/Variable.h>
9 #include <Variable/Variable.h>
10
10
11 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
12
12
13 namespace {
13 namespace {
14
14
15 class SqpDataContainer : public QCPGraphDataContainer {
15 class SqpDataContainer : public QCPGraphDataContainer {
16 public:
16 public:
17 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
17 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
18 };
18 };
19
19
20 /**
20 /**
21 * Struct used to create plottables, depending on the type of the data series from which to create
21 * Struct used to create plottables, depending on the type of the data series from which to create
22 * them
22 * them
23 * @tparam T the data series' type
23 * @tparam T the data series' type
24 * @remarks Default implementation can't create plottables
24 * @remarks Default implementation can't create plottables
25 */
25 */
26 template <typename T, typename Enabled = void>
26 template <typename T, typename Enabled = void>
27 struct PlottablesCreator {
27 struct PlottablesCreator {
28 static PlottablesMap createPlottables(T &, QCustomPlot &)
28 static PlottablesMap createPlottables(T &, QCustomPlot &)
29 {
29 {
30 qCCritical(LOG_DataSeries())
30 qCCritical(LOG_DataSeries())
31 << QObject::tr("Can't create plottables: unmanaged data series type");
31 << QObject::tr("Can't create plottables: unmanaged data series type");
32 return {};
32 return {};
33 }
33 }
34 };
34 };
35
35
36 /**
36 /**
37 * Specialization of PlottablesCreator for scalars and vectors
37 * Specialization of PlottablesCreator for scalars and vectors
38 * @sa ScalarSeries
38 * @sa ScalarSeries
39 * @sa VectorSeries
39 * @sa VectorSeries
40 */
40 */
41 template <typename T>
41 template <typename T>
42 struct PlottablesCreator<T,
42 struct PlottablesCreator<T,
43 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
43 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
44 or std::is_base_of<VectorSeries, T>::value> > {
44 or std::is_base_of<VectorSeries, T>::value> > {
45 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
45 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
46 {
46 {
47 PlottablesMap result{};
47 PlottablesMap result{};
48
48
49 // Gets the number of components of the data series
49 // Gets the number of components of the data series
50 dataSeries.lockRead();
50 dataSeries.lockRead();
51 auto componentCount = dataSeries.valuesData()->componentCount();
51 auto componentCount = dataSeries.valuesData()->componentCount();
52 dataSeries.unlock();
52 dataSeries.unlock();
53
53
54 // For each component of the data series, creates a QCPGraph to add to the plot
54 // For each component of the data series, creates a QCPGraph to add to the plot
55 for (auto i = 0; i < componentCount; ++i) {
55 for (auto i = 0; i < componentCount; ++i) {
56 auto graph = plot.addGraph();
56 auto graph = plot.addGraph();
57 result.insert({i, graph});
57 result.insert({i, graph});
58 }
58 }
59
59
60 plot.replot();
60 plot.replot();
61
61
62 return result;
62 return result;
63 }
63 }
64 };
64 };
65
65
66 /**
66 /**
67 * Specialization of PlottablesCreator for spectrograms
67 * Specialization of PlottablesCreator for spectrograms
68 * @sa SpectrogramSeries
68 * @sa SpectrogramSeries
69 */
69 */
70 template <typename T>
70 template <typename T>
71 struct PlottablesCreator<T,
71 struct PlottablesCreator<T,
72 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
72 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
73 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
73 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
74 {
74 {
75 PlottablesMap result{};
75 PlottablesMap result{};
76 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
76 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
77
77
78 plot.replot();
78 plot.replot();
79
79
80 return result;
80 return result;
81 }
81 }
82 };
82 };
83
83
84 /**
84 /**
85 * Struct used to update plottables, depending on the type of the data series from which to update
85 * Struct used to update plottables, depending on the type of the data series from which to update
86 * them
86 * them
87 * @tparam T the data series' type
87 * @tparam T the data series' type
88 * @remarks Default implementation can't update plottables
88 * @remarks Default implementation can't update plottables
89 */
89 */
90 template <typename T, typename Enabled = void>
90 template <typename T, typename Enabled = void>
91 struct PlottablesUpdater {
91 struct PlottablesUpdater {
92 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
92 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
93 {
93 {
94 qCCritical(LOG_VisualizationGraphHelper())
94 qCCritical(LOG_VisualizationGraphHelper())
95 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
95 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
96 }
96 }
97
97
98 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
98 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
99 {
99 {
100 qCCritical(LOG_VisualizationGraphHelper())
100 qCCritical(LOG_VisualizationGraphHelper())
101 << QObject::tr("Can't update plottables: unmanaged data series type");
101 << QObject::tr("Can't update plottables: unmanaged data series type");
102 }
102 }
103 };
103 };
104
104
105 /**
105 /**
106 * Specialization of PlottablesUpdater for scalars and vectors
106 * Specialization of PlottablesUpdater for scalars and vectors
107 * @sa ScalarSeries
107 * @sa ScalarSeries
108 * @sa VectorSeries
108 * @sa VectorSeries
109 */
109 */
110 template <typename T>
110 template <typename T>
111 struct PlottablesUpdater<T,
111 struct PlottablesUpdater<T,
112 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
112 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
113 or std::is_base_of<VectorSeries, T>::value> > {
113 or std::is_base_of<VectorSeries, T>::value> > {
114 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
114 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
115 {
115 {
116 auto minValue = 0., maxValue = 0.;
116 auto minValue = 0., maxValue = 0.;
117
117
118 dataSeries.lockRead();
118 dataSeries.lockRead();
119 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
119 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
120 auto end = dataSeries.cend();
120 auto end = dataSeries.cend();
121 if (valuesBounds.first != end && valuesBounds.second != end) {
121 if (valuesBounds.first != end && valuesBounds.second != end) {
122 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
122 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
123
123
124 minValue = rangeValue(valuesBounds.first->minValue());
124 minValue = rangeValue(valuesBounds.first->minValue());
125 maxValue = rangeValue(valuesBounds.second->maxValue());
125 maxValue = rangeValue(valuesBounds.second->maxValue());
126 }
126 }
127 dataSeries.unlock();
127 dataSeries.unlock();
128
128
129 plot.yAxis->setRange(QCPRange{minValue, maxValue});
129 plot.yAxis->setRange(QCPRange{minValue, maxValue});
130 }
130 }
131
131
132 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
132 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
133 bool rescaleAxes)
133 bool rescaleAxes)
134 {
134 {
135
135
136 // For each plottable to update, resets its data
136 // For each plottable to update, resets its data
137 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
137 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
138 for (const auto &plottable : plottables) {
138 for (const auto &plottable : plottables) {
139 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
139 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
140 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
140 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
141 graph->setData(dataContainer);
141 graph->setData(dataContainer);
142
142
143 dataContainers.insert({plottable.first, dataContainer});
143 dataContainers.insert({plottable.first, dataContainer});
144 }
144 }
145 }
145 }
146 dataSeries.lockRead();
146 dataSeries.lockRead();
147
147
148 // - Gets the data of the series included in the current range
148 // - Gets the data of the series included in the current range
149 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
149 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
150 // and value data. The correct value is retrieved according to the index of the component
150 // and value data. The correct value is retrieved according to the index of the component
151 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
151 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
152 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
152 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
153 for (const auto &dataContainer : dataContainers) {
153 for (const auto &dataContainer : dataContainers) {
154 auto componentIndex = dataContainer.first;
154 auto componentIndex = dataContainer.first;
155 dataContainer.second->appendGraphData(
155 dataContainer.second->appendGraphData(
156 QCPGraphData(it->x(), it->value(componentIndex)));
156 QCPGraphData(it->x(), it->value(componentIndex)));
157 }
157 }
158 }
158 }
159
159
160 dataSeries.unlock();
160 dataSeries.unlock();
161
161
162 if (!plottables.empty()) {
162 if (!plottables.empty()) {
163 auto plot = plottables.begin()->second->parentPlot();
163 auto plot = plottables.begin()->second->parentPlot();
164
164
165 if (rescaleAxes) {
165 if (rescaleAxes) {
166 plot->rescaleAxes();
166 plot->rescaleAxes();
167 }
167 }
168
169 plot->replot();
170 }
168 }
171 }
169 }
172 };
170 };
173
171
174 /**
172 /**
175 * Specialization of PlottablesUpdater for spectrograms
173 * Specialization of PlottablesUpdater for spectrograms
176 * @sa SpectrogramSeries
174 * @sa SpectrogramSeries
177 */
175 */
178 template <typename T>
176 template <typename T>
179 struct PlottablesUpdater<T,
177 struct PlottablesUpdater<T,
180 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
178 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
181 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
179 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
182 {
180 {
183 double min, max;
181 double min, max;
184 std::tie(min, max) = dataSeries.yBounds();
182 std::tie(min, max) = dataSeries.yBounds();
185
183
186 if (!std::isnan(min) && !std::isnan(max)) {
184 if (!std::isnan(min) && !std::isnan(max)) {
187 plot.yAxis->setRange(QCPRange{min, max});
185 plot.yAxis->setRange(QCPRange{min, max});
188 }
186 }
189 }
187 }
190
188
191 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
189 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
192 bool rescaleAxes)
190 bool rescaleAxes)
193 {
191 {
194 if (plottables.empty()) {
192 if (plottables.empty()) {
195 qCDebug(LOG_VisualizationGraphHelper())
193 qCDebug(LOG_VisualizationGraphHelper())
196 << QObject::tr("Can't update spectrogram: no colormap has been associated");
194 << QObject::tr("Can't update spectrogram: no colormap has been associated");
197 return;
195 return;
198 }
196 }
199
197
200 // Gets the colormap to update (normally there is only one colormap)
198 // Gets the colormap to update (normally there is only one colormap)
201 Q_ASSERT(plottables.size() == 1);
199 Q_ASSERT(plottables.size() == 1);
202 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
200 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
203 Q_ASSERT(colormap != nullptr);
201 Q_ASSERT(colormap != nullptr);
204
202
205 dataSeries.lockRead();
203 dataSeries.lockRead();
206
204
207 // Processing spectrogram data for display in QCustomPlot
205 // Processing spectrogram data for display in QCustomPlot
208 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
206 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
209
207
210 // Computes logarithmic y-axis resolution for the spectrogram
208 // Computes logarithmic y-axis resolution for the spectrogram
211 auto yData = its.first->y();
209 auto yData = its.first->y();
212 auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
210 auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true);
213
211
214 // Generates mesh for colormap
212 // Generates mesh for colormap
215 auto mesh = DataSeriesUtils::regularMesh(
213 auto mesh = DataSeriesUtils::regularMesh(
216 its.first, its.second, DataSeriesUtils::Resolution{dataSeries.xResolution()},
214 its.first, its.second, DataSeriesUtils::Resolution{dataSeries.xResolution()},
217 yResolution);
215 yResolution);
218
216
219 dataSeries.unlock();
217 dataSeries.unlock();
220
218
221 colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
219 colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY);
222 if (!mesh.isEmpty()) {
220 if (!mesh.isEmpty()) {
223 colormap->data()->setRange(
221 colormap->data()->setRange(
224 QCPRange{mesh.m_XMin, mesh.xMax()},
222 QCPRange{mesh.m_XMin, mesh.xMax()},
225 // y-axis range is converted to linear values
223 // y-axis range is converted to linear values
226 QCPRange{std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax())});
224 QCPRange{std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax())});
227
225
228 // Sets values
226 // Sets values
229 auto index = 0;
227 auto index = 0;
230 for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, ++index) {
228 for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, ++index) {
231 auto xIndex = index % mesh.m_NbX;
229 auto xIndex = index % mesh.m_NbX;
232 auto yIndex = index / mesh.m_NbX;
230 auto yIndex = index / mesh.m_NbX;
233
231
234 colormap->data()->setCell(xIndex, yIndex, *it);
232 colormap->data()->setCell(xIndex, yIndex, *it);
235
233
236 // Makes the NaN values to be transparent in the colormap
234 // Makes the NaN values to be transparent in the colormap
237 if (std::isnan(*it)) {
235 if (std::isnan(*it)) {
238 colormap->data()->setAlpha(xIndex, yIndex, 0);
236 colormap->data()->setAlpha(xIndex, yIndex, 0);
239 }
237 }
240 }
238 }
241 }
239 }
242
240
243 // Rescales axes
241 // Rescales axes
244 auto plot = colormap->parentPlot();
242 auto plot = colormap->parentPlot();
245
243
246 if (rescaleAxes) {
244 if (rescaleAxes) {
247 plot->rescaleAxes();
245 plot->rescaleAxes();
248 }
246 }
249
250 plot->replot();
251 }
247 }
252 };
248 };
253
249
254 /**
250 /**
255 * Helper used to create/update plottables
251 * Helper used to create/update plottables
256 */
252 */
257 struct IPlottablesHelper {
253 struct IPlottablesHelper {
258 virtual ~IPlottablesHelper() noexcept = default;
254 virtual ~IPlottablesHelper() noexcept = default;
259 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
255 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
260 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
256 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
261 virtual void update(PlottablesMap &plottables, const SqpRange &range,
257 virtual void update(PlottablesMap &plottables, const SqpRange &range,
262 bool rescaleAxes = false) const = 0;
258 bool rescaleAxes = false) const = 0;
263 };
259 };
264
260
265 /**
261 /**
266 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
262 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
267 * @tparam T the data series' type
263 * @tparam T the data series' type
268 */
264 */
269 template <typename T>
265 template <typename T>
270 struct PlottablesHelper : public IPlottablesHelper {
266 struct PlottablesHelper : public IPlottablesHelper {
271 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
267 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
272
268
273 PlottablesMap create(QCustomPlot &plot) const override
269 PlottablesMap create(QCustomPlot &plot) const override
274 {
270 {
275 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
271 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
276 }
272 }
277
273
278 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
274 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
279 {
275 {
280 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
276 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
281 }
277 }
282
278
283 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
279 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
284 {
280 {
285 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
281 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
286 }
282 }
287
283
288 T &m_DataSeries;
284 T &m_DataSeries;
289 };
285 };
290
286
291 /// Creates IPlottablesHelper according to a data series
287 /// Creates IPlottablesHelper according to a data series
292 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
288 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
293 {
289 {
294 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
290 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
295 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
291 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
296 }
292 }
297 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
293 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
298 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
294 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
299 }
295 }
300 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
296 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
301 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
297 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
302 }
298 }
303 else {
299 else {
304 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
300 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
305 }
301 }
306 }
302 }
307
303
308 } // namespace
304 } // namespace
309
305
310 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
306 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
311 QCustomPlot &plot) noexcept
307 QCustomPlot &plot) noexcept
312 {
308 {
313 if (variable) {
309 if (variable) {
314 auto helper = createHelper(variable->dataSeries());
310 auto helper = createHelper(variable->dataSeries());
315 auto plottables = helper->create(plot);
311 auto plottables = helper->create(plot);
316 return plottables;
312 return plottables;
317 }
313 }
318 else {
314 else {
319 qCDebug(LOG_VisualizationGraphHelper())
315 qCDebug(LOG_VisualizationGraphHelper())
320 << QObject::tr("Can't create graph plottables : the variable is null");
316 << QObject::tr("Can't create graph plottables : the variable is null");
321 return PlottablesMap{};
317 return PlottablesMap{};
322 }
318 }
323 }
319 }
324
320
325 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
321 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
326 QCustomPlot &plot) noexcept
322 QCustomPlot &plot) noexcept
327 {
323 {
328 if (variable) {
324 if (variable) {
329 auto helper = createHelper(variable->dataSeries());
325 auto helper = createHelper(variable->dataSeries());
330 helper->setYAxisRange(variable->range(), plot);
326 helper->setYAxisRange(variable->range(), plot);
331 }
327 }
332 else {
328 else {
333 qCDebug(LOG_VisualizationGraphHelper())
329 qCDebug(LOG_VisualizationGraphHelper())
334 << QObject::tr("Can't set y-axis range of plot: the variable is null");
330 << QObject::tr("Can't set y-axis range of plot: the variable is null");
335 }
331 }
336 }
332 }
337
333
338 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
334 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
339 std::shared_ptr<IDataSeries> dataSeries,
335 std::shared_ptr<IDataSeries> dataSeries,
340 const SqpRange &dateTime)
336 const SqpRange &dateTime)
341 {
337 {
342 auto helper = createHelper(dataSeries);
338 auto helper = createHelper(dataSeries);
343 helper->update(plottables, dateTime);
339 helper->update(plottables, dateTime);
344 }
340 }
@@ -1,258 +1,265
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/AxisRenderingUtils.h"
2 #include "Visualization/AxisRenderingUtils.h"
3 #include "Visualization/ColorScaleEditor.h"
3 #include "Visualization/ColorScaleEditor.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
4 #include "Visualization/PlottablesRenderingUtils.h"
5 #include "Visualization/SqpColorScale.h"
5 #include "Visualization/SqpColorScale.h"
6 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationGraphWidget.h"
7 #include "Visualization/qcustomplot.h"
7 #include "Visualization/qcustomplot.h"
8
8
9 #include <Common/DateUtils.h>
9 #include <Common/DateUtils.h>
10
10
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12
12
13 #include <SqpApplication.h>
13 #include <SqpApplication.h>
14
14
15 namespace {
15 namespace {
16
16
17 /// Name of the axes layer in QCustomPlot
17 /// Name of the axes layer in QCustomPlot
18 const auto AXES_LAYER = QStringLiteral("axes");
18 const auto AXES_LAYER = QStringLiteral("axes");
19
19
20 /// Icon used to show x-axis properties
20 /// Icon used to show x-axis properties
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
21 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
22
22
23 /// Name of the overlay layer in QCustomPlot
23 /// Name of the overlay layer in QCustomPlot
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
24 const auto OVERLAY_LAYER = QStringLiteral("overlay");
25
25
26 /// Pixmap used to show x-axis properties
26 /// Pixmap used to show x-axis properties
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
27 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
28
28
29 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
29 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
30
30
31 /// Offset used to shift the tooltip of the mouse
31 /// Offset used to shift the tooltip of the mouse
32 const auto TOOLTIP_OFFSET = QPoint{20, 20};
32 const auto TOOLTIP_OFFSET = QPoint{20, 20};
33
33
34 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
34 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
35 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
35 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
36
36
37 /// Timeout after which the tooltip is displayed
37 /// Timeout after which the tooltip is displayed
38 const auto TOOLTIP_TIMEOUT = 500;
38 const auto TOOLTIP_TIMEOUT = 500;
39
39
40 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
40 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
41 {
41 {
42 tracer.setInterpolating(false);
42 tracer.setInterpolating(false);
43 tracer.setStyle(QCPItemTracer::tsCircle);
43 tracer.setStyle(QCPItemTracer::tsCircle);
44 tracer.setSize(3);
44 tracer.setSize(3);
45 tracer.setPen(QPen(Qt::black));
45 tracer.setPen(QPen(Qt::black));
46 tracer.setBrush(Qt::black);
46 tracer.setBrush(Qt::black);
47 }
47 }
48
48
49 QPixmap pixmap(const QString &iconPath) noexcept
49 QPixmap pixmap(const QString &iconPath) noexcept
50 {
50 {
51 return QIcon{iconPath}.pixmap(QSize{16, 16});
51 return QIcon{iconPath}.pixmap(QSize{16, 16});
52 }
52 }
53
53
54 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
54 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
55 {
55 {
56 // Icon
56 // Icon
57 pixmap.setPixmap(
57 pixmap.setPixmap(
58 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
58 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
59
59
60 // Position
60 // Position
61 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
61 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
62 pixmap.topLeft->setCoords(1, 0);
62 pixmap.topLeft->setCoords(1, 0);
63 pixmap.setClipToAxisRect(false);
63 pixmap.setClipToAxisRect(false);
64
64
65 // Can be selected
65 // Can be selected
66 pixmap.setSelectable(true);
66 pixmap.setSelectable(true);
67 }
67 }
68
68
69 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
69 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
70 {
70 {
71 // Icon
71 // Icon
72 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
72 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
73
73
74 // Position
74 // Position
75 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
75 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
76 itemPixmap.topLeft->setCoords(0, 1);
76 itemPixmap.topLeft->setCoords(0, 1);
77 itemPixmap.setClipToAxisRect(false);
77 itemPixmap.setClipToAxisRect(false);
78
78
79 // Can be selected
79 // Can be selected
80 itemPixmap.setSelectable(true);
80 itemPixmap.setSelectable(true);
81 }
81 }
82
82
83 void initTitleTextStyle(QCPItemText &text) noexcept
83 void initTitleTextStyle(QCPItemText &text) noexcept
84 {
84 {
85 // Font and background styles
85 // Font and background styles
86 text.setColor(Qt::gray);
86 text.setColor(Qt::gray);
87 text.setBrush(Qt::white);
87 text.setBrush(Qt::white);
88
88
89 // Position
89 // Position
90 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
90 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
91 text.position->setType(QCPItemPosition::ptAxisRectRatio);
91 text.position->setType(QCPItemPosition::ptAxisRectRatio);
92 text.position->setCoords(0.5, 0);
92 text.position->setCoords(0.5, 0);
93 }
93 }
94
94
95 } // namespace
95 } // namespace
96
96
97 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
97 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
98 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
98 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
99 : m_Plot{graphWidget.plot()},
99 : m_Plot{graphWidget.plot()},
100 m_PointTracer{new QCPItemTracer{&m_Plot}},
100 m_PointTracer{new QCPItemTracer{&m_Plot}},
101 m_TracerTimer{},
101 m_TracerTimer{},
102 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
102 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
103 m_TitleText{new QCPItemText{&m_Plot}},
103 m_TitleText{new QCPItemText{&m_Plot}},
104 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
104 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
105 m_ShowXAxis{true},
105 m_ShowXAxis{true},
106 m_XAxisLabel{},
106 m_XAxisLabel{},
107 m_ColorScale{SqpColorScale{m_Plot}}
107 m_ColorScale{SqpColorScale{m_Plot}}
108 {
108 {
109 initPointTracerStyle(*m_PointTracer);
109 initPointTracerStyle(*m_PointTracer);
110
110
111 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
111 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
112 m_TracerTimer.setSingleShot(true);
112 m_TracerTimer.setSingleShot(true);
113
113
114 // Inits "close button" in plot overlay
114 // Inits "close button" in plot overlay
115 m_ClosePixmap->setLayer(OVERLAY_LAYER);
115 m_ClosePixmap->setLayer(OVERLAY_LAYER);
116 initClosePixmapStyle(*m_ClosePixmap);
116 initClosePixmapStyle(*m_ClosePixmap);
117
117
118 // Connects pixmap selection to graph widget closing
118 // Connects pixmap selection to graph widget closing
119 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
119 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
120 [&graphWidget](bool selected) {
120 [&graphWidget](bool selected) {
121 if (selected) {
121 if (selected) {
122 graphWidget.close();
122 graphWidget.close();
123 }
123 }
124 });
124 });
125
125
126 // Inits graph name in plot overlay
126 // Inits graph name in plot overlay
127 m_TitleText->setLayer(OVERLAY_LAYER);
127 m_TitleText->setLayer(OVERLAY_LAYER);
128 m_TitleText->setText(graphWidget.name());
128 m_TitleText->setText(graphWidget.name());
129 initTitleTextStyle(*m_TitleText);
129 initTitleTextStyle(*m_TitleText);
130
130
131 // Inits "show x-axis button" in plot overlay
131 // Inits "show x-axis button" in plot overlay
132 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
132 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
133 initXAxisPixmapStyle(*m_XAxisPixmap);
133 initXAxisPixmapStyle(*m_XAxisPixmap);
134
134
135 // Connects pixmap selection to graph x-axis showing/hiding
135 // Connects pixmap selection to graph x-axis showing/hiding
136 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
136 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
137 if (m_XAxisPixmap->selected()) {
137 if (m_XAxisPixmap->selected()) {
138 // Changes the selection state and refreshes the x-axis
138 // Changes the selection state and refreshes the x-axis
139 m_ShowXAxis = !m_ShowXAxis;
139 m_ShowXAxis = !m_ShowXAxis;
140 updateXAxisState();
140 updateXAxisState();
141 m_Plot.layer(AXES_LAYER)->replot();
141 m_Plot.layer(AXES_LAYER)->replot();
142
142
143 // Deselects the x-axis pixmap and updates icon
143 // Deselects the x-axis pixmap and updates icon
144 m_XAxisPixmap->setSelected(false);
144 m_XAxisPixmap->setSelected(false);
145 m_XAxisPixmap->setPixmap(
145 m_XAxisPixmap->setPixmap(
146 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
146 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
147 m_Plot.layer(OVERLAY_LAYER)->replot();
147 m_Plot.layer(OVERLAY_LAYER)->replot();
148 }
148 }
149 });
149 });
150 }
150 }
151
151
152 /// Updates state of x-axis according to the current selection of x-axis pixmap
152 /// Updates state of x-axis according to the current selection of x-axis pixmap
153 /// @remarks the method doesn't call plot refresh
153 /// @remarks the method doesn't call plot refresh
154 void updateXAxisState() noexcept
154 void updateXAxisState() noexcept
155 {
155 {
156 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
156 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
157 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
157 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
158 }
158 }
159
159
160 QCustomPlot &m_Plot;
160 QCustomPlot &m_Plot;
161 QCPItemTracer *m_PointTracer;
161 QCPItemTracer *m_PointTracer;
162 QTimer m_TracerTimer;
162 QTimer m_TracerTimer;
163 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
163 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
164 QCPItemText *m_TitleText; /// Graph's title
164 QCPItemText *m_TitleText; /// Graph's title
165 QCPItemPixmap *m_XAxisPixmap;
165 QCPItemPixmap *m_XAxisPixmap;
166 bool m_ShowXAxis; /// X-axis properties are shown or hidden
166 bool m_ShowXAxis; /// X-axis properties are shown or hidden
167 QString m_XAxisLabel;
167 QString m_XAxisLabel;
168 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
168 SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
169 };
169 };
170
170
171 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
171 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
172 VisualizationGraphWidget &graphWidget)
172 VisualizationGraphWidget &graphWidget)
173 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
173 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
174 {
174 {
175 }
175 }
176
176
177 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
177 void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent *event) noexcept
178 {
178 {
179 // Opens color scale editor if color scale is double clicked
179 // Opens color scale editor if color scale is double clicked
180 auto colorScale = dynamic_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
180 auto colorScale = dynamic_cast<QCPColorScale *>(impl->m_Plot.layoutElementAt(event->pos()));
181 if (impl->m_ColorScale.m_Scale == colorScale) {
181 if (impl->m_ColorScale.m_Scale == colorScale) {
182 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
182 if (ColorScaleEditor{impl->m_ColorScale}.exec() == QDialog::Accepted) {
183 impl->m_Plot.replot();
183 impl->m_Plot.replot();
184 }
184 }
185 }
185 }
186 }
186 }
187
187
188 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
188 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
189 {
189 {
190 // Cancels pending refresh
190 // Cancels pending refresh
191 impl->m_TracerTimer.disconnect();
191 impl->m_TracerTimer.disconnect();
192
192
193 // Reinits tracers
193 // Reinits tracers
194 impl->m_PointTracer->setGraph(nullptr);
194 impl->m_PointTracer->setGraph(nullptr);
195 impl->m_PointTracer->setVisible(false);
195 impl->m_PointTracer->setVisible(false);
196 impl->m_Plot.replot();
196 impl->m_Plot.replot();
197
197
198 // Gets the graph under the mouse position
198 // Gets the graph under the mouse position
199 auto eventPos = event->pos();
199 auto eventPos = event->pos();
200 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
200 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
201 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
201 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
202 auto graphData = graph->data();
202 auto graphData = graph->data();
203
203
204 // Gets the closest data point to the mouse
204 // Gets the closest data point to the mouse
205 auto graphDataIt = graphData->findBegin(mouseKey);
205 auto graphDataIt = graphData->findBegin(mouseKey);
206 if (graphDataIt != graphData->constEnd()) {
206 if (graphDataIt != graphData->constEnd()) {
207 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
207 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
208 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
208 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
209
209
210 // Displays point tracer
210 // Displays point tracer
211 impl->m_PointTracer->setGraph(graph);
211 impl->m_PointTracer->setGraph(graph);
212 impl->m_PointTracer->setGraphKey(graphDataIt->key);
212 impl->m_PointTracer->setGraphKey(graphDataIt->key);
213 impl->m_PointTracer->setLayer(
213 impl->m_PointTracer->setLayer(
214 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
214 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
215 impl->m_PointTracer->setVisible(true);
215 impl->m_PointTracer->setVisible(true);
216 impl->m_Plot.replot();
216 impl->m_Plot.replot();
217
217
218 // Starts timer to show tooltip after timeout
218 // Starts timer to show tooltip after timeout
219 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
219 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
220 {
220 {
221 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
221 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
222 &impl->m_Plot, TOOLTIP_RECT);
222 &impl->m_Plot, TOOLTIP_RECT);
223 };
223 };
224
224
225 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
225 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
226 impl->m_TracerTimer.start();
226 impl->m_TracerTimer.start();
227 }
227 }
228 }
228 }
229 }
229 }
230
230
231 void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept
232 {
233 // Updates color scale bounds
234 impl->m_ColorScale.updateDataRange();
235 impl->m_Plot.replot();
236 }
237
231 void VisualizationGraphRenderingDelegate::setAxesProperties(
238 void VisualizationGraphRenderingDelegate::setAxesProperties(
232 std::shared_ptr<IDataSeries> dataSeries) noexcept
239 std::shared_ptr<IDataSeries> dataSeries) noexcept
233 {
240 {
234 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
241 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
235 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
242 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
236
243
237 auto axisHelper = IAxisHelperFactory::create(dataSeries);
244 auto axisHelper = IAxisHelperFactory::create(dataSeries);
238 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
245 axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale);
239
246
240 // Updates x-axis state
247 // Updates x-axis state
241 impl->updateXAxisState();
248 impl->updateXAxisState();
242
249
243 impl->m_Plot.layer(AXES_LAYER)->replot();
250 impl->m_Plot.layer(AXES_LAYER)->replot();
244 }
251 }
245
252
246 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
253 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
247 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
254 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
248 {
255 {
249 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
256 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
250 plottablesHelper->setProperties(plottables);
257 plottablesHelper->setProperties(plottables);
251 }
258 }
252
259
253 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
260 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
254 {
261 {
255 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
262 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
256 overlay->setVisible(show);
263 overlay->setVisible(show);
257 overlay->replot();
264 overlay->replot();
258 }
265 }
@@ -1,604 +1,612
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationZoneWidget.h"
7 #include "Visualization/VisualizationZoneWidget.h"
8 #include "ui_VisualizationGraphWidget.h"
8 #include "ui_VisualizationGraphWidget.h"
9
9
10 #include <Common/MimeTypesDef.h>
10 #include <Common/MimeTypesDef.h>
11 #include <Data/ArrayData.h>
11 #include <Data/ArrayData.h>
12 #include <Data/IDataSeries.h>
12 #include <Data/IDataSeries.h>
13 #include <DragAndDrop/DragDropHelper.h>
13 #include <DragAndDrop/DragDropHelper.h>
14 #include <Settings/SqpSettingsDefs.h>
14 #include <Settings/SqpSettingsDefs.h>
15 #include <SqpApplication.h>
15 #include <SqpApplication.h>
16 #include <Time/TimeController.h>
16 #include <Time/TimeController.h>
17 #include <Variable/Variable.h>
17 #include <Variable/Variable.h>
18 #include <Variable/VariableController.h>
18 #include <Variable/VariableController.h>
19
19
20 #include <unordered_map>
20 #include <unordered_map>
21
21
22 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
22 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
23
23
24 namespace {
24 namespace {
25
25
26 /// Key pressed to enable zoom on horizontal axis
26 /// Key pressed to enable zoom on horizontal axis
27 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
27 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
28
28
29 /// Key pressed to enable zoom on vertical axis
29 /// Key pressed to enable zoom on vertical axis
30 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
30 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
31
31
32 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
32 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
33 const auto PAN_SPEED = 5;
33 const auto PAN_SPEED = 5;
34
34
35 /// Key pressed to enable a calibration pan
35 /// Key pressed to enable a calibration pan
36 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
36 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
37
37
38 /// Minimum size for the zoom box, in percentage of the axis range
38 /// Minimum size for the zoom box, in percentage of the axis range
39 const auto ZOOM_BOX_MIN_SIZE = 0.8;
39 const auto ZOOM_BOX_MIN_SIZE = 0.8;
40
40
41 /// Format of the dates appearing in the label of a cursor
41 /// Format of the dates appearing in the label of a cursor
42 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
42 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
43
43
44 } // namespace
44 } // namespace
45
45
46 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
46 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
47
47
48 explicit VisualizationGraphWidgetPrivate(const QString &name)
48 explicit VisualizationGraphWidgetPrivate(const QString &name)
49 : m_Name{name},
49 : m_Name{name},
50 m_DoAcquisition{true},
50 m_DoAcquisition{true},
51 m_IsCalibration{false},
51 m_IsCalibration{false},
52 m_RenderingDelegate{nullptr}
52 m_RenderingDelegate{nullptr}
53 {
53 {
54 }
54 }
55
55
56 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
57 const SqpRange &range)
58 {
59 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
60
61 // Prevents that data has changed to update rendering
62 m_RenderingDelegate->onPlotUpdated();
63 }
64
56 QString m_Name;
65 QString m_Name;
57 // 1 variable -> n qcpplot
66 // 1 variable -> n qcpplot
58 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
67 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
59 bool m_DoAcquisition;
68 bool m_DoAcquisition;
60 bool m_IsCalibration;
69 bool m_IsCalibration;
61 /// Delegate used to attach rendering features to the plot
70 /// Delegate used to attach rendering features to the plot
62 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
71 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
63
72
64 QCPItemRect *m_DrawingRect = nullptr;
73 QCPItemRect *m_DrawingRect = nullptr;
65 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
74 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
66 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
75 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
67
76
68 void configureDrawingRect()
77 void configureDrawingRect()
69 {
78 {
70 if (m_DrawingRect) {
79 if (m_DrawingRect) {
71 QPen p;
80 QPen p;
72 p.setWidth(2);
81 p.setWidth(2);
73 m_DrawingRect->setPen(p);
82 m_DrawingRect->setPen(p);
74 }
83 }
75 }
84 }
76
85
77 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
86 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
78 {
87 {
79 removeDrawingRect(plot);
88 removeDrawingRect(plot);
80
89
81 auto axisPos = posToAxisPos(pos, plot);
90 auto axisPos = posToAxisPos(pos, plot);
82
91
83 m_DrawingRect = new QCPItemRect{&plot};
92 m_DrawingRect = new QCPItemRect{&plot};
84 configureDrawingRect();
93 configureDrawingRect();
85
94
86 m_DrawingRect->topLeft->setCoords(axisPos);
95 m_DrawingRect->topLeft->setCoords(axisPos);
87 m_DrawingRect->bottomRight->setCoords(axisPos);
96 m_DrawingRect->bottomRight->setCoords(axisPos);
88 }
97 }
89
98
90 void removeDrawingRect(QCustomPlot &plot)
99 void removeDrawingRect(QCustomPlot &plot)
91 {
100 {
92 if (m_DrawingRect) {
101 if (m_DrawingRect) {
93 plot.removeItem(m_DrawingRect); // the item is deleted by QCustomPlot
102 plot.removeItem(m_DrawingRect); // the item is deleted by QCustomPlot
94 m_DrawingRect = nullptr;
103 m_DrawingRect = nullptr;
95 plot.replot(QCustomPlot::rpQueuedReplot);
104 plot.replot(QCustomPlot::rpQueuedReplot);
96 }
105 }
97 }
106 }
98
107
99 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
108 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
100 {
109 {
101 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
110 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
102 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
111 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
103 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
112 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
104 }
113 }
105
114
106 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
115 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
107 {
116 {
108 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
117 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
109 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
118 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
110
119
111 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
120 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
112 }
121 }
113 };
122 };
114
123
115 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
124 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
116 : VisualizationDragWidget{parent},
125 : VisualizationDragWidget{parent},
117 ui{new Ui::VisualizationGraphWidget},
126 ui{new Ui::VisualizationGraphWidget},
118 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
127 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
119 {
128 {
120 ui->setupUi(this);
129 ui->setupUi(this);
121
130
122 // 'Close' options : widget is deleted when closed
131 // 'Close' options : widget is deleted when closed
123 setAttribute(Qt::WA_DeleteOnClose);
132 setAttribute(Qt::WA_DeleteOnClose);
124
133
125 // Set qcpplot properties :
134 // Set qcpplot properties :
126 // - Drag (on x-axis) and zoom are enabled
135 // - Drag (on x-axis) and zoom are enabled
127 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
136 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
128 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
137 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
129
138
130 // The delegate must be initialized after the ui as it uses the plot
139 // The delegate must be initialized after the ui as it uses the plot
131 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
140 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
132
141
133 // Init the cursors
142 // Init the cursors
134 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
143 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
135 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
144 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
136 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
145 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
137 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
146 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
138
147
139 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
148 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
140 connect(ui->widget, &QCustomPlot::mouseRelease, this,
149 connect(ui->widget, &QCustomPlot::mouseRelease, this,
141 &VisualizationGraphWidget::onMouseRelease);
150 &VisualizationGraphWidget::onMouseRelease);
142 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
151 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
143 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
152 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
144 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
153 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
145 &VisualizationGraphWidget::onMouseDoubleClick);
154 &VisualizationGraphWidget::onMouseDoubleClick);
146 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
155 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
147 &QCPAxis::rangeChanged),
156 &QCPAxis::rangeChanged),
148 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
157 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
149
158
150 // Activates menu when right clicking on the graph
159 // Activates menu when right clicking on the graph
151 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
160 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
152 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
161 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
153 &VisualizationGraphWidget::onGraphMenuRequested);
162 &VisualizationGraphWidget::onGraphMenuRequested);
154
163
155 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
164 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
156 &VariableController::onRequestDataLoading);
165 &VariableController::onRequestDataLoading);
157
166
158 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
167 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
159 &VisualizationGraphWidget::onUpdateVarDisplaying);
168 &VisualizationGraphWidget::onUpdateVarDisplaying);
160
169
161 #ifdef Q_OS_MAC
170 #ifdef Q_OS_MAC
162 plot().setPlottingHint(QCP::phFastPolylines, true);
171 plot().setPlottingHint(QCP::phFastPolylines, true);
163 #endif
172 #endif
164 }
173 }
165
174
166
175
167 VisualizationGraphWidget::~VisualizationGraphWidget()
176 VisualizationGraphWidget::~VisualizationGraphWidget()
168 {
177 {
169 delete ui;
178 delete ui;
170 }
179 }
171
180
172 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
181 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
173 {
182 {
174 auto parent = parentWidget();
183 auto parent = parentWidget();
175 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
184 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
176 parent = parent->parentWidget();
185 parent = parent->parentWidget();
177 }
186 }
178
187
179 return qobject_cast<VisualizationZoneWidget *>(parent);
188 return qobject_cast<VisualizationZoneWidget *>(parent);
180 }
189 }
181
190
182 void VisualizationGraphWidget::enableAcquisition(bool enable)
191 void VisualizationGraphWidget::enableAcquisition(bool enable)
183 {
192 {
184 impl->m_DoAcquisition = enable;
193 impl->m_DoAcquisition = enable;
185 }
194 }
186
195
187 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
196 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
188 {
197 {
189 // Uses delegate to create the qcpplot components according to the variable
198 // Uses delegate to create the qcpplot components according to the variable
190 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
199 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
191
200
192 if (auto dataSeries = variable->dataSeries()) {
201 if (auto dataSeries = variable->dataSeries()) {
193 // Set axes properties according to the units of the data series
202 // Set axes properties according to the units of the data series
194 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
203 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
195
204
196 // Sets rendering properties for the new plottables
205 // Sets rendering properties for the new plottables
197 // Warning: this method must be called after setAxesProperties(), as it can access to some
206 // Warning: this method must be called after setAxesProperties(), as it can access to some
198 // axes properties that have to be initialized
207 // axes properties that have to be initialized
199 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
208 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
200 }
209 }
201
210
202 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
211 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
203
212
204 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
213 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
205
214
206 this->enableAcquisition(false);
215 this->enableAcquisition(false);
207 this->setGraphRange(range);
216 this->setGraphRange(range);
208 this->enableAcquisition(true);
217 this->enableAcquisition(true);
209
218
210 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
219 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
211
220
212 emit variableAdded(variable);
221 emit variableAdded(variable);
213 }
222 }
214
223
215 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
224 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
216 {
225 {
217 // Each component associated to the variable :
226 // Each component associated to the variable :
218 // - is removed from qcpplot (which deletes it)
227 // - is removed from qcpplot (which deletes it)
219 // - is no longer referenced in the map
228 // - is no longer referenced in the map
220 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
229 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
221 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
230 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
222 emit variableAboutToBeRemoved(variable);
231 emit variableAboutToBeRemoved(variable);
223
232
224 auto &plottablesMap = variableIt->second;
233 auto &plottablesMap = variableIt->second;
225
234
226 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
235 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
227 plottableIt != plottableEnd;) {
236 plottableIt != plottableEnd;) {
228 ui->widget->removePlottable(plottableIt->second);
237 ui->widget->removePlottable(plottableIt->second);
229 plottableIt = plottablesMap.erase(plottableIt);
238 plottableIt = plottablesMap.erase(plottableIt);
230 }
239 }
231
240
232 impl->m_VariableToPlotMultiMap.erase(variableIt);
241 impl->m_VariableToPlotMultiMap.erase(variableIt);
233 }
242 }
234
243
235 // Updates graph
244 // Updates graph
236 ui->widget->replot();
245 ui->widget->replot();
237 }
246 }
238
247
239 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
248 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
240 {
249 {
241 auto variables = QList<std::shared_ptr<Variable> >{};
250 auto variables = QList<std::shared_ptr<Variable> >{};
242 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
251 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
243 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
252 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
244 variables << it->first;
253 variables << it->first;
245 }
254 }
246
255
247 return variables;
256 return variables;
248 }
257 }
249
258
250 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
259 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
251 {
260 {
252 if (!variable) {
261 if (!variable) {
253 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
262 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
254 return;
263 return;
255 }
264 }
256
265
257 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
266 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
258 }
267 }
259
268
260 SqpRange VisualizationGraphWidget::graphRange() const noexcept
269 SqpRange VisualizationGraphWidget::graphRange() const noexcept
261 {
270 {
262 auto graphRange = ui->widget->xAxis->range();
271 auto graphRange = ui->widget->xAxis->range();
263 return SqpRange{graphRange.lower, graphRange.upper};
272 return SqpRange{graphRange.lower, graphRange.upper};
264 }
273 }
265
274
266 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
275 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
267 {
276 {
268 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
277 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
269 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
278 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
270 ui->widget->replot();
279 ui->widget->replot();
271 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
280 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
272 }
281 }
273
282
274 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
283 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
275 {
284 {
276 if (visitor) {
285 if (visitor) {
277 visitor->visit(this);
286 visitor->visit(this);
278 }
287 }
279 else {
288 else {
280 qCCritical(LOG_VisualizationGraphWidget())
289 qCCritical(LOG_VisualizationGraphWidget())
281 << tr("Can't visit widget : the visitor is null");
290 << tr("Can't visit widget : the visitor is null");
282 }
291 }
283 }
292 }
284
293
285 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
294 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
286 {
295 {
287 /// @todo : for the moment, a graph can always accomodate a variable
296 /// @todo : for the moment, a graph can always accomodate a variable
288 Q_UNUSED(variable);
297 Q_UNUSED(variable);
289 return true;
298 return true;
290 }
299 }
291
300
292 bool VisualizationGraphWidget::contains(const Variable &variable) const
301 bool VisualizationGraphWidget::contains(const Variable &variable) const
293 {
302 {
294 // Finds the variable among the keys of the map
303 // Finds the variable among the keys of the map
295 auto variablePtr = &variable;
304 auto variablePtr = &variable;
296 auto findVariable
305 auto findVariable
297 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
306 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
298
307
299 auto end = impl->m_VariableToPlotMultiMap.cend();
308 auto end = impl->m_VariableToPlotMultiMap.cend();
300 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
309 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
301 return it != end;
310 return it != end;
302 }
311 }
303
312
304 QString VisualizationGraphWidget::name() const
313 QString VisualizationGraphWidget::name() const
305 {
314 {
306 return impl->m_Name;
315 return impl->m_Name;
307 }
316 }
308
317
309 QMimeData *VisualizationGraphWidget::mimeData() const
318 QMimeData *VisualizationGraphWidget::mimeData() const
310 {
319 {
311 auto mimeData = new QMimeData;
320 auto mimeData = new QMimeData;
312 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
321 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
313
322
314 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
323 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
315 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
324 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
316
325
317 return mimeData;
326 return mimeData;
318 }
327 }
319
328
320 bool VisualizationGraphWidget::isDragAllowed() const
329 bool VisualizationGraphWidget::isDragAllowed() const
321 {
330 {
322 return true;
331 return true;
323 }
332 }
324
333
325 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
334 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
326 {
335 {
327 if (highlighted) {
336 if (highlighted) {
328 plot().setBackground(QBrush(QColor("#BBD5EE")));
337 plot().setBackground(QBrush(QColor("#BBD5EE")));
329 }
338 }
330 else {
339 else {
331 plot().setBackground(QBrush(Qt::white));
340 plot().setBackground(QBrush(Qt::white));
332 }
341 }
333
342
334 plot().update();
343 plot().update();
335 }
344 }
336
345
337 void VisualizationGraphWidget::addVerticalCursor(double time)
346 void VisualizationGraphWidget::addVerticalCursor(double time)
338 {
347 {
339 impl->m_VerticalCursor->setPosition(time);
348 impl->m_VerticalCursor->setPosition(time);
340 impl->m_VerticalCursor->setVisible(true);
349 impl->m_VerticalCursor->setVisible(true);
341
350
342 auto text
351 auto text
343 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
352 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
344 impl->m_VerticalCursor->setLabelText(text);
353 impl->m_VerticalCursor->setLabelText(text);
345 }
354 }
346
355
347 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
356 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
348 {
357 {
349 impl->m_VerticalCursor->setAbsolutePosition(position);
358 impl->m_VerticalCursor->setAbsolutePosition(position);
350 impl->m_VerticalCursor->setVisible(true);
359 impl->m_VerticalCursor->setVisible(true);
351
360
352 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
361 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
353 auto text
362 auto text
354 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
363 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
355 impl->m_VerticalCursor->setLabelText(text);
364 impl->m_VerticalCursor->setLabelText(text);
356 }
365 }
357
366
358 void VisualizationGraphWidget::removeVerticalCursor()
367 void VisualizationGraphWidget::removeVerticalCursor()
359 {
368 {
360 impl->m_VerticalCursor->setVisible(false);
369 impl->m_VerticalCursor->setVisible(false);
361 plot().replot(QCustomPlot::rpQueuedReplot);
370 plot().replot(QCustomPlot::rpQueuedReplot);
362 }
371 }
363
372
364 void VisualizationGraphWidget::addHorizontalCursor(double value)
373 void VisualizationGraphWidget::addHorizontalCursor(double value)
365 {
374 {
366 impl->m_HorizontalCursor->setPosition(value);
375 impl->m_HorizontalCursor->setPosition(value);
367 impl->m_HorizontalCursor->setVisible(true);
376 impl->m_HorizontalCursor->setVisible(true);
368 impl->m_HorizontalCursor->setLabelText(QString::number(value));
377 impl->m_HorizontalCursor->setLabelText(QString::number(value));
369 }
378 }
370
379
371 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
380 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
372 {
381 {
373 impl->m_HorizontalCursor->setAbsolutePosition(position);
382 impl->m_HorizontalCursor->setAbsolutePosition(position);
374 impl->m_HorizontalCursor->setVisible(true);
383 impl->m_HorizontalCursor->setVisible(true);
375
384
376 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
385 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
377 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
386 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
378 }
387 }
379
388
380 void VisualizationGraphWidget::removeHorizontalCursor()
389 void VisualizationGraphWidget::removeHorizontalCursor()
381 {
390 {
382 impl->m_HorizontalCursor->setVisible(false);
391 impl->m_HorizontalCursor->setVisible(false);
383 plot().replot(QCustomPlot::rpQueuedReplot);
392 plot().replot(QCustomPlot::rpQueuedReplot);
384 }
393 }
385
394
386 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
395 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
387 {
396 {
388 Q_UNUSED(event);
397 Q_UNUSED(event);
389
398
390 // Prevents that all variables will be removed from graph when it will be closed
399 // Prevents that all variables will be removed from graph when it will be closed
391 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
400 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
392 emit variableAboutToBeRemoved(variableEntry.first);
401 emit variableAboutToBeRemoved(variableEntry.first);
393 }
402 }
394 }
403 }
395
404
396 void VisualizationGraphWidget::enterEvent(QEvent *event)
405 void VisualizationGraphWidget::enterEvent(QEvent *event)
397 {
406 {
398 Q_UNUSED(event);
407 Q_UNUSED(event);
399 impl->m_RenderingDelegate->showGraphOverlay(true);
408 impl->m_RenderingDelegate->showGraphOverlay(true);
400 }
409 }
401
410
402 void VisualizationGraphWidget::leaveEvent(QEvent *event)
411 void VisualizationGraphWidget::leaveEvent(QEvent *event)
403 {
412 {
404 Q_UNUSED(event);
413 Q_UNUSED(event);
405 impl->m_RenderingDelegate->showGraphOverlay(false);
414 impl->m_RenderingDelegate->showGraphOverlay(false);
406
415
407 if (auto parentZone = parentZoneWidget()) {
416 if (auto parentZone = parentZoneWidget()) {
408 parentZone->notifyMouseLeaveGraph(this);
417 parentZone->notifyMouseLeaveGraph(this);
409 }
418 }
410 else {
419 else {
411 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
420 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
412 }
421 }
413 }
422 }
414
423
415 QCustomPlot &VisualizationGraphWidget::plot() noexcept
424 QCustomPlot &VisualizationGraphWidget::plot() noexcept
416 {
425 {
417 return *ui->widget;
426 return *ui->widget;
418 }
427 }
419
428
420 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
429 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
421 {
430 {
422 QMenu graphMenu{};
431 QMenu graphMenu{};
423
432
424 // Iterates on variables (unique keys)
433 // Iterates on variables (unique keys)
425 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
434 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
426 end = impl->m_VariableToPlotMultiMap.cend();
435 end = impl->m_VariableToPlotMultiMap.cend();
427 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
436 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
428 // 'Remove variable' action
437 // 'Remove variable' action
429 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
438 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
430 [ this, var = it->first ]() { removeVariable(var); });
439 [ this, var = it->first ]() { removeVariable(var); });
431 }
440 }
432
441
433 if (!graphMenu.isEmpty()) {
442 if (!graphMenu.isEmpty()) {
434 graphMenu.exec(QCursor::pos());
443 graphMenu.exec(QCursor::pos());
435 }
444 }
436 }
445 }
437
446
438 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
447 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
439 {
448 {
440 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
449 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
441 << QThread::currentThread()->objectName() << "DoAcqui"
450 << QThread::currentThread()->objectName() << "DoAcqui"
442 << impl->m_DoAcquisition;
451 << impl->m_DoAcquisition;
443
452
444 auto graphRange = SqpRange{t1.lower, t1.upper};
453 auto graphRange = SqpRange{t1.lower, t1.upper};
445 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
454 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
446
455
447 if (impl->m_DoAcquisition) {
456 if (impl->m_DoAcquisition) {
448 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
457 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
449
458
450 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
459 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
451 end = impl->m_VariableToPlotMultiMap.end();
460 end = impl->m_VariableToPlotMultiMap.end();
452 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
461 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
453 variableUnderGraphVector.push_back(it->first);
462 variableUnderGraphVector.push_back(it->first);
454 }
463 }
455 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
464 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
456 !impl->m_IsCalibration);
465 !impl->m_IsCalibration);
457
466
458 if (!impl->m_IsCalibration) {
467 if (!impl->m_IsCalibration) {
459 qCDebug(LOG_VisualizationGraphWidget())
468 qCDebug(LOG_VisualizationGraphWidget())
460 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
469 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
461 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
470 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
462 emit synchronize(graphRange, oldGraphRange);
471 emit synchronize(graphRange, oldGraphRange);
463 }
472 }
464 }
473 }
465
474
466 auto pos = mapFromGlobal(QCursor::pos());
475 auto pos = mapFromGlobal(QCursor::pos());
467 auto axisPos = impl->posToAxisPos(pos, plot());
476 auto axisPos = impl->posToAxisPos(pos, plot());
468 if (auto parentZone = parentZoneWidget()) {
477 if (auto parentZone = parentZoneWidget()) {
469 if (impl->pointIsInAxisRect(axisPos, plot())) {
478 if (impl->pointIsInAxisRect(axisPos, plot())) {
470 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
479 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
471 }
480 }
472 else {
481 else {
473 parentZone->notifyMouseLeaveGraph(this);
482 parentZone->notifyMouseLeaveGraph(this);
474 }
483 }
475 }
484 }
476 else {
485 else {
477 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
486 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
478 }
487 }
479 }
488 }
480
489
481 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
490 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
482 {
491 {
483 impl->m_RenderingDelegate->onMouseDoubleClick(event);
492 impl->m_RenderingDelegate->onMouseDoubleClick(event);
484 }
493 }
485
494
486 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
495 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
487 {
496 {
488 // Handles plot rendering when mouse is moving
497 // Handles plot rendering when mouse is moving
489 impl->m_RenderingDelegate->onMouseMove(event);
498 impl->m_RenderingDelegate->onMouseMove(event);
490
499
491 auto axisPos = impl->posToAxisPos(event->pos(), plot());
500 auto axisPos = impl->posToAxisPos(event->pos(), plot());
492
501
493 if (impl->m_DrawingRect) {
502 if (impl->m_DrawingRect) {
494 impl->m_DrawingRect->bottomRight->setCoords(axisPos);
503 impl->m_DrawingRect->bottomRight->setCoords(axisPos);
495 }
504 }
496
505
497 if (auto parentZone = parentZoneWidget()) {
506 if (auto parentZone = parentZoneWidget()) {
498 if (impl->pointIsInAxisRect(axisPos, plot())) {
507 if (impl->pointIsInAxisRect(axisPos, plot())) {
499 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
508 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
500 }
509 }
501 else {
510 else {
502 parentZone->notifyMouseLeaveGraph(this);
511 parentZone->notifyMouseLeaveGraph(this);
503 }
512 }
504 }
513 }
505 else {
514 else {
506 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
515 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
507 }
516 }
508
517
509 VisualizationDragWidget::mouseMoveEvent(event);
518 VisualizationDragWidget::mouseMoveEvent(event);
510 }
519 }
511
520
512 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
521 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
513 {
522 {
514 auto value = event->angleDelta().x() + event->angleDelta().y();
523 auto value = event->angleDelta().x() + event->angleDelta().y();
515 if (value != 0) {
524 if (value != 0) {
516
525
517 auto direction = value > 0 ? 1.0 : -1.0;
526 auto direction = value > 0 ? 1.0 : -1.0;
518 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
527 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
519 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
528 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
520 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
529 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
521
530
522 auto zoomOrientations = QFlags<Qt::Orientation>{};
531 auto zoomOrientations = QFlags<Qt::Orientation>{};
523 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
532 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
524 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
533 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
525
534
526 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
535 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
527
536
528 if (!isZoomX && !isZoomY) {
537 if (!isZoomX && !isZoomY) {
529 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
538 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
530 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
539 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
531
540
532 axis->setRange(axis->range() + diff);
541 axis->setRange(axis->range() + diff);
533
542
534 if (plot().noAntialiasingOnDrag()) {
543 if (plot().noAntialiasingOnDrag()) {
535 plot().setNotAntialiasedElements(QCP::aeAll);
544 plot().setNotAntialiasedElements(QCP::aeAll);
536 }
545 }
537
546
538 plot().replot(QCustomPlot::rpQueuedReplot);
547 plot().replot(QCustomPlot::rpQueuedReplot);
539 }
548 }
540 }
549 }
541 }
550 }
542
551
543 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
552 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
544 {
553 {
545 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
554 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
546 impl->startDrawingRect(event->pos(), plot());
555 impl->startDrawingRect(event->pos(), plot());
547 }
556 }
548
557
549 VisualizationDragWidget::mousePressEvent(event);
558 VisualizationDragWidget::mousePressEvent(event);
550 }
559 }
551
560
552 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
561 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
553 {
562 {
554 if (impl->m_DrawingRect) {
563 if (impl->m_DrawingRect) {
555
564
556 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
565 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
557 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
566 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
558
567
559 auto newAxisXRange = QCPRange{impl->m_DrawingRect->topLeft->coords().x(),
568 auto newAxisXRange = QCPRange{impl->m_DrawingRect->topLeft->coords().x(),
560 impl->m_DrawingRect->bottomRight->coords().x()};
569 impl->m_DrawingRect->bottomRight->coords().x()};
561
570
562 auto newAxisYRange = QCPRange{impl->m_DrawingRect->topLeft->coords().y(),
571 auto newAxisYRange = QCPRange{impl->m_DrawingRect->topLeft->coords().y(),
563 impl->m_DrawingRect->bottomRight->coords().y()};
572 impl->m_DrawingRect->bottomRight->coords().y()};
564
573
565 impl->removeDrawingRect(plot());
574 impl->removeDrawingRect(plot());
566
575
567 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
576 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
568 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
577 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
569 axisX->setRange(newAxisXRange);
578 axisX->setRange(newAxisXRange);
570 axisY->setRange(newAxisYRange);
579 axisY->setRange(newAxisYRange);
571
580
572 plot().replot(QCustomPlot::rpQueuedReplot);
581 plot().replot(QCustomPlot::rpQueuedReplot);
573 }
582 }
574 }
583 }
575
584
576 impl->m_IsCalibration = false;
585 impl->m_IsCalibration = false;
577 }
586 }
578
587
579 void VisualizationGraphWidget::onDataCacheVariableUpdated()
588 void VisualizationGraphWidget::onDataCacheVariableUpdated()
580 {
589 {
581 auto graphRange = ui->widget->xAxis->range();
590 auto graphRange = ui->widget->xAxis->range();
582 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
591 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
583
592
584 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
593 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
585 auto variable = variableEntry.first;
594 auto variable = variableEntry.first;
586 qCDebug(LOG_VisualizationGraphWidget())
595 qCDebug(LOG_VisualizationGraphWidget())
587 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
596 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
588 qCDebug(LOG_VisualizationGraphWidget())
597 qCDebug(LOG_VisualizationGraphWidget())
589 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
598 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
590 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
599 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
591 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
600 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
592 variable->range());
593 }
601 }
594 }
602 }
595 }
603 }
596
604
597 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
605 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
598 const SqpRange &range)
606 const SqpRange &range)
599 {
607 {
600 auto it = impl->m_VariableToPlotMultiMap.find(variable);
608 auto it = impl->m_VariableToPlotMultiMap.find(variable);
601 if (it != impl->m_VariableToPlotMultiMap.end()) {
609 if (it != impl->m_VariableToPlotMultiMap.end()) {
602 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
610 impl->updateData(it->second, variable->dataSeries(), range);
603 }
611 }
604 }
612 }
General Comments 0
You need to be logged in to leave comments. Login now