##// END OF EJS Templates
(Minor) Removes obsolete code
Alexandre Leroux -
r905:9ee11b23a95d
parent child
Show More
@@ -1,199 +1,198
1 #include "Data/SpectrogramSeries.h"
1 #include "Data/SpectrogramSeries.h"
2
2
3 #include "DataSeriesBuilders.h"
3 #include "DataSeriesBuilders.h"
4 #include "DataSeriesUtils.h"
4 #include "DataSeriesUtils.h"
5
5
6 #include <QObject>
6 #include <QObject>
7 #include <QtTest>
7 #include <QtTest>
8
8
9 namespace {
9 namespace {
10
10
11 // Aliases used to facilitate reading of test inputs
11 // Aliases used to facilitate reading of test inputs
12 using X = DataContainer;
12 using X = DataContainer;
13 using Y = DataContainer;
13 using Y = DataContainer;
14 using Values = DataContainer;
14 using Values = DataContainer;
15 using Components = std::vector<DataContainer>;
15 using Components = std::vector<DataContainer>;
16
16
17 } // namespace
17 } // namespace
18
18
19 /**
19 /**
20 * @brief The TestSpectrogramSeries class defines unit tests on spectrogram series.
20 * @brief The TestSpectrogramSeries class defines unit tests on spectrogram series.
21 *
21 *
22 * Most of these unit tests use generic tests defined for DataSeries (@sa DataSeriesUtils)
22 * Most of these unit tests use generic tests defined for DataSeries (@sa DataSeriesUtils)
23 */
23 */
24 class TestSpectrogramSeries : public QObject {
24 class TestSpectrogramSeries : public QObject {
25 Q_OBJECT
25 Q_OBJECT
26 private slots:
26 private slots:
27
27
28 /// Tests construction of a spectrogram series
28 /// Tests construction of a spectrogram series
29 void testCtor_data();
29 void testCtor_data();
30 void testCtor();
30 void testCtor();
31
31
32 /// Tests merge of two spectrogram series
32 /// Tests merge of two spectrogram series
33 void testMerge_data();
33 void testMerge_data();
34 void testMerge();
34 void testMerge();
35
35
36 /// @todo ALX: test subdataseries
37 /// Tests get subdata of a spectrogram series
36 /// Tests get subdata of a spectrogram series
38 void testSubDataSeries_data();
37 void testSubDataSeries_data();
39 void testSubDataSeries();
38 void testSubDataSeries();
40 };
39 };
41
40
42 void TestSpectrogramSeries::testCtor_data()
41 void TestSpectrogramSeries::testCtor_data()
43 {
42 {
44 // x-axis data
43 // x-axis data
45 QTest::addColumn<X>("xAxisData");
44 QTest::addColumn<X>("xAxisData");
46 // y-axis data
45 // y-axis data
47 QTest::addColumn<Y>("yAxisData");
46 QTest::addColumn<Y>("yAxisData");
48 // values data
47 // values data
49 QTest::addColumn<Values>("valuesData");
48 QTest::addColumn<Values>("valuesData");
50
49
51 // construction expected to be valid
50 // construction expected to be valid
52 QTest::addColumn<bool>("expectOK");
51 QTest::addColumn<bool>("expectOK");
53 // expected x-axis data (when construction is valid)
52 // expected x-axis data (when construction is valid)
54 QTest::addColumn<X>("expectedXAxisData");
53 QTest::addColumn<X>("expectedXAxisData");
55 // expected components data (when construction is valid)
54 // expected components data (when construction is valid)
56 QTest::addColumn<Components>("expectedComponentsData");
55 QTest::addColumn<Components>("expectedComponentsData");
57
56
58 QTest::newRow(
57 QTest::newRow(
59 "invalidData (number of values by component aren't equal to the number of x-axis data)")
58 "invalidData (number of values by component aren't equal to the number of x-axis data)")
60 << X{1., 2., 3., 4., 5.} << Y{1., 2., 3.} << Values{1., 2., 3.} << false << X{}
59 << X{1., 2., 3., 4., 5.} << Y{1., 2., 3.} << Values{1., 2., 3.} << false << X{}
61 << Components{};
60 << Components{};
62
61
63 QTest::newRow("invalidData (number of components aren't equal to the number of y-axis data)")
62 QTest::newRow("invalidData (number of components aren't equal to the number of y-axis data)")
64 << X{1., 2., 3., 4., 5.} << Y{1., 2.} // 2 y-axis data
63 << X{1., 2., 3., 4., 5.} << Y{1., 2.} // 2 y-axis data
65 << Values{1., 2., 3., 4., 5.} // 1 component
64 << Values{1., 2., 3., 4., 5.} // 1 component
66 << false << X{} << Components{};
65 << false << X{} << Components{};
67
66
68 QTest::newRow("sortedData") << X{1., 2., 3., 4., 5.} << Y{1., 2.} // 2 y-axis data
67 QTest::newRow("sortedData") << X{1., 2., 3., 4., 5.} << Y{1., 2.} // 2 y-axis data
69 << Values{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} // 2 components
68 << Values{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} // 2 components
70 << true << X{1., 2., 3., 4., 5.}
69 << true << X{1., 2., 3., 4., 5.}
71 << Components{{1., 3., 5., 7., 9.}, {2., 4., 6., 8., 10.}};
70 << Components{{1., 3., 5., 7., 9.}, {2., 4., 6., 8., 10.}};
72
71
73 QTest::newRow("unsortedData") << X{5., 4., 3., 2., 1.} << Y{1., 2.}
72 QTest::newRow("unsortedData") << X{5., 4., 3., 2., 1.} << Y{1., 2.}
74 << Values{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} << true
73 << Values{1., 2., 3., 4., 5., 6., 7., 8., 9., 10.} << true
75 << X{1., 2., 3., 4., 5.}
74 << X{1., 2., 3., 4., 5.}
76 << Components{{9., 7., 5., 3., 1.}, {10., 8., 6., 4., 2.}};
75 << Components{{9., 7., 5., 3., 1.}, {10., 8., 6., 4., 2.}};
77 }
76 }
78
77
79 void TestSpectrogramSeries::testCtor()
78 void TestSpectrogramSeries::testCtor()
80 {
79 {
81 // Creates series
80 // Creates series
82 QFETCH(X, xAxisData);
81 QFETCH(X, xAxisData);
83 QFETCH(Y, yAxisData);
82 QFETCH(Y, yAxisData);
84 QFETCH(Values, valuesData);
83 QFETCH(Values, valuesData);
85 QFETCH(bool, expectOK);
84 QFETCH(bool, expectOK);
86
85
87 if (expectOK) {
86 if (expectOK) {
88 auto series = SpectrogramBuilder{}
87 auto series = SpectrogramBuilder{}
89 .setX(std::move(xAxisData))
88 .setX(std::move(xAxisData))
90 .setY(std::move(yAxisData))
89 .setY(std::move(yAxisData))
91 .setValues(std::move(valuesData))
90 .setValues(std::move(valuesData))
92 .build();
91 .build();
93
92
94 // Validates results
93 // Validates results
95 QFETCH(X, expectedXAxisData);
94 QFETCH(X, expectedXAxisData);
96 QFETCH(Components, expectedComponentsData);
95 QFETCH(Components, expectedComponentsData);
97 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedComponentsData);
96 validateRange(series->cbegin(), series->cend(), expectedXAxisData, expectedComponentsData);
98 }
97 }
99 else {
98 else {
100 QVERIFY_EXCEPTION_THROWN(SpectrogramBuilder{}
99 QVERIFY_EXCEPTION_THROWN(SpectrogramBuilder{}
101 .setX(std::move(xAxisData))
100 .setX(std::move(xAxisData))
102 .setY(std::move(yAxisData))
101 .setY(std::move(yAxisData))
103 .setValues(std::move(valuesData))
102 .setValues(std::move(valuesData))
104 .build(),
103 .build(),
105 std::invalid_argument);
104 std::invalid_argument);
106 }
105 }
107 }
106 }
108
107
109 void TestSpectrogramSeries::testMerge_data()
108 void TestSpectrogramSeries::testMerge_data()
110 {
109 {
111 testMerge_struct<SpectrogramSeries, Components>();
110 testMerge_struct<SpectrogramSeries, Components>();
112
111
113 QTest::newRow("sortedMerge") << SpectrogramBuilder{}
112 QTest::newRow("sortedMerge") << SpectrogramBuilder{}
114 .setX({1., 2., 3.})
113 .setX({1., 2., 3.})
115 .setY({1., 2.})
114 .setY({1., 2.})
116 .setValues({10., 11., 20., 21., 30., 31})
115 .setValues({10., 11., 20., 21., 30., 31})
117 .build()
116 .build()
118 << SpectrogramBuilder{}
117 << SpectrogramBuilder{}
119 .setX({4., 5., 6.})
118 .setX({4., 5., 6.})
120 .setY({1., 2.})
119 .setY({1., 2.})
121 .setValues({40., 41., 50., 51., 60., 61})
120 .setValues({40., 41., 50., 51., 60., 61})
122 .build()
121 .build()
123 << DataContainer{1., 2., 3., 4., 5., 6.}
122 << DataContainer{1., 2., 3., 4., 5., 6.}
124 << Components{{10., 20., 30., 40., 50., 60.},
123 << Components{{10., 20., 30., 40., 50., 60.},
125 {11., 21., 31., 41., 51., 61}};
124 {11., 21., 31., 41., 51., 61}};
126
125
127 QTest::newRow(
126 QTest::newRow(
128 "unsortedMerge (merge not made because the two data series have different y-axes)")
127 "unsortedMerge (merge not made because the two data series have different y-axes)")
129 << SpectrogramBuilder{}
128 << SpectrogramBuilder{}
130 .setX({4., 5., 6.})
129 .setX({4., 5., 6.})
131 .setY({1., 2.})
130 .setY({1., 2.})
132 .setValues({40., 41., 50., 51., 60., 61})
131 .setValues({40., 41., 50., 51., 60., 61})
133 .build()
132 .build()
134 << SpectrogramBuilder{}
133 << SpectrogramBuilder{}
135 .setX({1., 2., 3.})
134 .setX({1., 2., 3.})
136 .setY({3., 4.})
135 .setY({3., 4.})
137 .setValues({10., 11., 20., 21., 30., 31})
136 .setValues({10., 11., 20., 21., 30., 31})
138 .build()
137 .build()
139 << DataContainer{4., 5., 6.} << Components{{40., 50., 60.}, {41., 51., 61}};
138 << DataContainer{4., 5., 6.} << Components{{40., 50., 60.}, {41., 51., 61}};
140
139
141 QTest::newRow(
140 QTest::newRow(
142 "unsortedMerge (unsortedMerge (merge is made because the two data series have the same "
141 "unsortedMerge (unsortedMerge (merge is made because the two data series have the same "
143 "y-axis)")
142 "y-axis)")
144 << SpectrogramBuilder{}
143 << SpectrogramBuilder{}
145 .setX({4., 5., 6.})
144 .setX({4., 5., 6.})
146 .setY({1., 2.})
145 .setY({1., 2.})
147 .setValues({40., 41., 50., 51., 60., 61})
146 .setValues({40., 41., 50., 51., 60., 61})
148 .build()
147 .build()
149 << SpectrogramBuilder{}
148 << SpectrogramBuilder{}
150 .setX({1., 2., 3.})
149 .setX({1., 2., 3.})
151 .setY({1., 2.})
150 .setY({1., 2.})
152 .setValues({10., 11., 20., 21., 30., 31})
151 .setValues({10., 11., 20., 21., 30., 31})
153 .build()
152 .build()
154 << DataContainer{1., 2., 3., 4., 5., 6.}
153 << DataContainer{1., 2., 3., 4., 5., 6.}
155 << Components{{10., 20., 30., 40., 50., 60.}, {11., 21., 31., 41., 51., 61}};
154 << Components{{10., 20., 30., 40., 50., 60.}, {11., 21., 31., 41., 51., 61}};
156 }
155 }
157
156
158 void TestSpectrogramSeries::testMerge()
157 void TestSpectrogramSeries::testMerge()
159 {
158 {
160 testMerge_t<SpectrogramSeries, Components>();
159 testMerge_t<SpectrogramSeries, Components>();
161 }
160 }
162
161
163 void TestSpectrogramSeries::testSubDataSeries_data()
162 void TestSpectrogramSeries::testSubDataSeries_data()
164 {
163 {
165 testSubDataSeries_struct<SpectrogramSeries, Components>();
164 testSubDataSeries_struct<SpectrogramSeries, Components>();
166
165
167 QTest::newRow("subDataSeries (the range includes all data)")
166 QTest::newRow("subDataSeries (the range includes all data)")
168 << SpectrogramBuilder{}
167 << SpectrogramBuilder{}
169 .setX({1., 2., 3.})
168 .setX({1., 2., 3.})
170 .setY({1., 2.})
169 .setY({1., 2.})
171 .setValues({10., 11., 20., 21., 30., 31})
170 .setValues({10., 11., 20., 21., 30., 31})
172 .build()
171 .build()
173 << SqpRange{0., 5.} << DataContainer{1., 2., 3.}
172 << SqpRange{0., 5.} << DataContainer{1., 2., 3.}
174 << Components{{10., 20., 30.}, {11., 21., 31.}};
173 << Components{{10., 20., 30.}, {11., 21., 31.}};
175
174
176 QTest::newRow("subDataSeries (the range includes no data)")
175 QTest::newRow("subDataSeries (the range includes no data)")
177 << SpectrogramBuilder{}
176 << SpectrogramBuilder{}
178 .setX({1., 2., 3.})
177 .setX({1., 2., 3.})
179 .setY({1., 2.})
178 .setY({1., 2.})
180 .setValues({10., 11., 20., 21., 30., 31})
179 .setValues({10., 11., 20., 21., 30., 31})
181 .build()
180 .build()
182 << SqpRange{4., 5.} << DataContainer{} << Components{{}, {}};
181 << SqpRange{4., 5.} << DataContainer{} << Components{{}, {}};
183
182
184 QTest::newRow("subDataSeries (the range includes some data)")
183 QTest::newRow("subDataSeries (the range includes some data)")
185 << SpectrogramBuilder{}
184 << SpectrogramBuilder{}
186 .setX({1., 2., 3.})
185 .setX({1., 2., 3.})
187 .setY({1., 2.})
186 .setY({1., 2.})
188 .setValues({10., 11., 20., 21., 30., 31})
187 .setValues({10., 11., 20., 21., 30., 31})
189 .build()
188 .build()
190 << SqpRange{1.1, 3} << DataContainer{2., 3.} << Components{{20., 30.}, {21., 31.}};
189 << SqpRange{1.1, 3} << DataContainer{2., 3.} << Components{{20., 30.}, {21., 31.}};
191 }
190 }
192
191
193 void TestSpectrogramSeries::testSubDataSeries()
192 void TestSpectrogramSeries::testSubDataSeries()
194 {
193 {
195 testSubDataSeries_t<SpectrogramSeries, Components>();
194 testSubDataSeries_t<SpectrogramSeries, Components>();
196 }
195 }
197
196
198 QTEST_MAIN(TestSpectrogramSeries)
197 QTEST_MAIN(TestSpectrogramSeries)
199 #include "TestSpectrogramSeries.moc"
198 #include "TestSpectrogramSeries.moc"
@@ -1,342 +1,342
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Common/ColorUtils.h>
4 #include <Common/ColorUtils.h>
5
5
6 #include <Data/ScalarSeries.h>
6 #include <Data/ScalarSeries.h>
7 #include <Data/SpectrogramSeries.h>
7 #include <Data/SpectrogramSeries.h>
8 #include <Data/VectorSeries.h>
8 #include <Data/VectorSeries.h>
9
9
10 #include <Variable/Variable.h>
10 #include <Variable/Variable.h>
11
11
12 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
12 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
13
13
14 namespace {
14 namespace {
15
15
16 class SqpDataContainer : public QCPGraphDataContainer {
16 class SqpDataContainer : public QCPGraphDataContainer {
17 public:
17 public:
18 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
18 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
19 };
19 };
20
20
21 /**
21 /**
22 * Struct used to create plottables, depending on the type of the data series from which to create
22 * Struct used to create plottables, depending on the type of the data series from which to create
23 * them
23 * them
24 * @tparam T the data series' type
24 * @tparam T the data series' type
25 * @remarks Default implementation can't create plottables
25 * @remarks Default implementation can't create plottables
26 */
26 */
27 template <typename T, typename Enabled = void>
27 template <typename T, typename Enabled = void>
28 struct PlottablesCreator {
28 struct PlottablesCreator {
29 static PlottablesMap createPlottables(T &, QCustomPlot &)
29 static PlottablesMap createPlottables(T &, QCustomPlot &)
30 {
30 {
31 qCCritical(LOG_DataSeries())
31 qCCritical(LOG_DataSeries())
32 << QObject::tr("Can't create plottables: unmanaged data series type");
32 << QObject::tr("Can't create plottables: unmanaged data series type");
33 return {};
33 return {};
34 }
34 }
35 };
35 };
36
36
37 /**
37 /**
38 * Specialization of PlottablesCreator for scalars and vectors
38 * Specialization of PlottablesCreator for scalars and vectors
39 * @sa ScalarSeries
39 * @sa ScalarSeries
40 * @sa VectorSeries
40 * @sa VectorSeries
41 */
41 */
42 template <typename T>
42 template <typename T>
43 struct PlottablesCreator<T,
43 struct PlottablesCreator<T,
44 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
44 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
45 or std::is_base_of<VectorSeries, T>::value> > {
45 or std::is_base_of<VectorSeries, T>::value> > {
46 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
46 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
47 {
47 {
48 PlottablesMap result{};
48 PlottablesMap result{};
49
49
50 // Gets the number of components of the data series
50 // Gets the number of components of the data series
51 dataSeries.lockRead();
51 dataSeries.lockRead();
52 auto componentCount = dataSeries.valuesData()->componentCount();
52 auto componentCount = dataSeries.valuesData()->componentCount();
53 dataSeries.unlock();
53 dataSeries.unlock();
54
54
55 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
55 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
56
56
57 // For each component of the data series, creates a QCPGraph to add to the plot
57 // For each component of the data series, creates a QCPGraph to add to the plot
58 for (auto i = 0; i < componentCount; ++i) {
58 for (auto i = 0; i < componentCount; ++i) {
59 auto graph = plot.addGraph();
59 auto graph = plot.addGraph();
60 graph->setPen(QPen{colors.at(i)});
60 graph->setPen(QPen{colors.at(i)});
61
61
62 result.insert({i, graph});
62 result.insert({i, graph});
63 }
63 }
64
64
65 plot.replot();
65 plot.replot();
66
66
67 return result;
67 return result;
68 }
68 }
69 };
69 };
70
70
71 /**
71 /**
72 * Specialization of PlottablesCreator for spectrograms
72 * Specialization of PlottablesCreator for spectrograms
73 * @sa SpectrogramSeries
73 * @sa SpectrogramSeries
74 */
74 */
75 template <typename T>
75 template <typename T>
76 struct PlottablesCreator<T,
76 struct PlottablesCreator<T,
77 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
77 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
78 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
78 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
79 {
79 {
80 PlottablesMap result{};
80 PlottablesMap result{};
81 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
81 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
82
82
83 plot.replot();
83 plot.replot();
84
84
85 return result;
85 return result;
86 }
86 }
87 };
87 };
88
88
89 /**
89 /**
90 * Struct used to update plottables, depending on the type of the data series from which to update
90 * Struct used to update plottables, depending on the type of the data series from which to update
91 * them
91 * them
92 * @tparam T the data series' type
92 * @tparam T the data series' type
93 * @remarks Default implementation can't update plottables
93 * @remarks Default implementation can't update plottables
94 */
94 */
95 template <typename T, typename Enabled = void>
95 template <typename T, typename Enabled = void>
96 struct PlottablesUpdater {
96 struct PlottablesUpdater {
97 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
97 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
98 {
98 {
99 qCCritical(LOG_DataSeries())
99 qCCritical(LOG_VisualizationGraphHelper())
100 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
100 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
101 }
101 }
102
102
103 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
103 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
104 {
104 {
105 qCCritical(LOG_DataSeries())
105 qCCritical(LOG_VisualizationGraphHelper())
106 << QObject::tr("Can't update plottables: unmanaged data series type");
106 << QObject::tr("Can't update plottables: unmanaged data series type");
107 }
107 }
108 };
108 };
109
109
110 /**
110 /**
111 * Specialization of PlottablesUpdater for scalars and vectors
111 * Specialization of PlottablesUpdater for scalars and vectors
112 * @sa ScalarSeries
112 * @sa ScalarSeries
113 * @sa VectorSeries
113 * @sa VectorSeries
114 */
114 */
115 template <typename T>
115 template <typename T>
116 struct PlottablesUpdater<T,
116 struct PlottablesUpdater<T,
117 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
117 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
118 or std::is_base_of<VectorSeries, T>::value> > {
118 or std::is_base_of<VectorSeries, T>::value> > {
119 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
119 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
120 {
120 {
121 auto minValue = 0., maxValue = 0.;
121 auto minValue = 0., maxValue = 0.;
122
122
123 dataSeries.lockRead();
123 dataSeries.lockRead();
124 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
124 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
125 auto end = dataSeries.cend();
125 auto end = dataSeries.cend();
126 if (valuesBounds.first != end && valuesBounds.second != end) {
126 if (valuesBounds.first != end && valuesBounds.second != end) {
127 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
127 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
128
128
129 minValue = rangeValue(valuesBounds.first->minValue());
129 minValue = rangeValue(valuesBounds.first->minValue());
130 maxValue = rangeValue(valuesBounds.second->maxValue());
130 maxValue = rangeValue(valuesBounds.second->maxValue());
131 }
131 }
132 dataSeries.unlock();
132 dataSeries.unlock();
133
133
134 plot.yAxis->setRange(QCPRange{minValue, maxValue});
134 plot.yAxis->setRange(QCPRange{minValue, maxValue});
135 }
135 }
136
136
137 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
137 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
138 bool rescaleAxes)
138 bool rescaleAxes)
139 {
139 {
140
140
141 // For each plottable to update, resets its data
141 // For each plottable to update, resets its data
142 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
142 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
143 for (const auto &plottable : plottables) {
143 for (const auto &plottable : plottables) {
144 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
144 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
145 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
145 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
146 graph->setData(dataContainer);
146 graph->setData(dataContainer);
147
147
148 dataContainers.insert({plottable.first, dataContainer});
148 dataContainers.insert({plottable.first, dataContainer});
149 }
149 }
150 }
150 }
151 dataSeries.lockRead();
151 dataSeries.lockRead();
152
152
153 // - Gets the data of the series included in the current range
153 // - Gets the data of the series included in the current range
154 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
154 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
155 // and value data. The correct value is retrieved according to the index of the component
155 // and value data. The correct value is retrieved according to the index of the component
156 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
156 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
157 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
157 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
158 for (const auto &dataContainer : dataContainers) {
158 for (const auto &dataContainer : dataContainers) {
159 auto componentIndex = dataContainer.first;
159 auto componentIndex = dataContainer.first;
160 dataContainer.second->appendGraphData(
160 dataContainer.second->appendGraphData(
161 QCPGraphData(it->x(), it->value(componentIndex)));
161 QCPGraphData(it->x(), it->value(componentIndex)));
162 }
162 }
163 }
163 }
164
164
165 dataSeries.unlock();
165 dataSeries.unlock();
166
166
167 if (!plottables.empty()) {
167 if (!plottables.empty()) {
168 auto plot = plottables.begin()->second->parentPlot();
168 auto plot = plottables.begin()->second->parentPlot();
169
169
170 if (rescaleAxes) {
170 if (rescaleAxes) {
171 plot->rescaleAxes();
171 plot->rescaleAxes();
172 }
172 }
173
173
174 plot->replot();
174 plot->replot();
175 }
175 }
176 }
176 }
177 };
177 };
178
178
179 /**
179 /**
180 * Specialization of PlottablesUpdater for spectrograms
180 * Specialization of PlottablesUpdater for spectrograms
181 * @sa SpectrogramSeries
181 * @sa SpectrogramSeries
182 */
182 */
183 template <typename T>
183 template <typename T>
184 struct PlottablesUpdater<T,
184 struct PlottablesUpdater<T,
185 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
185 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
186 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
186 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
187 {
187 {
188 double min, max;
188 double min, max;
189 /// @todo ALX: use iterators here
189 /// @todo ALX: use iterators here
190 std::tie(min, max) = dataSeries.yAxis().bounds();
190 std::tie(min, max) = dataSeries.yAxis().bounds();
191
191
192 if (!std::isnan(min) && !std::isnan(max)) {
192 if (!std::isnan(min) && !std::isnan(max)) {
193 plot.yAxis->setRange(QCPRange{min, max});
193 plot.yAxis->setRange(QCPRange{min, max});
194 }
194 }
195 }
195 }
196
196
197 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
197 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
198 bool rescaleAxes)
198 bool rescaleAxes)
199 {
199 {
200 if (plottables.empty()) {
200 if (plottables.empty()) {
201 qCDebug(LOG_VisualizationGraphHelper())
201 qCDebug(LOG_VisualizationGraphHelper())
202 << QObject::tr("Can't update spectrogram: no colormap has been associated");
202 << QObject::tr("Can't update spectrogram: no colormap has been associated");
203 return;
203 return;
204 }
204 }
205
205
206 // Gets the colormap to update (normally there is only one colormap)
206 // Gets the colormap to update (normally there is only one colormap)
207 Q_ASSERT(plottables.size() == 1);
207 Q_ASSERT(plottables.size() == 1);
208 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
208 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
209 Q_ASSERT(colormap != nullptr);
209 Q_ASSERT(colormap != nullptr);
210
210
211 dataSeries.lockRead();
211 dataSeries.lockRead();
212
212
213 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
213 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
214 /// @todo ALX: use iterators here
214 /// @todo ALX: use iterators here
215 auto yAxis = dataSeries.yAxis();
215 auto yAxis = dataSeries.yAxis();
216
216
217 // Gets properties of x-axis and y-axis to set size and range of the colormap
217 // Gets properties of x-axis and y-axis to set size and range of the colormap
218 auto nbX = std::distance(its.first, its.second);
218 auto nbX = std::distance(its.first, its.second);
219 auto xMin = nbX != 0 ? its.first->x() : 0.;
219 auto xMin = nbX != 0 ? its.first->x() : 0.;
220 auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.;
220 auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.;
221
221
222 auto nbY = yAxis.size();
222 auto nbY = yAxis.size();
223 auto yMin = 0., yMax = 0.;
223 auto yMin = 0., yMax = 0.;
224 if (nbY != 0) {
224 if (nbY != 0) {
225 std::tie(yMin, yMax) = yAxis.bounds();
225 std::tie(yMin, yMax) = yAxis.bounds();
226 }
226 }
227
227
228 colormap->data()->setSize(nbX, nbY);
228 colormap->data()->setSize(nbX, nbY);
229 colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax});
229 colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax});
230
230
231 // Sets values
231 // Sets values
232 auto xIndex = 0;
232 auto xIndex = 0;
233 for (auto it = its.first; it != its.second; ++it, ++xIndex) {
233 for (auto it = its.first; it != its.second; ++it, ++xIndex) {
234 for (auto yIndex = 0; yIndex < nbY; ++yIndex) {
234 for (auto yIndex = 0; yIndex < nbY; ++yIndex) {
235 colormap->data()->setCell(xIndex, yIndex, it->value(yIndex));
235 colormap->data()->setCell(xIndex, yIndex, it->value(yIndex));
236 }
236 }
237 }
237 }
238
238
239 dataSeries.unlock();
239 dataSeries.unlock();
240
240
241 // Rescales axes
241 // Rescales axes
242 auto plot = colormap->parentPlot();
242 auto plot = colormap->parentPlot();
243
243
244 if (rescaleAxes) {
244 if (rescaleAxes) {
245 plot->rescaleAxes();
245 plot->rescaleAxes();
246 }
246 }
247
247
248 plot->replot();
248 plot->replot();
249 }
249 }
250 };
250 };
251
251
252 /**
252 /**
253 * Helper used to create/update plottables
253 * Helper used to create/update plottables
254 */
254 */
255 struct IPlottablesHelper {
255 struct IPlottablesHelper {
256 virtual ~IPlottablesHelper() noexcept = default;
256 virtual ~IPlottablesHelper() noexcept = default;
257 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
257 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
258 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
258 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
259 virtual void update(PlottablesMap &plottables, const SqpRange &range,
259 virtual void update(PlottablesMap &plottables, const SqpRange &range,
260 bool rescaleAxes = false) const = 0;
260 bool rescaleAxes = false) const = 0;
261 };
261 };
262
262
263 /**
263 /**
264 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
264 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
265 * @tparam T the data series' type
265 * @tparam T the data series' type
266 */
266 */
267 template <typename T>
267 template <typename T>
268 struct PlottablesHelper : public IPlottablesHelper {
268 struct PlottablesHelper : public IPlottablesHelper {
269 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
269 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
270
270
271 PlottablesMap create(QCustomPlot &plot) const override
271 PlottablesMap create(QCustomPlot &plot) const override
272 {
272 {
273 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
273 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
274 }
274 }
275
275
276 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
276 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
277 {
277 {
278 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
278 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
279 }
279 }
280
280
281 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
281 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
282 {
282 {
283 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
283 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
284 }
284 }
285
285
286 T &m_DataSeries;
286 T &m_DataSeries;
287 };
287 };
288
288
289 /// Creates IPlottablesHelper according to a data series
289 /// Creates IPlottablesHelper according to a data series
290 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
290 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
291 {
291 {
292 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
292 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
293 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
293 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
294 }
294 }
295 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
295 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
296 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
296 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
297 }
297 }
298 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
298 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
299 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
299 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
300 }
300 }
301 else {
301 else {
302 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
302 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
303 }
303 }
304 }
304 }
305
305
306 } // namespace
306 } // namespace
307
307
308 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
308 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
309 QCustomPlot &plot) noexcept
309 QCustomPlot &plot) noexcept
310 {
310 {
311 if (variable) {
311 if (variable) {
312 auto helper = createHelper(variable->dataSeries());
312 auto helper = createHelper(variable->dataSeries());
313 auto plottables = helper->create(plot);
313 auto plottables = helper->create(plot);
314 return plottables;
314 return plottables;
315 }
315 }
316 else {
316 else {
317 qCDebug(LOG_VisualizationGraphHelper())
317 qCDebug(LOG_VisualizationGraphHelper())
318 << QObject::tr("Can't create graph plottables : the variable is null");
318 << QObject::tr("Can't create graph plottables : the variable is null");
319 return PlottablesMap{};
319 return PlottablesMap{};
320 }
320 }
321 }
321 }
322
322
323 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
323 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
324 QCustomPlot &plot) noexcept
324 QCustomPlot &plot) noexcept
325 {
325 {
326 if (variable) {
326 if (variable) {
327 auto helper = createHelper(variable->dataSeries());
327 auto helper = createHelper(variable->dataSeries());
328 helper->setYAxisRange(variable->range(), plot);
328 helper->setYAxisRange(variable->range(), plot);
329 }
329 }
330 else {
330 else {
331 qCDebug(LOG_VisualizationGraphHelper())
331 qCDebug(LOG_VisualizationGraphHelper())
332 << QObject::tr("Can't set y-axis range of plot: the variable is null");
332 << QObject::tr("Can't set y-axis range of plot: the variable is null");
333 }
333 }
334 }
334 }
335
335
336 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
336 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
337 std::shared_ptr<IDataSeries> dataSeries,
337 std::shared_ptr<IDataSeries> dataSeries,
338 const SqpRange &dateTime)
338 const SqpRange &dateTime)
339 {
339 {
340 auto helper = createHelper(dataSeries);
340 auto helper = createHelper(dataSeries);
341 helper->update(plottables, dateTime);
341 helper->update(plottables, dateTime);
342 }
342 }
@@ -1,406 +1,405
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationDefs.h"
3 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7 #include "ui_VisualizationGraphWidget.h"
7 #include "ui_VisualizationGraphWidget.h"
8
8
9 #include <Common/MimeTypesDef.h>
9 #include <Common/MimeTypesDef.h>
10 #include <Data/ArrayData.h>
10 #include <Data/ArrayData.h>
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <DragAndDrop/DragDropHelper.h>
12 #include <DragAndDrop/DragDropHelper.h>
13 #include <Settings/SqpSettingsDefs.h>
13 #include <Settings/SqpSettingsDefs.h>
14 #include <SqpApplication.h>
14 #include <SqpApplication.h>
15 #include <Time/TimeController.h>
15 #include <Time/TimeController.h>
16 #include <Variable/Variable.h>
16 #include <Variable/Variable.h>
17 #include <Variable/VariableController.h>
17 #include <Variable/VariableController.h>
18
18
19 #include <unordered_map>
19 #include <unordered_map>
20
20
21 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
21 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
22
22
23 namespace {
23 namespace {
24
24
25 /// Key pressed to enable zoom on horizontal axis
25 /// Key pressed to enable zoom on horizontal axis
26 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
26 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
27
27
28 /// Key pressed to enable zoom on vertical axis
28 /// Key pressed to enable zoom on vertical axis
29 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
29 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
30
30
31 } // namespace
31 } // namespace
32
32
33 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
33 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
34
34
35 explicit VisualizationGraphWidgetPrivate(const QString &name)
35 explicit VisualizationGraphWidgetPrivate(const QString &name)
36 : m_Name{name},
36 : m_Name{name},
37 m_DoAcquisition{true},
37 m_DoAcquisition{true},
38 m_IsCalibration{false},
38 m_IsCalibration{false},
39 m_RenderingDelegate{nullptr}
39 m_RenderingDelegate{nullptr}
40 {
40 {
41 }
41 }
42
42
43 QString m_Name;
43 QString m_Name;
44 // 1 variable -> n qcpplot
44 // 1 variable -> n qcpplot
45 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
45 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
46 bool m_DoAcquisition;
46 bool m_DoAcquisition;
47 bool m_IsCalibration;
47 bool m_IsCalibration;
48 QCPItemTracer *m_TextTracer;
49 /// Delegate used to attach rendering features to the plot
48 /// Delegate used to attach rendering features to the plot
50 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
51 };
50 };
52
51
53 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
54 : VisualizationDragWidget{parent},
53 : VisualizationDragWidget{parent},
55 ui{new Ui::VisualizationGraphWidget},
54 ui{new Ui::VisualizationGraphWidget},
56 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
57 {
56 {
58 ui->setupUi(this);
57 ui->setupUi(this);
59
58
60 // 'Close' options : widget is deleted when closed
59 // 'Close' options : widget is deleted when closed
61 setAttribute(Qt::WA_DeleteOnClose);
60 setAttribute(Qt::WA_DeleteOnClose);
62
61
63 // Set qcpplot properties :
62 // Set qcpplot properties :
64 // - Drag (on x-axis) and zoom are enabled
63 // - Drag (on x-axis) and zoom are enabled
65 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
66 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
67 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
68
67
69 // The delegate must be initialized after the ui as it uses the plot
68 // The delegate must be initialized after the ui as it uses the plot
70 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
71
70
72 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
73 connect(ui->widget, &QCustomPlot::mouseRelease, this,
72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
74 &VisualizationGraphWidget::onMouseRelease);
73 &VisualizationGraphWidget::onMouseRelease);
75 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
76 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
77 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
76 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
78 &QCPAxis::rangeChanged),
77 &QCPAxis::rangeChanged),
79 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
80
79
81 // Activates menu when right clicking on the graph
80 // Activates menu when right clicking on the graph
82 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
81 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
83 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
82 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
84 &VisualizationGraphWidget::onGraphMenuRequested);
83 &VisualizationGraphWidget::onGraphMenuRequested);
85
84
86 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
85 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
87 &VariableController::onRequestDataLoading);
86 &VariableController::onRequestDataLoading);
88
87
89 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
88 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
90 &VisualizationGraphWidget::onUpdateVarDisplaying);
89 &VisualizationGraphWidget::onUpdateVarDisplaying);
91 }
90 }
92
91
93
92
94 VisualizationGraphWidget::~VisualizationGraphWidget()
93 VisualizationGraphWidget::~VisualizationGraphWidget()
95 {
94 {
96 delete ui;
95 delete ui;
97 }
96 }
98
97
99 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
98 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
100 {
99 {
101 auto parent = parentWidget();
100 auto parent = parentWidget();
102 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
101 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
103 parent = parent->parentWidget();
102 parent = parent->parentWidget();
104 }
103 }
105
104
106 return qobject_cast<VisualizationZoneWidget *>(parent);
105 return qobject_cast<VisualizationZoneWidget *>(parent);
107 }
106 }
108
107
109 void VisualizationGraphWidget::enableAcquisition(bool enable)
108 void VisualizationGraphWidget::enableAcquisition(bool enable)
110 {
109 {
111 impl->m_DoAcquisition = enable;
110 impl->m_DoAcquisition = enable;
112 }
111 }
113
112
114 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
113 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
115 {
114 {
116 // Uses delegate to create the qcpplot components according to the variable
115 // Uses delegate to create the qcpplot components according to the variable
117 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
116 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
118 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
117 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
119
118
120 // Set axes properties according to the units of the data series
119 // Set axes properties according to the units of the data series
121 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
120 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
122 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
121 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
123 auto xAxisUnit = Unit{};
122 auto xAxisUnit = Unit{};
124 auto valuesUnit = Unit{};
123 auto valuesUnit = Unit{};
125
124
126 if (auto dataSeries = variable->dataSeries()) {
125 if (auto dataSeries = variable->dataSeries()) {
127 dataSeries->lockRead();
126 dataSeries->lockRead();
128 xAxisUnit = dataSeries->xAxisUnit();
127 xAxisUnit = dataSeries->xAxisUnit();
129 valuesUnit = dataSeries->valuesUnit();
128 valuesUnit = dataSeries->valuesUnit();
130 dataSeries->unlock();
129 dataSeries->unlock();
131 }
130 }
132 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
131 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
133
132
134 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
133 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
135
134
136 this->enableAcquisition(false);
135 this->enableAcquisition(false);
137 this->setGraphRange(range);
136 this->setGraphRange(range);
138 this->enableAcquisition(true);
137 this->enableAcquisition(true);
139
138
140 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
139 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
141
140
142 emit variableAdded(variable);
141 emit variableAdded(variable);
143 }
142 }
144
143
145 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
144 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
146 {
145 {
147 // Each component associated to the variable :
146 // Each component associated to the variable :
148 // - is removed from qcpplot (which deletes it)
147 // - is removed from qcpplot (which deletes it)
149 // - is no longer referenced in the map
148 // - is no longer referenced in the map
150 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
149 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
151 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
150 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
152 emit variableAboutToBeRemoved(variable);
151 emit variableAboutToBeRemoved(variable);
153
152
154 auto &plottablesMap = variableIt->second;
153 auto &plottablesMap = variableIt->second;
155
154
156 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
155 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
157 plottableIt != plottableEnd;) {
156 plottableIt != plottableEnd;) {
158 ui->widget->removePlottable(plottableIt->second);
157 ui->widget->removePlottable(plottableIt->second);
159 plottableIt = plottablesMap.erase(plottableIt);
158 plottableIt = plottablesMap.erase(plottableIt);
160 }
159 }
161
160
162 impl->m_VariableToPlotMultiMap.erase(variableIt);
161 impl->m_VariableToPlotMultiMap.erase(variableIt);
163 }
162 }
164
163
165 // Updates graph
164 // Updates graph
166 ui->widget->replot();
165 ui->widget->replot();
167 }
166 }
168
167
169 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
168 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
170 {
169 {
171 auto variables = QList<std::shared_ptr<Variable> >{};
170 auto variables = QList<std::shared_ptr<Variable> >{};
172 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
171 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
173 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
172 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
174 variables << it->first;
173 variables << it->first;
175 }
174 }
176
175
177 return variables;
176 return variables;
178 }
177 }
179
178
180 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
179 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
181 {
180 {
182 if (!variable) {
181 if (!variable) {
183 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
182 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
184 return;
183 return;
185 }
184 }
186
185
187 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
186 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
188 }
187 }
189
188
190 SqpRange VisualizationGraphWidget::graphRange() const noexcept
189 SqpRange VisualizationGraphWidget::graphRange() const noexcept
191 {
190 {
192 auto graphRange = ui->widget->xAxis->range();
191 auto graphRange = ui->widget->xAxis->range();
193 return SqpRange{graphRange.lower, graphRange.upper};
192 return SqpRange{graphRange.lower, graphRange.upper};
194 }
193 }
195
194
196 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
195 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
197 {
196 {
198 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
197 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
199 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
198 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
200 ui->widget->replot();
199 ui->widget->replot();
201 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
200 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
202 }
201 }
203
202
204 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
203 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
205 {
204 {
206 if (visitor) {
205 if (visitor) {
207 visitor->visit(this);
206 visitor->visit(this);
208 }
207 }
209 else {
208 else {
210 qCCritical(LOG_VisualizationGraphWidget())
209 qCCritical(LOG_VisualizationGraphWidget())
211 << tr("Can't visit widget : the visitor is null");
210 << tr("Can't visit widget : the visitor is null");
212 }
211 }
213 }
212 }
214
213
215 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
214 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
216 {
215 {
217 /// @todo : for the moment, a graph can always accomodate a variable
216 /// @todo : for the moment, a graph can always accomodate a variable
218 Q_UNUSED(variable);
217 Q_UNUSED(variable);
219 return true;
218 return true;
220 }
219 }
221
220
222 bool VisualizationGraphWidget::contains(const Variable &variable) const
221 bool VisualizationGraphWidget::contains(const Variable &variable) const
223 {
222 {
224 // Finds the variable among the keys of the map
223 // Finds the variable among the keys of the map
225 auto variablePtr = &variable;
224 auto variablePtr = &variable;
226 auto findVariable
225 auto findVariable
227 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
226 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
228
227
229 auto end = impl->m_VariableToPlotMultiMap.cend();
228 auto end = impl->m_VariableToPlotMultiMap.cend();
230 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
229 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
231 return it != end;
230 return it != end;
232 }
231 }
233
232
234 QString VisualizationGraphWidget::name() const
233 QString VisualizationGraphWidget::name() const
235 {
234 {
236 return impl->m_Name;
235 return impl->m_Name;
237 }
236 }
238
237
239 QMimeData *VisualizationGraphWidget::mimeData() const
238 QMimeData *VisualizationGraphWidget::mimeData() const
240 {
239 {
241 auto mimeData = new QMimeData;
240 auto mimeData = new QMimeData;
242 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
241 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
243
242
244 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
243 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
245 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
244 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
246
245
247 return mimeData;
246 return mimeData;
248 }
247 }
249
248
250 bool VisualizationGraphWidget::isDragAllowed() const
249 bool VisualizationGraphWidget::isDragAllowed() const
251 {
250 {
252 return true;
251 return true;
253 }
252 }
254
253
255 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
254 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
256 {
255 {
257 if (highlighted) {
256 if (highlighted) {
258 plot().setBackground(QBrush(QColor("#BBD5EE")));
257 plot().setBackground(QBrush(QColor("#BBD5EE")));
259 }
258 }
260 else {
259 else {
261 plot().setBackground(QBrush(Qt::white));
260 plot().setBackground(QBrush(Qt::white));
262 }
261 }
263
262
264 plot().update();
263 plot().update();
265 }
264 }
266
265
267 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
266 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
268 {
267 {
269 Q_UNUSED(event);
268 Q_UNUSED(event);
270
269
271 // Prevents that all variables will be removed from graph when it will be closed
270 // Prevents that all variables will be removed from graph when it will be closed
272 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
271 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
273 emit variableAboutToBeRemoved(variableEntry.first);
272 emit variableAboutToBeRemoved(variableEntry.first);
274 }
273 }
275 }
274 }
276
275
277 void VisualizationGraphWidget::enterEvent(QEvent *event)
276 void VisualizationGraphWidget::enterEvent(QEvent *event)
278 {
277 {
279 Q_UNUSED(event);
278 Q_UNUSED(event);
280 impl->m_RenderingDelegate->showGraphOverlay(true);
279 impl->m_RenderingDelegate->showGraphOverlay(true);
281 }
280 }
282
281
283 void VisualizationGraphWidget::leaveEvent(QEvent *event)
282 void VisualizationGraphWidget::leaveEvent(QEvent *event)
284 {
283 {
285 Q_UNUSED(event);
284 Q_UNUSED(event);
286 impl->m_RenderingDelegate->showGraphOverlay(false);
285 impl->m_RenderingDelegate->showGraphOverlay(false);
287 }
286 }
288
287
289 QCustomPlot &VisualizationGraphWidget::plot() noexcept
288 QCustomPlot &VisualizationGraphWidget::plot() noexcept
290 {
289 {
291 return *ui->widget;
290 return *ui->widget;
292 }
291 }
293
292
294 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
293 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
295 {
294 {
296 QMenu graphMenu{};
295 QMenu graphMenu{};
297
296
298 // Iterates on variables (unique keys)
297 // Iterates on variables (unique keys)
299 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
298 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
300 end = impl->m_VariableToPlotMultiMap.cend();
299 end = impl->m_VariableToPlotMultiMap.cend();
301 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
300 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
302 // 'Remove variable' action
301 // 'Remove variable' action
303 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
302 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
304 [ this, var = it->first ]() { removeVariable(var); });
303 [ this, var = it->first ]() { removeVariable(var); });
305 }
304 }
306
305
307 if (!graphMenu.isEmpty()) {
306 if (!graphMenu.isEmpty()) {
308 graphMenu.exec(QCursor::pos());
307 graphMenu.exec(QCursor::pos());
309 }
308 }
310 }
309 }
311
310
312 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
311 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
313 {
312 {
314 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
313 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
315 << QThread::currentThread()->objectName() << "DoAcqui"
314 << QThread::currentThread()->objectName() << "DoAcqui"
316 << impl->m_DoAcquisition;
315 << impl->m_DoAcquisition;
317
316
318 auto graphRange = SqpRange{t1.lower, t1.upper};
317 auto graphRange = SqpRange{t1.lower, t1.upper};
319 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
318 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
320
319
321 if (impl->m_DoAcquisition) {
320 if (impl->m_DoAcquisition) {
322 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
321 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
323
322
324 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
323 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
325 end = impl->m_VariableToPlotMultiMap.end();
324 end = impl->m_VariableToPlotMultiMap.end();
326 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
325 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
327 variableUnderGraphVector.push_back(it->first);
326 variableUnderGraphVector.push_back(it->first);
328 }
327 }
329 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
328 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
330 !impl->m_IsCalibration);
329 !impl->m_IsCalibration);
331
330
332 if (!impl->m_IsCalibration) {
331 if (!impl->m_IsCalibration) {
333 qCDebug(LOG_VisualizationGraphWidget())
332 qCDebug(LOG_VisualizationGraphWidget())
334 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
333 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
335 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
334 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
336 emit synchronize(graphRange, oldGraphRange);
335 emit synchronize(graphRange, oldGraphRange);
337 }
336 }
338 }
337 }
339 }
338 }
340
339
341 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
340 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
342 {
341 {
343 // Handles plot rendering when mouse is moving
342 // Handles plot rendering when mouse is moving
344 impl->m_RenderingDelegate->onMouseMove(event);
343 impl->m_RenderingDelegate->onMouseMove(event);
345
344
346 VisualizationDragWidget::mouseMoveEvent(event);
345 VisualizationDragWidget::mouseMoveEvent(event);
347 }
346 }
348
347
349 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
348 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
350 {
349 {
351 auto zoomOrientations = QFlags<Qt::Orientation>{};
350 auto zoomOrientations = QFlags<Qt::Orientation>{};
352
351
353 // Lambda that enables a zoom orientation if the key modifier related to this orientation
352 // Lambda that enables a zoom orientation if the key modifier related to this orientation
354 // has
353 // has
355 // been pressed
354 // been pressed
356 auto enableOrientation
355 auto enableOrientation
357 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
356 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
358 auto orientationEnabled = event->modifiers().testFlag(modifier);
357 auto orientationEnabled = event->modifiers().testFlag(modifier);
359 zoomOrientations.setFlag(orientation, orientationEnabled);
358 zoomOrientations.setFlag(orientation, orientationEnabled);
360 };
359 };
361 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
360 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
362 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
361 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
363
362
364 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
363 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
365 }
364 }
366
365
367 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
366 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
368 {
367 {
369 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
368 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
370
369
371 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
370 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
372
371
373 VisualizationDragWidget::mousePressEvent(event);
372 VisualizationDragWidget::mousePressEvent(event);
374 }
373 }
375
374
376 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
375 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
377 {
376 {
378 impl->m_IsCalibration = false;
377 impl->m_IsCalibration = false;
379 }
378 }
380
379
381 void VisualizationGraphWidget::onDataCacheVariableUpdated()
380 void VisualizationGraphWidget::onDataCacheVariableUpdated()
382 {
381 {
383 auto graphRange = ui->widget->xAxis->range();
382 auto graphRange = ui->widget->xAxis->range();
384 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
383 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
385
384
386 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
385 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
387 auto variable = variableEntry.first;
386 auto variable = variableEntry.first;
388 qCDebug(LOG_VisualizationGraphWidget())
387 qCDebug(LOG_VisualizationGraphWidget())
389 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
388 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
390 qCDebug(LOG_VisualizationGraphWidget())
389 qCDebug(LOG_VisualizationGraphWidget())
391 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
390 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
392 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
391 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
393 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
392 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
394 variable->range());
393 variable->range());
395 }
394 }
396 }
395 }
397 }
396 }
398
397
399 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
398 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
400 const SqpRange &range)
399 const SqpRange &range)
401 {
400 {
402 auto it = impl->m_VariableToPlotMultiMap.find(variable);
401 auto it = impl->m_VariableToPlotMultiMap.find(variable);
403 if (it != impl->m_VariableToPlotMultiMap.end()) {
402 if (it != impl->m_VariableToPlotMultiMap.end()) {
404 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
403 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
405 }
404 }
406 }
405 }
General Comments 0
You need to be logged in to leave comments. Login now