##// END OF EJS Templates
Mesh generation for QColorMap (1)...
Alexandre Leroux -
r991:c3f3d046e003
parent child
Show More
@@ -1,139 +1,185
1 #ifndef SCIQLOP_DATASERIESUTILS_H
1 #ifndef SCIQLOP_DATASERIESUTILS_H
2 #define SCIQLOP_DATASERIESUTILS_H
2 #define SCIQLOP_DATASERIESUTILS_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7
7
8 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeriesUtils)
8 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeriesUtils)
9
9
10 /**
10 /**
11 * Utility class with methods for data series
11 * Utility class with methods for data series
12 */
12 */
13 struct SCIQLOP_CORE_EXPORT DataSeriesUtils {
13 struct SCIQLOP_CORE_EXPORT DataSeriesUtils {
14 /**
14 /**
15 * Define a meshs.
16 *
17 * A mesh is a regular grid representing cells of the same width (in x) and of the same height
18 * (in y). At each mesh point is associated a value.
19 *
20 * Each axis of the mesh is defined by a minimum value, a number of values is a mesh step.
21 * For example: if min = 1, nbValues = 5 and step = 2 => the axis of the mesh will be [1, 3, 5,
22 * 7, 9].
23 *
24 * The values are defined in an array of size {nbX * nbY}. The data is stored along the X axis.
25 *
26 * For example, the mesh:
27 * Y = 2 [ 7 ; 8 ; 9
28 * Y = 1 4 ; 5 ; 6
29 * Y = 0 1 ; 2 ; 3 ]
30 * X = 0 X = 1 X = 2
31 *
32 * will be represented by data [1, 2, 3, 4, 5, 6, 7, 8, 9]
33 */
34 struct Mesh {
35 explicit Mesh() = default;
36 explicit Mesh(int nbX, double xMin, double xStep, int nbY, double yMin, double yStep)
37 : m_NbX{nbX},
38 m_XMin{xMin},
39 m_XStep{xStep},
40 m_NbY{nbY},
41 m_YMin{yMin},
42 m_YStep{yStep},
43 m_Data(nbX * nbY)
44 {
45 }
46
47 inline bool isEmpty() const { return m_Data.size() == 0; }
48 inline double xMax() const { return m_XMin + (m_NbX - 1) * m_XStep; }
49 inline double yMax() const { return m_YMin + (m_NbY - 1) * m_YStep; }
50
51 int m_NbX{0};
52 double m_XMin{};
53 double m_XStep{};
54 int m_NbY{0};
55 double m_YMin{};
56 double m_YStep{};
57 std::vector<double> m_Data{};
58 };
59
60 /**
15 * Represents a resolution used to generate the data of a mesh on the x-axis or in Y.
61 * Represents a resolution used to generate the data of a mesh on the x-axis or in Y.
16 *
62 *
17 * A resolution is represented by a value and flag indicating if it's in the logarithmic scale
63 * A resolution is represented by a value and flag indicating if it's in the logarithmic scale
18 * @sa Mesh
64 * @sa Mesh
19 */
65 */
20 struct Resolution {
66 struct Resolution {
21 double m_Val{std::numeric_limits<double>::quiet_NaN()};
67 double m_Val{std::numeric_limits<double>::quiet_NaN()};
22 bool m_Logarithmic{false};
68 bool m_Logarithmic{false};
23 };
69 };
24
70
25 /**
71 /**
26 * Processes data from a data series to complete the data holes with a fill value.
72 * Processes data from a data series to complete the data holes with a fill value.
27 *
73 *
28 * A data hole is determined by the resolution passed in parameter: if, between two continuous
74 * A data hole is determined by the resolution passed in parameter: if, between two continuous
29 * data on the x-axis, the difference between these data is greater than the resolution, then
75 * data on the x-axis, the difference between these data is greater than the resolution, then
30 * there is one or more holes between them. The holes are filled by adding:
76 * there is one or more holes between them. The holes are filled by adding:
31 * - for the x-axis, new data corresponding to the 'step resolution' starting from the first
77 * - for the x-axis, new data corresponding to the 'step resolution' starting from the first
32 * data;
78 * data;
33 * - for values, a default value (fill value) for each new data added on the x-axis.
79 * - for values, a default value (fill value) for each new data added on the x-axis.
34 *
80 *
35 * For example, with :
81 * For example, with :
36 * - xAxisData = [0, 1, 5, 7, 14 ]
82 * - xAxisData = [0, 1, 5, 7, 14 ]
37 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (two components per x-axis data)
83 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (two components per x-axis data)
38 * - fillValue = NaN
84 * - fillValue = NaN
39 * - and resolution = 2;
85 * - and resolution = 2;
40 *
86 *
41 * For the x axis, we calculate as data holes: [3, 9, 11, 13]. These holes are added to the
87 * For the x axis, we calculate as data holes: [3, 9, 11, 13]. These holes are added to the
42 * x-axis data, and NaNs (two per x-axis data) are added to the values:
88 * x-axis data, and NaNs (two per x-axis data) are added to the values:
43 * => xAxisData = [0, 1, 3, 5, 7, 9, 11, 13, 14 ]
89 * => xAxisData = [0, 1, 3, 5, 7, 9, 11, 13, 14 ]
44 * => valuesData = [0, 1, 2, 3, NaN, NaN, 4, 5, 6, 7, NaN, NaN, NaN, NaN, NaN, NaN, 8, 9]
90 * => valuesData = [0, 1, 2, 3, NaN, NaN, 4, 5, 6, 7, NaN, NaN, NaN, NaN, NaN, NaN, 8, 9]
45 *
91 *
46 * It is also possible to set bounds for the data series. If these bounds are defined and exceed
92 * It is also possible to set bounds for the data series. If these bounds are defined and exceed
47 * the limits of the data series, data holes are added to the series at the beginning and/or the
93 * the limits of the data series, data holes are added to the series at the beginning and/or the
48 * end.
94 * end.
49 *
95 *
50 * The generation of data holes at the beginning/end of the data series is performed starting
96 * The generation of data holes at the beginning/end of the data series is performed starting
51 * from the x-axis series limit and adding data holes at each 'resolution step' as long as the
97 * from the x-axis series limit and adding data holes at each 'resolution step' as long as the
52 * new bound is not reached.
98 * new bound is not reached.
53 *
99 *
54 * For example, with :
100 * For example, with :
55 * - xAxisData = [3, 4, 5, 6, 7 ]
101 * - xAxisData = [3, 4, 5, 6, 7 ]
56 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
102 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
57 * - fillValue = NaN
103 * - fillValue = NaN
58 * - minBound = 0
104 * - minBound = 0
59 * - maxBound = 12
105 * - maxBound = 12
60 * - and resolution = 2;
106 * - and resolution = 2;
61 *
107 *
62 * => Starting from 3 and decreasing 2 by 2 until reaching 0 : a data hole at value 1 will be
108 * => Starting from 3 and decreasing 2 by 2 until reaching 0 : a data hole at value 1 will be
63 * added to the beginning of the series
109 * added to the beginning of the series
64 * => Starting from 7 and increasing 2 by 2 until reaching 12 : data holes at values 9 and 11
110 * => Starting from 7 and increasing 2 by 2 until reaching 12 : data holes at values 9 and 11
65 * will be added to the end of the series
111 * will be added to the end of the series
66 *
112 *
67 * So :
113 * So :
68 * => xAxisData = [1, 3, 4, 5, 6, 7, 9, 11 ]
114 * => xAxisData = [1, 3, 4, 5, 6, 7, 9, 11 ]
69 * => valuesData = [NaN, NaN, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, NaN, NaN, NaN, NaN]
115 * => valuesData = [NaN, NaN, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, NaN, NaN, NaN, NaN]
70 *
116 *
71 * @param xAxisData the x-axis data of the data series
117 * @param xAxisData the x-axis data of the data series
72 * @param valuesData the values data of the data series
118 * @param valuesData the values data of the data series
73 * @param resolution the resoultion (on x-axis) used to determinate data holes
119 * @param resolution the resoultion (on x-axis) used to determinate data holes
74 * @param fillValue the fill value used for data holes in the values data
120 * @param fillValue the fill value used for data holes in the values data
75 * @param minBound the limit at which to start filling data holes for the series. If set to NaN,
121 * @param minBound the limit at which to start filling data holes for the series. If set to NaN,
76 * the limit is not used
122 * the limit is not used
77 * @param maxBound the limit at which to end filling data holes for the series. If set to NaN,
123 * @param maxBound the limit at which to end filling data holes for the series. If set to NaN,
78 * the limit is not used
124 * the limit is not used
79 *
125 *
80 * @remarks There is no control over the consistency between x-axis data and values data. The
126 * @remarks There is no control over the consistency between x-axis data and values data. The
81 * method considers that the data is well formed (the total number of values data is a multiple
127 * method considers that the data is well formed (the total number of values data is a multiple
82 * of the number of x-axis data)
128 * of the number of x-axis data)
83 */
129 */
84 static void fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
130 static void fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
85 double resolution,
131 double resolution,
86 double fillValue = std::numeric_limits<double>::quiet_NaN(),
132 double fillValue = std::numeric_limits<double>::quiet_NaN(),
87 double minBound = std::numeric_limits<double>::quiet_NaN(),
133 double minBound = std::numeric_limits<double>::quiet_NaN(),
88 double maxBound = std::numeric_limits<double>::quiet_NaN());
134 double maxBound = std::numeric_limits<double>::quiet_NaN());
89 /**
135 /**
90 * Computes the resolution of a dataset passed as a parameter.
136 * Computes the resolution of a dataset passed as a parameter.
91 *
137 *
92 * The resolution of a dataset is the minimum difference between two values that follow in the
138 * The resolution of a dataset is the minimum difference between two values that follow in the
93 * set.
139 * set.
94 * For example:
140 * For example:
95 * - for the set [0, 2, 4, 8, 10, 11, 13] => the resolution is 1 (difference between 10 and 11).
141 * - for the set [0, 2, 4, 8, 10, 11, 13] => the resolution is 1 (difference between 10 and 11).
96 *
142 *
97 * A resolution can be calculated on the logarithmic scale (base of 10). In this case, the
143 * A resolution can be calculated on the logarithmic scale (base of 10). In this case, the
98 * dataset is first converted to logarithmic values.
144 * dataset is first converted to logarithmic values.
99 * For example:
145 * For example:
100 * - for the set [10, 100, 10000, 1000000], the values are converted to [1, 2, 4, 6] => the
146 * - for the set [10, 100, 10000, 1000000], the values are converted to [1, 2, 4, 6] => the
101 * logarithmic resolution is 1 (difference between 1 and 2).
147 * logarithmic resolution is 1 (difference between 1 and 2).
102 *
148 *
103 * @param begin the iterator pointing to the beginning of the dataset
149 * @param begin the iterator pointing to the beginning of the dataset
104 * @param end the iterator pointing to the end of the dataset
150 * @param end the iterator pointing to the end of the dataset
105 * @param logarithmic computes a logarithmic resolution or not
151 * @param logarithmic computes a logarithmic resolution or not
106 * @return the resolution computed
152 * @return the resolution computed
107 * @warning the method considers the dataset as sorted and doesn't control it.
153 * @warning the method considers the dataset as sorted and doesn't control it.
108 */
154 */
109 template <typename Iterator>
155 template <typename Iterator>
110 static Resolution resolution(Iterator begin, Iterator end, bool logarithmic = false);
156 static Resolution resolution(Iterator begin, Iterator end, bool logarithmic = false);
111 };
157 };
112
158
113 template <typename Iterator>
159 template <typename Iterator>
114 DataSeriesUtils::Resolution DataSeriesUtils::resolution(Iterator begin, Iterator end,
160 DataSeriesUtils::Resolution DataSeriesUtils::resolution(Iterator begin, Iterator end,
115 bool logarithmic)
161 bool logarithmic)
116 {
162 {
117 // Retrieves data into a work dataset
163 // Retrieves data into a work dataset
118 using ValueType = typename Iterator::value_type;
164 using ValueType = typename Iterator::value_type;
119 std::vector<ValueType> values{};
165 std::vector<ValueType> values{};
120 std::copy(begin, end, std::back_inserter(values));
166 std::copy(begin, end, std::back_inserter(values));
121
167
122 // Converts data if logarithmic flag is activated
168 // Converts data if logarithmic flag is activated
123 if (logarithmic) {
169 if (logarithmic) {
124 std::for_each(values.begin(), values.end(),
170 std::for_each(values.begin(), values.end(),
125 [logarithmic](auto &val) { val = std::log10(val); });
171 [logarithmic](auto &val) { val = std::log10(val); });
126 }
172 }
127
173
128 // Computes the differences between the values in the dataset
174 // Computes the differences between the values in the dataset
129 std::adjacent_difference(values.begin(), values.end(), values.begin());
175 std::adjacent_difference(values.begin(), values.end(), values.begin());
130
176
131 // Retrieves the smallest difference
177 // Retrieves the smallest difference
132 auto resolutionIt = std::min_element(values.begin(), values.end());
178 auto resolutionIt = std::min_element(values.begin(), values.end());
133 auto resolution
179 auto resolution
134 = resolutionIt != values.end() ? *resolutionIt : std::numeric_limits<double>::quiet_NaN();
180 = resolutionIt != values.end() ? *resolutionIt : std::numeric_limits<double>::quiet_NaN();
135
181
136 return Resolution{resolution, logarithmic};
182 return Resolution{resolution, logarithmic};
137 }
183 }
138
184
139 #endif // SCIQLOP_DATASERIESUTILS_H
185 #endif // SCIQLOP_DATASERIESUTILS_H
General Comments 0
You need to be logged in to leave comments. Login now