85 lines
2.1 KiB
Dart
85 lines
2.1 KiB
Dart
import '../models/gps_coordinate.dart';
|
|
|
|
/// أداة ترميز وفك ترميز Polyline
|
|
/// تستخدم خوارزمية Google Encoded Polyline لضغط المسارات بنسبة ~95%
|
|
class PolylineUtility {
|
|
/// Encode a list of GPS coordinates to a polyline string
|
|
static String encode(List<GpsCoordinate> coordinates) {
|
|
if (coordinates.isEmpty) return '';
|
|
|
|
final buffer = StringBuffer();
|
|
int prevLat = 0;
|
|
int prevLng = 0;
|
|
|
|
for (final point in coordinates) {
|
|
int lat = (point.latitude * 1e5).round();
|
|
int lng = (point.longitude * 1e5).round();
|
|
|
|
_encodeValue(lat - prevLat, buffer);
|
|
_encodeValue(lng - prevLng, buffer);
|
|
|
|
prevLat = lat;
|
|
prevLng = lng;
|
|
}
|
|
|
|
return buffer.toString();
|
|
}
|
|
|
|
/// Decode a polyline string back to coordinates
|
|
static List<GpsCoordinate> decode(String encoded) {
|
|
if (encoded.isEmpty) return [];
|
|
|
|
final coordinates = <GpsCoordinate>[];
|
|
int index = 0;
|
|
int lat = 0;
|
|
int lng = 0;
|
|
|
|
while (index < encoded.length) {
|
|
lat += _decodeValue(encoded, index);
|
|
index = _lastIndex;
|
|
|
|
if (index >= encoded.length) break;
|
|
|
|
lng += _decodeValue(encoded, index);
|
|
index = _lastIndex;
|
|
|
|
coordinates.add(GpsCoordinate(
|
|
latitude: lat / 1e5,
|
|
longitude: lng / 1e5,
|
|
timestamp: DateTime.now(), // Polylines don't store timestamps
|
|
));
|
|
}
|
|
|
|
return coordinates;
|
|
}
|
|
|
|
// Internal tracking for decode position
|
|
static int _lastIndex = 0;
|
|
|
|
static void _encodeValue(int value, StringBuffer buffer) {
|
|
int v = value < 0 ? ~(value << 1) : (value << 1);
|
|
while (v >= 0x20) {
|
|
buffer.writeCharCode((0x20 | (v & 0x1f)) + 63);
|
|
v >>= 5;
|
|
}
|
|
buffer.writeCharCode(v + 63);
|
|
}
|
|
|
|
static int _decodeValue(String encoded, int startIndex) {
|
|
int result = 0;
|
|
int shift = 0;
|
|
int index = startIndex;
|
|
|
|
while (index < encoded.length) {
|
|
int byte = encoded.codeUnitAt(index) - 63;
|
|
index++;
|
|
result |= (byte & 0x1f) << shift;
|
|
shift += 5;
|
|
if (byte < 0x20) break;
|
|
}
|
|
|
|
_lastIndex = index;
|
|
return (result & 1) != 0 ? ~(result >> 1) : (result >> 1);
|
|
}
|
|
}
|