|
| 1 | +--- |
| 2 | +slug: 2025/introducing-bytey |
| 3 | +title: Introducing Bytey - A Google Polyline Encoding library |
| 4 | +authors: [connort] |
| 5 | +tags: [php, google, polyline, encoding] |
| 6 | +--- |
| 7 | + |
| 8 | +One day we saw an interesting crash that one of our applications was generating a URL so long that Google's static map generation refused to generate it. With a bit of research we discovered lodged in the official [documentation](https://developers.google.com/maps/documentation/maps-static/start#url-size-restriction) that there was a known limit. |
| 9 | + |
| 10 | +:::note |
| 11 | + |
| 12 | +_Maps Static API URLs are restricted to 16384 characters in size. In practice, you will probably not have need for URLs longer than this, unless you produce complicated maps with a high number of markers and paths._ |
| 13 | + |
| 14 | +::: |
| 15 | + |
| 16 | +This led us to discovering that Google had the [Encoded Polyline Algorithm Format](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) designed to help pack information in the URL into a dense binary format in plain ASCII text in order to reduce characters. This blog is our journey to writing a little package to accomplish this in PHP. |
| 17 | + |
| 18 | +{/* truncate */} |
| 19 | + |
| 20 | +We did start with a bit of research if any library existed for this, but nothing we found existed in a modern PHP format with a software license we could leverage. Thankfully this was a 10-step algorithm that we could implement in a fresh new library. The algorithm works roughly in this way: |
| 21 | + |
| 22 | +1. Starts with the signed coordinate pairs (`(38.5, -120.2)`) |
| 23 | +2. Converts the values into integers that were rounded. (`3850000`, `-12020000`) |
| 24 | +3. Converts the values into binary, supporting negatives by using two's complement. |
| 25 | +4. Left shifting the binary one bit to optionally invert if negative. |
| 26 | +5. Break the binary value into 5-bit chunks reversed. |
| 27 | +6. Optionally OR each value with `0x20` if another chunk applies. |
| 28 | +7. Convert each value to decimal and add `63` to each one. |
| 29 | +8. Convert the value to ASCII (`_p~iF~ps|U`) |
| 30 | + |
| 31 | +You can see how `38.5` became `_p~iF` and `-120.2` became `~ps|U`. The first coordinate doesn't have much of a cost savings, but as the coordinate pairs continue and each pair has the offset from the previous you can tell how the data savings begin to take place. |
| 32 | + |
| 33 | +We wrote a quick PHPUnit test to confirm our implementation of the algorithm, and it matched Google's documentation. |
| 34 | + |
| 35 | +```php |
| 36 | +#[DataProvider('googleDataProvider')] |
| 37 | +public function test_google_polyline_encode(array $coordinates, string $expected): void { |
| 38 | + $this->assertEquals($expected, Bytey::googlePolylineEncode($coordinates)); |
| 39 | +} |
| 40 | + |
| 41 | +public static function googleDataProvider(): array { |
| 42 | + return [ |
| 43 | + 'simple example' => [ |
| 44 | + 'coordinates' => [ |
| 45 | + [-179.9832104], |
| 46 | + ], |
| 47 | + 'expected' => '`~oia@', |
| 48 | + ], |
| 49 | + 'rounding example' => [ |
| 50 | + 'coordinates' => [ |
| 51 | + [48.000006, 2.000004], |
| 52 | + [48.00001, 2.00000], |
| 53 | + ], |
| 54 | + 'expected' => 'a_~cH_seK??', |
| 55 | + ], |
| 56 | + 'google example' => [ |
| 57 | + 'coordinates' => [ |
| 58 | + [38.5, -120.2], |
| 59 | + [40.7, -120.95], |
| 60 | + [43.252, -126.453], |
| 61 | + ], |
| 62 | + 'expected' => '_p~iF~ps|U_ulLnnqC_mqNvxq`@', |
| 63 | + ], |
| 64 | + ]; |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +So we took our affected entity that was generating a 19.5k character URL and ran it through the algorithm. The new URL was 3.3k characters, which suggested an 83% reduction in character length. A few more real life tests, and we had a fix out the door and a new package built. |
| 69 | + |
| 70 | +Thus, [Bytey](https://github.com/sourcetoad/Bytey) was born. |
| 71 | + |
| 72 | +* [GitHub Repo](https://github.com/sourcetoad/Bytey) |
| 73 | +* [Google's Polyline Docs](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) |
0 commit comments