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