89 lines
2.4 KiB
PHP
89 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
/**
|
|
* Class PolylineEncoder
|
|
*
|
|
* Encodes a list of latitude/longitude coordinates into an encoded polyline string.
|
|
*
|
|
* This implementation is compatible with Google's Polyline Algorithm Format:
|
|
* https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
|
*
|
|
* Example input:
|
|
* [
|
|
* [lat, lng],
|
|
* [lat, lng]
|
|
* ]
|
|
*
|
|
* or if `$lng_lat_format = true`:
|
|
* [
|
|
* [lng, lat],
|
|
* [lng, lat]
|
|
* ]
|
|
*
|
|
* @package App\Services
|
|
*/
|
|
class PolylineEncoder
|
|
{
|
|
/**
|
|
* Encode an array of coordinates into a polyline string.
|
|
*
|
|
* Each coordinate is encoded as a delta from the previous point,
|
|
* scaled by the given precision factor.
|
|
*
|
|
* @param array $coords Array of coordinate pairs:
|
|
* - default: [lat, lng]
|
|
* - if $lng_lat_format = true: [lng, lat]
|
|
* @param int $precision Number of decimal places to preserve (default: 6)
|
|
* @param bool $lng_lat_format If true, input is treated as [lng, lat] instead of [lat, lng]
|
|
*
|
|
* @return string Encoded polyline string
|
|
*/
|
|
public function encodePolyline(array $coords, int $precision = 6, bool $lng_lat_format = false): string
|
|
{
|
|
$factor = 10 ** $precision;
|
|
$output = '';
|
|
$prevLat = 0;
|
|
$prevLng = 0;
|
|
|
|
foreach ($coords as [$a, $b]) {
|
|
[$lat, $lng] = $lng_lat_format ? [$b, $a] : [$a, $b];
|
|
|
|
$output .= $this->encodeValue((int)round($lat * $factor) - $prevLat);
|
|
$output .= $this->encodeValue((int)round($lng * $factor) - $prevLng);
|
|
|
|
$prevLat = (int)round($lat * $factor);
|
|
$prevLng = (int)round($lng * $factor);
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Encodes a single integer value using Google's polyline encoding algorithm.
|
|
*
|
|
* Steps:
|
|
* - Left shift the value
|
|
* - Invert bits if negative
|
|
* - Split into 5-bit chunks
|
|
* - Convert to ASCII characters
|
|
*
|
|
* @param int $value Signed integer delta to encode
|
|
*
|
|
* @return string Encoded character sequence
|
|
*/
|
|
public function encodeValue(int $value): string
|
|
{
|
|
$value = $value < 0 ? ~($value << 1) : ($value << 1);
|
|
$result = '';
|
|
|
|
while ($value >= 0x20) {
|
|
$result .= chr((0x20 | ($value & 0x1f)) + 63);
|
|
$value >>= 5;
|
|
}
|
|
|
|
return $result . chr($value + 63);
|
|
}
|
|
}
|