├── .bazeliskrc
├── .bazelrc
├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── Documentation
├── External_Implementations.md
├── FAQ.md
├── README.md
├── Reference
│ ├── App_Developers.md
│ ├── Field_Collection_Data_Practices.md
│ ├── GIS_Software.md
│ ├── Plus_Code_Users.md
│ ├── Using_Spreadsheets.md
│ ├── comparison.adoc
│ └── plus.codes_Website_API.md
├── Specification
│ ├── Naming_Guidelines.md
│ ├── olc_definition.adoc
│ └── specification.md
└── images
│ ├── code_areas.png
│ ├── geohash36_grid.png
│ ├── olc_10_character.png
│ ├── olc_11_grid.png
│ └── openpostcode_grid.png
├── FAQ.txt
├── LICENSE
├── MODULE.bazel
├── README.md
├── TESTING.md
├── WORKSPACE
├── android_demo
├── .gitignore
├── README.md
├── android
│ ├── build.gradle
│ ├── libs
│ │ └── README.md
│ ├── proguard-rules.pro
│ └── src
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── com
│ │ │ └── openlocationcode
│ │ │ └── android
│ │ │ ├── code
│ │ │ ├── CodeContract.java
│ │ │ ├── CodePresenter.java
│ │ │ ├── CodeView.java
│ │ │ └── OpenLocationCodeUtil.java
│ │ │ ├── current
│ │ │ ├── GoogleApiModule.java
│ │ │ ├── LocationProvider.java
│ │ │ ├── LocationProviderFactoryComponent.java
│ │ │ └── LocationUtil.java
│ │ │ ├── direction
│ │ │ ├── Direction.java
│ │ │ ├── DirectionContract.java
│ │ │ ├── DirectionPresenter.java
│ │ │ ├── DirectionUtil.java
│ │ │ └── DirectionView.java
│ │ │ ├── localities
│ │ │ └── Locality.java
│ │ │ ├── main
│ │ │ ├── MainActivity.java
│ │ │ ├── MainFragment.java
│ │ │ ├── MainPresenter.java
│ │ │ └── WelcomeActivity.java
│ │ │ ├── map
│ │ │ ├── MapContract.java
│ │ │ ├── MapPresenter.java
│ │ │ └── MyMapView.java
│ │ │ └── search
│ │ │ ├── AutoCompleteEditor.java
│ │ │ ├── SearchContract.java
│ │ │ ├── SearchPresenter.java
│ │ │ └── SearchView.java
│ │ └── res
│ │ ├── drawable-hdpi
│ │ ├── ic_action_maps_navigation.png
│ │ ├── ic_launcher.png
│ │ ├── map_center.png
│ │ └── welcome_image.png
│ │ ├── drawable-ldpi
│ │ └── map_center.png
│ │ ├── drawable-mdpi
│ │ ├── ic_action_maps_navigation.png
│ │ ├── ic_launcher.png
│ │ └── map_center.png
│ │ ├── drawable-xhdpi
│ │ ├── ic_action_maps_navigation.png
│ │ ├── ic_launcher.png
│ │ ├── map_center.png
│ │ └── welcome_image.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_action_maps_navigation.png
│ │ ├── ic_launcher.png
│ │ ├── map_center.png
│ │ └── welcome_image.png
│ │ ├── drawable-xxxhdpi
│ │ ├── ic_action_maps_navigation.png
│ │ ├── ic_launcher.png
│ │ └── map_center.png
│ │ ├── drawable
│ │ ├── map_satellite_button.xml
│ │ ├── rounded_layout.xml
│ │ └── search_button.xml
│ │ ├── layout
│ │ ├── code.xml
│ │ ├── direction.xml
│ │ ├── main_act.xml
│ │ ├── main_frag.xml
│ │ ├── my_map.xml
│ │ ├── search.xml
│ │ └── welcome.xml
│ │ ├── menu
│ │ └── share_menu.xml
│ │ ├── values-pt
│ │ └── strings.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
├── build.gradle
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── openlocationcode_android.iml
└── settings.gradle
├── c
├── .clang-format
├── .gitignore
├── BUILD
├── README.md
├── benchmark
│ ├── .gitignore
│ ├── Makefile
│ ├── bm-c.c
│ ├── bm-cpp.cc
│ └── shared.c
├── clang_check.sh
├── example.c
├── openlocationcode_test.cc
└── src
│ ├── olc.c
│ ├── olc.h
│ └── olc_private.h
├── cpp
├── .clang-format
├── .gitignore
├── BUILD
├── README.md
├── clang_check.sh
├── codearea.cc
├── codearea.h
├── openlocationcode.cc
├── openlocationcode.h
├── openlocationcode_example.cc
└── openlocationcode_test.cc
├── dart
├── .gitignore
├── README.md
├── checks.sh
├── lib
│ ├── open_location_code.dart
│ └── src
│ │ └── open_location_code.dart
├── pubspec.yaml
└── test
│ ├── benchmark_test.dart
│ ├── clip_latitude_test.dart
│ ├── compute_precision_test.dart
│ ├── decode_test.dart
│ ├── encode_test.dart
│ ├── short_code_test.dart
│ ├── utils.dart
│ └── validity_test.dart
├── garmin
└── PlusCodeDatafield
│ ├── .project
│ ├── README.md
│ ├── manifest.xml
│ ├── monkey.jungle
│ ├── resources-d2bravo
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-d2bravo_titanium
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-edge1030
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-edge1030bontrager
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-edge130
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-edge520plus
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-edge820
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-edge_1000
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-edge_520
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-epix
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fenix3
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fenix3_hr
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fenix5
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fenix5plus
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fenix5s
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fenix5x
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fenixchronos
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fr235
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fr630
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fr645
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fr645m
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fr735xt
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fr920xt
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-fr935
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-oregon7xx
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-rino7xx
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-vivoactive
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-vivoactive3
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-vivoactive3m
│ ├── drawables.xml
│ └── launcher_icon.png
│ ├── resources-vivoactive_hr
│ ├── drawables.xml
│ ├── launcher_icon.png
│ └── resources-fenix3_hr
│ │ ├── drawables.xml
│ │ └── launcher_icon.png
│ ├── resources
│ ├── drawables.xml
│ ├── launcher_icon.png
│ ├── layouts.xml
│ └── strings.xml
│ └── source
│ ├── PlusCodeBackground.mc
│ ├── PlusCodeDatafield.mc
│ └── PlusCodeView.mc
├── go
├── .gitignore
├── README.md
├── corpus
│ ├── .gitignore
│ └── gen.go
├── decode.go
├── encode.go
├── go.mod
├── go.sum
├── olc.go
├── olc_gofuzz.go
├── olc_test.go
└── shorten.go
├── java
├── .gitignore
├── BUILD
├── README.md
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── com
│ │ └── google
│ │ └── openlocationcode
│ │ └── OpenLocationCode.java
│ └── test
│ └── java
│ └── com
│ └── google
│ └── openlocationcode
│ ├── BenchmarkTest.java
│ ├── DecodingTest.java
│ ├── EncodingTest.java
│ ├── PrecisionTest.java
│ ├── RecoverTest.java
│ ├── ShorteningTest.java
│ ├── TestUtils.java
│ ├── UtilsTest.java
│ └── ValidityTest.java
├── js
├── .eslintrc.js
├── README.md
├── checks.sh
├── closure
│ ├── BUILD
│ ├── README.md
│ ├── openlocationcode.js
│ └── openlocationcode_test.js
├── contrib
│ ├── README.md
│ ├── olc_grid_overlay.js
│ └── olc_grid_overlay.min.js
├── examples
│ ├── example1.html
│ ├── example2.html
│ ├── example3.html
│ ├── examples.css
│ └── examples.js
├── gulpfile.js
├── package.json
├── src
│ ├── openlocationcode.js
│ └── openlocationcode.min.js
└── test
│ ├── jasmine-tests.js
│ └── karma.config.js
├── package.json
├── plpgsql
├── README.md
├── pluscode_functions.sql
└── tests_script_l.sql
├── python
├── .gitignore
├── .style.yapf
├── BUILD
├── README.md
├── format_check.sh
├── openlocationcode
│ ├── __init__.py
│ └── openlocationcode.py
├── openlocationcode_test.py
└── setup.py
├── ruby
├── README.md
├── lib
│ ├── plus_codes.rb
│ └── plus_codes
│ │ ├── code_area.rb
│ │ └── open_location_code.rb
├── open-location-code.gemspec
├── rubocop.yml
└── test
│ └── plus_codes_test.rb
├── rust
├── Cargo.toml
├── README.md
├── src
│ ├── codearea.rs
│ ├── consts.rs
│ ├── interface.rs
│ ├── lib.rs
│ └── private.rs
└── tests
│ ├── all_test.rs
│ └── csv_reader.rs
├── test_data
├── BUILD
├── csv_to_json.go
├── decoding.csv
├── encoding.csv
├── shortCodeTests.csv
└── validityTests.csv
├── tile_server
├── README.md
├── example.html
├── gridserver
│ ├── geojson.go
│ ├── geojson_test.go
│ ├── go.mod
│ ├── go.sum
│ ├── gridserver.go
│ ├── image.go
│ ├── image_test.go
│ ├── mvt.go
│ ├── mvt_test.go
│ ├── projection.go
│ ├── projection_test.go
│ ├── testdata
│ │ ├── 21_1098232_1362659.json
│ │ ├── 21_1098232_1362659.mvt
│ │ ├── 21_1098232_1362659.png
│ │ ├── 21_1098232_1362659_geodetic.json
│ │ ├── 21_1098232_1362659_geodetic.mvt
│ │ ├── 21_1098232_1362659_geodetic.png
│ │ ├── 5_17_19.json
│ │ ├── 5_17_19.mvt
│ │ ├── 5_17_19.png
│ │ ├── 5_17_19_geodetic.json
│ │ ├── 5_17_19_geodetic.mvt
│ │ ├── 5_17_19_white_zoom_2.png
│ │ ├── 5_17_19_zoom_2.json
│ │ └── 5_17_19_zoom_2.mvt
│ └── tileref.go
└── main.go
└── visualbasic
├── OpenLocationCode.bas
└── README.md
/.bazeliskrc:
--------------------------------------------------------------------------------
1 | # Set options for Bazelisk, a wrapper for Bazel.
2 |
3 | # Set the version of Bazel to use.
4 | # TODO: #642 -- Update once the JS bazelbuild/rules_closure supports bazel modules.
5 | USE_BAZEL_VERSION=7.4.1
6 |
--------------------------------------------------------------------------------
/.bazelrc:
--------------------------------------------------------------------------------
1 | # Reduce OOM errors on TravisCI
2 | startup --host_jvm_args=-Xms500m
3 | startup --host_jvm_args=-Xmx500m
4 | startup --host_jvm_args=-XX:-UseParallelGC
5 | # build --local_resources=400,2,1.0
6 | build --worker_max_instances=auto
7 |
8 | # Configure tests - increase timeout, print everything and timeout warnings
9 | test --verbose_failures --test_output=all --test_verbose_timeout_warnings
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore backup and swap files.
2 | *~
3 | .*.swp
4 | # Bazel module lock file.
5 | MODULE.bazel.lock
6 | # Ignore all bazel-* links.
7 | /bazel-*
8 | # Ignore outputs generated during Bazel bootstrapping.
9 | /output/
10 | # Ignore compiled files
11 | **/target/
12 | # Ignore intelliJ auto generated dir
13 | **/.idea/
14 | # Ignore iml extensions files
15 | **/*.iml
16 | # Ignore visual studio auto generated dir
17 | **/.vscode/
18 | # Ignore JS NPM modules
19 | /js/node_modules/
20 | /js/package-lock.json
21 | # Ignore dynamically generated test JSON files.
22 | /js/test/*json
23 | # Ignore Rust lockfile.
24 | /rust/Cargo.lock
25 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 |
2 | # 2015-01-30 Formatting Change
3 |
4 | Code formatting was modified to make the common cases easier to recognise and use.
5 | A typical house level code of 10 digits is now represented as XXXXXXXX+XX, making
6 | the common short cases XXXX+XX and XX+XX.
7 |
--------------------------------------------------------------------------------
/Documentation/External_Implementations.md:
--------------------------------------------------------------------------------
1 | # External Implementations
2 |
3 | This page lists implementations of the Open Location Code library by third parties.
4 | These include implementations in languages other than the those in this repository.
5 |
6 | These implementations have not been tested or reviewed, and are included here as a convenience.
7 |
8 | | Language | Link | Notes |
9 | | ------------------ | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
10 | | Ada | https://github.com/malaise/ada/ | |
11 | | C# (.NET standard) | https://github.com/JonMcPherson/open-location-code | |
12 | | Common Lisp | https://github.com/ralph-schleicher/open-location-code | |
13 | | EMACS | https://gitlab.liu.se/davby02/olc | |
14 | | R | https://github.com/Ironholds/olctools | |
15 | | Solidity | https://etherscan.io/address/0xf85c6320cc60dec45af1f7ce82b13dd24d539690#code#F3#L28 | URL is a link to a contract, not a repo |
16 | | Swift 3.x, 4.x | https://github.com/curbmap/OpenLocationCode-swift | Not fully implemented |
17 | | Swift 5.0 | https://github.com/google/open-location-code-swift | This library supports Objective-C for iOS, macOS, tvOS, and watchOS. |
18 | | Typescript | https://github.com/tspoke/typescript-open-location-code | |
19 |
--------------------------------------------------------------------------------
/Documentation/README.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | The wiki is where you can find out information about using the software, the codes, or the API.
4 |
5 | ### Common pages
6 |
7 | * [External Implementations](External_Implementations.md) - need an Ada or Typescript library?
8 | * [Frequently Asked Questions (FAQ)](FAQ.md)
9 | * [Who is using Plus Codes?](Reference/Plus_Code_Users.md)
10 |
11 | ### Specification and technical implementation
12 |
13 | * [Open Location Code Overview](Specification/olc_definition.adoc)
14 | * [Open Location Code Specification](Specification/specification.md)
15 | * [Guidance for Shortening Codes](Specification/Short_Code_Guidance.md)
16 | * [Open Location Code Reference API](Specification/API.md)
17 | * [Plus Codes and Open Location Code Naming Guidelines](Specification/Naming_Guidelines.md)
18 |
19 | ### Technical
20 |
21 | * [An Evaluation of Location Encoding Systems](Reference/comparison.adoc)
22 | * [Supporting Plus Codes in GIS software](Reference/GIS_Software.md)
23 | * [Supporting Plus Codes in an app](Reference/App_Developers.md)
24 |
25 | ### Tools
26 |
27 | * [Field Data Collection Practices](Reference/Field_Collection_Data_Practices.md)
28 | * [https://plus.codes API Reference](Reference/plus.codes_Website_API.md)
29 | * [Using Plus Codes in Spreadsheets](Reference/Using_Spreadsheets.md)
30 |
--------------------------------------------------------------------------------
/Documentation/Reference/GIS_Software.md:
--------------------------------------------------------------------------------
1 | # Plus Codes in GIS software
2 |
3 | This page provides information about using Plus Codes in GIS software.
4 |
5 | ## Tile Service
6 |
7 | If you want to visualise the Plus Codes grid, you can use the [grid service](https://grid.plus.codes) to fetch the grid tiles.
8 |
9 | This is a shared service, and it may rate limit you.
10 | If you need to use the grid heavily, you can start your own [tile_server](https://github.com/google/open-location-code/blob/main/tile_server).
11 |
12 | The tile service provides GeoJSON objects, one per Plus Codes square, or PNG images that can be added as an overlay.
13 |
14 | ## Software
15 |
16 | ### QGIS
17 |
18 | | precision level | intervals in degrees |
19 | |-----|-----|
20 | | 10 | 0.000125 |
21 | | 8 | 0.0025 |
22 | | 6 | 0.05 |
23 | | 4 | 1 |
24 | | 2 | 20 |
25 |
26 | We can generate the grid lines in QGIS.
27 |
28 | Just make sure your starting lat-long values are an exact multiple of the interval values for your chosen precision level you want.
29 |
30 | Example : Creating a grid with precision 6 : starting latitude cannot be 16.4563.
31 | Change it to 16.45 or 16.50 so that when you divide it by 0.05 it gives you an integer answer.
32 |
33 | In QGIS, you can generate a grid by clicking in the top Menu: Vector > Research tools > Vector Grid
34 |
35 | * Grid extent (xmin,xmax,ymin,ymax): 78.1,79,16.9,18.2 (in my example, a city in India)
36 | * Set both lat and lon interval as per the precision level you want.
37 | So for precision level 6, enter 0.05 for both.
38 | * You can set output as lines or polygons, your choice.
39 | Lines make simpler and smaller shapefiles.
40 | * And that should generate the grid for you.
41 | You can save that layer as a shapefile in any format.
42 |
43 | Note that this will not put any information about the Plus Codes in your grid's metadata.
44 | They're just lines/boxes.
45 |
46 | But if you make polygons, then I can think of a roundabout way of adding Plus Code values to those polygons (I have not done this myself yet):
47 |
48 | * Generate a centroid layer (Vector > Geometry Tools > Polygon Centroid) from the grid-polygons layer.
49 | This will place points inside each grid box. (in a new points layer.)
50 | * Install "Lat Lon Tools" plugin.
51 | * That plugin can generate Plus Codes from points.
52 | So run it on the centroid layer you made.
53 | * (And this I can't quite figure out yet) Figure out a way to move the meta field from the centroid layer to the grid polygons layer.
54 |
55 | There is a plugin for QGIS, [Lat Lon tools](https://github.com/NationalSecurityAgency/qgis-latlontools-plugin).
56 |
57 |
--------------------------------------------------------------------------------
/Documentation/Reference/Plus_Code_Users.md:
--------------------------------------------------------------------------------
1 | # Where Are Plus Codes Being Used?
2 |
3 | This page lists the sites, apps and organisations that support Plus Codes / Open Location Code.
4 |
5 | # Organisations
6 |
7 | * [Correios de Cabo Verde](correios.cv) (August 2016).
8 | Support Plus Codes for postal delivery.
9 |
10 | # Apps and sites
11 |
12 | * Google (Search, Maps)
13 | * Search support for global and local codes (early 2016).
14 | * Display of global codes in [Android](https://play.google.com/store/apps/details?id=com.google.android.apps.maps) and [iOS](https://itunes.apple.com/app/id585027354) maps (September 2016).
15 | * [Assistant integration](https://assistant.google.com/services/a/uid/000000706b4e2cf1?hl=en) (early 2018)
16 | * [mapy.cz](mapy.cz) (mid 2016) Search support for global codes.
17 | * www.waze.com (early 2018?) Search support for Plus Code addresses (global and local)
18 | * www.locusmap.eu (early 2018) Supports using global codes to set the map location
19 | * [OSMAnd](https://osmand.net/) OpenStreetMap based offline mobile maps and navigation - Supports displaying OLC as the "coordinates" of any point on earth.
20 | * [QGIS](https://qgis.org/) via [Lat Lon Tools](https://plugins.qgis.org/plugins/latlontools/) plug in - good support, points to olc, olc to points
21 | * [nicesi.com](https://nicesi.com/) (early 2019) Nicesi Location API support for global codes in [reverse geocoding service](https://nicesi.com/doc/#reverse-geocoding)
--------------------------------------------------------------------------------
/Documentation/Reference/Using_Spreadsheets.md:
--------------------------------------------------------------------------------
1 | # Using Plus Codes in Spreadsheets
2 |
3 | Being able to work with Plus Codes in spreadsheets is, for most people, probably the easiest method to work with them in bulk.
4 |
5 | This page explains how you can access the Open Location Code functions from Excel, LibreOffice or Google Spreadsheets.
6 |
7 | ## Google Sheets
8 |
9 | There is an [add-on for Google Sheets](https://gsuite.google.com/marketplace/app/plus_codes/604254879289) that allows you to create Plus Codes from latitude and longitude coordinates, and to decode them as well.
10 |
11 | The [Google Maps YouTube channel](https://www.youtube.com/@googlemaps) has some [videos showing how to install and use the add-on](https://www.youtube.com/playlist?list=PLcRbp4LqBpwE5ofG2MN08D_4DJAk9gZBI).
12 |
13 | ## Excel/LibreOffice
14 |
15 | VBA script and instructions are checked into github [here](https://github.com/google/open-location-code/blob/main/visualbasic).
16 |
17 | LibreOffice does sometimes have problems.
18 | This may be due to slightly unreliable VBA support in some versions.
19 |
20 |
--------------------------------------------------------------------------------
/Documentation/Specification/Naming_Guidelines.md:
--------------------------------------------------------------------------------
1 | # Plus Codes and Open Location Code Naming Guidelines
2 |
3 | ## Why have guidelines?
4 |
5 | These guidelines are offered so that people see a consistent reference to the codes and technology.
6 | This will make it easier for them to understand what they are being shown or asked for.
7 |
8 | We have chosen two names - one for the technology and one for the actual codes.
9 | The name for the codes reflects and reinforces the importance of the plus symbol, which is how the codes can be recognised.
10 |
11 | ## Plus Codes
12 |
13 | When referring to Plus Codes in English, the **only** term that should be used is "Plus Code", in Title Case.
14 |
15 | Some examples of usage are:
16 | * "My Plus Code is CX37+M9."
17 | * "I gave your Plus Code to the cab driver and he found the way without any problems."
18 | * "Will the postcard arrive if I put your Plus Code as the address?"
19 | * "Enter your Plus Code or street address here."
20 |
21 | ### Global and local codes
22 |
23 | Codes that can be decoded to a lat/lng on their own, e.g. 796RWF8Q+WF are referred to as global codes.
24 |
25 | The shortened codes, e.g., WF8Q+WF are referred to as local codes, because they work within a local area.
26 |
27 | ## Open Location Code
28 |
29 | When discussing with organisations or developers, refer to the library, algorithm and technology as "Open Location Code".
30 | This can be abbreviated to OLC, is capitalised, and shouldn't be translated.
31 |
32 | It shouldn't be used to refer to the actual codes - don't say "Open Location Codes" for example.
33 |
34 | ## Summary
35 |
36 | Having consistent names and presentation will make it easier for people to recognise what is meant, and make it easier for them to use and benefit from the project.
37 |
38 |
--------------------------------------------------------------------------------
/Documentation/images/code_areas.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/Documentation/images/code_areas.png
--------------------------------------------------------------------------------
/Documentation/images/geohash36_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/Documentation/images/geohash36_grid.png
--------------------------------------------------------------------------------
/Documentation/images/olc_10_character.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/Documentation/images/olc_10_character.png
--------------------------------------------------------------------------------
/Documentation/images/olc_11_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/Documentation/images/olc_11_grid.png
--------------------------------------------------------------------------------
/Documentation/images/openpostcode_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/Documentation/images/openpostcode_grid.png
--------------------------------------------------------------------------------
/MODULE.bazel:
--------------------------------------------------------------------------------
1 | module(
2 | name = "openlocationcode",
3 | version = "1.0",
4 | )
5 |
6 | # bazel-skylib required by #@io_bazel_rules_closure.
7 | # https://github.com/bazelbuild/bazel-skylib
8 | bazel_dep(name = "bazel_skylib", version = "1.7.1")
9 |
10 | # googletest required by c/BUILD.
11 | # https://github.com/google/googletest
12 | bazel_dep(name = "googletest", version = "1.15.2")
13 |
14 |
--------------------------------------------------------------------------------
/WORKSPACE:
--------------------------------------------------------------------------------
1 | # Workspace configuration for Bazel build tools.
2 |
3 | # TODO: #642 -- Remove once io_bazel_rules_closure supports Bazel module configuration.
4 | workspace(name = "openlocationcode")
5 |
6 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
7 |
8 | http_archive(
9 | name = "io_bazel_rules_closure",
10 | integrity = "sha256-EvEWnr54L4Yx/LjagaoSuhkviVKHW0oejyDEn8bhAiM=",
11 | strip_prefix = "rules_closure-0.14.0",
12 | urls = [
13 | "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/0.14.0.tar.gz",
14 | "https://github.com/bazelbuild/rules_closure/archive/0.14.0.tar.gz",
15 | ],
16 | )
17 | load("@io_bazel_rules_closure//closure:repositories.bzl", "rules_closure_dependencies", "rules_closure_toolchains")
18 | rules_closure_dependencies()
19 | rules_closure_toolchains()
20 |
--------------------------------------------------------------------------------
/android_demo/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | */build/
3 |
4 | # Local configuration file (sdk path, etc)
5 | local.properties
6 |
7 | # IntelliJ configuration file
8 | android/android.iml
9 |
10 | # Gradle generated files
11 | .gradle/
12 |
13 | # Signing files
14 | .signing/
15 |
16 | # User-specific configurations
17 | .idea/*
18 |
19 | # OS-specific files
20 | .DS_Store
21 | ._*
22 | .Trashes
23 |
--------------------------------------------------------------------------------
/android_demo/README.md:
--------------------------------------------------------------------------------
1 | Android Open Location Code Demonstrator
2 | =======================================
3 |
4 | This is the source code for an Android app that uses
5 | [Open Location Code](https://maps.google.com/pluscodes/) and displays them on a
6 | map.
7 |
8 | It displays the current location, computes the code for that location, and uses
9 | a bundled set of place names to shorten the code to a more convenient form.
10 | Currently all the place names exist within Cape Verde. Other place names can be
11 | added to the source.
12 |
13 | Using a bundled set of places means that determining the current address, and
14 | locating an entered address will work offline.
15 |
16 | This project has been structured to be used with
17 | [Android Studio](https://developer.android.com/studio/index.html).
18 |
19 | An Open Location Code JAR file is in the directory `android/libs`. If the core library
20 | is updated, you will need to update this JAR file.
21 |
--------------------------------------------------------------------------------
/android_demo/android/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'com.neenbedankt.android-apt'
3 |
4 | android {
5 | compileSdkVersion rootProject.compileSdkVersion
6 | buildToolsVersion rootProject.buildToolsVersion
7 |
8 | defaultConfig {
9 | applicationId "com.openlocationcode.android"
10 | minSdkVersion rootProject.minSdkVersion
11 | targetSdkVersion rootProject.targetSdkVersion
12 | versionCode 1
13 | versionName "1.0"
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | compile fileTree(dir: 'libs', include: ['*.jar'])
25 | testCompile 'junit:junit:4.12'
26 | compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
27 | compile "com.android.support:design:$rootProject.supportLibraryVersion"
28 |
29 | // Dagger dependencies
30 | apt "com.google.dagger:dagger-compiler:$rootProject.daggerVersion"
31 | provided 'org.glassfish:javax.annotation:10.0-b28'
32 | compile "com.google.dagger:dagger:$rootProject.daggerVersion"
33 |
34 | compile "com.android.volley:volley:$rootProject.volleyVersion"
35 |
36 | compile "com.google.auto.factory:auto-factory:$rootProject.autoFactoryVersion"
37 |
38 |
39 | compile "com.google.android.gms:play-services-location:$rootProject.gmsVersion"
40 | compile "com.google.android.gms:play-services-base:$rootProject.gmsVersion"
41 | }
42 |
--------------------------------------------------------------------------------
/android_demo/android/libs/README.md:
--------------------------------------------------------------------------------
1 | Building the Open Location Code JAR file
2 | ==
3 |
4 | Using the source in the
5 | [Java](https://github.com/google/open-location-code/blob/master/java/com/google/openlocationcode/OpenLocationCode.java)
6 | implementation, build a JAR file and put it in this location.
7 |
8 | --
9 |
10 | Assuming you've downloaded this repository locally:
11 |
12 | ```
13 | cd open-location-code-master/java
14 | javac com/google/openlocationcode/OpenLocationCode.java
15 | jar -cfM ./openlocationcode.jar com/google/openlocationcode/OpenLocationCode\$CodeArea.class com/google/openlocationcode/OpenLocationCode.class
16 | ```
17 |
18 | The `.jar` file is in the `open-location-code-master/java` directory
19 |
20 | If working with Android Studio, add `openlocationcode.jar` to `/{PROJECT_NAME}/{APP}/libs` *(you may need to create the `/libs` folder)*
21 |
22 | Why don't we include a JAR file here?
23 | --
24 |
25 | Basically, we want to make sure that we don't fix a bug in the Java implementation and forget to
26 | update this JAR file.
27 |
28 | Why don't we have a Maven repository?
29 | --
30 |
31 | So far, we've only had one request. If you would like to be able to pull the library via Maven,
32 | file an issue and we'll consider it.
33 |
--------------------------------------------------------------------------------
/android_demo/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can edit the include path and order by changing the proguardFiles
3 | # directive in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # Add any project specific keep options here:
9 |
10 | # If your project uses WebView with JS, uncomment the following
11 | # and specify the fully qualified class name to the JavaScript interface
12 | # class:
13 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
14 | # public *;
15 | #}
16 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
16 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/code/CodeContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.code;
18 |
19 | import com.openlocationcode.android.direction.Direction;
20 |
21 | import com.google.openlocationcode.OpenLocationCode;
22 |
23 | /**
24 | * The contract for the functionality displaying the code, in {@link
25 | * com.openlocationcode.android.main.MainActivity}.
26 | */
27 | public interface CodeContract {
28 |
29 | interface View {
30 |
31 | /**
32 | * Implements displaying the {@code code}.
33 | */
34 | void displayCode(OpenLocationCode code);
35 | }
36 |
37 | interface ActionsListener {
38 |
39 | /**
40 | * Call this when the code is requested for a new location (eg when the map is dragged).
41 | *
42 | * @param latitude
43 | * @param longitude
44 | * @param isCurrent
45 | * @return
46 | */
47 | Direction codeLocationUpdated(double latitude, double longitude, boolean isCurrent);
48 |
49 | /**
50 | * @return the code currently displayed to the user.
51 | */
52 | OpenLocationCode getCurrentOpenLocationCode();
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/current/GoogleApiModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.current;
18 |
19 | import com.google.android.gms.common.GoogleApiAvailability;
20 | import com.google.android.gms.common.api.GoogleApiClient;
21 | import com.google.android.gms.location.FusedLocationProviderApi;
22 | import com.google.android.gms.location.LocationServices;
23 |
24 | import android.content.Context;
25 | import android.hardware.SensorManager;
26 | import android.location.LocationManager;
27 | import android.view.Display;
28 | import android.view.WindowManager;
29 |
30 | import dagger.Module;
31 | import dagger.Provides;
32 |
33 | import javax.inject.Singleton;
34 |
35 | @Module
36 | public class GoogleApiModule {
37 |
38 | private final Context mContext;
39 |
40 | public GoogleApiModule(Context context) {
41 | this.mContext = context;
42 | }
43 |
44 | @Provides
45 | @Singleton
46 | public GoogleApiClient provideGoogleApiClient() {
47 | return new GoogleApiClient.Builder(mContext).addApi(LocationServices.API).build();
48 | }
49 |
50 | @Provides
51 | @Singleton
52 | public GoogleApiAvailability provideGoogleApiAvailability() {
53 | return GoogleApiAvailability.getInstance();
54 | }
55 |
56 | @SuppressWarnings("SameReturnValue")
57 | @Provides
58 | @Singleton
59 | public FusedLocationProviderApi provideFusedLocationProviderApi() {
60 | return LocationServices.FusedLocationApi;
61 | }
62 |
63 | @Provides
64 | @Singleton
65 | public LocationManager provideLocationManager() {
66 | return (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
67 | }
68 |
69 | @Provides
70 | @Singleton
71 | public SensorManager provideSensorManager() {
72 | return (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
73 | }
74 |
75 | @Provides
76 | @Singleton
77 | public Display provideDisplayManager() {
78 | return ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
79 | .getDefaultDisplay();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/current/LocationProviderFactoryComponent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.current;
18 |
19 | import dagger.Component;
20 |
21 | import javax.inject.Singleton;
22 |
23 | @Component(modules = {GoogleApiModule.class})
24 | @Singleton
25 | public interface LocationProviderFactoryComponent {
26 | LocationProviderFactory locationProviderFactory();
27 | }
28 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/direction/Direction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.direction;
18 |
19 | import com.google.openlocationcode.OpenLocationCode;
20 |
21 | import java.util.Locale;
22 |
23 | /**
24 | * Immutable model representing the direction between two given locations. It contains the distance,
25 | * the initial and the final bearing. To understand the meaning of initial and final bearing, refer
26 | * to http://www.onlineconversion.com/map_greatcircle_bearings.htm.
27 | */
28 | public class Direction {
29 |
30 | private final int mDistanceInMeter;
31 |
32 | private final float mInitialBearing;
33 |
34 | private final OpenLocationCode mFromCode;
35 |
36 | private final OpenLocationCode mToCode;
37 |
38 | public Direction(
39 | OpenLocationCode fromCode,
40 | OpenLocationCode toCode,
41 | float distanceInMeter,
42 | float initialBearing) {
43 | mDistanceInMeter = (int) distanceInMeter;
44 | mInitialBearing = initialBearing;
45 | mFromCode = fromCode;
46 | mToCode = toCode;
47 | }
48 |
49 | /**
50 | * @return Bearing in degrees East of true North.
51 | */
52 | public float getInitialBearing() {
53 | return mInitialBearing;
54 | }
55 |
56 | /**
57 | * @return Distance in meter.
58 | */
59 | public int getDistance() {
60 | return mDistanceInMeter;
61 | }
62 |
63 | /**
64 | * @return The code representing the origin location.
65 | */
66 | public OpenLocationCode getFromCode() {
67 | return mFromCode;
68 | }
69 |
70 | /**
71 | * @return The code representing the destination location.
72 | */
73 | public OpenLocationCode getToCode() {
74 | return mToCode;
75 | }
76 |
77 | @Override
78 | public String toString() {
79 | return String.format(
80 | Locale.US,
81 | "Direction from code %s to %s, distance %d, initial bearing %f",
82 | mFromCode,
83 | mToCode,
84 | mDistanceInMeter,
85 | mInitialBearing);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/direction/DirectionContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.direction;
18 |
19 | /**
20 | * The contract for the direction feature. The direction shows the direction (bearing) and the
21 | * distance of a code, compared to the user current location.
22 | */
23 | public interface DirectionContract {
24 |
25 | interface View {
26 |
27 | void showDirection(float degreesFromNorth);
28 |
29 | void showDistance(int distanceInMeters);
30 | }
31 |
32 | interface ActionsListener {
33 |
34 | /**
35 | * Call this when the user current location or the code currently shown to the user is
36 | * updated.
37 | */
38 | void directionUpdated(Direction direction);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/direction/DirectionPresenter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.direction;
18 |
19 | public class DirectionPresenter implements DirectionContract.ActionsListener {
20 |
21 | private final DirectionView mView;
22 |
23 | public DirectionPresenter(DirectionView view) {
24 | mView = view;
25 | }
26 |
27 | @Override
28 | public void directionUpdated(Direction direction) {
29 | mView.showDirection(direction.getInitialBearing());
30 | mView.showDistance(direction.getDistance());
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/direction/DirectionUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.direction;
18 |
19 | import android.location.Location;
20 |
21 | import com.google.openlocationcode.OpenLocationCode;
22 | import com.google.openlocationcode.OpenLocationCode.CodeArea;
23 |
24 | import com.openlocationcode.android.code.OpenLocationCodeUtil;
25 |
26 | /**
27 | * Util functions related to direction.
28 | */
29 | public class DirectionUtil {
30 |
31 | /**
32 | * This computes a direction between {@code fromLocation} and a
33 | * {@code destinationCode}. The computation is done using
34 | * {@link Location#distanceBetween(double, double, double, double, float[])}.
35 | *
36 | * @param fromLocation The user position.
37 | * @param destinationCode The code to compute the direction to.
38 | * @return the {@link Direction}
39 | */
40 | public static Direction getDirection(Location fromLocation, OpenLocationCode destinationCode) {
41 | CodeArea destinationArea = destinationCode.decode();
42 | double toLatitude = destinationArea.getCenterLatitude();
43 | double toLongitude = destinationArea.getCenterLongitude();
44 | float[] results = new float[3];
45 | Location.distanceBetween(
46 | fromLocation.getLatitude(),
47 | fromLocation.getLongitude(),
48 | toLatitude,
49 | toLongitude,
50 | results);
51 |
52 | // The device bearing in the location object is 0-360, the value returned from
53 | // distanceBetween is -180 to 180. Adjust the device bearing to be in the same range.
54 | float deviceBearing = fromLocation.getBearing();
55 | if (deviceBearing > 180) {
56 | deviceBearing = deviceBearing - 360;
57 | }
58 |
59 | // Compensate the initial bearing for the device bearing.
60 | results[1] = results[1] - deviceBearing;
61 | if (results[1] > 180) {
62 | results[1] = -360 + results[1];
63 | } else if (results[1] < -180) {
64 | results[1] = 360 + results[1];
65 | }
66 | return new Direction(
67 | OpenLocationCodeUtil.createOpenLocationCode(
68 | fromLocation.getLatitude(), fromLocation.getLongitude()),
69 | destinationCode,
70 | results[0],
71 | results[1]);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/main/MainFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.main;
18 |
19 | import android.app.Fragment;
20 | import android.os.Bundle;
21 | import android.view.LayoutInflater;
22 | import android.view.View;
23 | import android.view.ViewGroup;
24 |
25 | import com.openlocationcode.android.R;
26 |
27 | /**
28 | * A placeholder fragment containing a simple view.
29 | */
30 | public class MainFragment extends Fragment {
31 |
32 | public MainFragment() {
33 | }
34 |
35 | @Override
36 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
37 | Bundle savedInstanceState) {
38 |
39 | return inflater.inflate(R.layout.main_frag, container, false);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/map/MapContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.map;
18 |
19 | import android.location.Location;
20 |
21 | import com.google.openlocationcode.OpenLocationCode;
22 | import com.google.android.gms.maps.model.CameraPosition;
23 |
24 |
25 | /**
26 | * The contract for the map feature.
27 | */
28 | public interface MapContract {
29 |
30 | interface View {
31 |
32 | void moveMapToLocation(OpenLocationCode code);
33 |
34 | void drawCodeArea(OpenLocationCode code);
35 |
36 | void showSatelliteView();
37 |
38 | void showRoadView();
39 |
40 | void setListener(ActionsListener listener);
41 |
42 | CameraPosition getCameraPosition();
43 |
44 | void setCameraPosition(double latitude, double longitude, float zoom);
45 |
46 | void stopUpdateCodeOnDrag();
47 |
48 | void startUpdateCodeOnDrag();
49 | }
50 |
51 | interface ActionsListener {
52 |
53 | void mapChanged(double latitude, double longitude);
54 |
55 | void requestSatelliteView();
56 |
57 | void requestRoadView();
58 |
59 | void moveMapToLocation(Location location);
60 |
61 | CameraPosition getMapCameraPosition();
62 |
63 | void setMapCameraPosition(double latitude, double longitude, float zoom);
64 |
65 | /**
66 | * Call this to stop updating the code feature on dragging the map. This is used by the
67 | * search feature, ie make sure the search result is shown and not cancelled by dragging
68 | * the map.
69 | */
70 | void stopUpdateCodeOnDrag();
71 |
72 | /**
73 | * Call this to start updating the code feature on dragging the map, eg when search is
74 | * cancelled.
75 | */
76 | void startUpdateCodeOnDrag();
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/search/AutoCompleteEditor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.search;
18 |
19 | import android.content.Context;
20 | import android.util.AttributeSet;
21 | import android.view.KeyEvent;
22 | import android.widget.AutoCompleteTextView;
23 |
24 | /**
25 | * Super class of AutoCompleteTextView that allows detection of the soft keyboard dismissal.
26 | */
27 | public class AutoCompleteEditor extends AutoCompleteTextView {
28 |
29 | private com.openlocationcode.android.search.SearchContract.SourceView imeBackListener;
30 |
31 | public AutoCompleteEditor(Context context) {
32 | super(context);
33 | }
34 |
35 | public AutoCompleteEditor(Context context, AttributeSet attrs) {
36 | super(context, attrs);
37 | }
38 |
39 | public void setImeBackListener(SearchContract.SourceView imeBackListener) {
40 | this.imeBackListener = imeBackListener;
41 | }
42 |
43 | @Override
44 | public boolean onKeyPreIme(int keyCode, KeyEvent event) {
45 | if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
46 | && event.getAction() == KeyEvent.ACTION_UP) {
47 | if (imeBackListener != null) {
48 | imeBackListener.imeBackHandler();
49 | }
50 | }
51 |
52 | return super.onKeyPreIme(keyCode, event);
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/java/com/openlocationcode/android/search/SearchContract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 Google Inc. All Rights Reserved.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.openlocationcode.android.search;
18 |
19 | import com.google.openlocationcode.OpenLocationCode;
20 |
21 | import java.util.List;
22 |
23 | /**
24 | * The contract for the search functionality.
25 | */
26 | public interface SearchContract {
27 |
28 | /**
29 | * The contract for a view allowing the user to enter search criteria.
30 | */
31 | interface SourceView {
32 |
33 | void showInvalidCode();
34 |
35 | void showEmptyCode();
36 |
37 | void setActionsListener(ActionsListener listener);
38 |
39 | void showSuggestions(List suggestions);
40 |
41 | void imeBackHandler();
42 |
43 | void setText(String text);
44 |
45 | }
46 |
47 | /**
48 | * The contract for a view displaying the result of the search.
49 | */
50 | interface TargetView {
51 |
52 | void showSearchCode(OpenLocationCode code);
53 |
54 | }
55 |
56 | interface ActionsListener {
57 |
58 | boolean searchCode(String code);
59 |
60 | void getSuggestions(String code);
61 |
62 | void setSearchText(String text);
63 |
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-hdpi/ic_action_maps_navigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-hdpi/ic_action_maps_navigation.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-hdpi/map_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-hdpi/map_center.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-hdpi/welcome_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-hdpi/welcome_image.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-ldpi/map_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-ldpi/map_center.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-mdpi/ic_action_maps_navigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-mdpi/ic_action_maps_navigation.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-mdpi/map_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-mdpi/map_center.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xhdpi/ic_action_maps_navigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xhdpi/ic_action_maps_navigation.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xhdpi/map_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xhdpi/map_center.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xhdpi/welcome_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xhdpi/welcome_image.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xxhdpi/ic_action_maps_navigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xxhdpi/ic_action_maps_navigation.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xxhdpi/map_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xxhdpi/map_center.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xxhdpi/welcome_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xxhdpi/welcome_image.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xxxhdpi/ic_action_maps_navigation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xxxhdpi/ic_action_maps_navigation.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable-xxxhdpi/map_center.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/android/src/main/res/drawable-xxxhdpi/map_center.png
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable/map_satellite_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable/rounded_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/drawable/search_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/layout/direction.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
23 |
24 |
31 |
32 |
37 |
38 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/layout/main_act.xml:
--------------------------------------------------------------------------------
1 |
16 |
22 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/layout/main_frag.xml:
--------------------------------------------------------------------------------
1 |
16 |
19 |
20 |
27 |
28 |
36 |
37 |
42 |
52 |
53 |
54 |
55 |
60 |
61 |
65 |
66 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/menu/share_menu.xml:
--------------------------------------------------------------------------------
1 |
16 |
24 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 | OLC Demo
18 | OLC Demo
19 |
20 | Obter o seu código
21 |
22 | Sem código para mostrar
23 | A carregar a sua localização
24 | Não identificámos a sua localização
25 |
26 | Partilhar através de…
27 | Partilhar…
28 | Guardar em contactos
29 |
30 | localidade desconhecida
31 |
32 | %d m
33 | %.1f km
34 | %.0f km
35 |
36 | Introduza um código
37 | Código não encontrado
38 | Introduza um código para procurar
39 |
40 | Descubra o seu OLC
41 | Descubra o OLC (Open Location Code) de sua casa. OLC são livres e funciona com o Google Maps.
42 |
43 | Navegar da sua localização ao código
44 | Partilhar código ou guardar em contactos
45 | Camada de satélite de alternância
46 | Mostrar a sua localização actual
47 | Anular pesquisa
48 |
49 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 | #A0CC0000
18 | #A0FF0000
19 | #CCCCCC
20 | #333
21 | #AAA
22 | #F16054
23 | #FFFFFF
24 |
25 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 | 14sp
18 | 18sp
19 |
20 | 4dp
21 | 2dp
22 |
23 | 16dp
24 | 104dp
25 |
26 | 60dp
27 | 8dp
28 |
29 | 8dp
30 |
31 | 48dp
32 | 16dp
33 | 16dp
34 | 8dp
35 | 8dp
36 | 16dp
37 | 2dp
38 | 10dp
39 |
40 | 90dp
41 | 20dp
42 | 8dp
43 |
44 | 8dp
45 | 24dp
46 | 32dp
47 |
48 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 | OLC Demo
18 | OLC Demo
19 |
20 | Get your code
21 |
22 | No code to display
23 | Loading your location
24 | Can\'t determine your location
25 |
26 | Share via
27 | Share…
28 | Save to contact
29 |
30 | unknown locality
31 |
32 | %d m
33 | %.1f km
34 | %.0f km
35 |
36 | Look up a code
37 | Code not found
38 | Enter a code to search
39 |
40 | Discover your OLC
41 | Discover the Plus Code of your home.\nPlus Codes are free and
42 | work with Google Maps.
43 |
44 | Navigate from your location to the code
45 | Share the code or add to a contact
46 | Toggle satellite layer
47 | Show your current location
48 | Cancel search
49 |
50 |
--------------------------------------------------------------------------------
/android_demo/android/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
26 |
27 |
30 |
31 |
34 |
35 |
36 |
40 |
41 |
42 |
48 |
49 |
53 |
54 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/android_demo/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | }
6 | dependencies {
7 | classpath 'com.android.tools.build:gradle:2.1.0'
8 |
9 | // Better IDE support for annotations (so Android Studio interacts better with Dagger)
10 | classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
27 | // Define versions in a single place
28 | ext {
29 | // Sdk and tools
30 | minSdkVersion = 14
31 | targetSdkVersion = 22
32 | compileSdkVersion = 23
33 | buildToolsVersion = '23.0.3'
34 |
35 | // App dependencies
36 | supportLibraryVersion = '23.3.0'
37 | guavaVersion = '18.0'
38 | junitVersion = '4.12'
39 | mockitoVersion = '1.10.19'
40 | powerMockito = '1.6.2'
41 | hamcrestVersion = '1.3'
42 | runnerVersion = '0.4.1'
43 | rulesVersion = '0.4.1'
44 | espressoVersion = '2.2.1'
45 | daggerVersion = '2.0'
46 | autoFactoryVersion = '1.0-beta3'
47 | volleyVersion = '1.0.0'
48 | gmsVersion = '8.4.0'
49 | }
--------------------------------------------------------------------------------
/android_demo/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/android_demo/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android_demo/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Oct 21 11:34:03 PDT 2015
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
7 |
--------------------------------------------------------------------------------
/android_demo/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/android_demo/openlocationcode_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/android_demo/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':android'
2 |
--------------------------------------------------------------------------------
/c/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | libolc.a
3 | example
4 | olc_test
5 | gmon.out
6 |
--------------------------------------------------------------------------------
/c/BUILD:
--------------------------------------------------------------------------------
1 | cc_library(
2 | name = "openlocationcode",
3 | srcs = [
4 | "src/olc.c",
5 | ],
6 | copts = [
7 | "-std=c99",
8 | "-Wall",
9 | "-Wextra",
10 | "-O2",
11 | ],
12 | hdrs = [
13 | "src/olc.h",
14 | "src/olc_private.h",
15 | ],
16 | includes = ["src"],
17 | visibility = ["//visibility:private"],
18 | )
19 |
20 | cc_test(
21 | name = "openlocationcode_test",
22 | size = "small",
23 | srcs = ["openlocationcode_test.cc"],
24 | copts = [
25 | "-pthread",
26 | "-I@googletest//:include",
27 | ],
28 | linkopts = ["-pthread"],
29 | linkstatic = False,
30 | data = [
31 | "//test_data",
32 | ],
33 | deps = [
34 | ":openlocationcode",
35 | "@googletest//:gtest_main",
36 | ],
37 | testonly = True,
38 | visibility = ["//visibility:private"],
39 | )
40 |
41 | cc_binary(
42 | name = "openlocationcode_example",
43 | srcs = [
44 | "example.c",
45 | ],
46 | deps = [
47 | ":openlocationcode",
48 | ],
49 | visibility = ["//visibility:private"],
50 | )
--------------------------------------------------------------------------------
/c/README.md:
--------------------------------------------------------------------------------
1 | # Open Location Code C API
2 |
3 | This is the C implementation of the Open Location Code API.
4 |
5 | # Code Style and Formatting
6 |
7 | Code style is based on Googles formatting rules. Code must be formatted
8 | using `clang-format`.
9 |
10 | The `clang_check.sh` script will check for formatting errors, output them,
11 | and automatically format files.
12 |
13 | # Usage
14 |
15 | See example.cc for how to use the library. To run the example, use:
16 |
17 | ```
18 | bazel run openlocationcode_example
19 | ```
20 |
21 | # Development
22 |
23 | The library is built/tested using [Bazel](https://bazel.build). To build the library, use:
24 |
25 | ```
26 | bazel build openlocationcode
27 | ```
28 |
29 | To run the tests, use:
30 |
31 | ```
32 | bazel test --test_output=all openlocationcode_test
33 | ```
34 |
35 | The tests use the CSV files in the test_data folder. Make sure you copy this folder to the
36 | root of your local workspace.
37 |
38 |
39 | # Authors
40 |
41 | * The authors of the C++ implementation, on which this is based.
42 | * [Gonzalo Diethelm](mailto:gonzalo.diethelm@gmail.com)
43 |
--------------------------------------------------------------------------------
/c/benchmark/.gitignore:
--------------------------------------------------------------------------------
1 | bm-c
2 | bm-cpp
3 |
--------------------------------------------------------------------------------
/c/benchmark/Makefile:
--------------------------------------------------------------------------------
1 | all: run
2 |
3 | RUNS = 1000000
4 |
5 | C_MAIN = bm-c.c
6 | CC_MAIN = bm-cpp.cc
7 |
8 | LD_FLAGS += -lm
9 |
10 | # C compilation
11 | C_FLAGS += -Wall
12 | C_FLAGS += -Wno-comment
13 | C_FLAGS += -I../../c
14 | # C_FLAGS += -Wextra
15 | # C_FLAGS += -DOLC_CHECK_RESULTS
16 |
17 | C_ALL_FLAGS += -std=c99
18 | # C_ALL_FLAGS += -g
19 |
20 | # C++ compilation
21 | CC_FLAGS += -Wall
22 | CC_FLAGS += -Wno-comment
23 | CC_FLAGS += -I../../cpp
24 | # CC_FLAGS += -Wextra
25 | # CC_FLAGS += -DOLC_CHECK_RESULTS
26 |
27 | CC_ALL_FLAGS += -std=c++11
28 | CC_ALL_FLAGS += -pthread
29 | # CC_ALL_FLAGS += -g
30 |
31 | # everything below here should be taken care of automatically
32 | # no need to edit these lines, except to add new binary targets
33 |
34 | LIB_NAME = olc
35 |
36 | C_OBJ = $(C_MAIN:.c=.o)
37 | C_EXE = $(C_MAIN:.c=)
38 |
39 | CC_OBJ = $(CC_MAIN:.cc=.o)
40 | CC_EXE = $(CC_MAIN:.cc=)
41 |
42 | %.o : %.c
43 | cc -c $(C_ALL_FLAGS) $(C_FLAGS) -o $@ $<
44 |
45 | %.o : %.cc
46 | c++ -c $(CC_ALL_FLAGS) $(CC_FLAGS) -o $@ $<
47 |
48 | $(C_EXE): $(C_OBJ)
49 | cc $(C_ALL_FLAGS) -o $(C_EXE) $(LD_FLAGS) $(C_OBJ) -L../../c -l$(LIB_NAME)
50 |
51 | $(CC_EXE): $(CC_OBJ)
52 | c++ $(CC_ALL_FLAGS) -o $(CC_EXE) $(LD_FLAGS) $(CC_OBJ) -L../../cpp -l$(LIB_NAME)
53 |
54 | run: bm-c bm-cpp
55 | ./$(C_EXE) $(RUNS)
56 | ./$(CC_EXE) $(RUNS)
57 |
58 | clean:
59 | rm -f crash-* slow-unit-* *.dSYM
60 | rm -f $(C_OBJ) $(CC_OBJ)
61 | rm -f $(C_EXE) $(CC_EXE)
62 |
--------------------------------------------------------------------------------
/c/benchmark/bm-c.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "olc.h"
3 |
4 | #include "shared.c"
5 |
6 | int main(int argc, char* argv[]) { return run(argc, argv); }
7 |
8 | static void encode(void) {
9 | char code[256];
10 | int len;
11 | OLC_LatLon location;
12 |
13 | // Encodes latitude and longitude into a Plus+Code.
14 | location.lat = data_pos_lat;
15 | location.lon = data_pos_lon;
16 | len = OLC_EncodeDefault(&location, code, 256);
17 |
18 | ASSERT_STR_EQ(code, "8FVC2222+22");
19 | ASSERT_INT_EQ(len, 11);
20 | }
21 |
22 | static void encode_len(void) {
23 | char code[256];
24 | int len;
25 | OLC_LatLon location;
26 |
27 | // Encodes latitude and longitude into a Plus+Code with a preferred length.
28 | location.lat = data_pos_lat;
29 | location.lon = data_pos_lon;
30 | len = OLC_Encode(&location, data_pos_len, code, 256);
31 |
32 | ASSERT_STR_EQ(code, "8FVC2222+22GCCCC");
33 | ASSERT_INT_EQ(len, 16);
34 | }
35 |
36 | static void decode(void) {
37 | OLC_CodeArea code_area;
38 |
39 | // Decodes a Plus+Code back into coordinates.
40 | OLC_Decode(data_code_16, 0, &code_area);
41 |
42 | ASSERT_FLT_EQ(code_area.lo.lat, 47.000062496);
43 | ASSERT_FLT_EQ(code_area.lo.lon, 8.00006250000001);
44 | ASSERT_FLT_EQ(code_area.hi.lat, 47.000062504);
45 | ASSERT_FLT_EQ(code_area.hi.lon, 8.0000625305176);
46 | ASSERT_INT_EQ(code_area.len, 15);
47 | }
48 |
49 | static void is_valid(void) {
50 | // Checks if a Plus+Code is valid.
51 | int ok = !!OLC_IsValid(data_code_16, 0);
52 | ASSERT_INT_EQ(ok, 1);
53 | }
54 |
55 | static void is_full(void) {
56 | // Checks if a Plus+Code is full.
57 | int ok = !!OLC_IsFull(data_code_16, 0);
58 | ASSERT_INT_EQ(ok, 1);
59 | }
60 |
61 | static void is_short(void) {
62 | // Checks if a Plus+Code is short.
63 | int ok = !!OLC_IsShort(data_code_16, 0);
64 | ASSERT_INT_EQ(ok, 0);
65 | }
66 |
67 | static void shorten(void) {
68 | // Shorten a Plus+Codes if possible by the given reference latitude and
69 | // longitude.
70 | char code[256];
71 | OLC_LatLon location;
72 | location.lat = data_ref_lat;
73 | location.lon = data_ref_lon;
74 | int len = OLC_Shorten(data_code_12, 0, &location, code, 256);
75 |
76 | ASSERT_STR_EQ(code, "CJ+2VX");
77 | ASSERT_INT_EQ(len, 6);
78 | }
79 |
80 | static void recover(void) {
81 | char code[256];
82 | OLC_LatLon location;
83 | location.lat = data_ref_lat;
84 | location.lon = data_ref_lon;
85 | // Extends a Plus+Code by the given reference latitude and longitude.
86 | int len = OLC_RecoverNearest(data_code_6, 0, &location, code, 256);
87 |
88 | ASSERT_STR_EQ(code, "9C3W9QCJ+2VX");
89 | ASSERT_INT_EQ(len, 12);
90 | }
91 |
--------------------------------------------------------------------------------
/c/benchmark/bm-cpp.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include "openlocationcode.h"
3 |
4 | #include "shared.c"
5 |
6 | int main(int argc, char* argv[])
7 | {
8 | return run(argc, argv);
9 | }
10 |
11 | static void encode(void)
12 | {
13 | // Encodes latitude and longitude into a Plus+Code.
14 | std::string code = openlocationcode::Encode({data_pos_lat, data_pos_lon});
15 |
16 | ASSERT_STR_EQ(code.c_str(), "8FVC2222+22");
17 | ASSERT_INT_EQ(code.length(), 11);
18 | }
19 |
20 | static void encode_len(void)
21 | {
22 | // Encodes latitude and longitude into a Plus+Code with a preferred length.
23 | std::string code = openlocationcode::Encode({data_pos_lat, data_pos_lon}, data_pos_len);
24 |
25 | ASSERT_STR_EQ(code.c_str(), "8FVC2222+22GCCCC");
26 | ASSERT_INT_EQ(code.length(), 16);
27 | }
28 |
29 | static void decode(void)
30 | {
31 | // Decodes a Plus+Code back into coordinates.
32 | openlocationcode::CodeArea code_area = openlocationcode::Decode(data_code_16);
33 |
34 | ASSERT_FLT_EQ(code_area.GetLatitudeLo(), 47.000062496);
35 | ASSERT_FLT_EQ(code_area.GetLongitudeLo(), 8.00006250000001);
36 | ASSERT_FLT_EQ(code_area.GetLatitudeHi(), 47.000062504);
37 | ASSERT_FLT_EQ(code_area.GetLongitudeHi(), 8.0000625305176);
38 | ASSERT_INT_EQ(code_area.GetCodeLength(), 15);
39 | }
40 |
41 | static void is_valid(void)
42 | {
43 | // Checks if a Plus+Code is valid.
44 | int ok = openlocationcode::IsValid(data_code_16);
45 |
46 | ASSERT_INT_EQ(ok, 1);
47 | }
48 |
49 | static void is_full(void)
50 | {
51 | // Checks if a Plus+Code is full.
52 | int ok = openlocationcode::IsFull(data_code_16);
53 |
54 | ASSERT_INT_EQ(ok, 1);
55 | }
56 |
57 | static void is_short(void)
58 | {
59 | // Checks if a Plus+Code is short.
60 | int ok = openlocationcode::IsShort(data_code_16);
61 |
62 | ASSERT_INT_EQ(ok, 0);
63 | }
64 |
65 | static void shorten(void)
66 | {
67 | // Shorten a Plus+Codes if possible by the given reference latitude and
68 | // longitude.
69 | std::string short_code =
70 | openlocationcode::Shorten(data_code_12, {data_ref_lat, data_ref_lon});
71 |
72 | ASSERT_STR_EQ(short_code.c_str(), "CJ+2VX");
73 | ASSERT_INT_EQ(short_code.length(), 6);
74 | }
75 |
76 | static void recover(void)
77 | {
78 | // Extends a Plus+Code by the given reference latitude and longitude.
79 | std::string recovered_code =
80 | openlocationcode::RecoverNearest(data_code_6, {data_ref_lat, data_ref_lon});
81 |
82 | ASSERT_STR_EQ(recovered_code.c_str(), "9C3W9QCJ+2VX");
83 | ASSERT_INT_EQ(recovered_code.length(), 12);
84 | }
85 |
--------------------------------------------------------------------------------
/c/clang_check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Check the C file and format them with clang-format, unless the script is
3 | # running in a GitHub workflow, in which case we just print an error message.
4 |
5 | CLANG_FORMAT="clang-format-5.0"
6 | if hash $CLANG_FORMAT 2>/dev/null; then
7 | echo "clang-format hashed"
8 | elif hash clang-format 2>/dev/null; then
9 | echo "Cannot find $CLANG_FORMAT, using clang-format"
10 | CLANG_FORMAT="clang-format"
11 | else
12 | echo "Cannot find clang-format"
13 | exit 1
14 | fi
15 |
16 | if [ ! -f ".clang-format" ]; then
17 | echo ".clang-format file not found!"
18 | exit 1
19 | fi
20 |
21 | RETURN=0
22 | :
23 | for FILE in `ls *.[ch] */*.[ch]`; do
24 | DIFF=`diff $FILE <($CLANG_FORMAT $FILE)`
25 | if [ $? -ne 0 ]; then
26 | if [ -z "$GITHUB_WORKFLOW" ]; then
27 | echo "Formatting $FILE" >&2
28 | $CLANG_FORMAT -i $FILE
29 | else
30 | echo -e "\e[31m$FILE has formatting errors:\e[30m" >&2
31 | echo "$DIFF" >&2
32 | fi
33 | RETURN=1
34 | fi
35 | done
36 | exit $RETURN
37 |
--------------------------------------------------------------------------------
/c/example.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "src/olc.h"
3 |
4 | int main(int argc, char* argv[]) {
5 | char code[256];
6 | int len;
7 | OLC_LatLon location;
8 |
9 | // Show current version
10 | printf("=== OLC version [%s] -- %d -- [%d] [%d] [%d] ===\n", OLC_VERSION_STR,
11 | OLC_VERSION_NUM, OLC_VERSION_MAJOR, OLC_VERSION_MINOR,
12 | OLC_VERSION_PATCH);
13 |
14 | // Encodes latitude and longitude into a Plus+Code.
15 | location.lat = 47.0000625;
16 | location.lon = 8.0000625;
17 | len = OLC_EncodeDefault(&location, code, 256);
18 | printf("%s (%d)\n", code, len);
19 | // => "8FVC2222+22"
20 |
21 | // Encodes latitude and longitude into a Plus+Code with a preferred length.
22 | len = OLC_Encode(&location, 16, code, 256);
23 | printf("%s (%d)\n", code, len);
24 | // => "8FVC2222+22GCCCC"
25 |
26 | // Decodes a Plus+Code back into coordinates.
27 | OLC_CodeArea code_area;
28 | OLC_Decode(code, 0, &code_area);
29 | printf("Code length: %.15f : %.15f to %.15f : %.15f (%lu)\n",
30 | code_area.lo.lat, code_area.lo.lon, code_area.hi.lat, code_area.hi.lon,
31 | code_area.len);
32 | // => 47.000062496 8.00006250000001 47.000062504 8.0000625305176 16
33 |
34 | int is_valid = OLC_IsValid(code, 0);
35 | printf("Is Valid: %d\n", is_valid);
36 | // => true
37 |
38 | int is_full = OLC_IsFull(code, 0);
39 | printf("Is Full: %d\n", is_full);
40 | // => true
41 |
42 | int is_short = OLC_IsShort(code, 0);
43 | printf("Is Short: %d\n", is_short);
44 | // => true
45 |
46 | // Shorten a Plus+Codes if possible by the given reference latitude and
47 | // longitude.
48 | const char* orig = "9C3W9QCJ+2VX";
49 | printf("Original: %s\n", orig);
50 | location.lat = 51.3708675;
51 | location.lon = -1.217765625;
52 | len = OLC_Shorten(orig, 0, &location, code, 256);
53 | printf("Shortened: %s\n", code);
54 | // => "CJ+2VX"
55 |
56 | // Extends a Plus+Code by the given reference latitude and longitude.
57 | OLC_RecoverNearest("CJ+2VX", 0, &location, code, 256);
58 | printf("Recovered: %s\n", code);
59 | // => orig
60 |
61 | return 0;
62 | }
63 |
--------------------------------------------------------------------------------
/cpp/.gitignore:
--------------------------------------------------------------------------------
1 | *.o
2 | *.a
3 | openlocationcode_example
4 |
--------------------------------------------------------------------------------
/cpp/BUILD:
--------------------------------------------------------------------------------
1 | # Library to handle Plus Codes
2 | cc_library(
3 | name = "openlocationcode",
4 | srcs = [
5 | "openlocationcode.cc",
6 | ],
7 | hdrs = [
8 | "codearea.h",
9 | "openlocationcode.h",
10 | ],
11 | copts = [
12 | "-pthread",
13 | "-Wall",
14 | "-Wextra",
15 | "-O2",
16 | ],
17 | linkopts = ["-pthread"],
18 | deps = [
19 | ":codearea",
20 | ],
21 | )
22 |
23 | # Code area library, used by Open Location Code
24 | cc_library(
25 | name = "codearea",
26 | srcs = [
27 | "codearea.cc",
28 | ],
29 | hdrs = [
30 | "codearea.h",
31 | ],
32 | visibility = ["//visibility:private"], # Keep private unless needed elsewhere
33 | )
34 |
35 | # Unit test for Open Location Code implementations
36 | cc_test(
37 | name = "openlocationcode_test",
38 | size = "small",
39 | srcs = ["openlocationcode_test.cc"],
40 | copts = [
41 | "-pthread",
42 | "-I@googletest//:include",
43 | ],
44 | linkopts = ["-pthread"],
45 | linkstatic = False,
46 | data = [
47 | "//test_data",
48 | ],
49 | deps = [
50 | ":openlocationcode",
51 | "@googletest//:gtest_main",
52 | ],
53 | testonly = True,
54 | )
55 |
56 | # Example binary for Open Location Code
57 | cc_binary(
58 | name = "openlocationcode_example",
59 | srcs = [
60 | "openlocationcode_example.cc",
61 | ],
62 | deps = [
63 | ":openlocationcode",
64 | ],
65 | )
--------------------------------------------------------------------------------
/cpp/README.md:
--------------------------------------------------------------------------------
1 | # Open Location Code C++ API
2 | This is the C++ implementation of the Open Location Code API.
3 |
4 | # Usage
5 |
6 | See openlocationcode_example.cc for how to use the library. To run the example, use:
7 |
8 | ```
9 | bazel run openlocationcode_example
10 | ```
11 |
12 | # Development
13 |
14 | The library is built/tested using [Bazel](https://bazel.build). To build the library, use:
15 |
16 | ```
17 | bazel build openlocationcode
18 | ```
19 |
20 | To run the tests, use:
21 |
22 | ```
23 | bazel test --test_output=all openlocationcode_test
24 | ```
25 |
26 | The tests use the CSV files in the test_data folder. Make sure you copy this folder to the
27 | root of your local workspace.
28 |
29 | # Formatting
30 |
31 | Code must be formatted using `clang-format`, and this will be checked in the
32 | tests. You can format your code using the script:
33 |
34 | ```
35 | sh clang_check.sh
36 | ```
37 |
--------------------------------------------------------------------------------
/cpp/clang_check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Check formatting of C++ source files using clang-format.
3 | # If running on TravisCI, will display the lines that need changing,
4 | # otherwise it will format the files in place.
5 |
6 | CLANG_FORMAT="clang-format-5.0"
7 | if hash $CLANG_FORMAT 2>/dev/null; then
8 | echo "clang-format hashed"
9 | elif hash clang-format 2>/dev/null; then
10 | echo "Cannot find $CLANG_FORMAT, using clang-format"
11 | CLANG_FORMAT="clang-format"
12 | else
13 | echo "Cannot find clang-format"
14 | exit 1
15 | fi
16 | $CLANG_FORMAT --version
17 |
18 | if [ ! -f ".clang-format" ]; then
19 | echo ".clang-format file not found!"
20 | exit 1
21 | fi
22 |
23 | RETURN=0
24 | :
25 | for FILE in `ls *.cc *.h`; do
26 | DIFF=`diff $FILE <($CLANG_FORMAT $FILE)`
27 | if [ $? -ne 0 ]; then
28 | if [ -z "$TRAVIS" ]; then
29 | echo "Formatting $FILE" >&2
30 | $CLANG_FORMAT -i $FILE
31 | else
32 | echo -e "\e[31m$FILE has formatting errors:\e[30m" >&2
33 | echo "$DIFF" >&2
34 | fi
35 | RETURN=1
36 | fi
37 | done
38 | exit $RETURN
39 |
--------------------------------------------------------------------------------
/cpp/codearea.cc:
--------------------------------------------------------------------------------
1 | #include "codearea.h"
2 |
3 | #include
4 |
5 | namespace openlocationcode {
6 |
7 | const double kLatitudeMaxDegrees = 90;
8 | const double kLongitudeMaxDegrees = 180;
9 |
10 | CodeArea::CodeArea(double latitude_lo, double longitude_lo, double latitude_hi,
11 | double longitude_hi, size_t code_length) {
12 | latitude_lo_ = latitude_lo;
13 | longitude_lo_ = longitude_lo;
14 | latitude_hi_ = latitude_hi;
15 | longitude_hi_ = longitude_hi;
16 | code_length_ = code_length;
17 | }
18 |
19 | double CodeArea::GetLatitudeLo() const { return latitude_lo_; }
20 |
21 | double CodeArea::GetLongitudeLo() const { return longitude_lo_; }
22 |
23 | double CodeArea::GetLatitudeHi() const { return latitude_hi_; }
24 |
25 | double CodeArea::GetLongitudeHi() const { return longitude_hi_; }
26 |
27 | size_t CodeArea::GetCodeLength() const { return code_length_; }
28 |
29 | LatLng CodeArea::GetCenter() const {
30 | const double latitude_center = std::min(
31 | latitude_lo_ + (latitude_hi_ - latitude_lo_) / 2, kLatitudeMaxDegrees);
32 | const double longitude_center =
33 | std::min(longitude_lo_ + (longitude_hi_ - longitude_lo_) / 2,
34 | kLongitudeMaxDegrees);
35 | const LatLng center = {latitude_center, longitude_center};
36 | return center;
37 | }
38 |
39 | } // namespace openlocationcode
40 |
--------------------------------------------------------------------------------
/cpp/codearea.h:
--------------------------------------------------------------------------------
1 | #ifndef LOCATION_OPENLOCATIONCODE_CODEAREA_H_
2 | #define LOCATION_OPENLOCATIONCODE_CODEAREA_H_
3 |
4 | #include
5 |
6 | namespace openlocationcode {
7 |
8 | struct LatLng {
9 | double latitude;
10 | double longitude;
11 | };
12 |
13 | class CodeArea {
14 | public:
15 | CodeArea(double latitude_lo, double longitude_lo, double latitude_hi,
16 | double longitude_hi, size_t code_length);
17 | double GetLatitudeLo() const;
18 | double GetLongitudeLo() const;
19 | double GetLatitudeHi() const;
20 | double GetLongitudeHi() const;
21 | size_t GetCodeLength() const;
22 | LatLng GetCenter() const;
23 |
24 | private:
25 | double latitude_lo_;
26 | double longitude_lo_;
27 | double latitude_hi_;
28 | double longitude_hi_;
29 | size_t code_length_;
30 | };
31 |
32 | } // namespace openlocationcode
33 |
34 | #endif // LOCATION_OPENLOCATIONCODE_CODEAREA_H_
35 |
--------------------------------------------------------------------------------
/cpp/openlocationcode_example.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "openlocationcode.h"
5 |
6 | int main() {
7 | // Encodes latitude and longitude into a Plus+Code.
8 | std::string code = openlocationcode::Encode({47.0000625, 8.0000625});
9 | std::cout << "Encoded: " << code << std::endl;
10 | // => "8FVC2222+22"
11 |
12 | // Encodes latitude and longitude into a Plus+Code with a preferred length.
13 | code = openlocationcode::Encode({47.0000625, 8.0000625}, 16);
14 | std::cout << "Encoded 16: " << code << std::endl;
15 | // => "8FVC2222+22GCCCC"
16 |
17 | // Decodes a Plus+Code back into coordinates.
18 | openlocationcode::CodeArea code_area = openlocationcode::Decode(code);
19 | std::cout << "Code length: " << std::fixed << std::setprecision(15) << ' '
20 | << code_area.GetLatitudeLo() // 47.000062479999997
21 | << ' ' << code_area.GetLongitudeLo() // 8.000062500000013
22 | << ' ' << code_area.GetLatitudeHi() // 47.000062520000000
23 | << ' ' << code_area.GetLongitudeHi() // 8.000062622070317
24 | << ' ' << code_area.GetCodeLength() // 15
25 | << std::endl;
26 |
27 | // Checks if a Plus+Code is valid.
28 | bool isValid = openlocationcode::IsValid(code);
29 | std::cout << "Is valid? " << isValid << std::endl;
30 | // => true
31 |
32 | // Checks if a Plus+Code is full.
33 | bool isFull = openlocationcode::IsFull(code);
34 | std::cout << "Is full? " << isFull << std::endl;
35 | // => true
36 |
37 | // Checks if a Plus+Code is short.
38 | bool isShort = openlocationcode::IsShort(code);
39 | std::cout << "Is short? " << isShort << std::endl;
40 | // => false
41 |
42 | // Shorten a Plus+Codes if possible by the given reference latitude and
43 | // longitude.
44 | std::string short_code =
45 | openlocationcode::Shorten("9C3W9QCJ+2VX", {51.3708675, -1.217765625});
46 | std::cout << "Shortened: " << short_code << std::endl;
47 | // => "CJ+2VX"
48 |
49 | // Extends a Plus+Code by the given reference latitude and longitude.
50 | std::string recovered_code =
51 | openlocationcode::RecoverNearest("CJ+2VX", {51.3708675, -1.217765625});
52 | std::cout << "Recovered: " << recovered_code << std::endl;
53 | // => "9C3W9QCJ+2VX"
54 | }
55 |
--------------------------------------------------------------------------------
/dart/.gitignore:
--------------------------------------------------------------------------------
1 | .packages
2 | pubspec.lock
3 | .dart_tool
--------------------------------------------------------------------------------
/dart/README.md:
--------------------------------------------------------------------------------
1 | # dart library for Open Location Code
2 |
3 | ## Formatting
4 |
5 | Code **must** be formatted using `dart format`.
6 |
7 | To format your files, just run `checks.sh` or:
8 |
9 | ```shell
10 | dart format .
11 | ```
12 |
13 | The TravisCI test **will fail if any files need formatting**.
14 |
15 | ## Hints
16 |
17 | The TravisCI test uses `dartanalyzer` to check the library for improvements. IF
18 | any are found the TravisCI tests **will fail**.
19 |
20 | ## Testing
21 |
22 | To test the dart version first download the dart sdk from
23 | [Dart main site](http://www.dartlang.org) and run this from the repository root
24 | directory:
25 |
26 | ```
27 | ~/open-location-code$ cd dart && dart test
28 | ```
29 |
--------------------------------------------------------------------------------
/dart/checks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Check the formatting of the Dart files and perform static analysis of the code
3 | # with dartanalyzer.
4 | # Run from within the dart directory.
5 |
6 | DART_CMD=dart
7 | $DART_CMD --version >/dev/null 2>&1
8 | if [ $? -ne 0 ]; then
9 | DART_CMD=/usr/lib/dart/bin/dart
10 | fi
11 |
12 | # Define the default return code.
13 | RETURN=0
14 |
15 | # For every dart file, check the formatting.
16 | for FILE in `find * | egrep "\.dart$"`; do
17 | FORMATTED=`$DART_CMD format -o none --set-exit-if-changed "$FILE"`
18 | if [ $? -ne 0 ]; then
19 | if [ -z "$TRAVIS" ]; then
20 | # Running locally, we can just format the file. Use colour codes.
21 | echo -e "\e[1;34m"
22 | $DART_CMD format $FILE
23 | echo -e "\e[0m"
24 | else
25 | # On TravisCI, send a comment with the diff to the pull request.
26 | DIFF=`echo "$FORMATTED" | diff $FILE -`
27 | echo -e "\e[1;31mFile has formatting errors: $FILE\e[0m"
28 | echo "$DIFF"
29 | RETURN=1
30 | go run ../travis-utils/github_comments.go --pr "$TRAVIS_PULL_REQUEST" \
31 | --comment '**File has `dartfmt` errors that must be fixed**. Here is a diff, or run `checks.sh`:'"
$DIFF
" \
32 | --file "dart/$FILE" \
33 | --commit "$TRAVIS_PULL_REQUEST_SHA"
34 | fi
35 | fi
36 | ANALYSIS=`$DART_CMD analyze "$FILE"`
37 | echo "$ANALYSIS" | grep "No issues found" >/dev/null
38 | if [ $? -ne 0 ]; then
39 | echo -e "\e[1;31mStatic analysis problems: $FILE\e[0m"
40 | echo "$ANALYSIS"
41 | if [ "$TRAVIS" != "" ]; then
42 | # On TravisCI, send a comment with the diff to the pull request.
43 | RETURN=1
44 | go run ../travis-utils/github_comments.go --pr "$TRAVIS_PULL_REQUEST" \
45 | --comment '**File has `dartanalyzer` errors that must be addressed**:'"
$ANALYSIS
" \
46 | --file "dart/$FILE" \
47 | --commit "$TRAVIS_PULL_REQUEST_SHA"
48 | fi
49 | fi
50 | done
51 |
52 | if [ $RETURN -ne 0 ]; then
53 | echo -e "\e[1;31mFiles have issues that must be addressed\e[0m"
54 | else
55 | echo -e "\e[1;32mFiles pass all checks\e[0m"
56 | fi
57 | exit $RETURN
58 |
--------------------------------------------------------------------------------
/dart/lib/open_location_code.dart:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Google Inc. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | library open_location_code;
18 |
19 | export 'src/open_location_code.dart';
20 |
--------------------------------------------------------------------------------
/dart/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: open_location_code
2 | description: Plus Codes are short, generated codes that can be used like street addresses, for places where street addresses don't exist.
3 | version: 0.0.1
4 | homepage: https://maps.google.com/pluscodes/
5 | environment:
6 | sdk: '^2.19.6'
7 | dev_dependencies:
8 | test: ^1.24.3
9 |
--------------------------------------------------------------------------------
/dart/test/benchmark_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:open_location_code/open_location_code.dart' as olc;
2 | import 'package:test/test.dart';
3 | import 'dart:math';
4 |
5 | void main() {
6 | test('Benchmarking encode and decode', () {
7 | var now = DateTime.now();
8 | var random = Random(now.millisecondsSinceEpoch);
9 | var testData = [];
10 | for (var i = 0; i < 1000000; i++) {
11 | var lat = random.nextDouble() * 180 - 90;
12 | var lng = random.nextDouble() * 360 - 180;
13 | var exp = pow(10, (random.nextDouble() * 10).toInt());
14 | lat = (lat * exp).round() / exp;
15 | lng = (lng * exp).round() / exp;
16 | var length = 2 + (random.nextDouble() * 13).round();
17 | if (length < 10 && length % 2 == 1) {
18 | length += 1;
19 | }
20 | var code = olc.encode(lat, lng, codeLength: length);
21 | olc.decode(code);
22 | testData.add([lat, lng, length, code]);
23 | }
24 | var stopwatch = Stopwatch()..start();
25 | for (var i = 0; i < testData.length; i++) {
26 | olc.encode(testData[i][0], testData[i][1], codeLength: testData[i][2]);
27 | }
28 | var duration = stopwatch.elapsedMicroseconds;
29 | print(
30 | 'Encoding benchmark ${testData.length}, duration ${duration} usec, '
31 | 'average ${duration / testData.length} usec',
32 | );
33 |
34 | stopwatch = Stopwatch()..start();
35 | for (var i = 0; i < testData.length; i++) {
36 | olc.decode(testData[i][3]);
37 | }
38 | duration = stopwatch.elapsedMicroseconds;
39 | print(
40 | 'Decoding benchmark ${testData.length}, duration ${duration} usec, '
41 | 'average ${duration / testData.length} usec',
42 | );
43 | });
44 | }
45 |
--------------------------------------------------------------------------------
/dart/test/clip_latitude_test.dart:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Google Inc. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import 'package:open_location_code/open_location_code.dart' as olc;
18 | import 'package:test/test.dart';
19 |
20 | void main() {
21 | test('Clip latitude test', () {
22 | expect(olc.clipLatitude(100.0), 90.0);
23 | expect(olc.clipLatitude(-100.0), -90.0);
24 | expect(olc.clipLatitude(10.0), 10.0);
25 | expect(olc.clipLatitude(-10.0), -10.0);
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/dart/test/compute_precision_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:open_location_code/open_location_code.dart' as olc;
2 | import 'package:test/test.dart';
3 |
4 | void main() {
5 | test('Compute precision test', () {
6 | expect(olc.computeLatitudePrecision(10), 0.000125);
7 | expect(olc.computeLatitudePrecision(11), 0.000025);
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/dart/test/decode_test.dart:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Google Inc. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import 'package:open_location_code/open_location_code.dart' as olc;
18 | import 'package:test/test.dart';
19 | import 'utils.dart';
20 |
21 | // code,lat,lng,latLo,lngLo,latHi,lngHi
22 | void checkEncodeDecode(String csvLine) {
23 | var elements = csvLine.split(',');
24 | var code = elements[0];
25 | num len = int.parse(elements[1]);
26 | num latLo = double.parse(elements[2]);
27 | num lngLo = double.parse(elements[3]);
28 | num latHi = double.parse(elements[4]);
29 | num lngHi = double.parse(elements[5]);
30 | var codeArea = olc.decode(code);
31 | expect(codeArea.codeLength, equals(len));
32 | expect(codeArea.south, closeTo(latLo, 0.001));
33 | expect(codeArea.north, closeTo(latHi, 0.001));
34 | expect(codeArea.west, closeTo(lngLo, 0.001));
35 | expect(codeArea.east, closeTo(lngHi, 0.001));
36 | }
37 |
38 | void main() {
39 | test('Check decode', () {
40 | csvLinesFromFile('decoding.csv').forEach(checkEncodeDecode);
41 | });
42 |
43 | test('MaxCodeLength', () {
44 | // Check that we do not return a code longer than is valid.
45 | var code = olc.encode(51.3701125, -10.202665625, codeLength: 1000000);
46 | expect(code.length, 16);
47 | expect(olc.isValid(code), true);
48 |
49 | // Extend the code with a valid character and make sure it is still valid.
50 | var tooLongCode = code + 'W';
51 | expect(olc.isValid(tooLongCode), true);
52 |
53 | // Extend the code with an invalid character and make sure it is invalid.
54 | tooLongCode = code + 'U';
55 | expect(olc.isValid(tooLongCode), false);
56 | });
57 | }
58 |
--------------------------------------------------------------------------------
/dart/test/short_code_test.dart:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Google Inc. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import 'package:open_location_code/open_location_code.dart' as olc;
18 | import 'package:test/test.dart';
19 | import 'utils.dart';
20 |
21 | // full code,lat,lng,shortcode
22 | void checkShortCode(String csvLine) {
23 | var elements = csvLine.split(',');
24 | var code = elements[0];
25 | num lat = double.parse(elements[1]);
26 | num lng = double.parse(elements[2]);
27 | var shortCode = elements[3];
28 | var testType = elements[4];
29 | if (testType == 'B' || testType == 'S') {
30 | var short = olc.shorten(code, lat, lng);
31 | expect(short, equals(shortCode));
32 | }
33 | if (testType == 'B' || testType == 'R') {
34 | var expanded = olc.recoverNearest(shortCode, lat, lng);
35 | expect(expanded, equals(code));
36 | }
37 | }
38 |
39 | void main() {
40 | test('Check short codes', () {
41 | csvLinesFromFile('shortCodeTests.csv').forEach(checkShortCode);
42 | });
43 | }
44 |
--------------------------------------------------------------------------------
/dart/test/utils.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 | import 'package:path/path.dart' as path;
3 |
4 | List getCsvLines(String fileName) {
5 | return File(fileName)
6 | .readAsLinesSync()
7 | .where((x) => x.isNotEmpty && !x.startsWith('#'))
8 | .map((x) => x.trim())
9 | .toList();
10 | }
11 |
12 | // Requires test csv files in a test_data directory under Open Location Code project root.
13 | String testDataPath() {
14 | var projectRoot = Directory.current.parent;
15 |
16 | return path.absolute(projectRoot.path, 'test_data');
17 | }
18 |
19 | String cvsWithAbsolutePath(String file) => path.absolute(testDataPath(), file);
20 |
21 | List csvLinesFromFile(String file) =>
22 | getCsvLines(cvsWithAbsolutePath(file));
23 |
--------------------------------------------------------------------------------
/dart/test/validity_test.dart:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2015 Google Inc. All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | import 'package:open_location_code/open_location_code.dart' as olc;
18 | import 'package:test/test.dart';
19 | import 'utils.dart';
20 |
21 | // code,isValid,isShort,isFull
22 | void checkValidity(String csvLine) {
23 | var elements = csvLine.split(',');
24 | var code = elements[0];
25 | var isValid = elements[1] == 'true';
26 | var isShort = elements[2] == 'true';
27 | var isFull = elements[3] == 'true';
28 | expect(olc.isValid(code), equals(isValid));
29 | expect(olc.isShort(code), equals(isShort));
30 | expect(olc.isFull(code), equals(isFull));
31 | }
32 |
33 | void main() {
34 | test('Check Validity', () {
35 | csvLinesFromFile('validityTests.csv').forEach(checkValidity);
36 | });
37 | }
38 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | PlusCodeDatafield
4 |
5 |
6 |
7 |
8 |
9 | connectiq.builder
10 |
11 |
12 |
13 |
14 |
15 | connectiq.projectNature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/monkey.jungle:
--------------------------------------------------------------------------------
1 | project.manifest = manifest.xml
2 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-d2bravo/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-d2bravo/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-d2bravo/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-d2bravo_titanium/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-d2bravo_titanium/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-d2bravo_titanium/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge1030/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge1030/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-edge1030/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge1030bontrager/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge1030bontrager/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-edge1030bontrager/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge130/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge130/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-edge130/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge520plus/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge520plus/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-edge520plus/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge820/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge820/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-edge820/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge_1000/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge_1000/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-edge_1000/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge_520/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-edge_520/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-edge_520/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-epix/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-epix/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-epix/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix3/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix3/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fenix3/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix3_hr/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix3_hr/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fenix3_hr/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fenix5/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5plus/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5plus/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fenix5plus/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5s/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5s/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fenix5s/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5x/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenix5x/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fenix5x/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenixchronos/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fenixchronos/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fenixchronos/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr235/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr235/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fr235/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr630/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr630/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fr630/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr645/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr645/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fr645/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr645m/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr645m/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fr645m/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr735xt/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr735xt/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fr735xt/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr920xt/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr920xt/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fr920xt/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr935/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-fr935/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-fr935/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-oregon7xx/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-oregon7xx/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-oregon7xx/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-rino7xx/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-rino7xx/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-rino7xx/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-vivoactive/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive3/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive3/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-vivoactive3/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive3m/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive3m/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-vivoactive3m/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive_hr/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive_hr/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-vivoactive_hr/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive_hr/resources-fenix3_hr/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources-vivoactive_hr/resources-fenix3_hr/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources-vivoactive_hr/resources-fenix3_hr/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/garmin/PlusCodeDatafield/resources/launcher_icon.png
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources/layouts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/resources/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Plus Codes
3 | plus.codes
4 | ---
5 |
6 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/source/PlusCodeBackground.mc:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc. All rights reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the 'License');
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an 'AS IS' BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using Toybox.WatchUi as Ui;
16 | using Toybox.Application as App;
17 | using Toybox.Graphics as Gfx;
18 |
19 | /**
20 | * Provides a Drawable object for the background of the datafield.
21 | * It's used in the layout.
22 | */
23 | class PlusCodeBackground extends Ui.Drawable {
24 |
25 | hidden var mColor;
26 |
27 | function initialize() {
28 | var dictionary = {
29 | :identifier => "Background"
30 | };
31 |
32 | Drawable.initialize(dictionary);
33 | }
34 |
35 | function setColor(color) {
36 | mColor = color;
37 | }
38 |
39 | function draw(dc) {
40 | dc.setColor(Gfx.COLOR_TRANSPARENT, mColor);
41 | dc.clear();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/garmin/PlusCodeDatafield/source/PlusCodeDatafield.mc:
--------------------------------------------------------------------------------
1 | // Copyright 2017 Google Inc. All rights reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the 'License');
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an 'AS IS' BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | using Toybox.Application as App;
16 |
17 | /**
18 | * Main class to draw the datafield.
19 | * Initialises and returns the app.
20 | */
21 | class PlusCodeDatafield extends App.AppBase {
22 |
23 | function initialize() {
24 | AppBase.initialize();
25 | }
26 |
27 | // onStart() is called on application start up
28 | function onStart(state) {
29 | }
30 |
31 | // onStop() is called when your application is exiting
32 | function onStop(state) {
33 | }
34 |
35 | // Return the initial view of your application here
36 | function getInitialView() {
37 | return [ new PlusCodeView() ];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/go/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | olc-fuzz.zip
3 |
--------------------------------------------------------------------------------
/go/README.md:
--------------------------------------------------------------------------------
1 | [](http://godoc.org/github.com/google/open-location-code/go)
2 |
3 | # Formatting
4 |
5 | Go files must be formatted with [gofmt](https://golang.org/cmd/gofmt/), and the
6 | tests will check that this is the case. If the files are not correctly
7 | formatted, the tests will fail.
8 |
9 | You can format your files by running:
10 |
11 | gofmt -w -s .
12 |
13 | # Testing
14 |
15 | Run the unit tests from within the `go` directory with:
16 |
17 | ```
18 | go test . -v
19 | ```
20 |
21 | To also run the benchmark tests, run:
22 |
23 | ```
24 | go test -bench=. . -v
25 | ```
26 |
27 | ## Test with Go-Fuzz
28 |
29 | go get github.com/dvyukov/go-fuzz/...
30 |
31 | go generate github.com/google/open-location-code/go
32 |
33 | go-fuzz-build github.com/google/open-location-code/go
34 | go-fuzz -bin=./olc-fuzz.zip -workdir=/tmp/olc-fuzz
35 |
36 | # Install
37 |
38 | go get github.com/google/open-location-code/go
39 |
40 |
--------------------------------------------------------------------------------
/go/corpus/.gitignore:
--------------------------------------------------------------------------------
1 | *.txt
2 | [0-9a-f][0-9a-f][0-9a-f][0-9a-f]*
3 |
--------------------------------------------------------------------------------
/go/corpus/gen.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Tamás Gulácsi. All rights reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the 'License');
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an 'AS IS' BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | // This little program generates 00%d.code.txt corpus for go-fuzz-build,
16 | // into the given directory.
17 | package main
18 |
19 | import (
20 | "bytes"
21 | "flag"
22 | "fmt"
23 | "io/ioutil"
24 | "log"
25 | "os"
26 | "path/filepath"
27 | "strings"
28 | )
29 |
30 | func main() {
31 | flagDir := flag.String("dest", ".", "destination directory")
32 | flagTestData := flag.String("test-data", filepath.Join("..", "..", "test_data"), "the js test_data with the csv files for tests")
33 | flag.Parse()
34 |
35 | if err := extractCorpus(*flagDir, *flagTestData); err != nil {
36 | log.Fatal(err)
37 | }
38 | }
39 |
40 | func extractCorpus(dir, src string) error {
41 | fis, err := ioutil.ReadDir(src)
42 | if err != nil {
43 | log.Printf("read test_data from %s: %v", src, err)
44 | return err
45 | }
46 | _ = os.MkdirAll(dir, 0755)
47 | n := 0
48 | for _, fi := range fis {
49 | if !strings.HasSuffix(fi.Name(), ".csv") {
50 | continue
51 | }
52 | fn := filepath.Join(src, fi.Name())
53 | data, err := ioutil.ReadFile(fn)
54 | if err != nil {
55 | log.Printf("read csv %s: %v", fn, err)
56 | continue
57 | }
58 | for _, row := range bytes.Split(data, []byte{'\n'}) {
59 | if i := bytes.IndexByte(row, '#'); i >= 0 {
60 | row = row[:i]
61 | }
62 | // assume that the first field is the code
63 | if i := bytes.IndexByte(row, ','); i >= 0 {
64 | fn := filepath.Join(dir, fmt.Sprintf("%003d.code.txt", n))
65 | if err := ioutil.WriteFile(fn, row[:i], 0644); err != nil {
66 | log.Printf("Write %s: %v", fn, err)
67 | continue
68 | }
69 | n++
70 | }
71 | }
72 | }
73 | return nil
74 | }
75 |
--------------------------------------------------------------------------------
/go/decode.go:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Tamás Gulácsi. All rights reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the 'License');
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an 'AS IS' BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | package olc
16 |
17 | import (
18 | "errors"
19 | "strings"
20 | )
21 |
22 | // Decode decodes an Open Location Code into the location coordinates.
23 | // Returns a CodeArea object that includes the coordinates of the bounding
24 | // box - the lower left, center and upper right.
25 | //
26 | // Longer codes are allowed, but only the first 15 is decoded.
27 | func Decode(code string) (CodeArea, error) {
28 | var area CodeArea
29 | if err := CheckFull(code); err != nil {
30 | return area, err
31 | }
32 | // Strip out separator character, padding characters and convert to upper
33 | // case.
34 | code = StripCode(code)
35 | codeLen := len(code)
36 | if codeLen < 2 {
37 | return area, errors.New("code too short")
38 | }
39 | // lat and lng build up the integer values.
40 | var lat int64
41 | var lng int64
42 | // height and width build up integer values for the height and width of the
43 | // code area. They get set to 1 for the last digit and then multiplied by
44 | // each remaining place.
45 | var height int64 = 1
46 | var width int64 = 1
47 | // Decode the paired digits.
48 | for i := 0; i < pairCodeLen; i += 2 {
49 | lat *= encBase
50 | lng *= encBase
51 | height *= encBase
52 | if i < codeLen {
53 | lat += int64(strings.IndexByte(Alphabet, code[i]))
54 | lng += int64(strings.IndexByte(Alphabet, code[i+1]))
55 | height = 1
56 | }
57 | }
58 | // The paired section has the same resolution for height and width.
59 | width = height
60 | // Decode the grid section.
61 | for i := pairCodeLen; i < maxCodeLen; i++ {
62 | lat *= gridRows
63 | height *= gridRows
64 | lng *= gridCols
65 | width *= gridCols
66 | if i < codeLen {
67 | dval := int64(strings.IndexByte(Alphabet, code[i]))
68 | lat += dval / gridCols
69 | lng += dval % gridCols
70 | height = 1
71 | width = 1
72 | }
73 | }
74 | // Convert everything into degrees and return the code area.
75 | var latDegrees float64 = float64(lat-latMax*finalLatPrecision) / float64(finalLatPrecision)
76 | var lngDegrees float64 = float64(lng-lngMax*finalLngPrecision) / float64(finalLngPrecision)
77 | var heightDegrees float64 = float64(height) / float64(finalLatPrecision)
78 | var widthDegrees float64 = float64(width) / float64(finalLngPrecision)
79 | return CodeArea{
80 | LatLo: latDegrees,
81 | LngLo: lngDegrees,
82 | LatHi: latDegrees + heightDegrees,
83 | LngHi: lngDegrees + widthDegrees,
84 | Len: codeLen,
85 | }, nil
86 | }
87 |
--------------------------------------------------------------------------------
/go/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/google/open-location-code/go
2 |
3 | go 1.12
4 |
--------------------------------------------------------------------------------
/go/go.sum:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/go/go.sum
--------------------------------------------------------------------------------
/go/olc_gofuzz.go:
--------------------------------------------------------------------------------
1 | //go:build gofuzz
2 | // +build gofuzz
3 |
4 | // Copyright 2015 Tamás Gulácsi. All rights reserved.
5 | //
6 | // Licensed under the Apache License, Version 2.0 (the 'License');
7 | // you may not use this file except in compliance with the License.
8 | // You may obtain a copy of the License at
9 | //
10 | // http://www.apache.org/licenses/LICENSE-2.0
11 | //
12 | // Unless required by applicable law or agreed to in writing, software
13 | // distributed under the License is distributed on an 'AS IS' BASIS,
14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | // See the License for the specific language governing permissions and
16 | // limitations under the License.
17 |
18 | package olc
19 |
20 | //go:generate go run corpus/gen.go -test-data=../test_data -dest=corpus
21 |
22 | // Fuzz usage:
23 | //
24 | // go get github.com/dvyukov/go-fuzz/...
25 | //
26 | // go-fuzz-build github.com/google/open-location-code/go && go-fuzz -bin=./olc-fuzz.zip -workdir=/tmp/olc-fuzz
27 | func Fuzz(data []byte) int {
28 | code := string(data)
29 | if err := Check(code); err != nil {
30 | return 0
31 | }
32 | area, err := Decode(code)
33 | if err != nil {
34 | return 2
35 | }
36 | if _, err = Decode(Encode(area.LatLo, area.LngLo, len(code))); err != nil {
37 | return 2
38 | }
39 | if _, err = Decode(Encode(area.LatHi, area.LngHi, len(code))); err != nil {
40 | return 2
41 | }
42 |
43 | return 1
44 | }
45 |
--------------------------------------------------------------------------------
/java/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore class and jar files
2 | *.class
3 | *.jar
4 | # Ignore generated Maven files
5 | target/*
6 |
--------------------------------------------------------------------------------
/java/src/test/java/com/google/openlocationcode/BenchmarkTest.java:
--------------------------------------------------------------------------------
1 | package com.google.openlocationcode;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Random;
6 |
7 | import org.junit.Before;
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 | import org.junit.runners.JUnit4;
11 |
12 | /** Benchmark the encode and decode methods. */
13 | @RunWith(JUnit4.class)
14 | public class BenchmarkTest {
15 |
16 | public static final int LOOPS = 1000000;
17 |
18 | public static Random generator = new Random();
19 |
20 | private static class TestData {
21 |
22 | private final double latitude;
23 | private final double longitude;
24 | private final int length;
25 | private final String code;
26 |
27 | public TestData() {
28 | this.latitude = generator.nextDouble() * 180 - 90;
29 | this.longitude = generator.nextDouble() * 360 - 180;
30 | int length = generator.nextInt(11) + 4;
31 | if (length < 10 && length % 2 == 1) {
32 | length += 1;
33 | }
34 | this.length = length;
35 | this.code = OpenLocationCode.encode(this.latitude, this.longitude, this.length);
36 | }
37 | }
38 |
39 | private final List testDataList = new ArrayList<>();
40 |
41 | @Before
42 | public void setUp() throws Exception {
43 | testDataList.clear();
44 | for (int i = 0; i < LOOPS; i++) {
45 | testDataList.add(new TestData());
46 | }
47 | }
48 |
49 | @Test
50 | public void benchmarkEncode() {
51 | long start = System.nanoTime();
52 | for (TestData testData : testDataList) {
53 | OpenLocationCode.encode(testData.latitude, testData.longitude, testData.length);
54 | }
55 | long microsecs = (System.nanoTime() - start) / 1000;
56 |
57 | System.out.printf(
58 | "Encode %d loops in %d usecs, %.3f usec per call\n",
59 | LOOPS, microsecs, (double) microsecs / LOOPS);
60 | }
61 |
62 | @Test
63 | public void benchmarkDecode() {
64 | long start = System.nanoTime();
65 | for (TestData testData : testDataList) {
66 | OpenLocationCode.decode(testData.code);
67 | }
68 | long microsecs = (System.nanoTime() - start) / 1000;
69 |
70 | System.out.printf(
71 | "Decode %d loops in %d usecs, %.3f usec per call\n",
72 | LOOPS, microsecs, (double) microsecs / LOOPS);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/java/src/test/java/com/google/openlocationcode/PrecisionTest.java:
--------------------------------------------------------------------------------
1 | package com.google.openlocationcode;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.junit.runners.JUnit4;
7 |
8 | /** Tests size of rectangles defined by Plus Codes of various size. */
9 | @RunWith(JUnit4.class)
10 | public class PrecisionTest {
11 |
12 | private static final double EPSILON = 1e-10;
13 |
14 | @Test
15 | public void testWidthInDegrees() {
16 | Assert.assertEquals(
17 | new OpenLocationCode("67000000+").decode().getLongitudeWidth(), 20., EPSILON);
18 | Assert.assertEquals(
19 | new OpenLocationCode("67890000+").decode().getLongitudeWidth(), 1., EPSILON);
20 | Assert.assertEquals(
21 | new OpenLocationCode("6789CF00+").decode().getLongitudeWidth(), 0.05, EPSILON);
22 | Assert.assertEquals(
23 | new OpenLocationCode("6789CFGH+").decode().getLongitudeWidth(), 0.0025, EPSILON);
24 | Assert.assertEquals(
25 | new OpenLocationCode("6789CFGH+JM").decode().getLongitudeWidth(), 0.000125, EPSILON);
26 | Assert.assertEquals(
27 | new OpenLocationCode("6789CFGH+JMP").decode().getLongitudeWidth(), 0.00003125, EPSILON);
28 | }
29 |
30 | @Test
31 | public void testHeightInDegrees() {
32 | Assert.assertEquals(
33 | new OpenLocationCode("67000000+").decode().getLatitudeHeight(), 20., EPSILON);
34 | Assert.assertEquals(
35 | new OpenLocationCode("67890000+").decode().getLatitudeHeight(), 1., EPSILON);
36 | Assert.assertEquals(
37 | new OpenLocationCode("6789CF00+").decode().getLatitudeHeight(), 0.05, EPSILON);
38 | Assert.assertEquals(
39 | new OpenLocationCode("6789CFGH+").decode().getLatitudeHeight(), 0.0025, EPSILON);
40 | Assert.assertEquals(
41 | new OpenLocationCode("6789CFGH+JM").decode().getLatitudeHeight(), 0.000125, EPSILON);
42 | Assert.assertEquals(
43 | new OpenLocationCode("6789CFGH+JMP").decode().getLatitudeHeight(), 0.000025, EPSILON);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/java/src/test/java/com/google/openlocationcode/RecoverTest.java:
--------------------------------------------------------------------------------
1 | package com.google.openlocationcode;
2 |
3 | import junit.framework.Assert;
4 |
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.junit.runners.JUnit4;
8 |
9 | /** Test recovery near the poles. */
10 | @RunWith(JUnit4.class)
11 | public class RecoverTest {
12 |
13 | @Test
14 | public void testRecoveryNearSouthPole() {
15 | OpenLocationCode olc = new OpenLocationCode("XXXXXX+XX");
16 | Assert.assertEquals("2CXXXXXX+XX", olc.recover(-81.0, 0.0).getCode());
17 | }
18 |
19 | @Test
20 | public void testRecoveryNearNorthPole() {
21 | OpenLocationCode olc = new OpenLocationCode("2222+22");
22 | Assert.assertEquals("CFX22222+22", olc.recover(89.6, 0.0).getCode());
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/java/src/test/java/com/google/openlocationcode/ShorteningTest.java:
--------------------------------------------------------------------------------
1 | package com.google.openlocationcode;
2 |
3 | import static java.nio.charset.StandardCharsets.UTF_8;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.FileInputStream;
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | import org.junit.Assert;
13 | import org.junit.Before;
14 | import org.junit.Test;
15 | import org.junit.runner.RunWith;
16 | import org.junit.runners.JUnit4;
17 |
18 | /** Tests shortening functionality of Open Location Code. */
19 | @RunWith(JUnit4.class)
20 | public class ShorteningTest {
21 |
22 | private static class TestData {
23 |
24 | private final String code;
25 | private final double referenceLatitude;
26 | private final double referenceLongitude;
27 | private final String shortCode;
28 | private final String testType;
29 |
30 | public TestData(String line) {
31 | String[] parts = line.split(",");
32 | if (parts.length != 5) {
33 | throw new IllegalArgumentException("Wrong format of testing data.");
34 | }
35 | this.code = parts[0];
36 | this.referenceLatitude = Double.parseDouble(parts[1]);
37 | this.referenceLongitude = Double.parseDouble(parts[2]);
38 | this.shortCode = parts[3];
39 | this.testType = parts[4];
40 | }
41 | }
42 |
43 | private final List testDataList = new ArrayList<>();
44 |
45 | @Before
46 | public void setUp() throws Exception {
47 | InputStream testDataStream = new FileInputStream(TestUtils.getTestFile("shortCodeTests.csv"));
48 | BufferedReader reader = new BufferedReader(new InputStreamReader(testDataStream, UTF_8));
49 | String line;
50 | while ((line = reader.readLine()) != null) {
51 | if (line.startsWith("#")) {
52 | continue;
53 | }
54 | testDataList.add(new TestData(line));
55 | }
56 | }
57 |
58 | @Test
59 | public void testShortening() {
60 | for (TestData testData : testDataList) {
61 | if (!"B".equals(testData.testType) && !"S".equals(testData.testType)) {
62 | continue;
63 | }
64 | OpenLocationCode olc = new OpenLocationCode(testData.code);
65 | OpenLocationCode shortened =
66 | olc.shorten(testData.referenceLatitude, testData.referenceLongitude);
67 | Assert.assertEquals(
68 | "Wrong shortening of code " + testData.code, testData.shortCode, shortened.getCode());
69 | }
70 | }
71 |
72 | @Test
73 | public void testRecovering() {
74 | for (TestData testData : testDataList) {
75 | if (!"B".equals(testData.testType) && !"R".equals(testData.testType)) {
76 | continue;
77 | }
78 | OpenLocationCode olc = new OpenLocationCode(testData.shortCode);
79 | OpenLocationCode recovered =
80 | olc.recover(testData.referenceLatitude, testData.referenceLongitude);
81 | Assert.assertEquals(testData.code, recovered.getCode());
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/java/src/test/java/com/google/openlocationcode/TestUtils.java:
--------------------------------------------------------------------------------
1 | package com.google.openlocationcode;
2 |
3 | import java.io.File;
4 |
5 | public class TestUtils {
6 | // Gets the test file, factoring in whether it's being built from Maven or Bazel.
7 | public static File getTestFile(String testFile) {
8 | String testPath;
9 | String bazelRootPath = System.getenv("JAVA_RUNFILES");
10 | if (bazelRootPath == null) {
11 | File userDir = new File(System.getProperty("user.dir"));
12 | testPath = userDir.getParent() + "/test_data";
13 | } else {
14 | testPath = bazelRootPath + "/_main/test_data";
15 | }
16 | return new File(testPath, testFile);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/java/src/test/java/com/google/openlocationcode/UtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.google.openlocationcode;
2 |
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 | import org.junit.runner.RunWith;
6 | import org.junit.runners.JUnit4;
7 |
8 | /** Tests various util methods. */
9 | @RunWith(JUnit4.class)
10 | public class UtilsTest {
11 |
12 | public static final double PRECISION = 1e-10;
13 |
14 | @Test
15 | public void testClipping() {
16 | Assert.assertEquals(
17 | "Clipping of negative latitude doesn't work.",
18 | OpenLocationCode.encode(-90, 5),
19 | OpenLocationCode.encode(-91, 5));
20 | Assert.assertEquals(
21 | "Clipping of positive latitude doesn't work.",
22 | OpenLocationCode.encode(90, 5),
23 | OpenLocationCode.encode(91, 5));
24 | Assert.assertEquals(
25 | "Clipping of negative longitude doesn't work.",
26 | OpenLocationCode.encode(5, 175),
27 | OpenLocationCode.encode(5, -185));
28 | Assert.assertEquals(
29 | "Clipping of very long negative longitude doesn't work.",
30 | OpenLocationCode.encode(5, 175),
31 | OpenLocationCode.encode(5, -905));
32 | Assert.assertEquals(
33 | "Clipping of very long positive longitude doesn't work.",
34 | OpenLocationCode.encode(5, -175),
35 | OpenLocationCode.encode(5, 905));
36 | }
37 |
38 | @Test
39 | public void testMaxCodeLength() {
40 | // Check that we do not return a code longer than is valid.
41 | String code = OpenLocationCode.encode(51.3701125, -10.202665625, 1000000);
42 | Assert.assertEquals(
43 | "Encoded code should have a length of MAX_DIGIT_COUNT + 1 for the plus symbol",
44 | OpenLocationCode.MAX_DIGIT_COUNT + 1,
45 | code.length());
46 | Assert.assertTrue("Code should be valid.", OpenLocationCode.isValidCode(code));
47 | // Extend the code with a valid character and make sure it is still valid.
48 | String tooLongCode = code + "W";
49 | Assert.assertTrue(
50 | "Too long code with all valid characters should be valid.",
51 | OpenLocationCode.isValidCode(tooLongCode));
52 | // Extend the code with an invalid character and make sure it is invalid.
53 | tooLongCode = code + "U";
54 | Assert.assertFalse(
55 | "Too long code with invalid character should be invalid.",
56 | OpenLocationCode.isValidCode(tooLongCode));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/java/src/test/java/com/google/openlocationcode/ValidityTest.java:
--------------------------------------------------------------------------------
1 | package com.google.openlocationcode;
2 |
3 | import static java.nio.charset.StandardCharsets.UTF_8;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.FileInputStream;
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | import org.junit.Assert;
13 | import org.junit.Before;
14 | import org.junit.Test;
15 | import org.junit.runner.RunWith;
16 | import org.junit.runners.JUnit4;
17 |
18 | /**
19 | * Tests methods {@link com.google.openlocationcode.OpenLocationCode#isValidCode(String)}, {@link
20 | * com.google.openlocationcode.OpenLocationCode#isShortCode(String)}} and {@link
21 | * com.google.openlocationcode.OpenLocationCode#isFullCode(String)} Open Location Code.
22 | */
23 | @RunWith(JUnit4.class)
24 | public class ValidityTest {
25 |
26 | private static class TestData {
27 |
28 | private final String code;
29 | private final boolean isValid;
30 | private final boolean isShort;
31 | private final boolean isFull;
32 |
33 | public TestData(String line) {
34 | String[] parts = line.split(",");
35 | if (parts.length != 4) {
36 | throw new IllegalArgumentException("Wrong format of testing data.");
37 | }
38 | this.code = parts[0];
39 | this.isValid = Boolean.parseBoolean(parts[1]);
40 | this.isShort = Boolean.parseBoolean(parts[2]);
41 | this.isFull = Boolean.parseBoolean(parts[3]);
42 | }
43 | }
44 |
45 | private final List testDataList = new ArrayList<>();
46 |
47 | @Before
48 | public void setUp() throws Exception {
49 | InputStream testDataStream = new FileInputStream(TestUtils.getTestFile("validityTests.csv"));
50 | BufferedReader reader = new BufferedReader(new InputStreamReader(testDataStream, UTF_8));
51 | String line;
52 | while ((line = reader.readLine()) != null) {
53 | if (line.startsWith("#")) {
54 | continue;
55 | }
56 | testDataList.add(new TestData(line));
57 | }
58 | }
59 |
60 | @Test
61 | public void testIsValid() {
62 | for (TestData testData : testDataList) {
63 | Assert.assertEquals(
64 | "Validity of code " + testData.code + " is wrong.",
65 | testData.isValid,
66 | OpenLocationCode.isValidCode(testData.code));
67 | }
68 | }
69 |
70 | @Test
71 | public void testIsShort() {
72 | for (TestData testData : testDataList) {
73 | Assert.assertEquals(
74 | "Shortness of code " + testData.code + " is wrong.",
75 | testData.isShort,
76 | OpenLocationCode.isShortCode(testData.code));
77 | }
78 | }
79 |
80 | @Test
81 | public void testIsFull() {
82 | for (TestData testData : testDataList) {
83 | Assert.assertEquals(
84 | "Fullness of code " + testData.code + " is wrong.",
85 | testData.isFull,
86 | OpenLocationCode.isFullCode(testData.code));
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/js/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "env": {
3 | "browser": true,
4 | "es6": true
5 | },
6 | "extends": "google",
7 | "globals": {
8 | "Atomics": "readonly",
9 | "SharedArrayBuffer": "readonly"
10 | },
11 | "parserOptions": {
12 | "ecmaVersion": 2018
13 | },
14 | "rules": {
15 | // Rules are based on the Google styleguide with the following overrides.
16 | "max-len": [2, {
17 | code: 100,
18 | tabWidth: 2,
19 | ignoreUrls: true,
20 | }],
21 | "no-var": 0,
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/js/checks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Run lint checks on files in the Javascript directory.
3 | # When running within TravisCI, post comments back to the pull request.
4 | # Also converts the test CSV files to JSON ready for the tests to execute.
5 | # Note: must run within the JS directory.
6 | if [ `basename "$PWD"` != "js" ]; then
7 | echo "$0: must be run from within the js directory!"
8 | exit 1
9 | fi
10 |
11 | # Require that the NPM install and CSV conversion commands succeed.
12 | set -e
13 |
14 | # Install all the dependencies.
15 | npm install
16 |
17 | # Convert the CSV test files to JSON and put them in the test directory for serving.
18 | go run ../test_data/csv_to_json.go --csv ../test_data/decoding.csv >test/decoding.json
19 | go run ../test_data/csv_to_json.go --csv ../test_data/encoding.csv >test/encoding.json
20 | go run ../test_data/csv_to_json.go --csv ../test_data/shortCodeTests.csv >test/shortCodeTests.json
21 | go run ../test_data/csv_to_json.go --csv ../test_data/validityTests.csv >test/validityTests.json
22 |
23 | set +e
24 |
25 | # Run the tests
26 | npm test
27 | # Save the return value for the end.
28 | RETURN=$?
29 |
30 | # Run eslint based on local installs as well as in PATH.
31 | # eslint errors will cause a build failure.
32 | ESLINT=eslint
33 | $ESLINT --version >/dev/null 2>&1
34 | if [ $? -ne 0 ]; then
35 | ESLINT=./node_modules/.bin/eslint
36 | fi
37 |
38 | $ESLINT --version >/dev/null 2>&1
39 | if [ $? -ne 0 ]; then
40 | echo "\e[1;31mCannot find eslint, check your installation\e[0m"
41 | else
42 | # Run eslint on the source file.
43 | FILE=src/openlocationcode.js
44 | LINT=`$ESLINT $FILE`
45 | if [ $? -ne 0 ]; then
46 | echo -e "\e[1;31mFile has formatting errors:\e[0m"
47 | echo "$LINT"
48 | RETURN=1
49 | if [ -v TRAVIS ]; then
50 | # On TravisCI, send a comment with the diff to the pull request.
51 | go run ../travis-utils/github_comments.go \
52 | --comment '**File has `eslint` errors that must be fixed**:'"
$LINT
" \
53 | --file "js/$FILE" \
54 | --pr "$TRAVIS_PULL_REQUEST" \
55 | --commit "$TRAVIS_PULL_REQUEST_SHA"
56 | fi
57 | fi
58 | fi
59 | exit $RETURN
60 |
--------------------------------------------------------------------------------
/js/closure/BUILD:
--------------------------------------------------------------------------------
1 | # Load the necessary Closure rules
2 | load("@io_bazel_rules_closure//closure:defs.bzl", "closure_js_library", "closure_js_test")
3 |
4 | # Define the Closure library for Open Location Code
5 | closure_js_library(
6 | name = "openlocationcode_lib",
7 | srcs = ["openlocationcode.js"],
8 | convention = "GOOGLE",
9 | )
10 |
11 | # Define the Closure test for Open Location Code
12 | closure_js_test(
13 | name = "openlocationcode_test",
14 | timeout = "short",
15 | srcs = ["openlocationcode_test.js"],
16 | data = [
17 | "//test_data:test_data", # Reference the filegroup for test data
18 | ],
19 | entry_points = ["goog:openlocationcode_test"],
20 | deps = [
21 | ":openlocationcode_lib",
22 | "@com_google_javascript_closure_library//closure/goog/net:eventtype",
23 | "@com_google_javascript_closure_library//closure/goog/net:xhrio",
24 | "@com_google_javascript_closure_library//closure/goog/testing:asserts",
25 | "@com_google_javascript_closure_library//closure/goog/testing:asynctestcase",
26 | "@com_google_javascript_closure_library//closure/goog/testing:testsuite",
27 | ],
28 | )
29 |
--------------------------------------------------------------------------------
/js/closure/README.md:
--------------------------------------------------------------------------------
1 | # Closure Library
2 |
3 | This is a version of the Open Location Code javascript library for use with the
4 | [Google Closure Compiler](https://github.com/google/closure-compiler).
5 |
6 | You can use it in Closure projects like this:
7 |
8 | ```javascript
9 | const openlocationcode = goog.require('google.openlocationcode');
10 | ...
11 | var code = openlocationcode.encode(47.36628,8.52513);
12 | ```
13 |
14 | ## Code Style And Formatting
15 |
16 | Code should be formatted according to the
17 | [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html).
18 |
19 | You can run checks on the code using `eslint`:
20 |
21 | ```shell
22 | cd js
23 | npm install eslint
24 | eslint closure/*js
25 | ```
26 |
27 | If there are any syntax or style errors, it will output messages. Note that
28 | syntax or style errors will cause the TravisCI tests to **fail**.
29 |
30 | ## Building and Testing
31 |
32 | Included is a `BUILD` file that uses the [Bazel](https://bazel.build/) build system to produce a JavaScript library and to run tests. You will need to install Bazel on your system to run the tests.
33 |
34 | The tests use the [Closure Rules for Basel](https://github.com/bazelbuild/rules_closure) project although this is retrieved automatically and you don't have to install anything.
35 |
36 | The test cases have been copied from the [`test_data`](https://github.com/google/open-location-code/blob/main/test_data) directory due to restrictions on loading data files within the test runner.
37 |
38 | Run the tests from the top-level github directory with:
39 |
40 | ```shell
41 | $ bazel test js/closure:openlocationcode_test
42 | INFO: Found 1 test target...
43 | Target //js/closure:openlocationcode_test up-to-date:
44 | bazel-bin/js/closure/openlocationcode_test
45 | INFO: Elapsed time: 0.174s, Critical Path: 0.00s
46 | //js/closure:openlocationcode_test PASSED in 1.1s
47 |
48 | Executed 0 out of 1 test: 1 test passes.
49 | $
50 | ```
51 |
52 |
--------------------------------------------------------------------------------
/js/examples/examples.css:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | Styles used by examples.
4 | */
5 | .map_label {
6 | font-weight: 300;
7 | font-family: Roboto,arial,sans-serif;
8 | color: #37474f;
9 | font-size: 12pt;
10 | background-color: #e0e0e0;
11 | -moz-border-radius: 3px;
12 | -webkit-border-radius: 3px;
13 | border-radius: 3px;
14 | padding: 2px;
15 | }
16 | #content {
17 | height: 100%;
18 | width: 100%;
19 | }
20 | #messageBox {
21 | position: absolute;
22 | top: 30px;
23 | left: 100px;
24 | max-height: 80%;
25 | width: 30%;
26 | z-index: 100;
27 | background: white;
28 | border: 1px solid #888;
29 | overflow-y: auto;
30 | padding: 10px;
31 | -moz-border-radius: 5px;
32 | -webkit-border-radius: 5px;
33 | border-radius: 5px;
34 | }
35 | .text_input {
36 | border: 1px solid #eeeeee;
37 | padding: 5px;
38 | font-size: 100%;
39 | color: inherit;
40 | width: 100%;
41 | -moz-box-sizing: border-box;
42 | -webkit-box-sizing: border-box;
43 | box-sizing: border-box;
44 | }
45 | .button {
46 | padding: 5px;
47 | background-color: #5677fc;
48 | border: none;
49 | min-width: 100px;
50 | }
51 | .button_label {
52 | font-weight: bold;
53 | font-size: 120%;
54 | font-family: Roboto,arial,sans-serif;
55 | -webkit-font-smoothing: antialiased;
56 | color: white;
57 | opacity: 0.87;
58 | }
59 | .note_p {
60 | font-size: 80%;
61 | }
62 | .map_frame {
63 | width: 100%;
64 | height: 100%;
65 | }
66 | em {
67 | font-weight: bold;
68 | font-style: normal;
69 | }
70 | h1 {
71 | font-size: 200%;
72 | font-weight: 300;
73 | -webkit-margin-before: 0em;
74 | -webkit-margin-after: 0em;
75 | }
76 | input {
77 | font-weight: 300;
78 | font-family: Roboto,arial,sans-serif;
79 | }
80 | body, html {
81 | height: 100%;
82 | width: 100%;
83 | margin: 0;
84 | font-weight: 300;
85 | font-family: Roboto,arial,sans-serif;
86 | -webkit-font-smoothing: antialiased;
87 | }
88 |
--------------------------------------------------------------------------------
/js/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var karma = require('karma');
3 |
4 | gulp.task('test', function(done) {
5 | var server = new karma.Server({
6 | configFile: __dirname + '/test/karma.config.js',
7 | singleRun: true
8 | });
9 |
10 | server.on('run_complete', function (browsers, results) {
11 | if (results.error || results.failed) {
12 | done(new Error('There are test failures'));
13 | }
14 | else {
15 | done();
16 | }
17 | });
18 |
19 | server.start();
20 | });
21 |
22 | const minify = require('gulp-minify');
23 | gulp.task('minify', function(done) {
24 | gulp.src('src/openlocationcode.js')
25 | .pipe(minify({
26 | ext:{
27 | src:'.js',
28 | min:'.min.js'
29 | },
30 | }))
31 | .pipe(gulp.dest('src'));
32 | done();
33 | });
34 |
--------------------------------------------------------------------------------
/js/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "open-location-code",
3 | "description": "Library to convert between lat/lng and OLC codes",
4 | "version": "20250411.0.0",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/google/open-location-code.git"
8 | },
9 | "bugs": {
10 | "url": "https://github.com/google/open-location-code/issues"
11 | },
12 | "author": "The Open Location Code Library Authors",
13 | "license": "Apache-2.0",
14 | "homepage": "http://openlocationcode.com/",
15 | "keywords": [
16 | "javascript",
17 | "library",
18 | "openlocationcode"
19 | ],
20 | "scripts": {
21 | "test": "gulp test"
22 | },
23 | "devDependencies": {
24 | "eslint": "^5.16.0",
25 | "eslint-config-google": "^0.12.0",
26 | "gulp": "^4.0.1",
27 | "gulp-cli": "^2.2.0",
28 | "gulp-minify": "^3.1.0",
29 | "jasmine": "^3.4.0",
30 | "jasmine-core": "^3.4.0",
31 | "karma": "^6.4.4",
32 | "karma-chrome-launcher": "^2.2.0",
33 | "karma-jasmine": "^2.0.1",
34 | "karma-jasmine-jquery": "^0.1.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/js/test/karma.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | browsers: ['ChromeHeadless'],
4 | frameworks: [
5 | 'jasmine-jquery',
6 | 'jasmine',
7 | ],
8 | plugins: [
9 | 'karma-chrome-launcher',
10 | 'karma-jasmine',
11 | 'karma-jasmine-jquery',
12 | ],
13 | files: [
14 | '../src/openlocationcode.js',
15 | 'jasmine-tests.js',
16 | { pattern: '*.json', included: false, served: true}
17 | ]
18 | });
19 | };
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "open-location-code",
3 | "description": "Library to convert between lat/lng and OLC codes",
4 | "version": "1.0.0",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/google/open-location-code.git"
8 | },
9 | "bugs": {
10 | "url": "https://github.com/google/open-location-code/issues"
11 | },
12 | "author": "The Open Location Code Library Authors",
13 | "license": "Apache-2.0",
14 | "homepage": "http://openlocationcode.com/",
15 | "keywords": [
16 | "javascript",
17 | "library",
18 | "openlocationcode"
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/python/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | *.pyc
3 | openlocationcode.egg-info/*
4 | dist/*
--------------------------------------------------------------------------------
/python/.style.yapf:
--------------------------------------------------------------------------------
1 | [style]
2 | # Use the Google style.
3 | based_on_style = google
4 |
--------------------------------------------------------------------------------
/python/BUILD:
--------------------------------------------------------------------------------
1 | py_library(
2 | name = "openlocationcode",
3 | srcs = ["openlocationcode/openlocationcode.py"],
4 | )
5 |
6 | py_test(
7 | name = "openlocationcode_test",
8 | python_version = "PY3",
9 | size = "small",
10 | srcs = ["openlocationcode_test.py"],
11 | data = ["//test_data:test_data"],
12 | deps = [":openlocationcode"],
13 | visibility = ["//visibility:private"]
14 | )
--------------------------------------------------------------------------------
/python/README.md:
--------------------------------------------------------------------------------
1 | # Python Library
2 |
3 | This is the Python Open Location Code library. It is tested for both python 2.7
4 | and python 3.6.
5 |
6 | ## Installing the library
7 |
8 | The python library is available on PyPi. You can install it using pip:
9 |
10 | ```
11 | pip install openlocationcode
12 | ```
13 |
14 | ## Formatting
15 |
16 | Code must be formatted according to the
17 | [Google Python Style Guide](http://google.github.io/styleguide/pyguide.html).
18 |
19 | You can format your code automatically using
20 | [YAPF](https://github.com/google/yapf/).
21 |
22 | ### Installing YAPF
23 |
24 | Ensure you have pip installed:
25 |
26 | ```
27 | wget https://bootstrap.pypa.io/get-pip.py
28 | sudo python get-pip.py
29 | ```
30 |
31 | Then install YAPF:
32 |
33 | ```
34 | pip install --user yapf
35 | ```
36 |
37 | ### Formatting code
38 |
39 | To format your files, just run:
40 |
41 | ```
42 | bash format_check.sh
43 | ```
44 |
45 | If you just want to see the changes, you can run `python -m yapf --diff *py`
46 |
47 | This script runs as part of the TravisCI tests - if files need formatting it
48 | will display the required changes **and fail the test**.
49 |
50 |
51 | ## Testing
52 |
53 | Run the unit tests and benchmarks locally with:
54 |
55 | ```
56 | bazel test python:openlocationcode_test
57 | ```
58 |
59 |
60 | ## Releasing to PyPi
61 |
62 | We release the python library to PyPi so users can install it using pip.
63 |
64 | Pre-reqs:
65 |
66 | ```
67 | pip install setuptools
68 | pip install twine
69 | ```
70 |
71 | To release a new version to PyPi, make sure you update the version number in setup.py. Then run:
72 |
73 | ```
74 | python setup.py sdist
75 | twine upload dist/*
76 | ```
77 |
78 | Make sure any older versions are cleared out from dist before uploading. twine will prompt you for your PyPi credentials, which will need to be a collaborator on the project.
79 |
--------------------------------------------------------------------------------
/python/format_check.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Check the format of the Python source files using YAPF.
3 |
4 | python -m yapf --version >/dev/null 2>&1
5 | if [ $? -eq 1 ]; then
6 | curl -o /tmp/get-pip.py https://bootstrap.pypa.io/get-pip.py && python /tmp/get-pip.py && pip install yapf
7 | fi
8 |
9 | # Run YAPF and check for diffs. If there aren't any, we're done.
10 | DIFF=`python -m yapf --diff *py`
11 | if [ $? -eq 0 ]; then
12 | echo -e "\e[32mPython files are correctly formatted\e[30m"
13 | exit 0
14 | fi
15 |
16 | if [ -z "$TRAVIS" ]; then
17 | # Not running on TravisCI, so format the files in place.
18 | echo -e "\e[34mPython files have formatting errors -formatting in place\e[30m"
19 | python -m yapf --in-place *py
20 | else
21 | echo -e "\e[31mPython files have formatting errors\e[30m"
22 | echo -e "\e[31mThese must be corrected using format_check.sh\e[30m"
23 | echo "$DIFF"
24 | fi
25 | exit 1
26 |
--------------------------------------------------------------------------------
/python/openlocationcode/__init__.py:
--------------------------------------------------------------------------------
1 | if __name__ == "__main__":
2 | from openlocationcode import *
3 | else:
4 | from .openlocationcode import *
5 |
--------------------------------------------------------------------------------
/python/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 | # This call to setup() does all the work
4 | setup(
5 | name="openlocationcode",
6 | version="1.0.1",
7 | description="Python library for Open Location Code (Plus Codes)",
8 | url="https://github.com/google/open-location-code",
9 | author="Google",
10 | author_email="open-location-code@googlegroups.com",
11 | license="Apache 2.0",
12 | classifiers=[
13 | "Programming Language :: Python :: 2.7",
14 | "Programming Language :: Python :: 3.6",
15 | ],
16 | packages=["openlocationcode"],
17 | include_package_data=True,
18 | install_requires=[],
19 | )
--------------------------------------------------------------------------------
/ruby/README.md:
--------------------------------------------------------------------------------
1 | # Plus Codes
2 |
3 | Ruby implementation of Open Location Code library.
4 |
5 | ## Contributing
6 |
7 | 1. Fork it
8 | 2. Create your feature branch (`git checkout -b my-new-feature`)
9 | 3. Commit your changes (`git commit -am 'Add some feature'`)
10 | 4. Push to the branch (`git push origin my-new-feature`)
11 | 5. Create a new Pull Request
12 |
13 | Your code must pass tests, and must be formatted with
14 | [rubocop](https://github.com/rubocop-hq/rubocop). This will check all the ruby
15 | files and print a list of corrections you need to make - it will not format your
16 | file automatically.
17 |
18 | ```
19 | gem install rubocop
20 | rubocop --config rubocop.yml
21 | ```
22 |
23 | If you can't run it yourself, it is run as part of the TravisCI tests.
24 |
25 |
26 | ### Testing
27 |
28 | ```
29 | gem install test-unit
30 | ruby test/plus_codes_test.rb
31 | ```
32 |
33 | ## Installation
34 |
35 | Add this line to your application's Gemfile:
36 |
37 | ```ruby
38 | gem 'plus_codes'
39 | ```
40 |
41 | And then execute:
42 |
43 | $ bundle
44 |
45 | Or install it yourself as:
46 |
47 | $ gem install plus_codes
48 |
49 | ## Usage
50 |
51 | ```ruby
52 | require 'plus_codes/open_location_code'
53 |
54 | olc = PlusCodes::OpenLocationCode.new
55 |
56 | # Encodes the latitude and longitude into a Plus+Codes
57 | code = olc.encode(47.0000625,8.0000625)
58 | # => "8FVC2222+22"
59 |
60 | # Encodes any latitude and longitude into a Plus+Codes with preferred length
61 | code = olc.encode(47.0000625,8.0000625, 16)
62 | # => "8FVC2222+22GCCCCC"
63 |
64 | # Decodes a Plus+Codes back into coordinates
65 | code_area = olc.decode(code)
66 | puts code_area
67 | # => lat_lo: 47.000062496 long_lo: 8.0000625 lat_hi: 47.000062504 long_hi: 8.000062530517578 code_len: 16
68 |
69 | # Checks if a Plus+Codes is valid or not
70 | olc.valid?(code)
71 | # => true
72 |
73 | # Checks if a Plus+Codes is full or not
74 | olc.full?(code)
75 | # => true
76 |
77 | # Checks if a Plus+Codes is short or not
78 | olc.short?(code)
79 | # => false
80 |
81 | # Shorten a Plus+Codes as possible by given reference latitude and longitude
82 | olc.shorten('9C3W9QCJ+2VX', 51.3708675, -1.217765625)
83 | # => "CJ+2VX"
84 |
85 | # Extends a Plus+Codes by given reference latitude and longitude
86 | olc.recover_nearest('CJ+2VX', 51.3708675, -1.217765625)
87 | # => "9C3W9QCJ+2VX"
88 | ```
89 |
90 | ## Contributing
91 |
--------------------------------------------------------------------------------
/ruby/lib/plus_codes.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | # Plus+Codes is a Ruby implementation of Google Open Location Code (Plus Codes).
4 | #
5 | # @author We-Ming Wu
6 | module PlusCodes
7 | # The character set used to encode coordinates.
8 | CODE_ALPHABET = '23456789CFGHJMPQRVWX'
9 |
10 | # The character used to pad a code
11 | PADDING = '0'
12 |
13 | # A separator used to separate the code into two parts.
14 | SEPARATOR = '+'
15 |
16 | # The max number of characters can be placed before the separator.
17 | SEPARATOR_POSITION = 8
18 |
19 | # Minimum number of digits to process in a Plus Code.
20 | MIN_CODE_LENGTH = 2
21 |
22 | # Maximum number of digits to process in a Plus Code.
23 | MAX_CODE_LENGTH = 15
24 |
25 | # Maximum code length using lat/lng pair encoding. The area of such a
26 | # code is approximately 13x13 meters (at the equator), and should be suitable
27 | # for identifying buildings. This excludes prefix and separator characters.
28 | PAIR_CODE_LENGTH = 10
29 |
30 | # Inverse of the precision of the pair code section.
31 | PAIR_CODE_PRECISION = 8000
32 |
33 | # Precision of the latitude grid.
34 | LAT_GRID_PRECISION = 5**(MAX_CODE_LENGTH - PAIR_CODE_LENGTH)
35 |
36 | # Precision of the longitude grid.
37 | LNG_GRID_PRECISION = 4**(MAX_CODE_LENGTH - PAIR_CODE_LENGTH)
38 |
39 | # ASCII lookup table.
40 | DECODE = (CODE_ALPHABET.chars + [PADDING, SEPARATOR]).each_with_object(
41 | []
42 | ) do |c, ary|
43 | ary[c.ord] = CODE_ALPHABET.index(c)
44 | ary[c.downcase.ord] = CODE_ALPHABET.index(c)
45 | ary[c.ord] ||= -1
46 | ary
47 | end.freeze
48 | end
49 |
--------------------------------------------------------------------------------
/ruby/lib/plus_codes/code_area.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module PlusCodes
4 | # [CodeArea] contains coordinates of a decoded Open Location Code(Plus+Codes).
5 | # The coordinates include the latitude and longitude of the lower left and
6 | # upper right corners and the center of the bounding box for the area the
7 | # code represents.
8 | #
9 | # @author We-Ming Wu
10 | class CodeArea
11 | attr_accessor :south_latitude, :west_longitude, :latitude_height,
12 | :longitude_width, :latitude_center, :longitude_center,
13 | :code_length
14 |
15 | # Creates a [CodeArea].
16 | #
17 | # @param south_latitude [Numeric] the latitude of the SW corner in degrees
18 | # @param west_longitude [Numeric] the longitude of the SW corner in degrees
19 | # @param latitude_height [Numeric] the height from the SW corner in degrees
20 | # @param longitude_width [Numeric] the width from the SW corner in degrees
21 | # @param code_length [Numeric] the number of significant digits in the code
22 | # @return [CodeArea] a code area which contains the coordinates
23 | def initialize(south_latitude, west_longitude, latitude_height,
24 | longitude_width, code_length)
25 | @south_latitude = south_latitude
26 | @west_longitude = west_longitude
27 | @latitude_height = latitude_height
28 | @longitude_width = longitude_width
29 | @code_length = code_length
30 | @latitude_center = south_latitude + latitude_height / 2.0
31 | @longitude_center = west_longitude + longitude_width / 2.0
32 | end
33 |
34 | def north_latitude
35 | @south_latitude + @latitude_height
36 | end
37 |
38 | def east_longitude
39 | @west_longitude + @longitude_width
40 | end
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/ruby/open-location-code.gemspec:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | lib = File.expand_path('lib', __dir__)
4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5 | require 'date'
6 |
7 | Gem::Specification.new do |s|
8 | s.name = 'open-location-code'
9 | s.version = '1.0.4'
10 | s.authors = ['Google', 'Wei-Ming Wu']
11 | s.date = Date.today.to_s
12 | s.email = ['open-location-code@googlegroups.com',
13 | 'wnameless@gmail.com']
14 | s.summary = 'Ruby implementation of Open Location Code (Plus Codes)'
15 | s.description = s.summary
16 | s.homepage = 'https://github.com/google/open-location-code'
17 | s.license = 'Apache License, Version 2.0'
18 |
19 | s.files = Dir['lib/**/*']
20 | s.test_files = Dir['test/**/*']
21 | s.require_paths = ['lib']
22 | s.required_ruby_version = '>= 2.6.0'
23 |
24 | s.add_development_dependency 'test-unit'
25 | end
26 |
--------------------------------------------------------------------------------
/ruby/rubocop.yml:
--------------------------------------------------------------------------------
1 | # Override rubocop defaults.
2 |
3 | AllCops:
4 | TargetRubyVersion: 2.6
5 |
6 | Layout/LineLength:
7 | Enabled: true
8 | Max: 80
9 |
10 | Metrics/AbcSize:
11 | Enabled: false
12 |
13 | Metrics/ClassLength:
14 | Enabled: false
15 |
16 | Metrics/CyclomaticComplexity:
17 | Enabled: false
18 |
19 | Metrics/PerceivedComplexity:
20 | Enabled: false
21 |
22 | Metrics/MethodLength:
23 | Enabled: false
24 |
25 | Style/NumericLiterals:
26 | Enabled: false
27 |
--------------------------------------------------------------------------------
/rust/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "open-location-code"
3 | description = "Library for translating between GPS coordinates (WGS84) and Open Location Code"
4 | version = "0.2.0"
5 | authors = ["James Fysh "]
6 | license = "Apache-2.0"
7 | repository = "https://github.com/google/open-location-code"
8 | keywords = ["geography", "geospatial", "gis", "gps", "olc"]
9 | exclude = ["rust.iml"]
10 | edition = "2024"
11 |
12 | [dependencies]
13 | geo = "0.30.0"
14 |
15 | [dev-dependencies]
16 | rand = "0.9.0"
17 |
--------------------------------------------------------------------------------
/rust/README.md:
--------------------------------------------------------------------------------
1 | This is the Rust implementation of the Open Location Code library.
2 |
3 | # Contributing
4 |
5 | ## Code Formatting
6 |
7 | Code must be formatted with `rustfmt`. You can do this by running `cargo fmt`.
8 |
9 | The formatting will be checked in the TravisCI integration tests. If the files
10 | need formatting the tests will fail.
11 |
12 | ## Testing
13 |
14 | Test code by running `cargo test -- --nocapture`. This will run the tests
15 | including the benchmark loops.
16 |
17 |
--------------------------------------------------------------------------------
/rust/src/codearea.rs:
--------------------------------------------------------------------------------
1 | use geo::Point;
2 |
3 | pub struct CodeArea {
4 | pub south: f64,
5 | pub west: f64,
6 | pub north: f64,
7 | pub east: f64,
8 | pub center: Point,
9 | pub code_length: usize,
10 | }
11 |
12 | impl CodeArea {
13 | pub fn new(south: f64, west: f64, north: f64, east: f64, code_length: usize) -> CodeArea {
14 | CodeArea {
15 | south,
16 | west,
17 | north,
18 | east,
19 | center: Point::new((west + east) / 2f64, (south + north) / 2f64),
20 | code_length,
21 | }
22 | }
23 |
24 | pub fn merge(self, other: CodeArea) -> CodeArea {
25 | CodeArea::new(
26 | self.south + other.south,
27 | self.west + other.west,
28 | self.north + other.north,
29 | self.east + other.east,
30 | self.code_length + other.code_length,
31 | )
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/rust/src/consts.rs:
--------------------------------------------------------------------------------
1 | // A separator used to break the code into two parts to aid memorability.
2 | pub const SEPARATOR: char = '+';
3 |
4 | // The number of characters to place before the separator.
5 | pub const SEPARATOR_POSITION: usize = 8;
6 |
7 | // The character used to pad codes.
8 | pub const PADDING_CHAR: char = '0';
9 | pub const PADDING_CHAR_STR: &str = "0";
10 |
11 | // The character set used to encode the values.
12 | pub const CODE_ALPHABET: [char; 20] = [
13 | '2', '3', '4', '5', '6', '7', '8', '9', 'C', 'F', 'G', 'H', 'J', 'M', 'P', 'Q', 'R', 'V', 'W',
14 | 'X',
15 | ];
16 |
17 | // The base to use to convert numbers to/from.
18 | pub const ENCODING_BASE: usize = 20;
19 |
20 | // The maximum value for latitude in degrees.
21 | pub const LATITUDE_MAX: f64 = 90f64;
22 |
23 | // The maximum value for longitude in degrees.
24 | pub const LONGITUDE_MAX: f64 = 180f64;
25 |
26 | // Minimum number of digits to process for Plus Codes.
27 | pub const MIN_CODE_LENGTH: usize = 2;
28 |
29 | // Maximum number of digits to process for Plus Codes.
30 | pub const MAX_CODE_LENGTH: usize = 15;
31 |
32 | // Maximum code length using lat/lng pair encoding. The area of such a
33 | // code is approximately 13x13 meters (at the equator), and should be suitable
34 | // for identifying buildings. This excludes prefix and separator characters.
35 | pub const PAIR_CODE_LENGTH: usize = 10;
36 |
37 | // Digits in the grid encoding..
38 | pub const GRID_CODE_LENGTH: usize = 5;
39 |
40 | // The resolution values in degrees for each position in the lat/lng pair
41 | // encoding. These give the place value of each position, and therefore the
42 | // dimensions of the resulting area.
43 | pub const PAIR_RESOLUTIONS: [f64; 5] = [20.0f64, 1.0f64, 0.05f64, 0.0025f64, 0.000125f64];
44 |
45 | // Number of columns in the grid refinement method.
46 | pub const GRID_COLUMNS: usize = 4;
47 |
48 | // Number of rows in the grid refinement method.
49 | pub const GRID_ROWS: usize = 5;
50 |
51 | // Minimum length of a code that can be shortened.
52 | pub const MIN_TRIMMABLE_CODE_LEN: usize = 6;
53 |
54 | // What to multiply latitude degrees by to get an integer value. There are three pairs representing
55 | // decimal digits, and five digits in the grid.
56 | pub const LAT_INTEGER_MULTIPLIER: i64 = (ENCODING_BASE
57 | * ENCODING_BASE
58 | * ENCODING_BASE
59 | * GRID_ROWS
60 | * GRID_ROWS
61 | * GRID_ROWS
62 | * GRID_ROWS
63 | * GRID_ROWS) as i64;
64 |
65 | // What to multiply longitude degrees by to get an integer value. There are three pairs representing
66 | // decimal digits, and five digits in the grid.
67 | pub const LNG_INTEGER_MULTIPLIER: i64 = (ENCODING_BASE
68 | * ENCODING_BASE
69 | * ENCODING_BASE
70 | * GRID_COLUMNS
71 | * GRID_COLUMNS
72 | * GRID_COLUMNS
73 | * GRID_COLUMNS
74 | * GRID_COLUMNS) as i64;
75 |
--------------------------------------------------------------------------------
/rust/src/lib.rs:
--------------------------------------------------------------------------------
1 | extern crate geo;
2 |
3 | mod codearea;
4 | mod consts;
5 | mod interface;
6 | mod private;
7 |
8 | pub use codearea::CodeArea;
9 | pub use interface::{
10 | decode, encode, encode_integers, is_full, is_short, is_valid, point_to_integers,
11 | recover_nearest, shorten,
12 | };
13 |
--------------------------------------------------------------------------------
/rust/src/private.rs:
--------------------------------------------------------------------------------
1 | use geo::Point;
2 |
3 | use crate::{
4 | consts::{
5 | CODE_ALPHABET, ENCODING_BASE, GRID_ROWS, LATITUDE_MAX, LONGITUDE_MAX, PAIR_CODE_LENGTH,
6 | },
7 | encode,
8 | };
9 |
10 | pub fn code_value(chr: char) -> usize {
11 | // We assume this function is only called by other functions that have
12 | // already ensured that the characters in the passed-in code are all valid
13 | // and have all been "treated" (upper-cased, padding and '+' stripped)
14 | CODE_ALPHABET.iter().position(|&x| x == chr).unwrap()
15 | }
16 |
17 | pub fn normalize_longitude(value: f64) -> f64 {
18 | let mut result: f64 = value;
19 | while result >= LONGITUDE_MAX {
20 | result -= LONGITUDE_MAX * 2f64;
21 | }
22 | while result < -LONGITUDE_MAX {
23 | result += LONGITUDE_MAX * 2f64;
24 | }
25 | result
26 | }
27 |
28 | pub fn clip_latitude(latitude_degrees: f64) -> f64 {
29 | latitude_degrees.min(LATITUDE_MAX).max(-LATITUDE_MAX)
30 | }
31 |
32 | pub fn compute_latitude_precision(code_length: usize) -> f64 {
33 | if code_length <= PAIR_CODE_LENGTH {
34 | return (ENCODING_BASE as f64).powf((code_length as f64 / -2f64 + 2f64).floor());
35 | }
36 | (ENCODING_BASE as f64).powf(-3f64)
37 | / GRID_ROWS.pow((code_length - PAIR_CODE_LENGTH) as u32) as f64
38 | }
39 |
40 | pub fn prefix_by_reference(pt: Point, code_length: usize) -> String {
41 | let precision = compute_latitude_precision(code_length);
42 |
43 | let (lng, lat) = pt.x_y();
44 |
45 | let mut code = encode(
46 | Point::new(
47 | (lng / precision).floor() * precision,
48 | (lat / precision).floor() * precision,
49 | ),
50 | PAIR_CODE_LENGTH,
51 | );
52 | code.drain(code_length..);
53 | code
54 | }
55 |
--------------------------------------------------------------------------------
/rust/tests/csv_reader.rs:
--------------------------------------------------------------------------------
1 | use std::env::current_dir;
2 | use std::fs::File;
3 | use std::io::{BufRead, BufReader, Lines};
4 |
5 | pub struct CSVReader {
6 | iter: Lines>,
7 | }
8 |
9 | impl CSVReader {
10 | pub fn new(csv_name: &str) -> CSVReader {
11 | // Assumes we're called from /rust
12 | let project_root = current_dir().unwrap();
13 | let olc_root = project_root.parent().unwrap();
14 | let csv_path = olc_root.join("test_data").join(csv_name);
15 | CSVReader {
16 | iter: BufReader::new(File::open(csv_path).unwrap()).lines(),
17 | }
18 | }
19 | }
20 |
21 | impl Iterator for CSVReader {
22 | type Item = String;
23 |
24 | fn next(&mut self) -> Option {
25 | // Iterate lines in the CSV file, dropping empty & comment lines
26 | while let Some(Ok(s)) = self.iter.next() {
27 | if s.is_empty() || s.starts_with("#") {
28 | continue;
29 | }
30 | return Some(s);
31 | }
32 | None
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/test_data/BUILD:
--------------------------------------------------------------------------------
1 | filegroup(
2 | name = "test_data",
3 | srcs = glob(["*.csv"]),
4 | visibility = ["//visibility:public"],
5 | )
6 |
--------------------------------------------------------------------------------
/test_data/csv_to_json.go:
--------------------------------------------------------------------------------
1 | // Package main converts test files from CSV to JSON.
2 | // This can be used by e.g. JS tests that cannot read data as CSV.
3 | // Example:
4 | // go run csv_to_json.go --csv encoding.csv >js/test/encoding.json
5 | package main
6 |
7 | import (
8 | "bufio"
9 | "encoding/csv"
10 | "flag"
11 | "fmt"
12 | "log"
13 | "os"
14 | "strconv"
15 | "strings"
16 | )
17 |
18 | var (
19 | csvPtr = flag.String("csv", "", "CSV file")
20 | )
21 |
22 | func main() {
23 | flag.Parse()
24 | if *csvPtr == "" {
25 | log.Fatal("--csv is required")
26 | }
27 | csvFile, err := os.Open(*csvPtr)
28 | if err != nil {
29 | log.Fatal(err)
30 | }
31 | reader := csv.NewReader(bufio.NewReader(csvFile))
32 | reader.Comment = '#'
33 | records, err := reader.ReadAll()
34 | if err != nil {
35 | log.Fatal(err)
36 | }
37 | var formatted []string
38 | for i := 0; i < len(records); i++ {
39 | for j := 0; j < len(records[i]); j++ {
40 | // Anything that can't be parsed as a float is a string and needs quotes.
41 | if _, err := strconv.ParseFloat(records[i][j], 64); err != nil {
42 | records[i][j] = "\"" + records[i][j] + "\""
43 | }
44 | }
45 | formatted = append(formatted, "["+strings.Join(records[i], ",")+"]")
46 | }
47 | fmt.Printf("[\n%s\n]\n", strings.Join(formatted, ",\n"))
48 | }
49 |
--------------------------------------------------------------------------------
/test_data/shortCodeTests.csv:
--------------------------------------------------------------------------------
1 | # Test shortening and extending codes.
2 | #
3 | # Format:
4 | # full code,lat,lng,shortcode,test_type
5 | # test_type is R for recovery only, S for shorten only, or B for both.
6 | 9C3W9QCJ+2VX,51.3701125,-1.217765625,+2VX,B
7 | # Adjust so we can't trim by 8 (+/- .000755)
8 | 9C3W9QCJ+2VX,51.3708675,-1.217765625,CJ+2VX,B
9 | 9C3W9QCJ+2VX,51.3693575,-1.217765625,CJ+2VX,B
10 | 9C3W9QCJ+2VX,51.3701125,-1.218520625,CJ+2VX,B
11 | 9C3W9QCJ+2VX,51.3701125,-1.217010625,CJ+2VX,B
12 | # Adjust so we can't trim by 6 (+/- .0151)
13 | 9C3W9QCJ+2VX,51.3852125,-1.217765625,9QCJ+2VX,B
14 | 9C3W9QCJ+2VX,51.3550125,-1.217765625,9QCJ+2VX,B
15 | 9C3W9QCJ+2VX,51.3701125,-1.232865625,9QCJ+2VX,B
16 | 9C3W9QCJ+2VX,51.3701125,-1.202665625,9QCJ+2VX,B
17 | # Added to detect error in recoverNearest functionality
18 | 8FJFW222+,42.899,9.012,22+,B
19 | 796RXG22+,14.95125,-23.5001,22+,B
20 | # Reference location is in the 4 digit cell to the south.
21 | 8FVC2GGG+GG,46.976,8.526,2GGG+GG,B
22 | # Reference location is in the 4 digit cell to the north.
23 | 8FRCXGGG+GG,47.026,8.526,XGGG+GG,B
24 | # Reference location is in the 4 digit cell to the east.
25 | 8FR9GXGG+GG,46.526,8.026,GXGG+GG,B
26 | # Reference location is in the 4 digit cell to the west.
27 | 8FRCG2GG+GG,46.526,7.976,G2GG+GG,B
28 | # Added to detect errors recovering codes near the poles.
29 | # This tests recovery function, but these codes won't shorten.
30 | CFX22222+22,89.6,0.0,2222+22,R
31 | 2CXXXXXX+XX,-81.0,0.0,XXXXXX+XX,R
32 | # Recovered full codes should be the full code
33 | 8FRCG2GG+GG,46.526,7.976,8FRCG2GG+GG,R
34 | # Recovered full codes should be the uppercased full code
35 | 8FRCG2GG+GG,46.526,7.976,8frCG2GG+gG,R
36 |
--------------------------------------------------------------------------------
/test_data/validityTests.csv:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | #
3 | # Test data for validity tests.
4 | # Format of each line is:
5 | # code,isValid,isShort,isFull
6 | #
7 | ################################################################################
8 | #
9 | # Valid full codes:
10 | #
11 | ################################################################################
12 | 8FWC2345+G6,true,false,true
13 | 8FWC2345+G6G,true,false,true
14 | 8fwc2345+,true,false,true
15 | 8FWCX400+,true,false,true
16 | 84000000+,true,false,true
17 | ################################################################################
18 | #
19 | # Valid short codes:
20 | #
21 | ################################################################################
22 | WC2345+G6g,true,true,false
23 | 2345+G6,true,true,false
24 | 45+G6,true,true,false
25 | +G6,true,true,false
26 | ################################################################################
27 | #
28 | # Invalid codes
29 | #
30 | ################################################################################
31 | G+,false,false,false
32 | +,false,false,false
33 | 8FWC2345+G,false,false,false
34 | 8FWC2_45+G6,false,false,false
35 | 8FWC2η45+G6,false,false,false
36 | 8FWC2345+G6+,false,false,false
37 | 8FWC2345G6+,false,false,false
38 | 8FWC2300+G6,false,false,false
39 | WC2300+G6g,false,false,false
40 | WC2345+G,false,false,false
41 | WC2300+,false,false,false
42 | 84900000+,false,false,false
43 | ################################################################################
44 | #
45 | # Validate that codes at and exceeding 15 digits are still valid when all their
46 | # digits are valid, and invalid when not.
47 | #
48 | ################################################################################
49 | 849VGJQF+VX7QR3J,true,false,true
50 | 849VGJQF+VX7QR3U,false,false,false
51 | 849VGJQF+VX7QR3JW,true,false,true
52 | 849VGJQF+VX7QR3JU,false,false,false
53 |
--------------------------------------------------------------------------------
/tile_server/gridserver/geojson_test.go:
--------------------------------------------------------------------------------
1 | package gridserver
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 | "testing"
7 |
8 | log "github.com/golang/glog"
9 | "github.com/google/go-cmp/cmp"
10 | "github.com/paulmach/orb/geojson"
11 | )
12 |
13 | const (
14 | testDataPath = "./testdata/"
15 | )
16 |
17 | func readTestData(p string) []byte {
18 | d, err := os.ReadFile(p)
19 | if err != nil {
20 | log.Fatal(err)
21 | }
22 | return d
23 | }
24 |
25 | func TestGeoJSON(t *testing.T) {
26 | var tests = []struct {
27 | x, y, z int
28 | opts *TileOptions
29 | testFile string
30 | }{
31 | {x: 17, y: 19, z: 5, testFile: testDataPath + "5_17_19.json"},
32 | {
33 | x: 17, y: 19, z: 5,
34 | opts: &TileOptions{Format: JSONTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewMercatorTMS(), ZoomAdjust: 2},
35 | testFile: testDataPath + "5_17_19_zoom_2.json",
36 | },
37 | {
38 | x: 1098232, y: 1362659, z: 21,
39 | opts: &TileOptions{Format: JSONTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewMercatorTMS(), ZoomAdjust: 0},
40 | testFile: testDataPath + "21_1098232_1362659.json",
41 | },
42 | {
43 | x: 17, y: 19, z: 5,
44 | opts: &TileOptions{Format: JSONTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewGeodeticTMS(), ZoomAdjust: 0},
45 | testFile: testDataPath + "5_17_19_geodetic.json",
46 | },
47 | {
48 | x: 1098232, y: 1362659, z: 21,
49 | opts: &TileOptions{Format: JSONTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewGeodeticTMS(), ZoomAdjust: 0},
50 | testFile: testDataPath + "21_1098232_1362659_geodetic.json",
51 | },
52 | }
53 | for n, test := range tests {
54 | // Read the test data, convert to struct.
55 | want := &geojson.FeatureCollection{}
56 | if err := json.Unmarshal(readTestData(test.testFile), want); err != nil {
57 | t.Errorf("Test %d: data unmarshal failed: %v", n, err)
58 | }
59 | // Make the tile reference and get the geojson struct.
60 | tr := MakeTileRef(test.x, test.y, test.z, test.opts)
61 | got, err := tr.GeoJSON()
62 | if err != nil {
63 | t.Errorf("Test %d: GeoJSON generation failed: %v", n, err)
64 | }
65 | if !cmp.Equal(got, want) {
66 | if blob, err := got.MarshalJSON(); err != nil {
67 | t.Errorf("Test %d: got %v, want %v", n, got, want)
68 | } else {
69 | t.Errorf("Test %d: got %s", n, string(blob))
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tile_server/gridserver/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/google/open-location-code/tile_server/gridserver
2 |
3 | go 1.17
4 |
5 | require (
6 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
7 | github.com/golang/glog v1.2.4
8 | github.com/google/go-cmp v0.6.0
9 | github.com/google/open-location-code/go v0.0.0-20210504205230-1796878d947c
10 | github.com/paulmach/orb v0.11.1
11 | golang.org/x/image v0.18.0
12 | )
13 |
14 | require (
15 | github.com/gogo/protobuf v1.3.2 // indirect
16 | github.com/paulmach/protoscan v0.2.1 // indirect
17 | go.mongodb.org/mongo-driver v1.11.4 // indirect
18 | )
19 |
--------------------------------------------------------------------------------
/tile_server/gridserver/image_test.go:
--------------------------------------------------------------------------------
1 | package gridserver
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 | )
7 |
8 | func TestImage(t *testing.T) {
9 | var tests = []struct {
10 | x, y, z int
11 | opts *TileOptions
12 | testFile string
13 | }{
14 | {
15 | x: 17, y: 19, z: 5,
16 | testFile: testDataPath + "5_17_19.png",
17 | },
18 | {
19 | x: 17, y: 19, z: 5,
20 | opts: &TileOptions{Format: ImageTile, LineColor: white, LabelColor: white, Projection: NewMercatorTMS(), ZoomAdjust: 2},
21 | testFile: testDataPath + "5_17_19_white_zoom_2.png",
22 | },
23 | {
24 | x: 1098232, y: 1362659, z: 21, testFile: testDataPath + "21_1098232_1362659.png",
25 | },
26 | {
27 | x: 1098232, y: 1362659, z: 21,
28 | opts: &TileOptions{Format: ImageTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewGeodeticTMS(), ZoomAdjust: 0},
29 | testFile: testDataPath + "21_1098232_1362659_geodetic.png",
30 | },
31 | }
32 | for n, td := range tests {
33 | want := readTestData(td.testFile)
34 | tr := MakeTileRef(td.x, td.y, td.z, td.opts)
35 | got, err := tr.Image()
36 | if err != nil {
37 | t.Errorf("Test %d: image failed: %v", n, err)
38 | }
39 | if !bytes.Equal(got, want) {
40 | t.Errorf("Test %d: got image != want image", n)
41 | }
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tile_server/gridserver/mvt.go:
--------------------------------------------------------------------------------
1 | package gridserver
2 |
3 | import (
4 | log "github.com/golang/glog"
5 | "github.com/paulmach/orb/encoding/mvt"
6 | "github.com/paulmach/orb/maptile"
7 | )
8 |
9 | const (
10 | layerName = "grid"
11 | layerVersion = 2
12 | layerExtent = 4096
13 | )
14 |
15 | // MVT returns a Mapbox Vector Tile (MVT) marshalled as bytes.
16 | func (t *TileRef) MVT() ([]byte, error) {
17 | log.Infof("Producing mvt for tile z/x/y %v/%v/%v (%s)", t.Z, t.X, t.Y, t.Path())
18 | gj, err := t.GeoJSON()
19 | if err != nil {
20 | return nil, err
21 | }
22 |
23 | layer := &mvt.Layer{
24 | Name: layerName,
25 | Version: layerVersion,
26 | Extent: layerExtent,
27 | Features: gj.Features,
28 | }
29 |
30 | // Since GeoJSON stores geometries in latitude and longitude (WGS84),
31 | // we only need to project the coordinates if the desired output projection is Mercator.
32 | if t.Options.Projection.String() == "mercator" {
33 | // Convert TMS coordinates to WMS coordinates
34 | wmsY := (1 << uint(t.Z)) - t.Y - 1
35 | layer.ProjectToTile(maptile.New(uint32(t.X), uint32(wmsY), maptile.Zoom(t.Z)))
36 | }
37 |
38 | data, err := mvt.Marshal(mvt.Layers{layer})
39 | if err != nil {
40 | return nil, err
41 | }
42 | return data, nil
43 | }
44 |
--------------------------------------------------------------------------------
/tile_server/gridserver/mvt_test.go:
--------------------------------------------------------------------------------
1 | package gridserver
2 |
3 | import (
4 | "bytes"
5 | "testing"
6 | )
7 |
8 | func TestMVT(t *testing.T) {
9 | var tests = []struct {
10 | x, y, z int
11 | opts *TileOptions
12 | testFile string
13 | }{
14 | {x: 17, y: 19, z: 5, testFile: testDataPath + "5_17_19.mvt"},
15 | {
16 | x: 17, y: 19, z: 5,
17 | opts: &TileOptions{Format: VectorTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewMercatorTMS(), ZoomAdjust: 2},
18 | testFile: testDataPath + "5_17_19_zoom_2.mvt",
19 | },
20 | {
21 | x: 1098232, y: 1362659, z: 21,
22 | opts: &TileOptions{Format: VectorTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewMercatorTMS(), ZoomAdjust: 0},
23 | testFile: testDataPath + "21_1098232_1362659.mvt",
24 | },
25 | {
26 | x: 17, y: 19, z: 5,
27 | opts: &TileOptions{Format: VectorTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewGeodeticTMS(), ZoomAdjust: 0},
28 | testFile: testDataPath + "5_17_19_geodetic.mvt",
29 | },
30 | {
31 | x: 1098232, y: 1362659, z: 21,
32 | opts: &TileOptions{Format: VectorTile, LineColor: lineColor, LabelColor: labelColor, Projection: NewGeodeticTMS(), ZoomAdjust: 0},
33 | testFile: testDataPath + "21_1098232_1362659_geodetic.mvt",
34 | },
35 | }
36 | for n, td := range tests {
37 | want := readTestData(td.testFile)
38 | tr := MakeTileRef(td.x, td.y, td.z, td.opts)
39 | got, err := tr.MVT()
40 | if err != nil {
41 | t.Errorf("Test %d: MVT failed: %v", n, err)
42 | }
43 | if !bytes.Equal(got, want) {
44 | t.Errorf("Test %d: got MVT != want MVT", n)
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tile_server/gridserver/projection_test.go:
--------------------------------------------------------------------------------
1 | package gridserver
2 |
3 | import (
4 | "math"
5 | "testing"
6 | )
7 |
8 | func TestTileLatLngBounds(t *testing.T) {
9 | var tests = []struct {
10 | x, y, z int
11 | p Projection
12 | sw, ne *LatLng
13 | }{
14 | {
15 | x: 0, y: 0, z: 1,
16 | p: NewMercatorTMS(),
17 | sw: &LatLng{-85.051128, -180},
18 | ne: &LatLng{0, 0},
19 | },
20 | {
21 | x: 0, y: 0, z: 0,
22 | p: NewGeodeticTMS(),
23 | sw: &LatLng{-90, -180},
24 | ne: &LatLng{90, 0},
25 | },
26 | {
27 | x: 1, y: 0, z: 0,
28 | p: NewGeodeticTMS(),
29 | sw: &LatLng{-90, 0},
30 | ne: &LatLng{90, 180},
31 | },
32 | }
33 | for _, test := range tests {
34 | latlo, lnglo, lathi, lnghi := test.p.TileLatLngBounds(test.x, test.y, test.z)
35 | if !floatEquals(latlo, test.sw.Lat, 1e-6) ||
36 | !floatEquals(lnglo, test.sw.Lng, 1e-6) ||
37 | !floatEquals(lathi, test.ne.Lat, 1e-6) ||
38 | !floatEquals(lnghi, test.ne.Lng, 1e-6) {
39 | t.Errorf(
40 | "TileLatLngBounds(%v, %v, %v): wanted %s - %s, got %v,%v - %v,%v",
41 | test.x, test.y, test.z, test.sw, test.ne, latlo, lnglo, lathi, lnghi)
42 | }
43 | }
44 | }
45 |
46 | func TestLatLngToRaster(t *testing.T) {
47 | var tests = []struct {
48 | p Projection
49 | lat, lng, zoom float64
50 | x, y float64
51 | }{
52 | {
53 | p: NewMercatorTMS(),
54 | lat: 90, lng: -180, zoom: 1,
55 | x: 0, y: -2786.073317,
56 | },
57 | {
58 | p: NewMercatorTMS(),
59 | lat: 85.05112875, lng: -180, zoom: 1,
60 | x: 0, y: 0,
61 | },
62 | {
63 | p: NewMercatorTMS(),
64 | lat: 0, lng: 0, zoom: 1,
65 | x: 256, y: 256,
66 | },
67 | {
68 | p: NewMercatorTMS(),
69 | lat: -85.05112875, lng: 180, zoom: 1,
70 | x: 512, y: 512,
71 | },
72 | {
73 | p: NewMercatorTMS(),
74 | lat: -90, lng: 180, zoom: 1,
75 | x: 512, y: 3298.073317,
76 | },
77 | }
78 | for _, test := range tests {
79 | gotx, goty := test.p.LatLngToRaster(test.lat, test.lng, test.zoom)
80 | if !floatEquals(gotx, test.x, 1e-6) ||
81 | !floatEquals(goty, test.y, 1e-6) {
82 | t.Errorf(
83 | "TestLatLngToRaster(%v, %v, %v): wanted %v,%v, got %v,%v diff (%v, %v)",
84 | test.lat, test.lng, test.zoom, test.x, test.y, gotx, goty,
85 | math.Abs(test.x-gotx), math.Abs(test.y-goty))
86 | }
87 | }
88 | }
89 |
90 | func floatEquals(a, b, margin float64) bool {
91 | return math.Abs(a-b) < margin
92 | }
93 |
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/21_1098232_1362659.mvt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/21_1098232_1362659.mvt
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/21_1098232_1362659.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/21_1098232_1362659.png
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/21_1098232_1362659_geodetic.json:
--------------------------------------------------------------------------------
1 | {
2 | "type":"FeatureCollection",
3 | "features":[
4 | {
5 | "type":"Feature",
6 | "geometry":{
7 | "type":"Polygon",
8 | "coordinates":[
9 | [
10 | [
11 | -85.738,
12 | 26.957875
13 | ],
14 | [
15 | -85.738,
16 | 26.958000000000002
17 | ],
18 | [
19 | -85.737875,
20 | 26.958000000000002
21 | ],
22 | [
23 | -85.737875,
24 | 26.957875
25 | ]
26 | ]
27 | ]
28 | },
29 | "properties":{
30 | "area_code":"76RP",
31 | "global_code":"76RPX756+5R",
32 | "local_code":"X756+5R",
33 | "name":"76RPX756+5R"
34 | }
35 | },
36 | {
37 | "type":"Feature",
38 | "geometry":{
39 | "type":"Polygon",
40 | "coordinates":[
41 | [
42 | [
43 | -85.738,
44 | 26.958000000000002
45 | ],
46 | [
47 | -85.738,
48 | 26.958125000000003
49 | ],
50 | [
51 | -85.737875,
52 | 26.958125000000003
53 | ],
54 | [
55 | -85.737875,
56 | 26.958000000000002
57 | ]
58 | ]
59 | ]
60 | },
61 | "properties":{
62 | "area_code":"76RP",
63 | "global_code":"76RPX756+6R",
64 | "local_code":"X756+6R",
65 | "name":"76RPX756+6R"
66 | }
67 | }
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/21_1098232_1362659_geodetic.mvt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/21_1098232_1362659_geodetic.mvt
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/21_1098232_1362659_geodetic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/21_1098232_1362659_geodetic.png
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/5_17_19.json:
--------------------------------------------------------------------------------
1 | {
2 | "type":"FeatureCollection",
3 | "features":[
4 | {
5 | "type":"Feature",
6 | "geometry":{"type":"Polygon","coordinates":[[[0,30],[0,50],[20,50],[20,30]]]},
7 | "properties":{"global_code":"8F000000+","name":"8F"}
8 | },
9 | {
10 | "type":"Feature",
11 | "geometry":{"type":"Polygon","coordinates":[[[20,30],[20,50],[40,50],[40,30]]]},
12 | "properties":{"global_code":"8G000000+","name":"8G"}
13 | }
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/5_17_19.mvt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/5_17_19.mvt
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/5_17_19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/5_17_19.png
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/5_17_19_geodetic.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "FeatureCollection", "features": [
3 | {
4 | "type": "Feature",
5 | "geometry": {
6 | "type": "Polygon",
7 | "coordinates": [[[-100, 10], [-100, 30], [-80, 30], [-80, 10]]]
8 | },
9 | "properties": {"global_code": "76000000+", "name": "76"}
10 | },
11 | {
12 | "type": "Feature",
13 | "geometry": {
14 | "type": "Polygon",
15 | "coordinates": [[[-80, 10], [-80, 30], [-60, 30], [-60, 10]]]
16 | },
17 | "properties": {"global_code": "77000000+", "name": "77"}
18 | }
19 | ]
20 | }
21 |
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/5_17_19_geodetic.mvt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/5_17_19_geodetic.mvt
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/5_17_19_white_zoom_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/5_17_19_white_zoom_2.png
--------------------------------------------------------------------------------
/tile_server/gridserver/testdata/5_17_19_zoom_2.mvt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/google/open-location-code/3cf9f806af4d1c47388badea615064544cec94f5/tile_server/gridserver/testdata/5_17_19_zoom_2.mvt
--------------------------------------------------------------------------------
/tile_server/main.go:
--------------------------------------------------------------------------------
1 | // main starts the server.
2 | package main
3 |
4 | import (
5 | "flag"
6 | "fmt"
7 | "net/http"
8 |
9 | log "github.com/golang/glog"
10 | // Use the production gridserver. In development, change to just "./gridserver".
11 | "github.com/google/open-location-code/tile_server/gridserver"
12 | "golang.org/x/image/font/gofont/goregular"
13 | )
14 |
15 | var (
16 | port = flag.Int("port", 8080, "Port to run the server on")
17 | )
18 |
19 | const (
20 | originHeader = "Access-Control-Allow-Origin"
21 | contentTypeHeader = "Content-Type"
22 | contentTypeGeoJSON = "application/vnd.geo+json"
23 | contentTypePNG = "image/png"
24 | contentTypeMVT = "application/vnd.mapbox-vector-tile"
25 | )
26 |
27 | func init() {
28 | flag.Parse()
29 | }
30 |
31 | func main() {
32 | log.Infof("Starting...")
33 | gridserver.SetImageFont(goregular.TTF)
34 | http.HandleFunc("/", Handler)
35 | log.Infof("Ready")
36 | if err := http.ListenAndServe(fmt.Sprintf(":%v", *port), nil); err != nil {
37 | panic(err)
38 | }
39 | }
40 |
41 | // Handler processes a tileReq for a single tile and writes either the GeoJSON or image as a response.
42 | func Handler(w http.ResponseWriter, r *http.Request) {
43 | if err := r.ParseForm(); err != nil {
44 | log.Errorf("Bad http request: %v: %v", r.URL, err)
45 | http.Error(w, err.Error(), 400)
46 | return
47 | }
48 | tile, err := gridserver.Parse(r)
49 | if err != nil {
50 | log.Errorf("Bad tile request: %v: %v", r.URL, err)
51 | http.Error(w, err.Error(), 400)
52 | return
53 | }
54 | w.Header().Set(originHeader, "*")
55 |
56 | // Response content. May be a tile or JSON.
57 | ctype := contentTypeGeoJSON
58 | blob := []byte("")
59 | if tile.Options.Format == gridserver.JSONTile {
60 | json, err := tile.GeoJSON()
61 | if err != nil {
62 | log.Errorf("Error producing geojson tile: %v", err)
63 | http.Error(w, err.Error(), 500)
64 | return
65 | }
66 | if blob, err = json.MarshalJSON(); err != nil {
67 | log.Errorf("Error marshaling geojson tile: %v", err)
68 | http.Error(w, err.Error(), 500)
69 | return
70 | }
71 | } else if tile.Options.Format == gridserver.ImageTile {
72 | ctype = contentTypePNG
73 | if blob, err = tile.Image(); err != nil {
74 | log.Errorf("Error producing image tile: %v", err)
75 | http.Error(w, err.Error(), 500)
76 | return
77 | }
78 | } else if tile.Options.Format == gridserver.VectorTile {
79 | ctype = contentTypeMVT
80 | if blob, err = tile.MVT(); err != nil {
81 | log.Errorf("Error producing mapbox vector tile: %v", err)
82 | http.Error(w, err.Error(), 500)
83 | return
84 | }
85 | }
86 | w.Header().Set(contentTypeHeader, ctype)
87 | w.Write(blob)
88 | }
89 |
--------------------------------------------------------------------------------