72 lines
2.2 KiB
Dart
72 lines
2.2 KiB
Dart
import '../map/map_provider_interface.dart';
|
|
|
|
/// Decodes Valhalla's precision-6 encoded polyline into standard AppLatLng coordinates.
|
|
class ValhallaPolylineDecoder {
|
|
/// Decodes precision-6 polyline string into a list of [AppLatLng].
|
|
///
|
|
/// Throws [FormatException] if the encoded string is truncated, contains
|
|
/// invalid character codes (< 63), or resolves to coordinates outside valid
|
|
/// geographic bounds (lat: [-90, 90], lng: [-180, 180]).
|
|
static List<AppLatLng> decode(String encoded) {
|
|
if (encoded.isEmpty) return const [];
|
|
|
|
final List<AppLatLng> polyline = [];
|
|
int index = 0;
|
|
int lat = 0;
|
|
int lng = 0;
|
|
final int len = encoded.length;
|
|
|
|
while (index < len) {
|
|
// Decode latitude delta
|
|
int b;
|
|
int shift = 0;
|
|
int result = 0;
|
|
do {
|
|
if (index >= len) {
|
|
throw const FormatException('Truncated polyline data while reading latitude');
|
|
}
|
|
final code = encoded.codeUnitAt(index++);
|
|
if (code < 63) {
|
|
throw FormatException('Invalid polyline character at index ${index - 1}: code $code');
|
|
}
|
|
b = code - 63;
|
|
result |= (b & 0x1f) << shift;
|
|
shift += 5;
|
|
} while (b >= 0x20);
|
|
|
|
final int dlat = (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
|
|
lat += dlat;
|
|
|
|
// Decode longitude delta
|
|
shift = 0;
|
|
result = 0;
|
|
do {
|
|
if (index >= len) {
|
|
throw const FormatException('Truncated polyline data while reading longitude');
|
|
}
|
|
final code = encoded.codeUnitAt(index++);
|
|
if (code < 63) {
|
|
throw FormatException('Invalid polyline character at index ${index - 1}: code $code');
|
|
}
|
|
b = code - 63;
|
|
result |= (b & 0x1f) << shift;
|
|
shift += 5;
|
|
} while (b >= 0x20);
|
|
|
|
final int dlng = (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
|
|
lng += dlng;
|
|
|
|
final latDeg = lat / 1e6;
|
|
final lngDeg = lng / 1e6;
|
|
|
|
if (latDeg < -90.0 || latDeg > 90.0 || lngDeg < -180.0 || lngDeg > 180.0) {
|
|
throw FormatException('Decoded coordinate out of geographic bounds: ($latDeg, $lngDeg)');
|
|
}
|
|
|
|
polyline.add(AppLatLng(latDeg, lngDeg));
|
|
}
|
|
|
|
return polyline;
|
|
}
|
|
}
|