##// END OF EJS Templates
Add mofif for clang format
perrinel -
r591:7644bba62054
parent child
Show More
@@ -1,240 +1,243
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/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 /// Format for datetimes on a axis
21 /// Format for datetimes on a axis
22 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
22 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
23
23
24 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
24 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
25 /// non-time data
25 /// non-time data
26 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
26 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
27 {
27 {
28 if (isTimeAxis) {
28 if (isTimeAxis) {
29 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
29 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
30 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
30 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
31 dateTicker->setDateTimeSpec(Qt::UTC);
31 dateTicker->setDateTimeSpec(Qt::UTC);
32
32
33 return dateTicker;
33 return dateTicker;
34 }
34 }
35 else {
35 else {
36 // default ticker
36 // default ticker
37 return QSharedPointer<QCPAxisTicker>::create();
37 return QSharedPointer<QCPAxisTicker>::create();
38 }
38 }
39 }
39 }
40
40
41 /// Sets axes properties according to the properties of a data series
41 /// Sets axes properties according to the properties of a data series
42 template <int Dim>
42 template <int Dim>
43 void setAxesProperties(const DataSeries<Dim> &dataSeries, QCustomPlot &plot) noexcept
43 void setAxesProperties(const DataSeries<Dim> &dataSeries, QCustomPlot &plot) noexcept
44 {
44 {
45 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
45 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
46 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
46 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
47 auto setAxisProperties = [](auto axis, const auto &unit) {
47 auto setAxisProperties = [](auto axis, const auto &unit) {
48 // label (unit name)
48 // label (unit name)
49 axis->setLabel(unit.m_Name);
49 axis->setLabel(unit.m_Name);
50
50
51 // ticker (depending on the type of unit)
51 // ticker (depending on the type of unit)
52 axis->setTicker(axisTicker(unit.m_TimeUnit));
52 axis->setTicker(axisTicker(unit.m_TimeUnit));
53 };
53 };
54 setAxisProperties(plot.xAxis, dataSeries.xAxisUnit());
54 setAxisProperties(plot.xAxis, dataSeries.xAxisUnit());
55 setAxisProperties(plot.yAxis, dataSeries.valuesUnit());
55 setAxisProperties(plot.yAxis, dataSeries.valuesUnit());
56 }
56 }
57
57
58 /**
58 /**
59 * Struct used to create plottables, depending on the type of the data series from which to create them
59 * Struct used to create plottables, depending on the type of the data series from which to create
60 * them
60 * @tparam T the data series' type
61 * @tparam T the data series' type
61 * @remarks Default implementation can't create plottables
62 * @remarks Default implementation can't create plottables
62 */
63 */
63 template <typename T, typename Enabled = void>
64 template <typename T, typename Enabled = void>
64 struct PlottablesCreator {
65 struct PlottablesCreator {
65 static PlottablesMap createPlottables(T &, QCustomPlot &)
66 static PlottablesMap createPlottables(T &, QCustomPlot &)
66 {
67 {
67 qCCritical(LOG_DataSeries())
68 qCCritical(LOG_DataSeries())
68 << QObject::tr("Can't create plottables: unmanaged data series type");
69 << QObject::tr("Can't create plottables: unmanaged data series type");
69 return {};
70 return {};
70 }
71 }
71 };
72 };
72
73
73 /**
74 /**
74 * Specialization of PlottablesCreator for scalars and vectors
75 * Specialization of PlottablesCreator for scalars and vectors
75 * @sa ScalarSeries
76 * @sa ScalarSeries
76 * @sa VectorSeries
77 * @sa VectorSeries
77 */
78 */
78 template <typename T>
79 template <typename T>
79 struct PlottablesCreator<T,
80 struct PlottablesCreator<T,
80 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
81 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
81 or std::is_base_of<VectorSeries, T>::value> > {
82 or std::is_base_of<VectorSeries, T>::value> > {
82 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
83 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
83 {
84 {
84 PlottablesMap result{};
85 PlottablesMap result{};
85
86
86 // Gets the number of components of the data series
87 // Gets the number of components of the data series
87 auto componentCount = dataSeries.valuesData()->componentCount();
88 auto componentCount = dataSeries.valuesData()->componentCount();
88
89
89 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
90 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
90
91
91 // For each component of the data series, creates a QCPGraph to add to the plot
92 // For each component of the data series, creates a QCPGraph to add to the plot
92 for (auto i = 0; i < componentCount; ++i) {
93 for (auto i = 0; i < componentCount; ++i) {
93 auto graph = plot.addGraph();
94 auto graph = plot.addGraph();
94 graph->setPen(QPen{colors.at(i)});
95 graph->setPen(QPen{colors.at(i)});
95
96
96 result.insert({i, graph});
97 result.insert({i, graph});
97 }
98 }
98
99
99 // Axes properties
100 // Axes properties
100 setAxesProperties(dataSeries, plot);
101 setAxesProperties(dataSeries, plot);
101
102
102 plot.replot();
103 plot.replot();
103
104
104 return result;
105 return result;
105 }
106 }
106 };
107 };
107
108
108 /**
109 /**
109 * Struct used to update plottables, depending on the type of the data series from which to update them
110 * Struct used to update plottables, depending on the type of the data series from which to update
111 * them
110 * @tparam T the data series' type
112 * @tparam T the data series' type
111 * @remarks Default implementation can't update plottables
113 * @remarks Default implementation can't update plottables
112 */
114 */
113 template <typename T, typename Enabled = void>
115 template <typename T, typename Enabled = void>
114 struct PlottablesUpdater {
116 struct PlottablesUpdater {
115 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
117 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
116 {
118 {
117 qCCritical(LOG_DataSeries())
119 qCCritical(LOG_DataSeries())
118 << QObject::tr("Can't update plottables: unmanaged data series type");
120 << QObject::tr("Can't update plottables: unmanaged data series type");
119 }
121 }
120 };
122 };
121
123
122 /**
124 /**
123 * Specialization of PlottablesUpdater for scalars and vectors
125 * Specialization of PlottablesUpdater for scalars and vectors
124 * @sa ScalarSeries
126 * @sa ScalarSeries
125 * @sa VectorSeries
127 * @sa VectorSeries
126 */
128 */
127 template <typename T>
129 template <typename T>
128 struct PlottablesUpdater<T,
130 struct PlottablesUpdater<T,
129 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
131 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
130 or std::is_base_of<VectorSeries, T>::value> > {
132 or std::is_base_of<VectorSeries, T>::value> > {
131 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
133 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
132 bool rescaleAxes)
134 bool rescaleAxes)
133 {
135 {
134 dataSeries.lockRead();
136 dataSeries.lockRead();
135
137
136 // For each plottable to update, resets its data
138 // For each plottable to update, resets its data
137 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
139 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
138 for (const auto &plottable : plottables) {
140 for (const auto &plottable : plottables) {
139 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
141 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
140 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
142 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
141 graph->setData(dataContainer);
143 graph->setData(dataContainer);
142
144
143 dataContainers.insert({plottable.first, dataContainer});
145 dataContainers.insert({plottable.first, dataContainer});
144 }
146 }
145 }
147 }
146
148
147 // - Gets the data of the series included in the current range
149 // - Gets the data of the series included in the current range
148 // - Updates each plottable by adding, for each data item, a point that takes x-axis data and value data. The correct value is retrieved according to the index of the component
150 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
151 // and value data. The correct value is retrieved according to the index of the component
149 auto subDataIts = dataSeries.subData(range.m_TStart, range.m_TEnd);
152 auto subDataIts = dataSeries.subData(range.m_TStart, range.m_TEnd);
150 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
153 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
151 for (const auto &dataContainer : dataContainers) {
154 for (const auto &dataContainer : dataContainers) {
152 auto componentIndex = dataContainer.first;
155 auto componentIndex = dataContainer.first;
153 dataContainer.second->appendGraphData(
156 dataContainer.second->appendGraphData(
154 QCPGraphData(it->x(), it->value(componentIndex)));
157 QCPGraphData(it->x(), it->value(componentIndex)));
155 }
158 }
156 }
159 }
157
160
158 dataSeries.unlock();
161 dataSeries.unlock();
159
162
160 if (!plottables.empty()) {
163 if (!plottables.empty()) {
161 auto plot = plottables.begin()->second->parentPlot();
164 auto plot = plottables.begin()->second->parentPlot();
162
165
163 if (rescaleAxes) {
166 if (rescaleAxes) {
164 plot->rescaleAxes();
167 plot->rescaleAxes();
165 }
168 }
166
169
167 plot->replot();
170 plot->replot();
168 }
171 }
169 }
172 }
170 };
173 };
171
174
172 /**
175 /**
173 * Helper used to create/update plottables
176 * Helper used to create/update plottables
174 */
177 */
175 struct IPlottablesHelper {
178 struct IPlottablesHelper {
176 virtual ~IPlottablesHelper() noexcept = default;
179 virtual ~IPlottablesHelper() noexcept = default;
177 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
180 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
178 virtual void update(PlottablesMap &plottables, const SqpRange &range,
181 virtual void update(PlottablesMap &plottables, const SqpRange &range,
179 bool rescaleAxes = false) const = 0;
182 bool rescaleAxes = false) const = 0;
180 };
183 };
181
184
182 /**
185 /**
183 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
186 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
184 * @tparam T the data series' type
187 * @tparam T the data series' type
185 */
188 */
186 template <typename T>
189 template <typename T>
187 struct PlottablesHelper : public IPlottablesHelper {
190 struct PlottablesHelper : public IPlottablesHelper {
188 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
191 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
189
192
190 PlottablesMap create(QCustomPlot &plot) const override
193 PlottablesMap create(QCustomPlot &plot) const override
191 {
194 {
192 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
195 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
193 }
196 }
194
197
195 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
198 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
196 {
199 {
197 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
200 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
198 }
201 }
199
202
200 T &m_DataSeries;
203 T &m_DataSeries;
201 };
204 };
202
205
203 /// Creates IPlottablesHelper according to a data series
206 /// Creates IPlottablesHelper according to a data series
204 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
207 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
205 {
208 {
206 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
209 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
207 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
210 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
208 }
211 }
209 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
212 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
210 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
213 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
211 }
214 }
212 else {
215 else {
213 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
216 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
214 }
217 }
215 }
218 }
216
219
217 } // namespace
220 } // namespace
218
221
219 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
222 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
220 QCustomPlot &plot) noexcept
223 QCustomPlot &plot) noexcept
221 {
224 {
222 if (variable) {
225 if (variable) {
223 auto helper = createHelper(variable->dataSeries());
226 auto helper = createHelper(variable->dataSeries());
224 auto plottables = helper->create(plot);
227 auto plottables = helper->create(plot);
225 return plottables;
228 return plottables;
226 }
229 }
227 else {
230 else {
228 qCDebug(LOG_VisualizationGraphHelper())
231 qCDebug(LOG_VisualizationGraphHelper())
229 << QObject::tr("Can't create graph plottables : the variable is null");
232 << QObject::tr("Can't create graph plottables : the variable is null");
230 return PlottablesMap{};
233 return PlottablesMap{};
231 }
234 }
232 }
235 }
233
236
234 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
237 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
235 std::shared_ptr<IDataSeries> dataSeries,
238 std::shared_ptr<IDataSeries> dataSeries,
236 const SqpRange &dateTime)
239 const SqpRange &dateTime)
237 {
240 {
238 auto helper = createHelper(dataSeries);
241 auto helper = createHelper(dataSeries);
239 helper->update(plottables, dateTime);
242 helper->update(plottables, dateTime);
240 }
243 }
General Comments 0
You need to be logged in to leave comments. Login now