##// END OF EJS Templates
Merge pull request 333 from SciQLop-fork develop...
trabillard -
r926:7347d93117b4 merge
parent child
Show More
@@ -0,0 +1,34
1 #ifndef SCIQLOP_AXISRENDERINGUTILS_H
2 #define SCIQLOP_AXISRENDERINGUTILS_H
3
4 #include <memory>
5
6 #include <QtCore/QString>
7
8 class IDataSeries;
9 class QCPAxis;
10 class QCPColorScale;
11 class QCustomPlot;
12
13 /// Formats a data value according to the axis on which it is present
14 QString formatValue(double value, const QCPAxis &axis);
15
16 /**
17 * Helper used to handle axes rendering
18 */
19 struct IAxisHelper {
20 virtual ~IAxisHelper() noexcept = default;
21
22 /// Set properties of the plot's axes and the color scale associated to plot passed as
23 /// parameters
24 /// @param plot the plot for which to set axe properties
25 /// @param colorScale the color scale for which to set properties
26 virtual void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) = 0;
27 };
28
29 struct IAxisHelperFactory {
30 /// Creates IAxisHelper according to a data series
31 static std::unique_ptr<IAxisHelper> create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
32 };
33
34 #endif // SCIQLOP_AXISRENDERINGUTILS_H
@@ -0,0 +1,29
1 #ifndef SCIQLOP_PLOTTABLESRENDERINGUTILS_H
2 #define SCIQLOP_PLOTTABLESRENDERINGUTILS_H
3
4 #include <Visualization/VisualizationDefs.h>
5
6 #include <memory>
7
8 class IDataSeries;
9 class QCPColorScale;
10 class QCustomPlot;
11
12 /**
13 * Helper used to handle plottables rendering
14 */
15 struct IPlottablesHelper {
16 virtual ~IPlottablesHelper() noexcept = default;
17
18 /// Set properties of the plottables passed as parameter
19 /// @param plottables the plottables for which to set properties
20 virtual void setProperties(PlottablesMap &plottables) = 0;
21 };
22
23 struct IPlottablesHelperFactory {
24 /// Creates IPlottablesHelper according to a data series
25 static std::unique_ptr<IPlottablesHelper>
26 create(std::shared_ptr<IDataSeries> dataSeries) noexcept;
27 };
28
29 #endif // SCIQLOP_PLOTTABLESRENDERINGUTILS_H
@@ -0,0 +1,163
1 #include "Visualization/AxisRenderingUtils.h"
2
3 #include <Data/ScalarSeries.h>
4 #include <Data/SpectrogramSeries.h>
5 #include <Data/VectorSeries.h>
6
7 #include <Visualization/qcustomplot.h>
8
9 namespace {
10
11 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
12
13 /// Format for datetimes on a axis
14 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
15
16 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
17 /// non-time data
18 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
19 {
20 if (isTimeAxis) {
21 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
22 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
23 dateTicker->setDateTimeSpec(Qt::UTC);
24
25 return dateTicker;
26 }
27 else {
28 // default ticker
29 return QSharedPointer<QCPAxisTicker>::create();
30 }
31 }
32
33 /**
34 * Sets properties of the axis passed as parameter
35 * @param axis the axis to set
36 * @param unit the unit to set for the axis
37 * @param scaleType the scale type to set for the axis
38 */
39 void setAxisProperties(QCPAxis &axis, const Unit &unit,
40 QCPAxis::ScaleType scaleType = QCPAxis::stLinear)
41 {
42 // label (unit name)
43 axis.setLabel(unit.m_Name);
44
45 // scale type
46 axis.setScaleType(scaleType);
47
48 // ticker (depending on the type of unit)
49 axis.setTicker(axisTicker(unit.m_TimeUnit));
50 }
51
52 /**
53 * Delegate used to set axes properties
54 */
55 template <typename T, typename Enabled = void>
56 struct AxisSetter {
57 static void setProperties(T &, QCustomPlot &, QCPColorScale &)
58 {
59 // Default implementation does nothing
60 }
61 };
62
63 /**
64 * Specialization of AxisSetter for scalars and vectors
65 * @sa ScalarSeries
66 * @sa VectorSeries
67 */
68 template <typename T>
69 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
70 or std::is_base_of<VectorSeries, T>::value> > {
71 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &)
72 {
73 dataSeries.lockRead();
74 auto xAxisUnit = dataSeries.xAxisUnit();
75 auto valuesUnit = dataSeries.valuesUnit();
76 dataSeries.unlock();
77
78 setAxisProperties(*plot.xAxis, xAxisUnit);
79 setAxisProperties(*plot.yAxis, valuesUnit);
80 }
81 };
82
83 /**
84 * Specialization of AxisSetter for spectrograms
85 * @sa SpectrogramSeries
86 */
87 template <typename T>
88 struct AxisSetter<T, typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
89 static void setProperties(T &dataSeries, QCustomPlot &plot, QCPColorScale &colorScale)
90 {
91 dataSeries.lockRead();
92 auto xAxisUnit = dataSeries.xAxisUnit();
93 /// @todo ALX: use iterators here
94 auto yAxisUnit = dataSeries.yAxis().unit();
95 auto valuesUnit = dataSeries.valuesUnit();
96 dataSeries.unlock();
97
98 setAxisProperties(*plot.xAxis, xAxisUnit);
99 setAxisProperties(*plot.yAxis, yAxisUnit);
100
101 // Displays color scale in plot
102 plot.plotLayout()->insertRow(0);
103 plot.plotLayout()->addElement(0, 0, &colorScale);
104 colorScale.setType(QCPAxis::atTop);
105 colorScale.setMinimumMargins(QMargins{0, 0, 0, 0});
106
107 // Aligns color scale with axes
108 auto marginGroups = plot.axisRect()->marginGroups();
109 for (auto it = marginGroups.begin(), end = marginGroups.end(); it != end; ++it) {
110 colorScale.setMarginGroup(it.key(), it.value());
111 }
112
113 // Set color scale properties
114 colorScale.setLabel(valuesUnit.m_Name);
115 colorScale.setDataScaleType(QCPAxis::stLogarithmic); // Logarithmic scale
116 }
117 };
118
119 /**
120 * Default implementation of IAxisHelper, which takes data series to set axes properties
121 * @tparam T the data series' type
122 */
123 template <typename T>
124 struct AxisHelper : public IAxisHelper {
125 explicit AxisHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
126
127 void setProperties(QCustomPlot &plot, QCPColorScale &colorScale) override
128 {
129 AxisSetter<T>::setProperties(m_DataSeries, plot, colorScale);
130 }
131
132 T &m_DataSeries;
133 };
134
135 } // namespace
136
137 QString formatValue(double value, const QCPAxis &axis)
138 {
139 // If the axis is a time axis, formats the value as a date
140 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
141 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
142 }
143 else {
144 return QString::number(value);
145 }
146 }
147
148 std::unique_ptr<IAxisHelper>
149 IAxisHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
150 {
151 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
152 return std::make_unique<AxisHelper<ScalarSeries> >(*scalarSeries);
153 }
154 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
155 return std::make_unique<AxisHelper<SpectrogramSeries> >(*spectrogramSeries);
156 }
157 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
158 return std::make_unique<AxisHelper<VectorSeries> >(*vectorSeries);
159 }
160 else {
161 return std::make_unique<AxisHelper<IDataSeries> >(*dataSeries);
162 }
163 }
@@ -0,0 +1,120
1 #include "Visualization/PlottablesRenderingUtils.h"
2
3 #include <Common/ColorUtils.h>
4
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
8
9 #include <Visualization/qcustomplot.h>
10
11 namespace {
12
13 /// Default gradient used for colormap
14 const auto DEFAULT_COLORMAP_GRADIENT = QCPColorGradient::gpJet;
15
16 /**
17 * Delegate used to set plottables properties
18 */
19 template <typename T, typename Enabled = void>
20 struct PlottablesSetter {
21 static void setProperties(T &, PlottablesMap &)
22 {
23 // Default implementation does nothing
24 }
25 };
26
27 /**
28 * Specialization of PlottablesSetter for scalars and vectors
29 * @sa ScalarSeries
30 * @sa VectorSeries
31 */
32 template <typename T>
33 struct PlottablesSetter<T, typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
34 or std::is_base_of<VectorSeries, T>::value> > {
35 static void setProperties(T &dataSeries, PlottablesMap &plottables)
36 {
37 // Gets the number of components of the data series
38 dataSeries.lockRead();
39 auto componentCount = dataSeries.valuesData()->componentCount();
40 dataSeries.unlock();
41
42 // Generates colors for each component
43 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
44
45 // For each component of the data series, creates a QCPGraph to add to the plot
46 for (auto i = 0; i < componentCount; ++i) {
47 auto graph = plottables.at(i);
48 graph->setPen(QPen{colors.at(i)});
49 }
50 }
51 };
52
53 /**
54 * Specialization of PlottablesSetter for spectrograms
55 * @sa SpectrogramSeries
56 */
57 template <typename T>
58 struct PlottablesSetter<T,
59 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
60 static void setProperties(T &, PlottablesMap &plottables)
61 {
62 // Checks that for a spectrogram there is only one plottable, that is a colormap
63 if (plottables.size() != 1) {
64 return;
65 }
66
67 if (auto colormap = dynamic_cast<QCPColorMap *>(plottables.begin()->second)) {
68 colormap->setInterpolate(false); // No value interpolation
69 colormap->setTightBoundary(true);
70
71 // Finds color scale in the colormap's plot to associate with it
72 auto plot = colormap->parentPlot();
73 auto plotElements = plot->plotLayout()->elements(false);
74 for (auto plotElement : plotElements) {
75 if (auto colorScale = dynamic_cast<QCPColorScale *>(plotElement)) {
76 colormap->setColorScale(colorScale);
77 }
78 }
79
80 // Sets gradient used for color scale
81 colormap->setGradient(DEFAULT_COLORMAP_GRADIENT);
82 colormap->rescaleDataRange();
83 }
84 }
85 };
86
87 /**
88 * Default implementation of IPlottablesHelper, which takes data series to set plottables properties
89 * @tparam T the data series' type
90 */
91 template <typename T>
92 struct PlottablesHelper : public IPlottablesHelper {
93 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
94
95 void setProperties(PlottablesMap &plottables) override
96 {
97 PlottablesSetter<T>::setProperties(m_DataSeries, plottables);
98 }
99
100 T &m_DataSeries;
101 };
102
103 } // namespace
104
105 std::unique_ptr<IPlottablesHelper>
106 IPlottablesHelperFactory::create(std::shared_ptr<IDataSeries> dataSeries) noexcept
107 {
108 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
109 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
110 }
111 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
112 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
113 }
114 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
115 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
116 }
117 else {
118 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
119 }
120 }
@@ -1,99 +1,101
1 #include <Data/OptionalAxis.h>
1 #include <Data/OptionalAxis.h>
2
2
3 #include "Data/ArrayData.h"
3 #include "Data/ArrayData.h"
4
4
5 OptionalAxis::OptionalAxis() : m_Defined{false}, m_Data{nullptr}, m_Unit{}
5 OptionalAxis::OptionalAxis() : m_Defined{false}, m_Data{nullptr}, m_Unit{}
6 {
6 {
7 }
7 }
8
8
9 OptionalAxis::OptionalAxis(std::shared_ptr<ArrayData<1> > data, Unit unit)
9 OptionalAxis::OptionalAxis(std::shared_ptr<ArrayData<1> > data, Unit unit)
10 : m_Defined{true}, m_Data{data}, m_Unit{std::move(unit)}
10 : m_Defined{true}, m_Data{data}, m_Unit{std::move(unit)}
11 {
11 {
12 if (m_Data == nullptr) {
12 if (m_Data == nullptr) {
13 throw std::invalid_argument{"Data can't be null for a defined axis"};
13 throw std::invalid_argument{"Data can't be null for a defined axis"};
14 }
14 }
15 }
15 }
16
16
17 OptionalAxis::OptionalAxis(const OptionalAxis &other)
17 OptionalAxis::OptionalAxis(const OptionalAxis &other)
18 : m_Defined{other.m_Defined},
18 : m_Defined{other.m_Defined},
19 m_Data{other.m_Data ? std::make_shared<ArrayData<1> >(*other.m_Data) : nullptr},
19 m_Data{other.m_Data ? std::make_shared<ArrayData<1> >(*other.m_Data) : nullptr},
20 m_Unit{other.m_Unit}
20 m_Unit{other.m_Unit}
21 {
21 {
22 }
22 }
23
23
24 OptionalAxis &OptionalAxis::operator=(OptionalAxis other)
24 OptionalAxis &OptionalAxis::operator=(OptionalAxis other)
25 {
25 {
26 std::swap(m_Defined, other.m_Defined);
26 std::swap(m_Defined, other.m_Defined);
27 std::swap(m_Data, other.m_Data);
27 std::swap(m_Data, other.m_Data);
28 std::swap(m_Unit, other.m_Unit);
28 std::swap(m_Unit, other.m_Unit);
29
30 return *this;
29 }
31 }
30
32
31 bool OptionalAxis::isDefined() const
33 bool OptionalAxis::isDefined() const
32 {
34 {
33 return m_Defined;
35 return m_Defined;
34 }
36 }
35
37
36 double OptionalAxis::at(int index) const
38 double OptionalAxis::at(int index) const
37 {
39 {
38 if (m_Defined) {
40 if (m_Defined) {
39 return (index >= 0 && index < m_Data->size()) ? m_Data->at(index)
41 return (index >= 0 && index < m_Data->size()) ? m_Data->at(index)
40 : std::numeric_limits<double>::quiet_NaN();
42 : std::numeric_limits<double>::quiet_NaN();
41 }
43 }
42 else {
44 else {
43 return std::numeric_limits<double>::quiet_NaN();
45 return std::numeric_limits<double>::quiet_NaN();
44 }
46 }
45 }
47 }
46
48
47 std::pair<double, double> OptionalAxis::bounds() const
49 std::pair<double, double> OptionalAxis::bounds() const
48 {
50 {
49 if (!m_Defined || m_Data->size() == 0) {
51 if (!m_Defined || m_Data->size() == 0) {
50 return std::make_pair(std::numeric_limits<double>::quiet_NaN(),
52 return std::make_pair(std::numeric_limits<double>::quiet_NaN(),
51 std::numeric_limits<double>::quiet_NaN());
53 std::numeric_limits<double>::quiet_NaN());
52 }
54 }
53 else {
55 else {
54
56
55 auto minIt = std::min_element(
57 auto minIt = std::min_element(
56 m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) {
58 m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) {
57 return SortUtils::minCompareWithNaN(it1.first(), it2.first());
59 return SortUtils::minCompareWithNaN(it1.first(), it2.first());
58 });
60 });
59
61
60 // Gets the iterator on the max of all values data
62 // Gets the iterator on the max of all values data
61 auto maxIt = std::max_element(
63 auto maxIt = std::max_element(
62 m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) {
64 m_Data->cbegin(), m_Data->cend(), [](const auto &it1, const auto &it2) {
63 return SortUtils::maxCompareWithNaN(it1.first(), it2.first());
65 return SortUtils::maxCompareWithNaN(it1.first(), it2.first());
64 });
66 });
65
67
66 auto pair = std::make_pair(minIt->first(), maxIt->first());
68 auto pair = std::make_pair(minIt->first(), maxIt->first());
67
69
68 return std::make_pair(minIt->first(), maxIt->first());
70 return std::make_pair(minIt->first(), maxIt->first());
69 }
71 }
70 }
72 }
71
73
72 int OptionalAxis::size() const
74 int OptionalAxis::size() const
73 {
75 {
74 return m_Defined ? m_Data->size() : 0;
76 return m_Defined ? m_Data->size() : 0;
75 }
77 }
76
78
77 Unit OptionalAxis::unit() const
79 Unit OptionalAxis::unit() const
78 {
80 {
79 return m_Defined ? m_Unit : Unit{};
81 return m_Defined ? m_Unit : Unit{};
80 }
82 }
81
83
82 bool OptionalAxis::operator==(const OptionalAxis &other)
84 bool OptionalAxis::operator==(const OptionalAxis &other)
83 {
85 {
84 // Axis not defined
86 // Axis not defined
85 if (!m_Defined) {
87 if (!m_Defined) {
86 return !other.m_Defined;
88 return !other.m_Defined;
87 }
89 }
88
90
89 // Axis defined
91 // Axis defined
90 return m_Unit == other.m_Unit
92 return m_Unit == other.m_Unit
91 && std::equal(
93 && std::equal(
92 m_Data->cbegin(), m_Data->cend(), other.m_Data->cbegin(), other.m_Data->cend(),
94 m_Data->cbegin(), m_Data->cend(), other.m_Data->cbegin(), other.m_Data->cend(),
93 [](const auto &it1, const auto &it2) { return it1.values() == it2.values(); });
95 [](const auto &it1, const auto &it2) { return it1.values() == it2.values(); });
94 }
96 }
95
97
96 bool OptionalAxis::operator!=(const OptionalAxis &other)
98 bool OptionalAxis::operator!=(const OptionalAxis &other)
97 {
99 {
98 return !(*this == other);
100 return !(*this == other);
99 }
101 }
@@ -1,31 +1,39
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>
7
8 class IDataSeries;
6 class QCustomPlot;
9 class QCustomPlot;
7 class QMouseEvent;
10 class QMouseEvent;
8 class Unit;
11 class Unit;
9 class VisualizationGraphWidget;
12 class VisualizationGraphWidget;
10
13
11 class VisualizationGraphRenderingDelegate {
14 class VisualizationGraphRenderingDelegate {
12 public:
15 public:
13 /// Ctor
16 /// Ctor
14 /// @param graphWidget the graph widget to which the delegate is associated
17 /// @param graphWidget the graph widget to which the delegate is associated
15 /// @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
16 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
19 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
17
20
18 void onMouseMove(QMouseEvent *event) noexcept;
21 void onMouseMove(QMouseEvent *event) noexcept;
19
22
20 /// Sets properties of the plot's axes
23 /// Sets properties of the plot's axes from the data series passed as parameter
21 void setAxesProperties(const Unit &xAxisUnit, const Unit &valuesUnit) noexcept;
24 void setAxesProperties(std::shared_ptr<IDataSeries> dataSeries) noexcept;
25
26 /// Sets rendering properties of the plottables passed as parameter, from the data series that
27 /// generated these
28 void setPlottablesProperties(std::shared_ptr<IDataSeries> dataSeries,
29 PlottablesMap &plottables) noexcept;
22
30
23 /// Shows or hides graph overlay (name, close button, etc.)
31 /// Shows or hides graph overlay (name, close button, etc.)
24 void showGraphOverlay(bool show) noexcept;
32 void showGraphOverlay(bool show) noexcept;
25
33
26 private:
34 private:
27 class VisualizationGraphRenderingDelegatePrivate;
35 class VisualizationGraphRenderingDelegatePrivate;
28 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
36 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
29 };
37 };
30
38
31 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
39 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
@@ -1,95 +1,97
1
1
2 gui_moc_headers = [
2 gui_moc_headers = [
3 'include/DataSource/DataSourceWidget.h',
3 'include/DataSource/DataSourceWidget.h',
4 'include/DataSource/DataSourceTreeWidget.h',
4 'include/DataSource/DataSourceTreeWidget.h',
5 'include/Settings/SqpSettingsDialog.h',
5 'include/Settings/SqpSettingsDialog.h',
6 'include/Settings/SqpSettingsGeneralWidget.h',
6 'include/Settings/SqpSettingsGeneralWidget.h',
7 'include/SidePane/SqpSidePane.h',
7 'include/SidePane/SqpSidePane.h',
8 'include/SqpApplication.h',
8 'include/SqpApplication.h',
9 'include/DragAndDrop/DragDropHelper.h',
9 'include/DragAndDrop/DragDropHelper.h',
10 'include/DragAndDrop/DragDropScroller.h',
10 'include/DragAndDrop/DragDropScroller.h',
11 'include/DragAndDrop/DragDropTabSwitcher.h',
11 'include/DragAndDrop/DragDropTabSwitcher.h',
12 'include/TimeWidget/TimeWidget.h',
12 'include/TimeWidget/TimeWidget.h',
13 'include/Variable/VariableInspectorWidget.h',
13 'include/Variable/VariableInspectorWidget.h',
14 'include/Variable/VariableInspectorTableView.h',
14 'include/Variable/VariableInspectorTableView.h',
15 'include/Variable/RenameVariableDialog.h',
15 'include/Variable/RenameVariableDialog.h',
16 'include/Visualization/qcustomplot.h',
16 'include/Visualization/qcustomplot.h',
17 'include/Visualization/VisualizationGraphWidget.h',
17 'include/Visualization/VisualizationGraphWidget.h',
18 'include/Visualization/VisualizationTabWidget.h',
18 'include/Visualization/VisualizationTabWidget.h',
19 'include/Visualization/VisualizationWidget.h',
19 'include/Visualization/VisualizationWidget.h',
20 'include/Visualization/VisualizationZoneWidget.h',
20 'include/Visualization/VisualizationZoneWidget.h',
21 'include/Visualization/VisualizationDragDropContainer.h',
21 'include/Visualization/VisualizationDragDropContainer.h',
22 'include/Visualization/VisualizationDragWidget.h'
22 'include/Visualization/VisualizationDragWidget.h'
23 ]
23 ]
24
24
25 gui_ui_files = [
25 gui_ui_files = [
26 'ui/DataSource/DataSourceWidget.ui',
26 'ui/DataSource/DataSourceWidget.ui',
27 'ui/Settings/SqpSettingsDialog.ui',
27 'ui/Settings/SqpSettingsDialog.ui',
28 'ui/Settings/SqpSettingsGeneralWidget.ui',
28 'ui/Settings/SqpSettingsGeneralWidget.ui',
29 'ui/SidePane/SqpSidePane.ui',
29 'ui/SidePane/SqpSidePane.ui',
30 'ui/TimeWidget/TimeWidget.ui',
30 'ui/TimeWidget/TimeWidget.ui',
31 'ui/Variable/VariableInspectorWidget.ui',
31 'ui/Variable/VariableInspectorWidget.ui',
32 'ui/Variable/RenameVariableDialog.ui',
32 'ui/Variable/RenameVariableDialog.ui',
33 'ui/Variable/VariableMenuHeaderWidget.ui',
33 'ui/Variable/VariableMenuHeaderWidget.ui',
34 'ui/Visualization/VisualizationGraphWidget.ui',
34 'ui/Visualization/VisualizationGraphWidget.ui',
35 'ui/Visualization/VisualizationTabWidget.ui',
35 'ui/Visualization/VisualizationTabWidget.ui',
36 'ui/Visualization/VisualizationWidget.ui',
36 'ui/Visualization/VisualizationWidget.ui',
37 'ui/Visualization/VisualizationZoneWidget.ui'
37 'ui/Visualization/VisualizationZoneWidget.ui'
38 ]
38 ]
39
39
40 gui_qresources = ['resources/sqpguiresources.qrc']
40 gui_qresources = ['resources/sqpguiresources.qrc']
41
41
42 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
42 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
43 ui_files : gui_ui_files,
43 ui_files : gui_ui_files,
44 qresources : gui_qresources)
44 qresources : gui_qresources)
45
45
46 gui_sources = [
46 gui_sources = [
47 'src/SqpApplication.cpp',
47 'src/SqpApplication.cpp',
48 'src/DragAndDrop/DragDropHelper.cpp',
48 'src/DragAndDrop/DragDropHelper.cpp',
49 'src/DragAndDrop/DragDropScroller.cpp',
49 'src/DragAndDrop/DragDropScroller.cpp',
50 'src/DragAndDrop/DragDropTabSwitcher.cpp',
50 'src/DragAndDrop/DragDropTabSwitcher.cpp',
51 'src/Common/ColorUtils.cpp',
51 'src/Common/ColorUtils.cpp',
52 'src/Common/VisualizationDef.cpp',
52 'src/Common/VisualizationDef.cpp',
53 'src/DataSource/DataSourceTreeWidgetItem.cpp',
53 'src/DataSource/DataSourceTreeWidgetItem.cpp',
54 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
54 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
55 'src/DataSource/DataSourceWidget.cpp',
55 'src/DataSource/DataSourceWidget.cpp',
56 'src/DataSource/DataSourceTreeWidget.cpp',
56 'src/DataSource/DataSourceTreeWidget.cpp',
57 'src/Settings/SqpSettingsDialog.cpp',
57 'src/Settings/SqpSettingsDialog.cpp',
58 'src/Settings/SqpSettingsGeneralWidget.cpp',
58 'src/Settings/SqpSettingsGeneralWidget.cpp',
59 'src/SidePane/SqpSidePane.cpp',
59 'src/SidePane/SqpSidePane.cpp',
60 'src/TimeWidget/TimeWidget.cpp',
60 'src/TimeWidget/TimeWidget.cpp',
61 'src/Variable/VariableInspectorWidget.cpp',
61 'src/Variable/VariableInspectorWidget.cpp',
62 'src/Variable/VariableInspectorTableView.cpp',
62 'src/Variable/VariableInspectorTableView.cpp',
63 'src/Variable/VariableMenuHeaderWidget.cpp',
63 'src/Variable/VariableMenuHeaderWidget.cpp',
64 'src/Variable/RenameVariableDialog.cpp',
64 'src/Variable/RenameVariableDialog.cpp',
65 'src/Visualization/VisualizationGraphHelper.cpp',
65 'src/Visualization/VisualizationGraphHelper.cpp',
66 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
66 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
67 'src/Visualization/VisualizationGraphWidget.cpp',
67 'src/Visualization/VisualizationGraphWidget.cpp',
68 'src/Visualization/VisualizationTabWidget.cpp',
68 'src/Visualization/VisualizationTabWidget.cpp',
69 'src/Visualization/VisualizationWidget.cpp',
69 'src/Visualization/VisualizationWidget.cpp',
70 'src/Visualization/VisualizationZoneWidget.cpp',
70 'src/Visualization/VisualizationZoneWidget.cpp',
71 'src/Visualization/qcustomplot.cpp',
71 'src/Visualization/qcustomplot.cpp',
72 'src/Visualization/QCustomPlotSynchronizer.cpp',
72 'src/Visualization/QCustomPlotSynchronizer.cpp',
73 'src/Visualization/operations/FindVariableOperation.cpp',
73 'src/Visualization/operations/FindVariableOperation.cpp',
74 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
74 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
75 'src/Visualization/operations/MenuBuilder.cpp',
75 'src/Visualization/operations/MenuBuilder.cpp',
76 'src/Visualization/operations/RemoveVariableOperation.cpp',
76 'src/Visualization/operations/RemoveVariableOperation.cpp',
77 'src/Visualization/operations/RescaleAxeOperation.cpp',
77 'src/Visualization/operations/RescaleAxeOperation.cpp',
78 'src/Visualization/VisualizationDragDropContainer.cpp',
78 'src/Visualization/VisualizationDragDropContainer.cpp',
79 'src/Visualization/VisualizationDragWidget.cpp'
79 'src/Visualization/VisualizationDragWidget.cpp'
80 'src/Visualization/AxisRenderingUtils.cpp',
81 'src/Visualization/PlottablesRenderingUtils.cpp'
80 ]
82 ]
81
83
82 gui_inc = include_directories(['include'])
84 gui_inc = include_directories(['include'])
83
85
84 sciqlop_gui_lib = library('sciqlopgui',
86 sciqlop_gui_lib = library('sciqlopgui',
85 gui_sources,
87 gui_sources,
86 gui_moc_files,
88 gui_moc_files,
87 include_directories : [gui_inc],
89 include_directories : [gui_inc],
88 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
90 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
89 install : true
91 install : true
90 )
92 )
91
93
92 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
94 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
93 include_directories : gui_inc,
95 include_directories : gui_inc,
94 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
96 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
95
97
@@ -1,342 +1,345
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Common/ColorUtils.h>
5
6 #include <Data/ScalarSeries.h>
4 #include <Data/ScalarSeries.h>
7 #include <Data/SpectrogramSeries.h>
5 #include <Data/SpectrogramSeries.h>
8 #include <Data/VectorSeries.h>
6 #include <Data/VectorSeries.h>
9
7
10 #include <Variable/Variable.h>
8 #include <Variable/Variable.h>
11
9
12 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
10 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
13
11
14 namespace {
12 namespace {
15
13
16 class SqpDataContainer : public QCPGraphDataContainer {
14 class SqpDataContainer : public QCPGraphDataContainer {
17 public:
15 public:
18 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
16 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
19 };
17 };
20
18
21 /**
19 /**
22 * Struct used to create plottables, depending on the type of the data series from which to create
20 * Struct used to create plottables, depending on the type of the data series from which to create
23 * them
21 * them
24 * @tparam T the data series' type
22 * @tparam T the data series' type
25 * @remarks Default implementation can't create plottables
23 * @remarks Default implementation can't create plottables
26 */
24 */
27 template <typename T, typename Enabled = void>
25 template <typename T, typename Enabled = void>
28 struct PlottablesCreator {
26 struct PlottablesCreator {
29 static PlottablesMap createPlottables(T &, QCustomPlot &)
27 static PlottablesMap createPlottables(T &, QCustomPlot &)
30 {
28 {
31 qCCritical(LOG_DataSeries())
29 qCCritical(LOG_DataSeries())
32 << QObject::tr("Can't create plottables: unmanaged data series type");
30 << QObject::tr("Can't create plottables: unmanaged data series type");
33 return {};
31 return {};
34 }
32 }
35 };
33 };
36
34
37 /**
35 /**
38 * Specialization of PlottablesCreator for scalars and vectors
36 * Specialization of PlottablesCreator for scalars and vectors
39 * @sa ScalarSeries
37 * @sa ScalarSeries
40 * @sa VectorSeries
38 * @sa VectorSeries
41 */
39 */
42 template <typename T>
40 template <typename T>
43 struct PlottablesCreator<T,
41 struct PlottablesCreator<T,
44 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
42 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
45 or std::is_base_of<VectorSeries, T>::value> > {
43 or std::is_base_of<VectorSeries, T>::value> > {
46 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
44 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
47 {
45 {
48 PlottablesMap result{};
46 PlottablesMap result{};
49
47
50 // Gets the number of components of the data series
48 // Gets the number of components of the data series
51 dataSeries.lockRead();
49 dataSeries.lockRead();
52 auto componentCount = dataSeries.valuesData()->componentCount();
50 auto componentCount = dataSeries.valuesData()->componentCount();
53 dataSeries.unlock();
51 dataSeries.unlock();
54
52
55 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
56
57 // For each component of the data series, creates a QCPGraph to add to the plot
53 // For each component of the data series, creates a QCPGraph to add to the plot
58 for (auto i = 0; i < componentCount; ++i) {
54 for (auto i = 0; i < componentCount; ++i) {
59 auto graph = plot.addGraph();
55 auto graph = plot.addGraph();
60 graph->setPen(QPen{colors.at(i)});
61
62 result.insert({i, graph});
56 result.insert({i, graph});
63 }
57 }
64
58
65 plot.replot();
59 plot.replot();
66
60
67 return result;
61 return result;
68 }
62 }
69 };
63 };
70
64
71 /**
65 /**
72 * Specialization of PlottablesCreator for spectrograms
66 * Specialization of PlottablesCreator for spectrograms
73 * @sa SpectrogramSeries
67 * @sa SpectrogramSeries
74 */
68 */
75 template <typename T>
69 template <typename T>
76 struct PlottablesCreator<T,
70 struct PlottablesCreator<T,
77 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
71 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
78 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
72 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
79 {
73 {
80 PlottablesMap result{};
74 PlottablesMap result{};
81 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
75 result.insert({0, new QCPColorMap{plot.xAxis, plot.yAxis}});
82
76
83 plot.replot();
77 plot.replot();
84
78
85 return result;
79 return result;
86 }
80 }
87 };
81 };
88
82
89 /**
83 /**
90 * Struct used to update plottables, depending on the type of the data series from which to update
84 * Struct used to update plottables, depending on the type of the data series from which to update
91 * them
85 * them
92 * @tparam T the data series' type
86 * @tparam T the data series' type
93 * @remarks Default implementation can't update plottables
87 * @remarks Default implementation can't update plottables
94 */
88 */
95 template <typename T, typename Enabled = void>
89 template <typename T, typename Enabled = void>
96 struct PlottablesUpdater {
90 struct PlottablesUpdater {
97 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
91 static void setPlotYAxisRange(T &, const SqpRange &, QCustomPlot &)
98 {
92 {
99 qCCritical(LOG_VisualizationGraphHelper())
93 qCCritical(LOG_VisualizationGraphHelper())
100 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
94 << QObject::tr("Can't set plot y-axis range: unmanaged data series type");
101 }
95 }
102
96
103 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
97 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
104 {
98 {
105 qCCritical(LOG_VisualizationGraphHelper())
99 qCCritical(LOG_VisualizationGraphHelper())
106 << QObject::tr("Can't update plottables: unmanaged data series type");
100 << QObject::tr("Can't update plottables: unmanaged data series type");
107 }
101 }
108 };
102 };
109
103
110 /**
104 /**
111 * Specialization of PlottablesUpdater for scalars and vectors
105 * Specialization of PlottablesUpdater for scalars and vectors
112 * @sa ScalarSeries
106 * @sa ScalarSeries
113 * @sa VectorSeries
107 * @sa VectorSeries
114 */
108 */
115 template <typename T>
109 template <typename T>
116 struct PlottablesUpdater<T,
110 struct PlottablesUpdater<T,
117 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
111 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
118 or std::is_base_of<VectorSeries, T>::value> > {
112 or std::is_base_of<VectorSeries, T>::value> > {
119 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
113 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
120 {
114 {
121 auto minValue = 0., maxValue = 0.;
115 auto minValue = 0., maxValue = 0.;
122
116
123 dataSeries.lockRead();
117 dataSeries.lockRead();
124 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
118 auto valuesBounds = dataSeries.valuesBounds(xAxisRange.m_TStart, xAxisRange.m_TEnd);
125 auto end = dataSeries.cend();
119 auto end = dataSeries.cend();
126 if (valuesBounds.first != end && valuesBounds.second != end) {
120 if (valuesBounds.first != end && valuesBounds.second != end) {
127 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
121 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
128
122
129 minValue = rangeValue(valuesBounds.first->minValue());
123 minValue = rangeValue(valuesBounds.first->minValue());
130 maxValue = rangeValue(valuesBounds.second->maxValue());
124 maxValue = rangeValue(valuesBounds.second->maxValue());
131 }
125 }
132 dataSeries.unlock();
126 dataSeries.unlock();
133
127
134 plot.yAxis->setRange(QCPRange{minValue, maxValue});
128 plot.yAxis->setRange(QCPRange{minValue, maxValue});
135 }
129 }
136
130
137 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
131 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
138 bool rescaleAxes)
132 bool rescaleAxes)
139 {
133 {
140
134
141 // For each plottable to update, resets its data
135 // For each plottable to update, resets its data
142 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
136 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
143 for (const auto &plottable : plottables) {
137 for (const auto &plottable : plottables) {
144 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
138 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
145 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
139 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
146 graph->setData(dataContainer);
140 graph->setData(dataContainer);
147
141
148 dataContainers.insert({plottable.first, dataContainer});
142 dataContainers.insert({plottable.first, dataContainer});
149 }
143 }
150 }
144 }
151 dataSeries.lockRead();
145 dataSeries.lockRead();
152
146
153 // - Gets the data of the series included in the current range
147 // - 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
148 // - 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
149 // 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);
150 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
157 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
151 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
158 for (const auto &dataContainer : dataContainers) {
152 for (const auto &dataContainer : dataContainers) {
159 auto componentIndex = dataContainer.first;
153 auto componentIndex = dataContainer.first;
160 dataContainer.second->appendGraphData(
154 dataContainer.second->appendGraphData(
161 QCPGraphData(it->x(), it->value(componentIndex)));
155 QCPGraphData(it->x(), it->value(componentIndex)));
162 }
156 }
163 }
157 }
164
158
165 dataSeries.unlock();
159 dataSeries.unlock();
166
160
167 if (!plottables.empty()) {
161 if (!plottables.empty()) {
168 auto plot = plottables.begin()->second->parentPlot();
162 auto plot = plottables.begin()->second->parentPlot();
169
163
170 if (rescaleAxes) {
164 if (rescaleAxes) {
171 plot->rescaleAxes();
165 plot->rescaleAxes();
172 }
166 }
173
167
174 plot->replot();
168 plot->replot();
175 }
169 }
176 }
170 }
177 };
171 };
178
172
179 /**
173 /**
180 * Specialization of PlottablesUpdater for spectrograms
174 * Specialization of PlottablesUpdater for spectrograms
181 * @sa SpectrogramSeries
175 * @sa SpectrogramSeries
182 */
176 */
183 template <typename T>
177 template <typename T>
184 struct PlottablesUpdater<T,
178 struct PlottablesUpdater<T,
185 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
179 typename std::enable_if_t<std::is_base_of<SpectrogramSeries, T>::value> > {
186 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
180 static void setPlotYAxisRange(T &dataSeries, const SqpRange &xAxisRange, QCustomPlot &plot)
187 {
181 {
188 double min, max;
182 double min, max;
189 /// @todo ALX: use iterators here
183 /// @todo ALX: use iterators here
190 std::tie(min, max) = dataSeries.yAxis().bounds();
184 std::tie(min, max) = dataSeries.yAxis().bounds();
191
185
192 if (!std::isnan(min) && !std::isnan(max)) {
186 if (!std::isnan(min) && !std::isnan(max)) {
193 plot.yAxis->setRange(QCPRange{min, max});
187 plot.yAxis->setRange(QCPRange{min, max});
194 }
188 }
195 }
189 }
196
190
197 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
191 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
198 bool rescaleAxes)
192 bool rescaleAxes)
199 {
193 {
200 if (plottables.empty()) {
194 if (plottables.empty()) {
201 qCDebug(LOG_VisualizationGraphHelper())
195 qCDebug(LOG_VisualizationGraphHelper())
202 << QObject::tr("Can't update spectrogram: no colormap has been associated");
196 << QObject::tr("Can't update spectrogram: no colormap has been associated");
203 return;
197 return;
204 }
198 }
205
199
206 // Gets the colormap to update (normally there is only one colormap)
200 // Gets the colormap to update (normally there is only one colormap)
207 Q_ASSERT(plottables.size() == 1);
201 Q_ASSERT(plottables.size() == 1);
208 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
202 auto colormap = dynamic_cast<QCPColorMap *>(plottables.at(0));
209 Q_ASSERT(colormap != nullptr);
203 Q_ASSERT(colormap != nullptr);
210
204
211 dataSeries.lockRead();
205 dataSeries.lockRead();
212
206
213 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
207 auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
214 /// @todo ALX: use iterators here
208 /// @todo ALX: use iterators here
215 auto yAxis = dataSeries.yAxis();
209 auto yAxis = dataSeries.yAxis();
216
210
217 // Gets properties of x-axis and y-axis to set size and range of the colormap
211 // Gets properties of x-axis and y-axis to set size and range of the colormap
218 auto nbX = std::distance(its.first, its.second);
212 auto nbX = std::distance(its.first, its.second);
219 auto xMin = nbX != 0 ? its.first->x() : 0.;
213 auto xMin = nbX != 0 ? its.first->x() : 0.;
220 auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.;
214 auto xMax = nbX != 0 ? (its.second - 1)->x() : 0.;
221
215
222 auto nbY = yAxis.size();
216 auto nbY = yAxis.size();
223 auto yMin = 0., yMax = 0.;
217 auto yMin = 0., yMax = 0.;
224 if (nbY != 0) {
218 if (nbY != 0) {
225 std::tie(yMin, yMax) = yAxis.bounds();
219 std::tie(yMin, yMax) = yAxis.bounds();
226 }
220 }
227
221
228 colormap->data()->setSize(nbX, nbY);
222 colormap->data()->setSize(nbX, nbY);
229 colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax});
223 colormap->data()->setRange(QCPRange{xMin, xMax}, QCPRange{yMin, yMax});
230
224
231 // Sets values
225 // Sets values
232 auto xIndex = 0;
226 auto xIndex = 0;
233 for (auto it = its.first; it != its.second; ++it, ++xIndex) {
227 for (auto it = its.first; it != its.second; ++it, ++xIndex) {
234 for (auto yIndex = 0; yIndex < nbY; ++yIndex) {
228 for (auto yIndex = 0; yIndex < nbY; ++yIndex) {
235 colormap->data()->setCell(xIndex, yIndex, it->value(yIndex));
229 auto value = it->value(yIndex);
230
231 colormap->data()->setCell(xIndex, yIndex, value);
232
233 // Processing spectrogram data for display in QCustomPlot
234 /// For the moment, we just make the NaN values to be transparent in the colormap
235 /// @todo ALX: complete treatments (mesh generation, etc.)
236 if (std::isnan(value)) {
237 colormap->data()->setAlpha(xIndex, yIndex, 0);
238 }
236 }
239 }
237 }
240 }
238
241
239 dataSeries.unlock();
242 dataSeries.unlock();
240
243
241 // Rescales axes
244 // Rescales axes
242 auto plot = colormap->parentPlot();
245 auto plot = colormap->parentPlot();
243
246
244 if (rescaleAxes) {
247 if (rescaleAxes) {
245 plot->rescaleAxes();
248 plot->rescaleAxes();
246 }
249 }
247
250
248 plot->replot();
251 plot->replot();
249 }
252 }
250 };
253 };
251
254
252 /**
255 /**
253 * Helper used to create/update plottables
256 * Helper used to create/update plottables
254 */
257 */
255 struct IPlottablesHelper {
258 struct IPlottablesHelper {
256 virtual ~IPlottablesHelper() noexcept = default;
259 virtual ~IPlottablesHelper() noexcept = default;
257 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
260 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
258 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
261 virtual void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const = 0;
259 virtual void update(PlottablesMap &plottables, const SqpRange &range,
262 virtual void update(PlottablesMap &plottables, const SqpRange &range,
260 bool rescaleAxes = false) const = 0;
263 bool rescaleAxes = false) const = 0;
261 };
264 };
262
265
263 /**
266 /**
264 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
267 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
265 * @tparam T the data series' type
268 * @tparam T the data series' type
266 */
269 */
267 template <typename T>
270 template <typename T>
268 struct PlottablesHelper : public IPlottablesHelper {
271 struct PlottablesHelper : public IPlottablesHelper {
269 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
272 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
270
273
271 PlottablesMap create(QCustomPlot &plot) const override
274 PlottablesMap create(QCustomPlot &plot) const override
272 {
275 {
273 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
276 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
274 }
277 }
275
278
276 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
279 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
277 {
280 {
278 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
281 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
279 }
282 }
280
283
281 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
284 void setYAxisRange(const SqpRange &xAxisRange, QCustomPlot &plot) const override
282 {
285 {
283 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
286 return PlottablesUpdater<T>::setPlotYAxisRange(m_DataSeries, xAxisRange, plot);
284 }
287 }
285
288
286 T &m_DataSeries;
289 T &m_DataSeries;
287 };
290 };
288
291
289 /// Creates IPlottablesHelper according to a data series
292 /// Creates IPlottablesHelper according to a data series
290 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
293 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
291 {
294 {
292 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
295 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
293 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
296 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
294 }
297 }
295 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
298 else if (auto spectrogramSeries = std::dynamic_pointer_cast<SpectrogramSeries>(dataSeries)) {
296 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
299 return std::make_unique<PlottablesHelper<SpectrogramSeries> >(*spectrogramSeries);
297 }
300 }
298 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
301 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
299 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
302 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
300 }
303 }
301 else {
304 else {
302 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
305 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
303 }
306 }
304 }
307 }
305
308
306 } // namespace
309 } // namespace
307
310
308 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
311 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
309 QCustomPlot &plot) noexcept
312 QCustomPlot &plot) noexcept
310 {
313 {
311 if (variable) {
314 if (variable) {
312 auto helper = createHelper(variable->dataSeries());
315 auto helper = createHelper(variable->dataSeries());
313 auto plottables = helper->create(plot);
316 auto plottables = helper->create(plot);
314 return plottables;
317 return plottables;
315 }
318 }
316 else {
319 else {
317 qCDebug(LOG_VisualizationGraphHelper())
320 qCDebug(LOG_VisualizationGraphHelper())
318 << QObject::tr("Can't create graph plottables : the variable is null");
321 << QObject::tr("Can't create graph plottables : the variable is null");
319 return PlottablesMap{};
322 return PlottablesMap{};
320 }
323 }
321 }
324 }
322
325
323 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
326 void VisualizationGraphHelper::setYAxisRange(std::shared_ptr<Variable> variable,
324 QCustomPlot &plot) noexcept
327 QCustomPlot &plot) noexcept
325 {
328 {
326 if (variable) {
329 if (variable) {
327 auto helper = createHelper(variable->dataSeries());
330 auto helper = createHelper(variable->dataSeries());
328 helper->setYAxisRange(variable->range(), plot);
331 helper->setYAxisRange(variable->range(), plot);
329 }
332 }
330 else {
333 else {
331 qCDebug(LOG_VisualizationGraphHelper())
334 qCDebug(LOG_VisualizationGraphHelper())
332 << QObject::tr("Can't set y-axis range of plot: the variable is null");
335 << QObject::tr("Can't set y-axis range of plot: the variable is null");
333 }
336 }
334 }
337 }
335
338
336 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
339 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
337 std::shared_ptr<IDataSeries> dataSeries,
340 std::shared_ptr<IDataSeries> dataSeries,
338 const SqpRange &dateTime)
341 const SqpRange &dateTime)
339 {
342 {
340 auto helper = createHelper(dataSeries);
343 auto helper = createHelper(dataSeries);
341 helper->update(plottables, dateTime);
344 helper->update(plottables, dateTime);
342 }
345 }
@@ -1,275 +1,245
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/AxisRenderingUtils.h"
3 #include "Visualization/PlottablesRenderingUtils.h"
2 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/qcustomplot.h"
5 #include "Visualization/qcustomplot.h"
4
6
5 #include <Common/DateUtils.h>
7 #include <Common/DateUtils.h>
6
8
7 #include <Data/IDataSeries.h>
9 #include <Data/IDataSeries.h>
8
10
9 #include <SqpApplication.h>
11 #include <SqpApplication.h>
10
12
11 namespace {
13 namespace {
12
14
13 /// Name of the axes layer in QCustomPlot
15 /// Name of the axes layer in QCustomPlot
14 const auto AXES_LAYER = QStringLiteral("axes");
16 const auto AXES_LAYER = QStringLiteral("axes");
15
17
16 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
17
18 /// Format for datetimes on a axis
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20
21 /// Icon used to show x-axis properties
18 /// Icon used to show x-axis properties
22 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
19 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
23
20
24 /// Name of the overlay layer in QCustomPlot
21 /// Name of the overlay layer in QCustomPlot
25 const auto OVERLAY_LAYER = QStringLiteral("overlay");
22 const auto OVERLAY_LAYER = QStringLiteral("overlay");
26
23
27 /// Pixmap used to show x-axis properties
24 /// Pixmap used to show x-axis properties
28 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
25 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
29
26
30 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
27 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
31
28
32 /// Offset used to shift the tooltip of the mouse
29 /// Offset used to shift the tooltip of the mouse
33 const auto TOOLTIP_OFFSET = QPoint{20, 20};
30 const auto TOOLTIP_OFFSET = QPoint{20, 20};
34
31
35 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
32 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
36 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
33 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
37
34
38 /// Timeout after which the tooltip is displayed
35 /// Timeout after which the tooltip is displayed
39 const auto TOOLTIP_TIMEOUT = 500;
36 const auto TOOLTIP_TIMEOUT = 500;
40
37
41 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
42 /// non-time data
43 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
44 {
45 if (isTimeAxis) {
46 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
47 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
48 dateTicker->setDateTimeSpec(Qt::UTC);
49
50 return dateTicker;
51 }
52 else {
53 // default ticker
54 return QSharedPointer<QCPAxisTicker>::create();
55 }
56 }
57
58 /// Formats a data value according to the axis on which it is present
59 QString formatValue(double value, const QCPAxis &axis)
60 {
61 // If the axis is a time axis, formats the value as a date
62 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
63 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
64 }
65 else {
66 return QString::number(value);
67 }
68 }
69
70 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
38 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
71 {
39 {
72 tracer.setInterpolating(false);
40 tracer.setInterpolating(false);
73 tracer.setStyle(QCPItemTracer::tsCircle);
41 tracer.setStyle(QCPItemTracer::tsCircle);
74 tracer.setSize(3);
42 tracer.setSize(3);
75 tracer.setPen(QPen(Qt::black));
43 tracer.setPen(QPen(Qt::black));
76 tracer.setBrush(Qt::black);
44 tracer.setBrush(Qt::black);
77 }
45 }
78
46
79 QPixmap pixmap(const QString &iconPath) noexcept
47 QPixmap pixmap(const QString &iconPath) noexcept
80 {
48 {
81 return QIcon{iconPath}.pixmap(QSize{16, 16});
49 return QIcon{iconPath}.pixmap(QSize{16, 16});
82 }
50 }
83
51
84 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
52 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
85 {
53 {
86 // Icon
54 // Icon
87 pixmap.setPixmap(
55 pixmap.setPixmap(
88 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
56 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
89
57
90 // Position
58 // Position
91 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
59 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
92 pixmap.topLeft->setCoords(1, 0);
60 pixmap.topLeft->setCoords(1, 0);
93 pixmap.setClipToAxisRect(false);
61 pixmap.setClipToAxisRect(false);
94
62
95 // Can be selected
63 // Can be selected
96 pixmap.setSelectable(true);
64 pixmap.setSelectable(true);
97 }
65 }
98
66
99 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
67 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
100 {
68 {
101 // Icon
69 // Icon
102 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
70 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
103
71
104 // Position
72 // Position
105 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
73 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
106 itemPixmap.topLeft->setCoords(0, 1);
74 itemPixmap.topLeft->setCoords(0, 1);
107 itemPixmap.setClipToAxisRect(false);
75 itemPixmap.setClipToAxisRect(false);
108
76
109 // Can be selected
77 // Can be selected
110 itemPixmap.setSelectable(true);
78 itemPixmap.setSelectable(true);
111 }
79 }
112
80
113 void initTitleTextStyle(QCPItemText &text) noexcept
81 void initTitleTextStyle(QCPItemText &text) noexcept
114 {
82 {
115 // Font and background styles
83 // Font and background styles
116 text.setColor(Qt::gray);
84 text.setColor(Qt::gray);
117 text.setBrush(Qt::white);
85 text.setBrush(Qt::white);
118
86
119 // Position
87 // Position
120 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
88 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
121 text.position->setType(QCPItemPosition::ptAxisRectRatio);
89 text.position->setType(QCPItemPosition::ptAxisRectRatio);
122 text.position->setCoords(0.5, 0);
90 text.position->setCoords(0.5, 0);
123 }
91 }
124
92
125 } // namespace
93 } // namespace
126
94
127 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
95 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
128 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
96 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
129 : m_Plot{graphWidget.plot()},
97 : m_Plot{graphWidget.plot()},
130 m_PointTracer{new QCPItemTracer{&m_Plot}},
98 m_PointTracer{new QCPItemTracer{&m_Plot}},
131 m_TracerTimer{},
99 m_TracerTimer{},
132 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
100 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
133 m_TitleText{new QCPItemText{&m_Plot}},
101 m_TitleText{new QCPItemText{&m_Plot}},
134 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
102 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
135 m_ShowXAxis{true},
103 m_ShowXAxis{true},
136 m_XAxisLabel{}
104 m_XAxisLabel{},
105 m_ColorScale{new QCPColorScale{&m_Plot}}
137 {
106 {
138 initPointTracerStyle(*m_PointTracer);
107 initPointTracerStyle(*m_PointTracer);
139
108
140 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
109 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
141 m_TracerTimer.setSingleShot(true);
110 m_TracerTimer.setSingleShot(true);
142
111
143 // Inits "close button" in plot overlay
112 // Inits "close button" in plot overlay
144 m_ClosePixmap->setLayer(OVERLAY_LAYER);
113 m_ClosePixmap->setLayer(OVERLAY_LAYER);
145 initClosePixmapStyle(*m_ClosePixmap);
114 initClosePixmapStyle(*m_ClosePixmap);
146
115
147 // Connects pixmap selection to graph widget closing
116 // Connects pixmap selection to graph widget closing
148 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
117 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
149 [&graphWidget](bool selected) {
118 [&graphWidget](bool selected) {
150 if (selected) {
119 if (selected) {
151 graphWidget.close();
120 graphWidget.close();
152 }
121 }
153 });
122 });
154
123
155 // Inits graph name in plot overlay
124 // Inits graph name in plot overlay
156 m_TitleText->setLayer(OVERLAY_LAYER);
125 m_TitleText->setLayer(OVERLAY_LAYER);
157 m_TitleText->setText(graphWidget.name());
126 m_TitleText->setText(graphWidget.name());
158 initTitleTextStyle(*m_TitleText);
127 initTitleTextStyle(*m_TitleText);
159
128
160 // Inits "show x-axis button" in plot overlay
129 // Inits "show x-axis button" in plot overlay
161 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
130 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
162 initXAxisPixmapStyle(*m_XAxisPixmap);
131 initXAxisPixmapStyle(*m_XAxisPixmap);
163
132
164 // Connects pixmap selection to graph x-axis showing/hiding
133 // Connects pixmap selection to graph x-axis showing/hiding
165 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
134 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
166 if (m_XAxisPixmap->selected()) {
135 if (m_XAxisPixmap->selected()) {
167 // Changes the selection state and refreshes the x-axis
136 // Changes the selection state and refreshes the x-axis
168 m_ShowXAxis = !m_ShowXAxis;
137 m_ShowXAxis = !m_ShowXAxis;
169 updateXAxisState();
138 updateXAxisState();
170 m_Plot.layer(AXES_LAYER)->replot();
139 m_Plot.layer(AXES_LAYER)->replot();
171
140
172 // Deselects the x-axis pixmap and updates icon
141 // Deselects the x-axis pixmap and updates icon
173 m_XAxisPixmap->setSelected(false);
142 m_XAxisPixmap->setSelected(false);
174 m_XAxisPixmap->setPixmap(
143 m_XAxisPixmap->setPixmap(
175 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
144 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
176 m_Plot.layer(OVERLAY_LAYER)->replot();
145 m_Plot.layer(OVERLAY_LAYER)->replot();
177 }
146 }
178 });
147 });
179 }
148 }
180
149
181 /// Updates state of x-axis according to the current selection of x-axis pixmap
150 /// Updates state of x-axis according to the current selection of x-axis pixmap
182 /// @remarks the method doesn't call plot refresh
151 /// @remarks the method doesn't call plot refresh
183 void updateXAxisState() noexcept
152 void updateXAxisState() noexcept
184 {
153 {
185 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
154 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
186 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
155 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
187 }
156 }
188
157
189 QCustomPlot &m_Plot;
158 QCustomPlot &m_Plot;
190 QCPItemTracer *m_PointTracer;
159 QCPItemTracer *m_PointTracer;
191 QTimer m_TracerTimer;
160 QTimer m_TracerTimer;
192 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
161 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
193 QCPItemText *m_TitleText; /// Graph's title
162 QCPItemText *m_TitleText; /// Graph's title
194 QCPItemPixmap *m_XAxisPixmap;
163 QCPItemPixmap *m_XAxisPixmap;
195 bool m_ShowXAxis; /// X-axis properties are shown or hidden
164 bool m_ShowXAxis; /// X-axis properties are shown or hidden
196 QString m_XAxisLabel;
165 QString m_XAxisLabel;
166 QCPColorScale *m_ColorScale; /// Color scale used for some types of graphs (as spectrograms)
197 };
167 };
198
168
199 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
169 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
200 VisualizationGraphWidget &graphWidget)
170 VisualizationGraphWidget &graphWidget)
201 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
171 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
202 {
172 {
203 }
173 }
204
174
205 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
175 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
206 {
176 {
207 // Cancels pending refresh
177 // Cancels pending refresh
208 impl->m_TracerTimer.disconnect();
178 impl->m_TracerTimer.disconnect();
209
179
210 // Reinits tracers
180 // Reinits tracers
211 impl->m_PointTracer->setGraph(nullptr);
181 impl->m_PointTracer->setGraph(nullptr);
212 impl->m_PointTracer->setVisible(false);
182 impl->m_PointTracer->setVisible(false);
213 impl->m_Plot.replot();
183 impl->m_Plot.replot();
214
184
215 // Gets the graph under the mouse position
185 // Gets the graph under the mouse position
216 auto eventPos = event->pos();
186 auto eventPos = event->pos();
217 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
187 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
218 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
188 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
219 auto graphData = graph->data();
189 auto graphData = graph->data();
220
190
221 // Gets the closest data point to the mouse
191 // Gets the closest data point to the mouse
222 auto graphDataIt = graphData->findBegin(mouseKey);
192 auto graphDataIt = graphData->findBegin(mouseKey);
223 if (graphDataIt != graphData->constEnd()) {
193 if (graphDataIt != graphData->constEnd()) {
224 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
194 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
225 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
195 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
226
196
227 // Displays point tracer
197 // Displays point tracer
228 impl->m_PointTracer->setGraph(graph);
198 impl->m_PointTracer->setGraph(graph);
229 impl->m_PointTracer->setGraphKey(graphDataIt->key);
199 impl->m_PointTracer->setGraphKey(graphDataIt->key);
230 impl->m_PointTracer->setLayer(
200 impl->m_PointTracer->setLayer(
231 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
201 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
232 impl->m_PointTracer->setVisible(true);
202 impl->m_PointTracer->setVisible(true);
233 impl->m_Plot.replot();
203 impl->m_Plot.replot();
234
204
235 // Starts timer to show tooltip after timeout
205 // Starts timer to show tooltip after timeout
236 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
206 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
237 {
207 {
238 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
208 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
239 &impl->m_Plot, TOOLTIP_RECT);
209 &impl->m_Plot, TOOLTIP_RECT);
240 };
210 };
241
211
242 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
212 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
243 impl->m_TracerTimer.start();
213 impl->m_TracerTimer.start();
244 }
214 }
245 }
215 }
246 }
216 }
247
217
248 void VisualizationGraphRenderingDelegate::setAxesProperties(const Unit &xAxisUnit,
218 void VisualizationGraphRenderingDelegate::setAxesProperties(
249 const Unit &valuesUnit) noexcept
219 std::shared_ptr<IDataSeries> dataSeries) noexcept
250 {
220 {
251 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
221 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
252 impl->m_XAxisLabel = xAxisUnit.m_Name;
222 impl->m_XAxisLabel = dataSeries->xAxisUnit().m_Name;
253
223
254 auto setAxisProperties = [](auto axis, const auto &unit) {
224 auto axisHelper = IAxisHelperFactory::create(dataSeries);
255 // label (unit name)
225 axisHelper->setProperties(impl->m_Plot, *impl->m_ColorScale);
256 axis->setLabel(unit.m_Name);
257
258 // ticker (depending on the type of unit)
259 axis->setTicker(axisTicker(unit.m_TimeUnit));
260 };
261 setAxisProperties(impl->m_Plot.xAxis, xAxisUnit);
262 setAxisProperties(impl->m_Plot.yAxis, valuesUnit);
263
226
264 // Updates x-axis state
227 // Updates x-axis state
265 impl->updateXAxisState();
228 impl->updateXAxisState();
266
229
267 impl->m_Plot.layer(AXES_LAYER)->replot();
230 impl->m_Plot.layer(AXES_LAYER)->replot();
268 }
231 }
269
232
233 void VisualizationGraphRenderingDelegate::setPlottablesProperties(
234 std::shared_ptr<IDataSeries> dataSeries, PlottablesMap &plottables) noexcept
235 {
236 auto plottablesHelper = IPlottablesHelperFactory::create(dataSeries);
237 plottablesHelper->setProperties(plottables);
238 }
239
270 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
240 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
271 {
241 {
272 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
242 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
273 overlay->setVisible(show);
243 overlay->setVisible(show);
274 overlay->replot();
244 overlay->replot();
275 }
245 }
@@ -1,405 +1,402
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 /// Delegate used to attach rendering features to the plot
48 /// Delegate used to attach rendering features to the plot
49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
49 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
50 };
50 };
51
51
52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
52 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
53 : VisualizationDragWidget{parent},
53 : VisualizationDragWidget{parent},
54 ui{new Ui::VisualizationGraphWidget},
54 ui{new Ui::VisualizationGraphWidget},
55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
55 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
56 {
56 {
57 ui->setupUi(this);
57 ui->setupUi(this);
58
58
59 // 'Close' options : widget is deleted when closed
59 // 'Close' options : widget is deleted when closed
60 setAttribute(Qt::WA_DeleteOnClose);
60 setAttribute(Qt::WA_DeleteOnClose);
61
61
62 // Set qcpplot properties :
62 // Set qcpplot properties :
63 // - Drag (on x-axis) and zoom are enabled
63 // - Drag (on x-axis) and zoom are enabled
64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
67
67
68 // 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
69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
69 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
70
70
71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
71 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
72 connect(ui->widget, &QCustomPlot::mouseRelease, this,
73 &VisualizationGraphWidget::onMouseRelease);
73 &VisualizationGraphWidget::onMouseRelease);
74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
74 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
75 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
76 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 &)>(
77 &QCPAxis::rangeChanged),
77 &QCPAxis::rangeChanged),
78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
78 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
79
79
80 // Activates menu when right clicking on the graph
80 // Activates menu when right clicking on the graph
81 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
81 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
82 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
82 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
83 &VisualizationGraphWidget::onGraphMenuRequested);
83 &VisualizationGraphWidget::onGraphMenuRequested);
84
84
85 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
85 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
86 &VariableController::onRequestDataLoading);
86 &VariableController::onRequestDataLoading);
87
87
88 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
88 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
89 &VisualizationGraphWidget::onUpdateVarDisplaying);
89 &VisualizationGraphWidget::onUpdateVarDisplaying);
90 }
90 }
91
91
92
92
93 VisualizationGraphWidget::~VisualizationGraphWidget()
93 VisualizationGraphWidget::~VisualizationGraphWidget()
94 {
94 {
95 delete ui;
95 delete ui;
96 }
96 }
97
97
98 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
98 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
99 {
99 {
100 auto parent = parentWidget();
100 auto parent = parentWidget();
101 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
101 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
102 parent = parent->parentWidget();
102 parent = parent->parentWidget();
103 }
103 }
104
104
105 return qobject_cast<VisualizationZoneWidget *>(parent);
105 return qobject_cast<VisualizationZoneWidget *>(parent);
106 }
106 }
107
107
108 void VisualizationGraphWidget::enableAcquisition(bool enable)
108 void VisualizationGraphWidget::enableAcquisition(bool enable)
109 {
109 {
110 impl->m_DoAcquisition = enable;
110 impl->m_DoAcquisition = enable;
111 }
111 }
112
112
113 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
113 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
114 {
114 {
115 // Uses delegate to create the qcpplot components according to the variable
115 // Uses delegate to create the qcpplot components according to the variable
116 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
116 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
117 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
118
119 // Set axes properties according to the units of the data series
120 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
121 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
122 auto xAxisUnit = Unit{};
123 auto valuesUnit = Unit{};
124
117
125 if (auto dataSeries = variable->dataSeries()) {
118 if (auto dataSeries = variable->dataSeries()) {
126 dataSeries->lockRead();
119 // Set axes properties according to the units of the data series
127 xAxisUnit = dataSeries->xAxisUnit();
120 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
128 valuesUnit = dataSeries->valuesUnit();
121
129 dataSeries->unlock();
122 // Sets rendering properties for the new plottables
123 // Warning: this method must be called after setAxesProperties(), as it can access to some
124 // axes properties that have to be initialized
125 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
130 }
126 }
131 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
127
128 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
132
129
133 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
130 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
134
131
135 this->enableAcquisition(false);
132 this->enableAcquisition(false);
136 this->setGraphRange(range);
133 this->setGraphRange(range);
137 this->enableAcquisition(true);
134 this->enableAcquisition(true);
138
135
139 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
136 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
140
137
141 emit variableAdded(variable);
138 emit variableAdded(variable);
142 }
139 }
143
140
144 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
141 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
145 {
142 {
146 // Each component associated to the variable :
143 // Each component associated to the variable :
147 // - is removed from qcpplot (which deletes it)
144 // - is removed from qcpplot (which deletes it)
148 // - is no longer referenced in the map
145 // - is no longer referenced in the map
149 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
146 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
150 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
147 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
151 emit variableAboutToBeRemoved(variable);
148 emit variableAboutToBeRemoved(variable);
152
149
153 auto &plottablesMap = variableIt->second;
150 auto &plottablesMap = variableIt->second;
154
151
155 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
152 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
156 plottableIt != plottableEnd;) {
153 plottableIt != plottableEnd;) {
157 ui->widget->removePlottable(plottableIt->second);
154 ui->widget->removePlottable(plottableIt->second);
158 plottableIt = plottablesMap.erase(plottableIt);
155 plottableIt = plottablesMap.erase(plottableIt);
159 }
156 }
160
157
161 impl->m_VariableToPlotMultiMap.erase(variableIt);
158 impl->m_VariableToPlotMultiMap.erase(variableIt);
162 }
159 }
163
160
164 // Updates graph
161 // Updates graph
165 ui->widget->replot();
162 ui->widget->replot();
166 }
163 }
167
164
168 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
165 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
169 {
166 {
170 auto variables = QList<std::shared_ptr<Variable> >{};
167 auto variables = QList<std::shared_ptr<Variable> >{};
171 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
168 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
172 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
169 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
173 variables << it->first;
170 variables << it->first;
174 }
171 }
175
172
176 return variables;
173 return variables;
177 }
174 }
178
175
179 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
176 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
180 {
177 {
181 if (!variable) {
178 if (!variable) {
182 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
179 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
183 return;
180 return;
184 }
181 }
185
182
186 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
183 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
187 }
184 }
188
185
189 SqpRange VisualizationGraphWidget::graphRange() const noexcept
186 SqpRange VisualizationGraphWidget::graphRange() const noexcept
190 {
187 {
191 auto graphRange = ui->widget->xAxis->range();
188 auto graphRange = ui->widget->xAxis->range();
192 return SqpRange{graphRange.lower, graphRange.upper};
189 return SqpRange{graphRange.lower, graphRange.upper};
193 }
190 }
194
191
195 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
192 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
196 {
193 {
197 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
194 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
198 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
195 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
199 ui->widget->replot();
196 ui->widget->replot();
200 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
197 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
201 }
198 }
202
199
203 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
200 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
204 {
201 {
205 if (visitor) {
202 if (visitor) {
206 visitor->visit(this);
203 visitor->visit(this);
207 }
204 }
208 else {
205 else {
209 qCCritical(LOG_VisualizationGraphWidget())
206 qCCritical(LOG_VisualizationGraphWidget())
210 << tr("Can't visit widget : the visitor is null");
207 << tr("Can't visit widget : the visitor is null");
211 }
208 }
212 }
209 }
213
210
214 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
211 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
215 {
212 {
216 /// @todo : for the moment, a graph can always accomodate a variable
213 /// @todo : for the moment, a graph can always accomodate a variable
217 Q_UNUSED(variable);
214 Q_UNUSED(variable);
218 return true;
215 return true;
219 }
216 }
220
217
221 bool VisualizationGraphWidget::contains(const Variable &variable) const
218 bool VisualizationGraphWidget::contains(const Variable &variable) const
222 {
219 {
223 // Finds the variable among the keys of the map
220 // Finds the variable among the keys of the map
224 auto variablePtr = &variable;
221 auto variablePtr = &variable;
225 auto findVariable
222 auto findVariable
226 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
223 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
227
224
228 auto end = impl->m_VariableToPlotMultiMap.cend();
225 auto end = impl->m_VariableToPlotMultiMap.cend();
229 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
226 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
230 return it != end;
227 return it != end;
231 }
228 }
232
229
233 QString VisualizationGraphWidget::name() const
230 QString VisualizationGraphWidget::name() const
234 {
231 {
235 return impl->m_Name;
232 return impl->m_Name;
236 }
233 }
237
234
238 QMimeData *VisualizationGraphWidget::mimeData() const
235 QMimeData *VisualizationGraphWidget::mimeData() const
239 {
236 {
240 auto mimeData = new QMimeData;
237 auto mimeData = new QMimeData;
241 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
238 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
242
239
243 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
240 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
244 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
241 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
245
242
246 return mimeData;
243 return mimeData;
247 }
244 }
248
245
249 bool VisualizationGraphWidget::isDragAllowed() const
246 bool VisualizationGraphWidget::isDragAllowed() const
250 {
247 {
251 return true;
248 return true;
252 }
249 }
253
250
254 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
251 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
255 {
252 {
256 if (highlighted) {
253 if (highlighted) {
257 plot().setBackground(QBrush(QColor("#BBD5EE")));
254 plot().setBackground(QBrush(QColor("#BBD5EE")));
258 }
255 }
259 else {
256 else {
260 plot().setBackground(QBrush(Qt::white));
257 plot().setBackground(QBrush(Qt::white));
261 }
258 }
262
259
263 plot().update();
260 plot().update();
264 }
261 }
265
262
266 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
263 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
267 {
264 {
268 Q_UNUSED(event);
265 Q_UNUSED(event);
269
266
270 // Prevents that all variables will be removed from graph when it will be closed
267 // Prevents that all variables will be removed from graph when it will be closed
271 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
268 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
272 emit variableAboutToBeRemoved(variableEntry.first);
269 emit variableAboutToBeRemoved(variableEntry.first);
273 }
270 }
274 }
271 }
275
272
276 void VisualizationGraphWidget::enterEvent(QEvent *event)
273 void VisualizationGraphWidget::enterEvent(QEvent *event)
277 {
274 {
278 Q_UNUSED(event);
275 Q_UNUSED(event);
279 impl->m_RenderingDelegate->showGraphOverlay(true);
276 impl->m_RenderingDelegate->showGraphOverlay(true);
280 }
277 }
281
278
282 void VisualizationGraphWidget::leaveEvent(QEvent *event)
279 void VisualizationGraphWidget::leaveEvent(QEvent *event)
283 {
280 {
284 Q_UNUSED(event);
281 Q_UNUSED(event);
285 impl->m_RenderingDelegate->showGraphOverlay(false);
282 impl->m_RenderingDelegate->showGraphOverlay(false);
286 }
283 }
287
284
288 QCustomPlot &VisualizationGraphWidget::plot() noexcept
285 QCustomPlot &VisualizationGraphWidget::plot() noexcept
289 {
286 {
290 return *ui->widget;
287 return *ui->widget;
291 }
288 }
292
289
293 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
290 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
294 {
291 {
295 QMenu graphMenu{};
292 QMenu graphMenu{};
296
293
297 // Iterates on variables (unique keys)
294 // Iterates on variables (unique keys)
298 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
295 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
299 end = impl->m_VariableToPlotMultiMap.cend();
296 end = impl->m_VariableToPlotMultiMap.cend();
300 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
297 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
301 // 'Remove variable' action
298 // 'Remove variable' action
302 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
299 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
303 [ this, var = it->first ]() { removeVariable(var); });
300 [ this, var = it->first ]() { removeVariable(var); });
304 }
301 }
305
302
306 if (!graphMenu.isEmpty()) {
303 if (!graphMenu.isEmpty()) {
307 graphMenu.exec(QCursor::pos());
304 graphMenu.exec(QCursor::pos());
308 }
305 }
309 }
306 }
310
307
311 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
308 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
312 {
309 {
313 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
310 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
314 << QThread::currentThread()->objectName() << "DoAcqui"
311 << QThread::currentThread()->objectName() << "DoAcqui"
315 << impl->m_DoAcquisition;
312 << impl->m_DoAcquisition;
316
313
317 auto graphRange = SqpRange{t1.lower, t1.upper};
314 auto graphRange = SqpRange{t1.lower, t1.upper};
318 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
315 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
319
316
320 if (impl->m_DoAcquisition) {
317 if (impl->m_DoAcquisition) {
321 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
318 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
322
319
323 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
320 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
324 end = impl->m_VariableToPlotMultiMap.end();
321 end = impl->m_VariableToPlotMultiMap.end();
325 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
322 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
326 variableUnderGraphVector.push_back(it->first);
323 variableUnderGraphVector.push_back(it->first);
327 }
324 }
328 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
325 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
329 !impl->m_IsCalibration);
326 !impl->m_IsCalibration);
330
327
331 if (!impl->m_IsCalibration) {
328 if (!impl->m_IsCalibration) {
332 qCDebug(LOG_VisualizationGraphWidget())
329 qCDebug(LOG_VisualizationGraphWidget())
333 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
330 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
334 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
331 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
335 emit synchronize(graphRange, oldGraphRange);
332 emit synchronize(graphRange, oldGraphRange);
336 }
333 }
337 }
334 }
338 }
335 }
339
336
340 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
337 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
341 {
338 {
342 // Handles plot rendering when mouse is moving
339 // Handles plot rendering when mouse is moving
343 impl->m_RenderingDelegate->onMouseMove(event);
340 impl->m_RenderingDelegate->onMouseMove(event);
344
341
345 VisualizationDragWidget::mouseMoveEvent(event);
342 VisualizationDragWidget::mouseMoveEvent(event);
346 }
343 }
347
344
348 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
345 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
349 {
346 {
350 auto zoomOrientations = QFlags<Qt::Orientation>{};
347 auto zoomOrientations = QFlags<Qt::Orientation>{};
351
348
352 // Lambda that enables a zoom orientation if the key modifier related to this orientation
349 // Lambda that enables a zoom orientation if the key modifier related to this orientation
353 // has
350 // has
354 // been pressed
351 // been pressed
355 auto enableOrientation
352 auto enableOrientation
356 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
353 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
357 auto orientationEnabled = event->modifiers().testFlag(modifier);
354 auto orientationEnabled = event->modifiers().testFlag(modifier);
358 zoomOrientations.setFlag(orientation, orientationEnabled);
355 zoomOrientations.setFlag(orientation, orientationEnabled);
359 };
356 };
360 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
357 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
361 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
358 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
362
359
363 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
360 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
364 }
361 }
365
362
366 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
363 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
367 {
364 {
368 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
365 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
369
366
370 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
367 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
371
368
372 VisualizationDragWidget::mousePressEvent(event);
369 VisualizationDragWidget::mousePressEvent(event);
373 }
370 }
374
371
375 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
372 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
376 {
373 {
377 impl->m_IsCalibration = false;
374 impl->m_IsCalibration = false;
378 }
375 }
379
376
380 void VisualizationGraphWidget::onDataCacheVariableUpdated()
377 void VisualizationGraphWidget::onDataCacheVariableUpdated()
381 {
378 {
382 auto graphRange = ui->widget->xAxis->range();
379 auto graphRange = ui->widget->xAxis->range();
383 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
380 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
384
381
385 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
382 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
386 auto variable = variableEntry.first;
383 auto variable = variableEntry.first;
387 qCDebug(LOG_VisualizationGraphWidget())
384 qCDebug(LOG_VisualizationGraphWidget())
388 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
385 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
389 qCDebug(LOG_VisualizationGraphWidget())
386 qCDebug(LOG_VisualizationGraphWidget())
390 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
387 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
391 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
388 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
392 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
389 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
393 variable->range());
390 variable->range());
394 }
391 }
395 }
392 }
396 }
393 }
397
394
398 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
395 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
399 const SqpRange &range)
396 const SqpRange &range)
400 {
397 {
401 auto it = impl->m_VariableToPlotMultiMap.find(variable);
398 auto it = impl->m_VariableToPlotMultiMap.find(variable);
402 if (it != impl->m_VariableToPlotMultiMap.end()) {
399 if (it != impl->m_VariableToPlotMultiMap.end()) {
403 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
400 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
404 }
401 }
405 }
402 }
@@ -1,274 +1,291
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <cmath>
9 #include <cmath>
10 #include <set>
10
11
11 #include <QFuture>
12 #include <QFuture>
12 #include <QThread>
13 #include <QThread>
13 #include <QtConcurrent/QtConcurrent>
14 #include <QtConcurrent/QtConcurrent>
14
15
15 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
16 Q_LOGGING_CATEGORY(LOG_CosinusProvider, "CosinusProvider")
16
17
17 namespace {
18 namespace {
18
19
19 /// Number of bands generated for a spectrogram
20 /// Number of bands generated for a spectrogram
20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21
22
23 /// Bands for which to generate NaN values for a spectrogram
24 const auto SPECTROGRAM_NAN_BANDS = std::set<int>{1, 3, 10, 20};
25
26 /// Bands for which to generate zeros for a spectrogram
27 const auto SPECTROGRAM_ZERO_BANDS = std::set<int>{2, 15, 19, 29};
28
22 /// Abstract cosinus type
29 /// Abstract cosinus type
23 struct ICosinusType {
30 struct ICosinusType {
24 virtual ~ICosinusType() = default;
31 virtual ~ICosinusType() = default;
25 /// @return the number of components generated for the type
32 /// @return the number of components generated for the type
26 virtual int componentCount() const = 0;
33 virtual int componentCount() const = 0;
27 /// @return the data series created for the type
34 /// @return the data series created for the type
28 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
35 virtual std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
29 std::vector<double> valuesData,
36 std::vector<double> valuesData) const = 0;
30 Unit xAxisUnit,
31 Unit valuesUnit) const = 0;
32 /// Generates values (one value per component)
37 /// Generates values (one value per component)
33 /// @param x the x-axis data used to generate values
38 /// @param x the x-axis data used to generate values
34 /// @param values the vector in which to insert the generated values
39 /// @param values the vector in which to insert the generated values
35 /// @param dataIndex the index of insertion of the generated values
40 /// @param dataIndex the index of insertion of the generated values
36 ///
41 ///
37 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
42 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
38 };
43 };
39
44
40 struct ScalarCosinus : public ICosinusType {
45 struct ScalarCosinus : public ICosinusType {
41 int componentCount() const override { return 1; }
46 int componentCount() const override { return 1; }
42
47
43 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
48 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
44 std::vector<double> valuesData, Unit xAxisUnit,
49 std::vector<double> valuesData) const override
45 Unit valuesUnit) const override
46 {
50 {
47 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
51 return std::make_shared<ScalarSeries>(std::move(xAxisData), std::move(valuesData),
48 xAxisUnit, valuesUnit);
52 Unit{QStringLiteral("t"), true}, Unit{});
49 }
53 }
50
54
51 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
55 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
52 {
56 {
53 values[dataIndex] = std::cos(x);
57 values[dataIndex] = std::cos(x);
54 }
58 }
55 };
59 };
56
60
57 struct SpectrogramCosinus : public ICosinusType {
61 struct SpectrogramCosinus : public ICosinusType {
58 /// Ctor with y-axis
62 /// Ctor with y-axis
59 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit)
63 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit, Unit valuesUnit)
60 : m_YAxisData{std::move(yAxisData)}, m_YAxisUnit{std::move(yAxisUnit)}
64 : m_YAxisData{std::move(yAxisData)},
65 m_YAxisUnit{std::move(yAxisUnit)},
66 m_ValuesUnit{std::move(valuesUnit)}
61 {
67 {
62 }
68 }
63
69
64 int componentCount() const override { return m_YAxisData.size(); }
70 int componentCount() const override { return m_YAxisData.size(); }
65
71
66 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
72 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
67 std::vector<double> valuesData, Unit xAxisUnit,
73 std::vector<double> valuesData) const override
68 Unit valuesUnit) const override
69 {
74 {
70 return std::make_shared<SpectrogramSeries>(std::move(xAxisData), m_YAxisData,
75 return std::make_shared<SpectrogramSeries>(
71 std::move(valuesData), xAxisUnit, m_YAxisUnit,
76 std::move(xAxisData), m_YAxisData, std::move(valuesData),
72 valuesUnit);
77 Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit);
73 }
78 }
74
79
75 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
80 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
76 {
81 {
77 auto componentCount = this->componentCount();
82 auto componentCount = this->componentCount();
78 for (int i = 0; i < componentCount; ++i) {
83 for (int i = 0; i < componentCount; ++i) {
79 auto y = m_YAxisData[i];
84 auto y = m_YAxisData[i];
80 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
85
81 auto value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
86 double value;
87
88 if (SPECTROGRAM_ZERO_BANDS.find(y) != SPECTROGRAM_ZERO_BANDS.end()) {
89 value = 0.;
90 }
91 else if (SPECTROGRAM_NAN_BANDS.find(y) != SPECTROGRAM_NAN_BANDS.end()) {
92 value = std::numeric_limits<double>::quiet_NaN();
93 }
94 else {
95 // Generates value for non NaN/zero bands
96 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
97 value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
98 }
82
99
83 values[componentCount * dataIndex + i] = value;
100 values[componentCount * dataIndex + i] = value;
84 }
101 }
85 }
102 }
86
103
87 std::vector<double> m_YAxisData;
104 std::vector<double> m_YAxisData;
88 Unit m_YAxisUnit;
105 Unit m_YAxisUnit;
106 Unit m_ValuesUnit;
89 };
107 };
90
108
91 struct VectorCosinus : public ICosinusType {
109 struct VectorCosinus : public ICosinusType {
92 int componentCount() const override { return 3; }
110 int componentCount() const override { return 3; }
93
111
94 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
112 std::shared_ptr<IDataSeries> createDataSeries(std::vector<double> xAxisData,
95 std::vector<double> valuesData, Unit xAxisUnit,
113 std::vector<double> valuesData) const override
96 Unit valuesUnit) const override
97 {
114 {
98 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
115 return std::make_shared<VectorSeries>(std::move(xAxisData), std::move(valuesData),
99 xAxisUnit, valuesUnit);
116 Unit{QStringLiteral("t"), true}, Unit{});
100 }
117 }
101
118
102 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
119 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
103 {
120 {
104 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
121 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
105 auto xValue = std::cos(x);
122 auto xValue = std::cos(x);
106 auto componentCount = this->componentCount();
123 auto componentCount = this->componentCount();
107 for (auto i = 0; i < componentCount; ++i) {
124 for (auto i = 0; i < componentCount; ++i) {
108 values[componentCount * dataIndex + i] = xValue / (i + 1);
125 values[componentCount * dataIndex + i] = xValue / (i + 1);
109 }
126 }
110 }
127 }
111 };
128 };
112
129
113 /// Converts string to cosinus type
130 /// Converts string to cosinus type
114 /// @return the cosinus type if the string could be converted, nullptr otherwise
131 /// @return the cosinus type if the string could be converted, nullptr otherwise
115 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
132 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
116 {
133 {
117 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
134 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
118 return std::make_unique<ScalarCosinus>();
135 return std::make_unique<ScalarCosinus>();
119 }
136 }
120 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
137 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
121 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
138 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
122 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
139 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
123 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
140 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
124
141
125 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"});
142 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"},
143 Unit{"eV/(cm^2-s-sr-eV)"});
126 }
144 }
127 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
145 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
128 return std::make_unique<VectorCosinus>();
146 return std::make_unique<VectorCosinus>();
129 }
147 }
130 else {
148 else {
131 return nullptr;
149 return nullptr;
132 }
150 }
133 }
151 }
134
152
135 } // namespace
153 } // namespace
136
154
137 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
155 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
138 {
156 {
139 // No copy is made in clone
157 // No copy is made in clone
140 return std::make_shared<CosinusProvider>();
158 return std::make_shared<CosinusProvider>();
141 }
159 }
142
160
143 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
161 std::shared_ptr<IDataSeries> CosinusProvider::retrieveData(QUuid acqIdentifier,
144 const SqpRange &dataRangeRequested,
162 const SqpRange &dataRangeRequested,
145 const QVariantHash &data)
163 const QVariantHash &data)
146 {
164 {
147 // TODO: Add Mutex
165 // TODO: Add Mutex
148 auto dataIndex = 0;
166 auto dataIndex = 0;
149
167
150 // Retrieves cosinus type
168 // Retrieves cosinus type
151 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
169 auto typeVariant = data.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
152 if (!typeVariant.canConvert<QString>()) {
170 if (!typeVariant.canConvert<QString>()) {
153 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
171 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid type");
154 return nullptr;
172 return nullptr;
155 }
173 }
156
174
157 auto type = cosinusType(typeVariant.toString());
175 auto type = cosinusType(typeVariant.toString());
158 if (!type) {
176 if (!type) {
159 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
177 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: unknown type");
160 return nullptr;
178 return nullptr;
161 }
179 }
162
180
163 // Retrieves frequency
181 // Retrieves frequency
164 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
182 auto freqVariant = data.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
165 if (!freqVariant.canConvert<double>()) {
183 if (!freqVariant.canConvert<double>()) {
166 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
184 qCCritical(LOG_CosinusProvider()) << tr("Can't retrieve data: invalid frequency");
167 return nullptr;
185 return nullptr;
168 }
186 }
169
187
170 // Gets the timerange from the parameters
188 // Gets the timerange from the parameters
171 double freq = freqVariant.toDouble();
189 double freq = freqVariant.toDouble();
172 double start = std::ceil(dataRangeRequested.m_TStart * freq);
190 double start = std::ceil(dataRangeRequested.m_TStart * freq);
173 double end = std::floor(dataRangeRequested.m_TEnd * freq);
191 double end = std::floor(dataRangeRequested.m_TEnd * freq);
174
192
175 // We assure that timerange is valid
193 // We assure that timerange is valid
176 if (end < start) {
194 if (end < start) {
177 std::swap(start, end);
195 std::swap(start, end);
178 }
196 }
179
197
180 // Generates scalar series containing cosinus values (one value per second, end value is
198 // Generates scalar series containing cosinus values (one value per second, end value is
181 // included)
199 // included)
182 auto dataCount = end - start + 1;
200 auto dataCount = end - start + 1;
183
201
184 // Number of components (depending on the cosinus type)
202 // Number of components (depending on the cosinus type)
185 auto componentCount = type->componentCount();
203 auto componentCount = type->componentCount();
186
204
187 auto xAxisData = std::vector<double>{};
205 auto xAxisData = std::vector<double>{};
188 xAxisData.resize(dataCount);
206 xAxisData.resize(dataCount);
189
207
190 auto valuesData = std::vector<double>{};
208 auto valuesData = std::vector<double>{};
191 valuesData.resize(dataCount * componentCount);
209 valuesData.resize(dataCount * componentCount);
192
210
193 int progress = 0;
211 int progress = 0;
194 auto progressEnd = dataCount;
212 auto progressEnd = dataCount;
195 for (auto time = start; time <= end; ++time, ++dataIndex) {
213 for (auto time = start; time <= end; ++time, ++dataIndex) {
196 auto it = m_VariableToEnableProvider.find(acqIdentifier);
214 auto it = m_VariableToEnableProvider.find(acqIdentifier);
197 if (it != m_VariableToEnableProvider.end() && it.value()) {
215 if (it != m_VariableToEnableProvider.end() && it.value()) {
198 const auto x = time / freq;
216 const auto x = time / freq;
199
217
200 xAxisData[dataIndex] = x;
218 xAxisData[dataIndex] = x;
201
219
202 // Generates values (depending on the type)
220 // Generates values (depending on the type)
203 type->generateValues(x, valuesData, dataIndex);
221 type->generateValues(x, valuesData, dataIndex);
204
222
205 // progression
223 // progression
206 int currentProgress = (time - start) * 100.0 / progressEnd;
224 int currentProgress = (time - start) * 100.0 / progressEnd;
207 if (currentProgress != progress) {
225 if (currentProgress != progress) {
208 progress = currentProgress;
226 progress = currentProgress;
209
227
210 emit dataProvidedProgress(acqIdentifier, progress);
228 emit dataProvidedProgress(acqIdentifier, progress);
211 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
229 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::retrieveData"
212 << QThread::currentThread()->objectName()
230 << QThread::currentThread()->objectName()
213 << progress;
231 << progress;
214 // NOTE: Try to use multithread if possible
232 // NOTE: Try to use multithread if possible
215 }
233 }
216 }
234 }
217 else {
235 else {
218 if (!it.value()) {
236 if (!it.value()) {
219 qCDebug(LOG_CosinusProvider())
237 qCDebug(LOG_CosinusProvider())
220 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
238 << "CosinusProvider::retrieveData: ARRET De l'acquisition detectΓ©"
221 << end - time;
239 << end - time;
222 }
240 }
223 }
241 }
224 }
242 }
225 if (progress != 100) {
243 if (progress != 100) {
226 // We can close progression beacause all data has been retrieved
244 // We can close progression beacause all data has been retrieved
227 emit dataProvidedProgress(acqIdentifier, 100);
245 emit dataProvidedProgress(acqIdentifier, 100);
228 }
246 }
229 return type->createDataSeries(std::move(xAxisData), std::move(valuesData),
247 return type->createDataSeries(std::move(xAxisData), std::move(valuesData));
230 Unit{QStringLiteral("t"), true}, Unit{});
231 }
248 }
232
249
233 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
250 void CosinusProvider::requestDataLoading(QUuid acqIdentifier,
234 const DataProviderParameters &parameters)
251 const DataProviderParameters &parameters)
235 {
252 {
236 // TODO: Add Mutex
253 // TODO: Add Mutex
237 m_VariableToEnableProvider[acqIdentifier] = true;
254 m_VariableToEnableProvider[acqIdentifier] = true;
238 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
255 qCDebug(LOG_CosinusProvider()) << "TORM: CosinusProvider::requestDataLoading"
239 << QThread::currentThread()->objectName();
256 << QThread::currentThread()->objectName();
240 // NOTE: Try to use multithread if possible
257 // NOTE: Try to use multithread if possible
241 const auto times = parameters.m_Times;
258 const auto times = parameters.m_Times;
242
259
243 for (const auto &dateTime : qAsConst(times)) {
260 for (const auto &dateTime : qAsConst(times)) {
244 if (m_VariableToEnableProvider[acqIdentifier]) {
261 if (m_VariableToEnableProvider[acqIdentifier]) {
245 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
262 auto scalarSeries = this->retrieveData(acqIdentifier, dateTime, parameters.m_Data);
246 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
263 emit dataProvided(acqIdentifier, scalarSeries, dateTime);
247 }
264 }
248 }
265 }
249 }
266 }
250
267
251 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
268 void CosinusProvider::requestDataAborting(QUuid acqIdentifier)
252 {
269 {
253 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
270 qCDebug(LOG_CosinusProvider()) << "CosinusProvider::requestDataAborting" << acqIdentifier
254 << QThread::currentThread()->objectName();
271 << QThread::currentThread()->objectName();
255 auto it = m_VariableToEnableProvider.find(acqIdentifier);
272 auto it = m_VariableToEnableProvider.find(acqIdentifier);
256 if (it != m_VariableToEnableProvider.end()) {
273 if (it != m_VariableToEnableProvider.end()) {
257 it.value() = false;
274 it.value() = false;
258 }
275 }
259 else {
276 else {
260 qCDebug(LOG_CosinusProvider())
277 qCDebug(LOG_CosinusProvider())
261 << tr("Aborting progression of inexistant identifier detected !!!");
278 << tr("Aborting progression of inexistant identifier detected !!!");
262 }
279 }
263 }
280 }
264
281
265 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
282 std::shared_ptr<IDataSeries> CosinusProvider::provideDataSeries(const SqpRange &dataRangeRequested,
266 const QVariantHash &data)
283 const QVariantHash &data)
267 {
284 {
268 auto uid = QUuid::createUuid();
285 auto uid = QUuid::createUuid();
269 m_VariableToEnableProvider[uid] = true;
286 m_VariableToEnableProvider[uid] = true;
270 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
287 auto dataSeries = this->retrieveData(uid, dataRangeRequested, data);
271
288
272 m_VariableToEnableProvider.remove(uid);
289 m_VariableToEnableProvider.remove(uid);
273 return dataSeries;
290 return dataSeries;
274 }
291 }
General Comments 0
You need to be logged in to leave comments. Login now