##// END OF EJS Templates
Mesh generation for QColorMap (2)...
Alexandre Leroux -
r1034:3411e62bc9af
parent child
Show More
@@ -1,185 +1,227
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 <Data/DataSeriesIterator.h>
7
6 #include <QLoggingCategory>
8 #include <QLoggingCategory>
7
9
8 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeriesUtils)
10 Q_DECLARE_LOGGING_CATEGORY(LOG_DataSeriesUtils)
9
11
10 /**
12 /**
11 * Utility class with methods for data series
13 * Utility class with methods for data series
12 */
14 */
13 struct SCIQLOP_CORE_EXPORT DataSeriesUtils {
15 struct SCIQLOP_CORE_EXPORT DataSeriesUtils {
14 /**
16 /**
15 * Define a meshs.
17 * Define a meshs.
16 *
18 *
17 * A mesh is a regular grid representing cells of the same width (in x) and of the same height
19 * 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.
20 * (in y). At each mesh point is associated a value.
19 *
21 *
20 * Each axis of the mesh is defined by a minimum value, a number of values is a mesh step.
22 * 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,
23 * For example: if min = 1, nbValues = 5 and step = 2 => the axis of the mesh will be [1, 3, 5,
22 * 7, 9].
24 * 7, 9].
23 *
25 *
24 * The values are defined in an array of size {nbX * nbY}. The data is stored along the X axis.
26 * The values are defined in an array of size {nbX * nbY}. The data is stored along the X axis.
25 *
27 *
26 * For example, the mesh:
28 * For example, the mesh:
27 * Y = 2 [ 7 ; 8 ; 9
29 * Y = 2 [ 7 ; 8 ; 9
28 * Y = 1 4 ; 5 ; 6
30 * Y = 1 4 ; 5 ; 6
29 * Y = 0 1 ; 2 ; 3 ]
31 * Y = 0 1 ; 2 ; 3 ]
30 * X = 0 X = 1 X = 2
32 * X = 0 X = 1 X = 2
31 *
33 *
32 * will be represented by data [1, 2, 3, 4, 5, 6, 7, 8, 9]
34 * will be represented by data [1, 2, 3, 4, 5, 6, 7, 8, 9]
33 */
35 */
34 struct Mesh {
36 struct Mesh {
35 explicit Mesh() = default;
37 explicit Mesh() = default;
36 explicit Mesh(int nbX, double xMin, double xStep, int nbY, double yMin, double yStep)
38 explicit Mesh(int nbX, double xMin, double xStep, int nbY, double yMin, double yStep)
37 : m_NbX{nbX},
39 : m_NbX{nbX},
38 m_XMin{xMin},
40 m_XMin{xMin},
39 m_XStep{xStep},
41 m_XStep{xStep},
40 m_NbY{nbY},
42 m_NbY{nbY},
41 m_YMin{yMin},
43 m_YMin{yMin},
42 m_YStep{yStep},
44 m_YStep{yStep},
43 m_Data(nbX * nbY)
45 m_Data(nbX * nbY)
44 {
46 {
45 }
47 }
46
48
47 inline bool isEmpty() const { return m_Data.size() == 0; }
49 inline bool isEmpty() const { return m_Data.size() == 0; }
48 inline double xMax() const { return m_XMin + (m_NbX - 1) * m_XStep; }
50 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; }
51 inline double yMax() const { return m_YMin + (m_NbY - 1) * m_YStep; }
50
52
51 int m_NbX{0};
53 int m_NbX{0};
52 double m_XMin{};
54 double m_XMin{};
53 double m_XStep{};
55 double m_XStep{};
54 int m_NbY{0};
56 int m_NbY{0};
55 double m_YMin{};
57 double m_YMin{};
56 double m_YStep{};
58 double m_YStep{};
57 std::vector<double> m_Data{};
59 std::vector<double> m_Data{};
58 };
60 };
59
61
60 /**
62 /**
61 * Represents a resolution used to generate the data of a mesh on the x-axis or in Y.
63 * Represents a resolution used to generate the data of a mesh on the x-axis or in Y.
62 *
64 *
63 * A resolution is represented by a value and flag indicating if it's in the logarithmic scale
65 * A resolution is represented by a value and flag indicating if it's in the logarithmic scale
64 * @sa Mesh
66 * @sa Mesh
65 */
67 */
66 struct Resolution {
68 struct Resolution {
67 double m_Val{std::numeric_limits<double>::quiet_NaN()};
69 double m_Val{std::numeric_limits<double>::quiet_NaN()};
68 bool m_Logarithmic{false};
70 bool m_Logarithmic{false};
69 };
71 };
70
72
71 /**
73 /**
72 * Processes data from a data series to complete the data holes with a fill value.
74 * Processes data from a data series to complete the data holes with a fill value.
73 *
75 *
74 * A data hole is determined by the resolution passed in parameter: if, between two continuous
76 * A data hole is determined by the resolution passed in parameter: if, between two continuous
75 * data on the x-axis, the difference between these data is greater than the resolution, then
77 * data on the x-axis, the difference between these data is greater than the resolution, then
76 * there is one or more holes between them. The holes are filled by adding:
78 * there is one or more holes between them. The holes are filled by adding:
77 * - for the x-axis, new data corresponding to the 'step resolution' starting from the first
79 * - for the x-axis, new data corresponding to the 'step resolution' starting from the first
78 * data;
80 * data;
79 * - for values, a default value (fill value) for each new data added on the x-axis.
81 * - for values, a default value (fill value) for each new data added on the x-axis.
80 *
82 *
81 * For example, with :
83 * For example, with :
82 * - xAxisData = [0, 1, 5, 7, 14 ]
84 * - xAxisData = [0, 1, 5, 7, 14 ]
83 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (two components per x-axis data)
85 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (two components per x-axis data)
84 * - fillValue = NaN
86 * - fillValue = NaN
85 * - and resolution = 2;
87 * - and resolution = 2;
86 *
88 *
87 * For the x axis, we calculate as data holes: [3, 9, 11, 13]. These holes are added to the
89 * For the x axis, we calculate as data holes: [3, 9, 11, 13]. These holes are added to the
88 * x-axis data, and NaNs (two per x-axis data) are added to the values:
90 * x-axis data, and NaNs (two per x-axis data) are added to the values:
89 * => xAxisData = [0, 1, 3, 5, 7, 9, 11, 13, 14 ]
91 * => xAxisData = [0, 1, 3, 5, 7, 9, 11, 13, 14 ]
90 * => valuesData = [0, 1, 2, 3, NaN, NaN, 4, 5, 6, 7, NaN, NaN, NaN, NaN, NaN, NaN, 8, 9]
92 * => valuesData = [0, 1, 2, 3, NaN, NaN, 4, 5, 6, 7, NaN, NaN, NaN, NaN, NaN, NaN, 8, 9]
91 *
93 *
92 * It is also possible to set bounds for the data series. If these bounds are defined and exceed
94 * It is also possible to set bounds for the data series. If these bounds are defined and exceed
93 * the limits of the data series, data holes are added to the series at the beginning and/or the
95 * the limits of the data series, data holes are added to the series at the beginning and/or the
94 * end.
96 * end.
95 *
97 *
96 * The generation of data holes at the beginning/end of the data series is performed starting
98 * The generation of data holes at the beginning/end of the data series is performed starting
97 * from the x-axis series limit and adding data holes at each 'resolution step' as long as the
99 * from the x-axis series limit and adding data holes at each 'resolution step' as long as the
98 * new bound is not reached.
100 * new bound is not reached.
99 *
101 *
100 * For example, with :
102 * For example, with :
101 * - xAxisData = [3, 4, 5, 6, 7 ]
103 * - xAxisData = [3, 4, 5, 6, 7 ]
102 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
104 * - valuesData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
103 * - fillValue = NaN
105 * - fillValue = NaN
104 * - minBound = 0
106 * - minBound = 0
105 * - maxBound = 12
107 * - maxBound = 12
106 * - and resolution = 2;
108 * - and resolution = 2;
107 *
109 *
108 * => Starting from 3 and decreasing 2 by 2 until reaching 0 : a data hole at value 1 will be
110 * => Starting from 3 and decreasing 2 by 2 until reaching 0 : a data hole at value 1 will be
109 * added to the beginning of the series
111 * added to the beginning of the series
110 * => Starting from 7 and increasing 2 by 2 until reaching 12 : data holes at values 9 and 11
112 * => Starting from 7 and increasing 2 by 2 until reaching 12 : data holes at values 9 and 11
111 * will be added to the end of the series
113 * will be added to the end of the series
112 *
114 *
113 * So :
115 * So :
114 * => xAxisData = [1, 3, 4, 5, 6, 7, 9, 11 ]
116 * => xAxisData = [1, 3, 4, 5, 6, 7, 9, 11 ]
115 * => valuesData = [NaN, NaN, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, NaN, NaN, NaN, NaN]
117 * => valuesData = [NaN, NaN, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, NaN, NaN, NaN, NaN]
116 *
118 *
117 * @param xAxisData the x-axis data of the data series
119 * @param xAxisData the x-axis data of the data series
118 * @param valuesData the values data of the data series
120 * @param valuesData the values data of the data series
119 * @param resolution the resoultion (on x-axis) used to determinate data holes
121 * @param resolution the resoultion (on x-axis) used to determinate data holes
120 * @param fillValue the fill value used for data holes in the values data
122 * @param fillValue the fill value used for data holes in the values data
121 * @param minBound the limit at which to start filling data holes for the series. If set to NaN,
123 * @param minBound the limit at which to start filling data holes for the series. If set to NaN,
122 * the limit is not used
124 * the limit is not used
123 * @param maxBound the limit at which to end filling data holes for the series. If set to NaN,
125 * @param maxBound the limit at which to end filling data holes for the series. If set to NaN,
124 * the limit is not used
126 * the limit is not used
125 *
127 *
126 * @remarks There is no control over the consistency between x-axis data and values data. The
128 * @remarks There is no control over the consistency between x-axis data and values data. The
127 * method considers that the data is well formed (the total number of values data is a multiple
129 * method considers that the data is well formed (the total number of values data is a multiple
128 * of the number of x-axis data)
130 * of the number of x-axis data)
129 */
131 */
130 static void fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
132 static void fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
131 double resolution,
133 double resolution,
132 double fillValue = std::numeric_limits<double>::quiet_NaN(),
134 double fillValue = std::numeric_limits<double>::quiet_NaN(),
133 double minBound = std::numeric_limits<double>::quiet_NaN(),
135 double minBound = std::numeric_limits<double>::quiet_NaN(),
134 double maxBound = std::numeric_limits<double>::quiet_NaN());
136 double maxBound = std::numeric_limits<double>::quiet_NaN());
135 /**
137 /**
136 * Computes the resolution of a dataset passed as a parameter.
138 * Computes the resolution of a dataset passed as a parameter.
137 *
139 *
138 * The resolution of a dataset is the minimum difference between two values that follow in the
140 * The resolution of a dataset is the minimum difference between two values that follow in the
139 * set.
141 * set.
140 * For example:
142 * For example:
141 * - for the set [0, 2, 4, 8, 10, 11, 13] => the resolution is 1 (difference between 10 and 11).
143 * - for the set [0, 2, 4, 8, 10, 11, 13] => the resolution is 1 (difference between 10 and 11).
142 *
144 *
143 * A resolution can be calculated on the logarithmic scale (base of 10). In this case, the
145 * A resolution can be calculated on the logarithmic scale (base of 10). In this case, the
144 * dataset is first converted to logarithmic values.
146 * dataset is first converted to logarithmic values.
145 * For example:
147 * For example:
146 * - for the set [10, 100, 10000, 1000000], the values are converted to [1, 2, 4, 6] => the
148 * - for the set [10, 100, 10000, 1000000], the values are converted to [1, 2, 4, 6] => the
147 * logarithmic resolution is 1 (difference between 1 and 2).
149 * logarithmic resolution is 1 (difference between 1 and 2).
148 *
150 *
149 * @param begin the iterator pointing to the beginning of the dataset
151 * @param begin the iterator pointing to the beginning of the dataset
150 * @param end the iterator pointing to the end of the dataset
152 * @param end the iterator pointing to the end of the dataset
151 * @param logarithmic computes a logarithmic resolution or not
153 * @param logarithmic computes a logarithmic resolution or not
152 * @return the resolution computed
154 * @return the resolution computed
153 * @warning the method considers the dataset as sorted and doesn't control it.
155 * @warning the method considers the dataset as sorted and doesn't control it.
154 */
156 */
155 template <typename Iterator>
157 template <typename Iterator>
156 static Resolution resolution(Iterator begin, Iterator end, bool logarithmic = false);
158 static Resolution resolution(Iterator begin, Iterator end, bool logarithmic = false);
159
160 /**
161 * Computes a regular mesh for a data series, according to resolutions for x-axis and y-axis
162 * passed as parameters.
163 *
164 * The mesh is created from the resolutions in x and y and the boundaries delimiting the data
165 * series. If the resolutions do not allow to obtain a regular mesh, they are recalculated.
166 *
167 * For example :
168 * Let x-axis data = [0, 1, 3, 5, 9], its associated values ​​= [0, 10, 30, 50, 90] and
169 * xResolution = 2.
170 * Based on the resolution, the mesh would be [0, 2, 4, 6, 8, 10] and would be invalid because
171 * it exceeds the maximum bound of the data. The resolution is thus recalculated so that the
172 * mesh holds between the data terminals.
173 * So => resolution is 1.8 and the mesh is [0, 1.8, 3.6, 5.4, 7.2, 9].
174 *
175 * Once the mesh is generated in x and y, the values ​​are associated with each mesh point,
176 * based on the data in the series, finding the existing data at which the mesh point would be
177 * or would be closest to, without exceeding it.
178 *
179 * In the example, we determine the value of each mesh point:
180 * - x = 0 => value = 0 (existing x in the data series)
181 * - x = 1.8 => value = 10 (the closest existing x: 1)
182 * - x = 3.6 => value = 30 (the closest existing x: 3)
183 * - x = 5.4 => value = 50 (the closest existing x: 5)
184 * - x = 7.2 => value = 50 (the closest existing x: 5)
185 * - x = 9 => value = 90 (existing x in the data series)
186 *
187 * Same algorithm is applied for y-axis.
188 *
189 * @param begin the iterator pointing to the beginning of the data series
190 * @param end the iterator pointing to the end of the data series
191 * @param xResolution the resolution expected for the mesh's x-axis
192 * @param yResolution the resolution expected for the mesh's y-axis
193 * @return the mesh created, an empty mesh if the input data do not allow to generate a regular
194 * mesh (empty data, null resolutions, logarithmic x-axis)
195 * @warning the method considers the dataset as sorted and doesn't control it.
196 */
197 static Mesh regularMesh(DataSeriesIterator begin, DataSeriesIterator end,
198 Resolution xResolution, Resolution yResolution);
157 };
199 };
158
200
159 template <typename Iterator>
201 template <typename Iterator>
160 DataSeriesUtils::Resolution DataSeriesUtils::resolution(Iterator begin, Iterator end,
202 DataSeriesUtils::Resolution DataSeriesUtils::resolution(Iterator begin, Iterator end,
161 bool logarithmic)
203 bool logarithmic)
162 {
204 {
163 // Retrieves data into a work dataset
205 // Retrieves data into a work dataset
164 using ValueType = typename Iterator::value_type;
206 using ValueType = typename Iterator::value_type;
165 std::vector<ValueType> values{};
207 std::vector<ValueType> values{};
166 std::copy(begin, end, std::back_inserter(values));
208 std::copy(begin, end, std::back_inserter(values));
167
209
168 // Converts data if logarithmic flag is activated
210 // Converts data if logarithmic flag is activated
169 if (logarithmic) {
211 if (logarithmic) {
170 std::for_each(values.begin(), values.end(),
212 std::for_each(values.begin(), values.end(),
171 [logarithmic](auto &val) { val = std::log10(val); });
213 [logarithmic](auto &val) { val = std::log10(val); });
172 }
214 }
173
215
174 // Computes the differences between the values in the dataset
216 // Computes the differences between the values in the dataset
175 std::adjacent_difference(values.begin(), values.end(), values.begin());
217 std::adjacent_difference(values.begin(), values.end(), values.begin());
176
218
177 // Retrieves the smallest difference
219 // Retrieves the smallest difference
178 auto resolutionIt = std::min_element(values.begin(), values.end());
220 auto resolutionIt = std::min_element(values.begin(), values.end());
179 auto resolution
221 auto resolution
180 = resolutionIt != values.end() ? *resolutionIt : std::numeric_limits<double>::quiet_NaN();
222 = resolutionIt != values.end() ? *resolutionIt : std::numeric_limits<double>::quiet_NaN();
181
223
182 return Resolution{resolution, logarithmic};
224 return Resolution{resolution, logarithmic};
183 }
225 }
184
226
185 #endif // SCIQLOP_DATASERIESUTILS_H
227 #endif // SCIQLOP_DATASERIESUTILS_H
@@ -1,81 +1,116
1 #include "Data/DataSeriesUtils.h"
1 #include "Data/DataSeriesUtils.h"
2
2
3 #include <cmath>
4
3 Q_LOGGING_CATEGORY(LOG_DataSeriesUtils, "DataSeriesUtils")
5 Q_LOGGING_CATEGORY(LOG_DataSeriesUtils, "DataSeriesUtils")
4
6
5 void DataSeriesUtils::fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
7 void DataSeriesUtils::fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
6 double resolution, double fillValue, double minBound,
8 double resolution, double fillValue, double minBound,
7 double maxBound)
9 double maxBound)
8 {
10 {
9 if (resolution == 0. || std::isnan(resolution)) {
11 if (resolution == 0. || std::isnan(resolution)) {
10 qCWarning(LOG_DataSeriesUtils())
12 qCWarning(LOG_DataSeriesUtils())
11 << "Can't fill data holes with a null resolution, no changes will be made";
13 << "Can't fill data holes with a null resolution, no changes will be made";
12 return;
14 return;
13 }
15 }
14
16
15 if (xAxisData.empty()) {
17 if (xAxisData.empty()) {
16 qCWarning(LOG_DataSeriesUtils())
18 qCWarning(LOG_DataSeriesUtils())
17 << "Can't fill data holes for empty data, no changes will be made";
19 << "Can't fill data holes for empty data, no changes will be made";
18 return;
20 return;
19 }
21 }
20
22
21 // Gets the number of values per x-axis data
23 // Gets the number of values per x-axis data
22 auto nbComponents = valuesData.size() / xAxisData.size();
24 auto nbComponents = valuesData.size() / xAxisData.size();
23
25
24 // Generates fill values that will be used to complete values data
26 // Generates fill values that will be used to complete values data
25 std::vector<double> fillValues(nbComponents, fillValue);
27 std::vector<double> fillValues(nbComponents, fillValue);
26
28
27 // Checks if there are data holes on the beginning of the data and generates the hole at the
29 // Checks if there are data holes on the beginning of the data and generates the hole at the
28 // extremity if it's the case
30 // extremity if it's the case
29 auto minXAxisData = xAxisData.front();
31 auto minXAxisData = xAxisData.front();
30 if (!std::isnan(minBound) && minBound < minXAxisData) {
32 if (!std::isnan(minBound) && minBound < minXAxisData) {
31 auto holeSize = static_cast<int>((minXAxisData - minBound) / resolution);
33 auto holeSize = static_cast<int>((minXAxisData - minBound) / resolution);
32 if (holeSize > 0) {
34 if (holeSize > 0) {
33 xAxisData.insert(xAxisData.begin(), minXAxisData - holeSize * resolution);
35 xAxisData.insert(xAxisData.begin(), minXAxisData - holeSize * resolution);
34 valuesData.insert(valuesData.begin(), fillValues.begin(), fillValues.end());
36 valuesData.insert(valuesData.begin(), fillValues.begin(), fillValues.end());
35 }
37 }
36 }
38 }
37
39
38 // Same for the end of the data
40 // Same for the end of the data
39 auto maxXAxisData = xAxisData.back();
41 auto maxXAxisData = xAxisData.back();
40 if (!std::isnan(maxBound) && maxBound > maxXAxisData) {
42 if (!std::isnan(maxBound) && maxBound > maxXAxisData) {
41 auto holeSize = static_cast<int>((maxBound - maxXAxisData) / resolution);
43 auto holeSize = static_cast<int>((maxBound - maxXAxisData) / resolution);
42 if (holeSize > 0) {
44 if (holeSize > 0) {
43 xAxisData.insert(xAxisData.end(), maxXAxisData + holeSize * resolution);
45 xAxisData.insert(xAxisData.end(), maxXAxisData + holeSize * resolution);
44 valuesData.insert(valuesData.end(), fillValues.begin(), fillValues.end());
46 valuesData.insert(valuesData.end(), fillValues.begin(), fillValues.end());
45 }
47 }
46 }
48 }
47
49
48 // Generates other data holes
50 // Generates other data holes
49 auto xAxisIt = xAxisData.begin();
51 auto xAxisIt = xAxisData.begin();
50 while (xAxisIt != xAxisData.end()) {
52 while (xAxisIt != xAxisData.end()) {
51 // Stops at first value which has a gap greater than resolution with the value next to it
53 // Stops at first value which has a gap greater than resolution with the value next to it
52 xAxisIt = std::adjacent_find(
54 xAxisIt = std::adjacent_find(
53 xAxisIt, xAxisData.end(),
55 xAxisIt, xAxisData.end(),
54 [resolution](const auto &a, const auto &b) { return (b - a) > resolution; });
56 [resolution](const auto &a, const auto &b) { return (b - a) > resolution; });
55
57
56 if (xAxisIt != xAxisData.end()) {
58 if (xAxisIt != xAxisData.end()) {
57 auto nextXAxisIt = xAxisIt + 1;
59 auto nextXAxisIt = xAxisIt + 1;
58
60
59 // Gets the values that has a gap greater than resolution between them
61 // Gets the values that has a gap greater than resolution between them
60 auto lowValue = *xAxisIt;
62 auto lowValue = *xAxisIt;
61 auto highValue = *nextXAxisIt;
63 auto highValue = *nextXAxisIt;
62
64
63 // Completes holes between the two values by creating new values (according to the
65 // Completes holes between the two values by creating new values (according to the
64 // resolution)
66 // resolution)
65 for (auto i = lowValue + resolution; i < highValue; i += resolution) {
67 for (auto i = lowValue + resolution; i < highValue; i += resolution) {
66 // Gets the iterator of values data from which to insert fill values
68 // Gets the iterator of values data from which to insert fill values
67 auto nextValuesIt = valuesData.begin()
69 auto nextValuesIt = valuesData.begin()
68 + std::distance(xAxisData.begin(), nextXAxisIt) * nbComponents;
70 + std::distance(xAxisData.begin(), nextXAxisIt) * nbComponents;
69
71
70 // New value is inserted before nextXAxisIt
72 // New value is inserted before nextXAxisIt
71 nextXAxisIt = xAxisData.insert(nextXAxisIt, i) + 1;
73 nextXAxisIt = xAxisData.insert(nextXAxisIt, i) + 1;
72
74
73 // New values are inserted before nextValuesIt
75 // New values are inserted before nextValuesIt
74 valuesData.insert(nextValuesIt, fillValues.begin(), fillValues.end());
76 valuesData.insert(nextValuesIt, fillValues.begin(), fillValues.end());
75 }
77 }
76
78
77 // Moves to the next value to continue loop on the x-axis data
79 // Moves to the next value to continue loop on the x-axis data
78 xAxisIt = nextXAxisIt;
80 xAxisIt = nextXAxisIt;
79 }
81 }
80 }
82 }
81 }
83 }
84 DataSeriesUtils::Mesh DataSeriesUtils::regularMesh(DataSeriesIterator begin, DataSeriesIterator end,
85 Resolution xResolution, Resolution yResolution)
86 {
87 // Checks preconditions
88 if (xResolution.m_Val == 0. || std::isnan(xResolution.m_Val) || yResolution.m_Val == 0.
89 || std::isnan(yResolution.m_Val)) {
90 qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh with a null resolution";
91 return Mesh{};
92 }
93
94 if (xResolution.m_Logarithmic) {
95 qCWarning(LOG_DataSeriesUtils())
96 << "Can't generate mesh with a logarithmic x-axis resolution";
97 return Mesh{};
98 }
99
100 if (std::distance(begin, end) == 0) {
101 qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh for empty data";
102 return Mesh{};
103 }
104
105 auto yData = begin->y();
106 if (yData.empty()) {
107 qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh for data with no y-axis";
108 return Mesh{};
109 }
110
111 // Converts y-axis and its resolution to logarithmic values
112 if (yResolution.m_Logarithmic) {
113 std::for_each(yData.begin(), yData.end(), [](auto &val) { val = std::log10(val); });
114 }
115
116 }
General Comments 0
You need to be logged in to leave comments. Login now