Files
backend/app/Services/PolylineEncoder.php
2026-06-10 14:37:36 +03:30

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);
}
}