Skip to content

Update specification #463

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0414cd8
Add specifications
fulldecent Jun 4, 2021
fef6352
Remove outdated API recommendations (replaced by API specification)
fulldecent Jun 4, 2021
bf50614
Move implementations to Implementations/ and reference in README
fulldecent Jun 4, 2021
aec2a47
Consolidate normative references and documentation to Documentation/
fulldecent Jun 4, 2021
26352cb
Add tests for new normative behavior
fulldecent Jun 4, 2021
618ad5b
Fix typo
fulldecent Jun 4, 2021
d7a7a91
Bump both spec versions to 1.1.0
fulldecent Jun 7, 2021
e05cd31
Clean up overloading specification in API
fulldecent Jun 7, 2021
2ce7dca
Specify south west corner is included, add test cases
fulldecent Jun 7, 2021
8345cf4
Move poles onto the prime meridian
fulldecent Jun 7, 2021
aef4682
Factor out moving implementations and demos
fulldecent Jun 7, 2021
3e08100
Change "long code" to "full code"
bocops Jun 7, 2021
6929a0c
Merge pull request #1 from bocops/patch-1
fulldecent Jun 10, 2021
d4ef272
long code -> full code
fulldecent Jun 10, 2021
89063bd
Crisper modulo language
fulldecent Jun 10, 2021
ffe0a3a
Add breaking change warning for poles
fulldecent Jun 11, 2021
daa1c35
Show breaking change of API validation methods
fulldecent Jun 11, 2021
ce6bb6d
Mark breaking optional change
fulldecent Jun 11, 2021
d7c6d25
Remove (incorrect) copyright note
fulldecent Jun 11, 2021
a2b4168
Reword code length lookup
fulldecent Jun 11, 2021
33044f5
Longest edge is more specific about precision
fulldecent Jun 11, 2021
64ffd9c
Add case-insensitive notes to PCREs
fulldecent Jun 11, 2021
fe29a44
Remove calculation details from API spec, it is Plus Codes spec
fulldecent Jun 11, 2021
f0a9771
Shorten definition of "center"
fulldecent Jun 11, 2021
2e8ac0a
Specify REQURIED/OPTIONAL methods as breaking change
fulldecent Jun 13, 2021
a896494
Do not use fully qualified reference to "short code" and "long code"
fulldecent Jun 14, 2021
5752d8d
Define rectilinear distance
fulldecent Jun 14, 2021
362c8ec
Require isValid
fulldecent Jun 14, 2021
79ca2c2
To the moon and beyond!
fulldecent Jul 2, 2021
9a959bd
Merge branch 'main' into new-spec
fulldecent Feb 15, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 0 additions & 67 deletions API.txt

This file was deleted.

6 changes: 0 additions & 6 deletions CHANGELOG.md

This file was deleted.

178 changes: 178 additions & 0 deletions Documentation/Comparison.md

Large diffs are not rendered by default.

166 changes: 166 additions & 0 deletions Documentation/Introduction.md

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions Documentation/Open Location Code API Specification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Open Location Code API Reference Specification

## Version history

All substantial changes changes to this document are listed here.

