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 decode(String encoded) { if (encoded.isEmpty) return const []; final List 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; } }