| 105 | } |
| 106 | |
| 107 | bool NormalizeChartData(vector<double> const & distanceDataM, geometry::Altitudes const & altitudeDataM, |
| 108 | size_t resultPointCount, vector<double> & uniformAltitudeDataM) |
| 109 | { |
| 110 | double constexpr kEpsilon = 1e-6; |
| 111 | |
| 112 | if (distanceDataM.size() != altitudeDataM.size()) |
| 113 | { |
| 114 | LOG(LERROR, ("Altitude and distance data have different size.")); |
| 115 | return false; |
| 116 | } |
| 117 | |
| 118 | if (!is_sorted(distanceDataM.cbegin(), distanceDataM.cend())) |
| 119 | { |
| 120 | LOG(LERROR, ("Route segment distances are not sorted.")); |
| 121 | return false; |
| 122 | } |
| 123 | |
| 124 | if (distanceDataM.empty() || resultPointCount == 0) |
| 125 | { |
| 126 | uniformAltitudeDataM.clear(); |
| 127 | return true; |
| 128 | } |
| 129 | |
| 130 | auto const calculateAltitude = [&](double distFormStartM) |
| 131 | { |
| 132 | if (distFormStartM <= distanceDataM.front()) |
| 133 | return static_cast<double>(altitudeDataM.front()); |
| 134 | if (distFormStartM >= distanceDataM.back()) |
| 135 | return static_cast<double>(altitudeDataM.back()); |
| 136 | |
| 137 | auto const lowerIt = lower_bound(distanceDataM.cbegin(), distanceDataM.cend(), distFormStartM); |
| 138 | size_t const nextPointIdx = distance(distanceDataM.cbegin(), lowerIt); |
| 139 | ASSERT_LESS(0, nextPointIdx, ("distFormStartM is greater than 0 but nextPointIdx == 0.")); |
| 140 | size_t const prevPointIdx = nextPointIdx - 1; |
| 141 | |
| 142 | if (AlmostEqualAbs(distanceDataM[prevPointIdx], distanceDataM[nextPointIdx], kEpsilon)) |
| 143 | return static_cast<double>(altitudeDataM[prevPointIdx]); |
| 144 | |
| 145 | double const k = (altitudeDataM[nextPointIdx] - altitudeDataM[prevPointIdx]) / |
| 146 | (distanceDataM[nextPointIdx] - distanceDataM[prevPointIdx]); |
| 147 | return static_cast<double>(altitudeDataM[prevPointIdx]) + k * (distFormStartM - distanceDataM[prevPointIdx]); |
| 148 | }; |
| 149 | |
| 150 | double const routeLenM = distanceDataM.back(); |
| 151 | uniformAltitudeDataM.resize(resultPointCount); |
| 152 | double const stepLenM = resultPointCount <= 1 ? 0.0 : routeLenM / (resultPointCount - 1); |
| 153 | |
| 154 | for (size_t i = 0; i < resultPointCount; ++i) |
| 155 | uniformAltitudeDataM[i] = calculateAltitude(static_cast<double>(i) * stepLenM); |
| 156 | |
| 157 | return true; |
| 158 | } |
| 159 | |
| 160 | bool GenerateYAxisChartData(uint32_t height, double minMetersPerPxl, vector<double> const & altitudeDataM, |
| 161 | vector<double> & yAxisDataPxl) |