##// END OF EJS Templates
Mesh generation for QColorMap (3)...
Alexandre Leroux -
r993:ac59fa41a164
parent child
Show More
@@ -1,116 +1,161
1 1 #include "Data/DataSeriesUtils.h"
2 2
3 3 #include <cmath>
4 4
5 5 Q_LOGGING_CATEGORY(LOG_DataSeriesUtils, "DataSeriesUtils")
6 6
7 7 void DataSeriesUtils::fillDataHoles(std::vector<double> &xAxisData, std::vector<double> &valuesData,
8 8 double resolution, double fillValue, double minBound,
9 9 double maxBound)
10 10 {
11 11 if (resolution == 0. || std::isnan(resolution)) {
12 12 qCWarning(LOG_DataSeriesUtils())
13 13 << "Can't fill data holes with a null resolution, no changes will be made";
14 14 return;
15 15 }
16 16
17 17 if (xAxisData.empty()) {
18 18 qCWarning(LOG_DataSeriesUtils())
19 19 << "Can't fill data holes for empty data, no changes will be made";
20 20 return;
21 21 }
22 22
23 23 // Gets the number of values per x-axis data
24 24 auto nbComponents = valuesData.size() / xAxisData.size();
25 25
26 26 // Generates fill values that will be used to complete values data
27 27 std::vector<double> fillValues(nbComponents, fillValue);
28 28
29 29 // Checks if there are data holes on the beginning of the data and generates the hole at the
30 30 // extremity if it's the case
31 31 auto minXAxisData = xAxisData.front();
32 32 if (!std::isnan(minBound) && minBound < minXAxisData) {
33 33 auto holeSize = static_cast<int>((minXAxisData - minBound) / resolution);
34 34 if (holeSize > 0) {
35 35 xAxisData.insert(xAxisData.begin(), minXAxisData - holeSize * resolution);
36 36 valuesData.insert(valuesData.begin(), fillValues.begin(), fillValues.end());
37 37 }
38 38 }
39 39
40 40 // Same for the end of the data
41 41 auto maxXAxisData = xAxisData.back();
42 42 if (!std::isnan(maxBound) && maxBound > maxXAxisData) {
43 43 auto holeSize = static_cast<int>((maxBound - maxXAxisData) / resolution);
44 44 if (holeSize > 0) {
45 45 xAxisData.insert(xAxisData.end(), maxXAxisData + holeSize * resolution);
46 46 valuesData.insert(valuesData.end(), fillValues.begin(), fillValues.end());
47 47 }
48 48 }
49 49
50 50 // Generates other data holes
51 51 auto xAxisIt = xAxisData.begin();
52 52 while (xAxisIt != xAxisData.end()) {
53 53 // Stops at first value which has a gap greater than resolution with the value next to it
54 54 xAxisIt = std::adjacent_find(
55 55 xAxisIt, xAxisData.end(),
56 56 [resolution](const auto &a, const auto &b) { return (b - a) > resolution; });
57 57
58 58 if (xAxisIt != xAxisData.end()) {
59 59 auto nextXAxisIt = xAxisIt + 1;
60 60
61 61 // Gets the values that has a gap greater than resolution between them
62 62 auto lowValue = *xAxisIt;
63 63 auto highValue = *nextXAxisIt;
64 64
65 65 // Completes holes between the two values by creating new values (according to the
66 66 // resolution)
67 67 for (auto i = lowValue + resolution; i < highValue; i += resolution) {
68 68 // Gets the iterator of values data from which to insert fill values
69 69 auto nextValuesIt = valuesData.begin()
70 70 + std::distance(xAxisData.begin(), nextXAxisIt) * nbComponents;
71 71
72 72 // New value is inserted before nextXAxisIt
73 73 nextXAxisIt = xAxisData.insert(nextXAxisIt, i) + 1;
74 74
75 75 // New values are inserted before nextValuesIt
76 76 valuesData.insert(nextValuesIt, fillValues.begin(), fillValues.end());
77 77 }
78 78
79 79 // Moves to the next value to continue loop on the x-axis data
80 80 xAxisIt = nextXAxisIt;
81 81 }
82 82 }
83 83 }
84
85 namespace {
86
87 /**
88 * Generates axis's mesh properties according to data and resolution
89 * @param begin the iterator pointing to the beginning of the data
90 * @param end the iterator pointing to the end of the data
91 * @param fun the function to retrieve data from the data iterators
92 * @param resolution the resolution to use for the axis' mesh
93 * @return a tuple representing the mesh properties : <nb values, min value, value step>
94 */
95 template <typename Iterator, typename IteratorFun>
96 std::tuple<int, double, double> meshProperties(Iterator begin, Iterator end, IteratorFun fun,
97 double resolution)
98 {
99 // Computes the gap between min and max data. This will be used to determinate the step between
100 // each data of the mesh
101 auto min = fun(begin);
102 auto max = fun(end - 1);
103 auto gap = max - min;
104
105 // Computes the step trying to use the fixed resolution. If the resolution doesn't separate the
106 // values evenly , it is recalculated.
107 // For example, for a resolution of 2.0:
108 // - for interval [0; 8] => resolution is valid, the generated mesh will be [0, 2, 4, 6, 8]
109 // - for interval [0; 9] => it's impossible to create a regular mesh with this resolution
110 // The resolution is recalculated and is worth 1.8. The generated mesh will be [0, 1.8, 3.6,
111 // 5.4, 7.2, 9]
112 auto nbVal = static_cast<int>(std::ceil(gap / resolution));
113 auto step = gap / nbVal;
114
115 // last data is included in the total number of values
116 return std::make_tuple(nbVal + 1, min, step);
117 }
118
119 } // namespace
120
84 121 DataSeriesUtils::Mesh DataSeriesUtils::regularMesh(DataSeriesIterator begin, DataSeriesIterator end,
85 122 Resolution xResolution, Resolution yResolution)
86 123 {
87 124 // Checks preconditions
88 125 if (xResolution.m_Val == 0. || std::isnan(xResolution.m_Val) || yResolution.m_Val == 0.
89 126 || std::isnan(yResolution.m_Val)) {
90 127 qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh with a null resolution";
91 128 return Mesh{};
92 129 }
93 130
94 131 if (xResolution.m_Logarithmic) {
95 132 qCWarning(LOG_DataSeriesUtils())
96 133 << "Can't generate mesh with a logarithmic x-axis resolution";
97 134 return Mesh{};
98 135 }
99 136
100 137 if (std::distance(begin, end) == 0) {
101 138 qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh for empty data";
102 139 return Mesh{};
103 140 }
104 141
105 142 auto yData = begin->y();
106 143 if (yData.empty()) {
107 144 qCWarning(LOG_DataSeriesUtils()) << "Can't generate mesh for data with no y-axis";
108 145 return Mesh{};
109 146 }
110 147
111 148 // Converts y-axis and its resolution to logarithmic values
112 149 if (yResolution.m_Logarithmic) {
113 150 std::for_each(yData.begin(), yData.end(), [](auto &val) { val = std::log10(val); });
114 151 }
115 152
153 // Computes mesh properties
154 int nbX, nbY;
155 double xMin, xStep, yMin, yStep;
156 std::tie(nbX, xMin, xStep)
157 = meshProperties(begin, end, [](const auto &it) { return it->x(); }, xResolution.m_Val);
158 std::tie(nbY, yMin, yStep) = meshProperties(
159 yData.begin(), yData.end(), [](const auto &it) { return *it; }, yResolution.m_Val);
160
116 161 }
General Comments 0
You need to be logged in to leave comments. Login now