| 287 | } |
| 288 | |
| 289 | std::string RecoverNearest(const std::string &short_code, |
| 290 | const LatLng &reference_location) { |
| 291 | if (!IsShort(short_code)) { |
| 292 | std::string code = short_code; |
| 293 | std::transform(code.begin(), code.end(), code.begin(), ::toupper); |
| 294 | return code; |
| 295 | } |
| 296 | // Ensure that latitude and longitude are valid. |
| 297 | double latitude = |
| 298 | adjust_latitude(reference_location.latitude, CodeLength(short_code)); |
| 299 | double longitude = normalize_longitude(reference_location.longitude); |
| 300 | // Compute the number of digits we need to recover. |
| 301 | size_t padding_length = |
| 302 | internal::kSeparatorPosition - short_code.find(internal::kSeparator); |
| 303 | // The resolution (height and width) of the padded area in degrees. |
| 304 | double resolution = |
| 305 | pow_neg(internal::kEncodingBase, 2.0 - (padding_length / 2.0)); |
| 306 | // Distance from the center to an edge (in degrees). |
| 307 | double half_res = resolution / 2.0; |
| 308 | // Use the reference location to pad the supplied short code and decode it. |
| 309 | LatLng latlng = {latitude, longitude}; |
| 310 | std::string padding_code = Encode(latlng); |
| 311 | CodeArea code_rect = |
| 312 | Decode(std::string(padding_code.substr(0, padding_length)) + |
| 313 | std::string(short_code)); |
| 314 | // How many degrees latitude is the code from the reference? If it is more |
| 315 | // than half the resolution, we need to move it north or south but keep it |
| 316 | // within -90 to 90 degrees. |
| 317 | double center_lat = code_rect.GetCenter().latitude; |
| 318 | double center_lng = code_rect.GetCenter().longitude; |
| 319 | if (latitude + half_res < center_lat && |
| 320 | center_lat - resolution > -internal::kLatitudeMaxDegrees) { |
| 321 | // If the proposed code is more than half a cell north of the reference |
| 322 | // location, it's too far, and the best match will be one cell south. |
| 323 | center_lat -= resolution; |
| 324 | } else if (latitude - half_res > center_lat && |
| 325 | center_lat + resolution < internal::kLatitudeMaxDegrees) { |
| 326 | // If the proposed code is more than half a cell south of the reference |
| 327 | // location, it's too far, and the best match will be one cell north. |
| 328 | center_lat += resolution; |
| 329 | } |
| 330 | // How many degrees longitude is the code from the reference? |
| 331 | if (longitude + half_res < center_lng) { |
| 332 | center_lng -= resolution; |
| 333 | } else if (longitude - half_res > center_lng) { |
| 334 | center_lng += resolution; |
| 335 | } |
| 336 | LatLng center_latlng = {center_lat, center_lng}; |
| 337 | return Encode(center_latlng, CodeLength(short_code) + padding_length); |
| 338 | } |
| 339 | |
| 340 | bool IsValid(const std::string &code) { |
| 341 | if (code.empty()) { |
no test coverage detected