| 120 | } // anonymous namespace |
| 121 | |
| 122 | std::string Encode(const LatLng &location, size_t code_length) { |
| 123 | // Limit the maximum number of digits in the code. |
| 124 | code_length = std::min(code_length, internal::kMaximumDigitCount); |
| 125 | // Adjust latitude and longitude so that they are normalized/clipped. |
| 126 | double latitude = adjust_latitude(location.latitude, code_length); |
| 127 | double longitude = normalize_longitude(location.longitude); |
| 128 | // Reserve 15 characters for the code digits. The separator will be inserted |
| 129 | // at the end. |
| 130 | std::string code = "123456789abcdef"; |
| 131 | |
| 132 | // Compute the code. |
| 133 | // This approach converts each value to an integer after multiplying it by |
| 134 | // the final precision. This allows us to use only integer operations, so |
| 135 | // avoiding any accumulation of floating point representation errors. |
| 136 | |
| 137 | // Multiply values by their precision and convert to positive without any |
| 138 | // floating point operations. |
| 139 | int64_t lat_val = |
| 140 | internal::kLatitudeMaxDegrees * internal::kGridLatPrecisionInverse; |
| 141 | int64_t lng_val = |
| 142 | internal::kLongitudeMaxDegrees * internal::kGridLngPrecisionInverse; |
| 143 | lat_val += latitude * internal::kGridLatPrecisionInverse; |
| 144 | lng_val += longitude * internal::kGridLngPrecisionInverse; |
| 145 | |
| 146 | size_t pos = internal::kMaximumDigitCount - 1; |
| 147 | // Compute the grid part of the code if necessary. |
| 148 | if (code_length > internal::kPairCodeLength) { |
| 149 | for (size_t i = 0; i < internal::kGridCodeLength; i++) { |
| 150 | int lat_digit = lat_val % internal::kGridRows; |
| 151 | int lng_digit = lng_val % internal::kGridColumns; |
| 152 | int ndx = lat_digit * internal::kGridColumns + lng_digit; |
| 153 | code.replace(pos--, 1, 1, internal::kAlphabet[ndx]); |
| 154 | // Note! Integer division. |
| 155 | lat_val /= internal::kGridRows; |
| 156 | lng_val /= internal::kGridColumns; |
| 157 | } |
| 158 | } else { |
| 159 | lat_val /= pow(internal::kGridRows, internal::kGridCodeLength); |
| 160 | lng_val /= pow(internal::kGridColumns, internal::kGridCodeLength); |
| 161 | } |
| 162 | pos = internal::kPairCodeLength - 1; |
| 163 | // Compute the pair section of the code. |
| 164 | for (size_t i = 0; i < internal::kPairCodeLength / 2; i++) { |
| 165 | int lat_ndx = lat_val % internal::kEncodingBase; |
| 166 | int lng_ndx = lng_val % internal::kEncodingBase; |
| 167 | code.replace(pos--, 1, 1, internal::kAlphabet[lng_ndx]); |
| 168 | code.replace(pos--, 1, 1, internal::kAlphabet[lat_ndx]); |
| 169 | // Note! Integer division. |
| 170 | lat_val /= internal::kEncodingBase; |
| 171 | lng_val /= internal::kEncodingBase; |
| 172 | } |
| 173 | |
| 174 | // Add the separator character. |
| 175 | code.insert(internal::kSeparatorPosition, &(internal::kSeparator), 1); |
| 176 | |
| 177 | // If we don't need to pad the code, return the requested section. |
| 178 | if (code_length >= internal::kSeparatorPosition) { |
| 179 | return code.substr(0, code_length + 1); |
no test coverage detected