* Version 1.1.0 / 2021-06-04 / [William Entriken](https://github.com/fulldecent/)
* Update to match nomenclature in [Plus Codes specification](./Plus%20Codes%20Specification.md)
* Specify the number of significant digits that a short code may omit
* `isFull`, `isShort`, `isValid` methods must now validate whether the input actually is a valid Plus Code ignoring case (breaking change, previously `true` could be returned for some invalid inputs)
* Public methods are specified as REQUIRED or OPTIONAL (breaking change: previously it may have been unclear which methods were REQUIRED)

- Version 1.0.0 / 2014-10-27 / [Doug Rinckes](https://github.com/drinckes), Google / Philipp Bunge, Google
- Initial public release

## REQUIRED public methods

An implementation of the Open Location Code API SHALL implement these REQUIRED methods:

| Method name | Input(s) | Output(s) |
| -------------------- | ------------------------------- | ------------------------------------------------------------ |
| `isValid` | Plus Code string | True if this is a Plus Code (full code or short code), false otherwise |
| `isFull` | Plus Code string | True if this is a full code, false otherwise |
| `encode` | Latitude, longitude | The Plus Code with code length 10 with area that contains the specified coordinates |
| `decode` | Full code string with code length 10 | The southern parallel and western meridian for the Plus Code area |

Implementations are RECOMMENDED to use the method names above.

Note: it is possible to implement `isFull` using a Perl Compatible Regular Expression, see the Plus Code specification and use case-insensitive matching.

## OPTIONAL public methods

An implementation MAY implement these methods.

| Method name | Input(s) | Output(s) |
| ------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| `isShort` | Plus Code string | True if this is a short code, false otherwise |
| `encode` | Latitude, longitude, code length | The full code with specified code length with area that contains the specified coordinates |
| `decode` | Full code string | The southern parallel and western meridian for the Plus Code area |
| `shorten` | Full code, reference location latitude and longitude | The short code representing the input where all significant digits that are allowed to be omitted are omitted; or if no digits are allowed to be omitted then the input is returned |
| `recoverNearest` | Short code, reference location latitude and longitude | The unique full code represented by the input |

Implementations are RECOMMENDED to use the method names above. Note that the OPTIONAL `decode` public method overrides and tightens the specification for the REQUIRED `decode` public method. Note that The OPTIONAL `encode` public method adds a parameter. This MAY be implemented as an overloaded method or another way that is customary for the programming language.

An implementation MAY implement `shorten` using separate `shortenBy4` and `shortenBy6` methods.

Note: it is possible to implement `isValid` and `isShort` using a Perl Compatible Regular Expression, see the Plus Code specification and use case-insensitive matching.

## REQUIREMENTS for all public methods

Implementations MUST follow these REQUIREMENTS for all public methods:

* Plus Code Inputs MUST treat non-upper-case inputs as if they were upper case.
* Plus Code outputs MUST be uppercase and conform to the [Plus Codes Specification].
* Latitude inputs MUST treat a latitude greater than 90° N as if it were the North Pole (i.e. at 90° N).
* Latitude inputs MUST treat a latitude lower than 90° S as if it were the South Pole (i.e. at 90° S).
* Longitude inputs MUST treat values outside the range from (including) 180° W to (excluding) 180° E as if they were the equivalent longitude in this range.
* Longitude inputs MUST NOT cause runtime performance linearly dependent on the longitude. E.g. use use a modulo operator, not a subtracting/adding while loop.

## OPTIONAL notes for all public methods

Implementations MAY follow these specifications for all public methods.

* Every public method that returns a southern parallel and western meridian may also return the northern parallel, the eastern meridian as well as the center. See definition of center in the Plus Codes specification.

## Implementation RECOMMENDATION

An implementation MAY use the following RECOMMENDATIONS.

- If latitude is 90° N or higher, directly return the Plus Code `C2X2X2X2+X2RRRRR`, truncated as necessary.
- If latitude is 90° S or lower, directly return the Plus Code `22222222+2222222`, truncated as necessary.
- If longitude is outside [180° W, 180° E), use a single modular calculation to enter the correct range.
- If your platform supports floating point numbers with mantissa of at least 35 bits (e.g. IEEE 754 double precision or better), then:
- Multiply the input latitude by 2.5e7 and the longitude by 8.192e7 one time. This prevents inaccurate floating point math resulting from repeated multiplications/divisions. All remaining calculations can be done using base-20, base-4 and base-5 math on this integer value.
- If your platform only supports floating point numbers with mantissa up to 24 bits (e.g. IEEE 754 single precision) then your application will not produce accurate results in all cases for Plus Codes with code length greater than 12. This should produce a warning or error if greater than this precision is requested.

## References

- [Plus Codes specification](./Plus%20Codes%20Specification.md)
122 changes: 122 additions & 0 deletions Documentation/Plus Codes Specification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Plus Codes Specification

## Version history

All substantial changes changes to this document are listed here.

* Version 1.1.0 / 2021-06-04 / [William Entriken](https://github.com/fulldecent/)
* Separate Plus Codes specification from [Open Location Code API specification](./Open Location Code API Specification.md)
* Define one code for the North Pole at each code level
* Define one code for the South Pole at each code level (breaking change, previously many codes included the South Pole)
* Specify which code levels of full codes may be shortened to which code levels of short codes
* Establish consistent wording/naming
* Version 1.0.0 / 2019-04-29 / [Doug Rinckes](https://github.com/drinckes), Google / Philipp Bunge, Google
* Initial public release

## Area and bounds

A **Plus Code** represents a locus of coordinates ("**area**") with **bounds** on northern & southern parallels and western & eastern meridians. This area includes exactly the coordinates:

1. Inside (excluding) the bounds;
2. On the western bound between (excluding) the northern and southern bounds;
3. (If the northern bound is 90° N and the western bound is 0° W) the North Pole (i.e. the point at 90° N);
4. (If the southern bound is 90° S and the western bound is 0° W) the South Pole (i.e. the point at 90° S); and
5. (If the southern bound is not 90° S) on the southern bound from (including) the western bound to (excluding) the eastern bound.

This specification references latitudes and longitudes on a sphere which MUST be agreed between the producer and consumer of a Plus Code. Typically Earth and the [WGS 84 geodetic](https://earth-info.nga.mil) are used, which is the standard used by the Global Positioning System.

The **center** of a Plus Code is defined as the arithmetic mean of its bound's parallels and meridians.

## Precision

Plus Codes are characterized by their **code length**. This specifies the distance between the northern & southern bounds and the western & eastern bounds. Plus codes MUST use one of these code lengths:

| Code length | North-south distance | West-east distance | Longest edge |
| :---------: | -------------------- | ------------------ | :----------: |
| 2 | 20 degrees | 20 degrees | < 2300 km |
| 4 | 1 degrees | 1 degrees | < 120 km |
| 6 | 1/20 degrees | 1/20 degrees | < 5.6 km |
| 8 | 1/400 degrees | 1/400 degrees | < 280 meters |
| 10 | 1/8000 degrees | 1/8000 degrees | < 14 meters |
| 11 | 1/40000 degrees | 1/32000 degrees | < 4 meters |
| 12 | 1/200000 degrees | 1/128000 degrees | < 90 cm |
| 13 | 1/1e6 degrees | 1/512000 degrees | < 22 cm |
| 14 | 1/5e6 degrees | 1/2.048e6 degrees | < 6 cm |
| 15 | 1/2.5e7 degrees | 1/8.192e7 degrees | < 14 mm |

Longest edges above are provided for informational purposes only and are not normative, these assume a Plus Code over Earth with the WGS 84 geodetic.

## Formatting

A Plus Code consists of two or more **significant digits**, zero or more **padding characters** and exactly one **format separator**. Plus Code formatting has been selected to reduce writing errors and prevent spelling words.

There are eight **digit places** to the left of the **format separator** and seven to the right:

<kbd>1</kbd><kbd>2</kbd><kbd>3</kbd><kbd>4</kbd><kbd>5</kbd><kbd>6</kbd><kbd>7</kbd><kbd>8</kbd><kbd>+</kbd><kbd>9</kbd><kbd>10</kbd><kbd>11</kbd><kbd>12</kbd><kbd>13</kbd><kbd>14</kbd><kbd>15</kbd>

Plus Codes SHALL NOT be formatted differently for right-to-left languages. This avoids ambiguity.

A significant digit represents a numeric value as:

| Value | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
| ----- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- |
| Digit | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | C | F | G | H | J | M | P | Q | R | V | W | X |

The padding character is defined as the zero ("0") character ([U+0030](http://unicode.org/charts/PDF/U0000.pdf)).

The format separator is defined as the plus ("+") character ([U+002B](http://unicode.org/charts/PDF/U0000.pdf)).

## Encoding

A Plus Code uses significant digits to encode its southern and western bounds. The significant digits of a Plus Code represent latitude (north) and then longitude (east) offsets from the starting location 90° S, 180° W.

A significant digit in digit places 1, 3, 5, 7 and 9 represents an offset north equal to the north-south distance for that code length (find the code length for one more than the digit place in the code length table above) multiplied by the significant digit value.

A significant digit in digit places 2, 4, 6, 8 and 10 represents an offset east equal to the west-east distance for that code length multiplied by the significant digit value.

A significant digit in places 11 and higher represents:

* an offset north equal to the north-south distance for that code length multiplied by (the significant digit value divided by four and rounded down)
* an offset east equal to the west-east distance for that code length multiplied by (the significant digit value modulo 4)

<kbd>N</kbd><kbd>E</kbd><kbd>N</kbd><kbd>E</kbd><kbd>N</kbd><kbd>E</kbd><kbd>N</kbd><kbd>E</kbd><kbd>+</kbd><kbd>N</kbd><kbd>E</kbd><kbd>X</kbd><kbd>X</kbd><kbd>X</kbd><kbd>X</kbd><kbd>X</kbd>

:information_source: Note that latitudes greater than 90° N do not exist and therefore the digit place 1 MUST only have values 0–8. Likewise, digit place 2 MUST only have values 0–17.

## Full code

A **full code** representation of a Plus Code is globally usable and requires no other reference to interpret.

Every full code MUST include significant digits in digit places 1 up through the code length. If the code length is less than 8, then the padding character is placed in digit places after the last significant digit up to and including the 8th digit place. The format separator is added after the 8th digit place.

Therefore, the set of full codes exactly matches the [Perl Compatible Regular Expression](http://pcre.org):

````perl
/^[2-9C][2-9CFGHJMPQRV](0{6}\+|[2-9CFGHJMPQRVWX]{2}(0000\+|[2-9CFGHJMPQRVWX]{2}(00\+|[2-9CFGHJMPQRVWX]{2}\+([2-9CFGHJMPQRVWX]{2,7})?)))$/
````

The full code representation is the default representation of a Plus Code.

## Short code

A **short code** representation of a Plus Code is meaningful only when the producer and consumer agree on the approximate latitude and longitude of a **reference location**. A short code can be easier to use and remember than a full code.

Plus Codes with code length less than 8 SHALL NOT be represented as short codes.

The **2-D rectilinear distance** between two latitude/longitude coordinates is defined as the sum of (the absolute difference of latitudes) and (the absolute difference of longitudes).

The 2-D rectilinear distance distance between a Plus Code's center and a reference location determines which digit places can be omitted in the short code representation:

* If both distances are less than 10 degrees, digit places 1–2 MAY be omitted.
Copy link
Contributor

@bocops bocops Jun 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementations actually use a magic number of 0.3* the distances given here, and I believe I've also seen multiplying by 0.4 suggested somewhere (probably the Wiki). I agree that being mathematically exact is preferable to strange magic numbers, but should these be integrated here somehow at least as a suggestion for a safety margin?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! This is built into the spec under "Short codes" where it specifies the "if both distances..." part. These use half the distance as the precision amount for that code level.

I believe this amounts to 50% margin. Is that correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true that, with an exact reference location agreed upon between both parties, a short code can be recovered within one full code area for any given code level (e.g. within +/- 10° if the full code was shortened by two digits). However, often the reference locations aren't exact, so to make short codes more useful many parts of the current documentation warn about pushing the limits where this isn't necessary.

For example, this wiki page mentions a safety margin of 20% (which I falsely remembered as a factor of 0.4 - should of course be 0.8): https://github.com/google/open-location-code/wiki/Guidance-for-shortening-codes

That page, by the way, is referenced from this repo's README, which also states:

If the reference location is derived from a town or city name, it is dependent on the accuracy of the geocoding service. Although one service may place "Zurich" close to the Google office, another may move it by a hundred meters or more, and this could be enough to prevent the original code being recovered. Rather than a large city size feature to generate the reference location, it is better to use smaller, neighbourhood features, that will not have as much variation in their geocode results.

Guidelines for shortening codes are in the wiki.

Recovering shortened codes works by providing the short code and a reference location. This does not need to be the same as the location used to shorten the code, but it does need to be nearby.

* If both distances are less than 0.5 degrees, digit places 1–2 or 1–4 MAY be omitted.
* If both distances are less than 1/40 degrees, digit places 1–2, 1–4 or 1–6 MAY be omitted.

A short code represents the unique full code Plus Code nearest (minimal 2-D rectilinear distance, prefer southernmost and westernmost if tied) to the reference location.

:information_source: Note that omitted digits places of a short code will not necessarily be the same as the reference location.

Therefore, the set of short code representations exactly matches the Perl Compatible Regular Expression:

```perl
/^([2-9CFGHJMPQRVWX]{2})?([2-9CFGHJMPQRVWX]{2})?[2-9CFGHJMPQRVWX]{2}\+([2-9CFGHJMPQRVWX]{2,7})?$/
```
File renamed without changes
File renamed without changes
Loading