Skip to content

Commit c522748

Browse files
authored
feat: bytey blog (#49)
* feat: bytey blog * feat: add example
1 parent 7f9e87e commit c522748

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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+
Imagine if we went to draw a box around our office we might get the coordinate pairs of:
34+
35+
* `28.03630, -82.49009`
36+
* `28.03654, -82.49009`
37+
* `28.03655, -82.49099`
38+
* `28.03629, -82.49100`
39+
* `28.03630, -82.49009`
40+
41+
This helps establish the point that most coordinates are just small iterations of the previous coordinate -- not shifting much in terms of the positioning. If we were to render those with a 19 zoom we'd get this image.
42+
43+
<div class="text--center">
44+
![](./static-map-google.png)
45+
</div>
46+
47+
This would form a URL that compounded the coordinate pairs to draw the lines.
48+
49+
```
50+
&markers=28.03630,-82.49009,28.03654,-82.49009,28.03655,-82.49099,28.03629,-82.49100,28.03630,-82.49009
51+
```
52+
53+
If we apply the algorithm we see a much smaller URL decreasing 94 characters to 22.
54+
55+
```
56+
&markers={ybjD`jnvNo@?ArDr@@AuD
57+
```
58+
59+
This was a savings of ~75% less characters and was promising for a real integration. We wrote a quick PHPUnit test to confirm our implementation of the algorithm, and it matched Google's documentation.
60+
61+
```php
62+
#[DataProvider('googleDataProvider')]
63+
public function test_google_polyline_encode(array $coordinates, string $expected): void {
64+
$this->assertEquals($expected, Bytey::googlePolylineEncode($coordinates));
65+
}
66+
67+
public static function googleDataProvider(): array {
68+
return [
69+
'simple example' => [
70+
'coordinates' => [
71+
[-179.9832104],
72+
],
73+
'expected' => '`~oia@',
74+
],
75+
'rounding example' => [
76+
'coordinates' => [
77+
[48.000006, 2.000004],
78+
[48.00001, 2.00000],
79+
],
80+
'expected' => 'a_~cH_seK??',
81+
],
82+
'google example' => [
83+
'coordinates' => [
84+
[38.5, -120.2],
85+
[40.7, -120.95],
86+
[43.252, -126.453],
87+
],
88+
'expected' => '_p~iF~ps|U_ulLnnqC_mqNvxq`@',
89+
],
90+
];
91+
}
92+
```
93+
94+
So we took our affected entity that was generating a 19.5k character length URL and ran it through the algorithm. The new URL was 3.3k characters, which suggested an 83% reduction in length in a more real life example. A few more real life tests, and we had a fix out the door and a new package built.
95+
96+
Thus, [Bytey](https://github.com/sourcetoad/Bytey) was born.
97+
98+
* [GitHub Repo](https://github.com/sourcetoad/Bytey)
99+
* [Google's Polyline Docs](https://developers.google.com/maps/documentation/utilities/polylinealgorithm)
13 KB
Loading

0 commit comments

Comments
 (0)