Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 21 additions & 22 deletions cpp/openlocationcode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,19 @@ double adjust_latitude(double latitude_degrees, size_t code_length) {
return latitude_degrees - precision / 2;
}

// Remove the separator and padding characters from the code.
std::string clean_code_chars(const std::string &code) {
std::string clean_code(code);
clean_code.erase(
std::remove(clean_code.begin(), clean_code.end(), internal::kSeparator),
clean_code.end());
if (clean_code.find(internal::kPaddingCharacter)) {
clean_code = clean_code.substr(
0, clean_code.find(internal::kPaddingCharacter));
}
return clean_code;
}


// Encodes positive range lat,lng into a sequence of OLC lat/lng pairs.
// This uses pairs of characters (latitude and longitude in that order) to
Expand Down Expand Up @@ -198,15 +211,10 @@ std::string Encode(const LatLng &location) {
}

CodeArea Decode(const std::string &code) {
// Make a copy that doesn't have the separator and stops at the first padding
// character.
std::string clean_code(code);
clean_code.erase(
std::remove(clean_code.begin(), clean_code.end(), internal::kSeparator),
clean_code.end());
if (clean_code.find(internal::kPaddingCharacter)) {
clean_code = clean_code.substr(0,
clean_code.find(internal::kPaddingCharacter));
std::string clean_code = clean_code_chars(code);
// Constrain to the maximum length.
if (clean_code.size() > internal::kMaximumDigitCount) {
clean_code = clean_code.substr(0, internal::kMaximumDigitCount);
}
double resolution_degrees = internal::kEncodingBase;
double latitude = 0.0;
Expand Down Expand Up @@ -242,9 +250,8 @@ CodeArea Decode(const std::string &code) {
// With a grid, the latitude and longitude resolutions are no longer equal.
double latitude_resolution = resolution_degrees;
double longitude_resolution = resolution_degrees;
// Decode only up to the maximum digit count.
for (size_t i = internal::kPairCodeLength;
i < std::min(internal::kMaximumDigitCount, clean_code.size()); i++) {
// Decode grid square characters.
for (size_t i = internal::kPairCodeLength; i < clean_code.size(); i++) {
// Get the value of the character at i and convert it to the degree value.
size_t value = get_alphabet_position(clean_code[i]);
size_t row = value / internal::kGridColumns;
Expand All @@ -264,7 +271,7 @@ CodeArea Decode(const std::string &code) {
longitude - internal::kLongitudeMaxDegrees,
latitude_high - internal::kLatitudeMaxDegrees,
longitude_high - internal::kLongitudeMaxDegrees,
CodeLength(code));
clean_code.size());
}

std::string Shorten(const std::string &code, const LatLng &reference_location) {
Expand Down Expand Up @@ -454,15 +461,7 @@ bool IsFull(const std::string &code) {
}

size_t CodeLength(const std::string &code) {
// Remove the separator and any padding characters.
std::string clean_code(code);
clean_code.erase(
std::remove(clean_code.begin(), clean_code.end(), internal::kSeparator),
clean_code.end());
if (clean_code.find(internal::kPaddingCharacter)) {
clean_code = clean_code.substr(
0, clean_code.find(internal::kPaddingCharacter));
}
std::string clean_code = clean_code_chars(code);
return clean_code.size();
}

Expand Down
10 changes: 10 additions & 0 deletions js/closure/openlocationcode.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ var GRID_SIZE_DEGREES = 0.000125;
*/
var MIN_TRIMMABLE_CODE_LEN = 6;

/**
* Maximum length of a code.
*/
var MAX_CODE_LEN = 15;

/**
* Returns the characters used to produce the codes.
* @return {string} the OLC alphabet.
Expand Down Expand Up @@ -311,6 +316,7 @@ function encode(latitude, longitude, opt_length) {
(opt_length < PAIR_CODE_LENGTH && opt_length % 2 == 1)) {
throw 'IllegalArgumentException: Invalid Open Location Code length';
}
opt_length = Math.min(opt_length, MAX_CODE_LEN);
// Ensure that latitude and longitude are valid.
latitude = clipLatitude(latitude);
longitude = normalizeLongitude(longitude);
Expand Down Expand Up @@ -351,6 +357,10 @@ function decode(code) {
code = code.replace(SEPARATOR, '');
code = code.replace(new RegExp(PADDING_CHARACTER + '+'), '');
code = code.toUpperCase();
if (code.length > MAX_CODE_LEN) {
code = code.substring(0, MAX_CODE_LEN);
}

var /** @type {number} */ precision = ENCODING_BASE;
var latitude = 0.0;
var longitude = 0.0;
Expand Down
10 changes: 8 additions & 2 deletions python/openlocationcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@
#Minimum length of a code that can be shortened.
MIN_TRIMMABLE_CODE_LEN_ = 6

#The maximum significant digits in a plus code.
MAX_CODE_LENGTH = 15

SP = '+0'


Expand Down Expand Up @@ -213,6 +216,7 @@ def isFull(code):
def encode(latitude, longitude, codeLength=PAIR_CODE_LENGTH_):
if codeLength < 2 or (codeLength < PAIR_CODE_LENGTH_ and codeLength % 2 == 1):
raise ValueError('Invalid Open Location Code length - ' + str(codeLength))
codeLength = min(codeLength, MAX_CODE_LENGTH)
# Ensure that latitude and longitude are valid.
latitude = clipLatitude(latitude)
longitude = normalizeLongitude(longitude)
Expand Down Expand Up @@ -240,10 +244,12 @@ def decode(code):
if not isFull(code):
raise ValueError('Passed Open Location Code is not a valid full code - ' + str(code))
# Strip out separator character (we've already established the code is
# valid so the maximum is one), padding characters and convert to upper
# case.
# valid so the maximum is one), and padding characters. Convert to upper
# case and constrain to the maximum number of digits.
code = re.sub('[+0]','',code)
code = code.upper()
code = code[:MAX_CODE_LENGTH]

# Decode the lat/lng pair component.
codeArea = decodePairs(code[0:PAIR_CODE_LENGTH_])
if len(code) <= PAIR_CODE_LENGTH_:
Expand Down
5 changes: 4 additions & 1 deletion rust/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,13 @@ pub fn decode(_code: &str) -> Result<CodeArea, String> {
if !is_full(_code) {
return Err(format!("Code must be a valid full code: {}", _code));
}
let code = _code.to_string()
let mut code = _code.to_string()
.replace(SEPARATOR, "")
.replace(PADDING_CHAR_STR, "")
.to_uppercase();
if code.len() > MAX_CODE_LENGTH {
code = code.chars().take(MAX_CODE_LENGTH).collect();
}

let mut lat = -LATITUDE_MAX;
let mut lng = -LONGITUDE_MAX;
Expand Down
3 changes: 3 additions & 0 deletions test_data/decoding.csv
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ CFX30000+,4,89,1,90,2
CFX3X2X2+X2,10,89.9998750,1,90,1.0001250
# Test non-precise latitude/longitude value
6FH56C22+22,10,1.2000000000000028,3.4000000000000057,1.2001249999999999,3.4001250000000027
# Validate that digits after the first 15 are ignored when decoding
849VGJQF+VX7QR3J,15,37.5396691200,-122.3750698242,37.5396691600,-122.3750697021
849VGJQF+VX7QR3J7QR3J,15,37.5396691200,-122.3750698242,37.5396691600,-122.3750697021
5 changes: 5 additions & 0 deletions test_data/encoding.csv
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@
90,1,10,CFX3X2X2+X2
# Test non-precise latitude/longitude value
1.2,3.4,10,6FH56C22+22
# Validate that codes generated with a length exceeding 15 significant digits
# return a 15-digit code
37.539669125,-122.375069724,15,849VGJQF+VX7QR3J
37.539669125,-122.375069724,16,849VGJQF+VX7QR3J
37.539669125,-122.375069724,100,849VGJQF+VX7QR3J
6 changes: 6 additions & 0 deletions test_data/validityTests.csv
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,9 @@ G+,false,false,false
WC2300+G6g,false,false,false
WC2345+G,false,false,false
WC2300+,false,false,false
# Validate that codes at and exceeding 15 digits are still valid when all their
# digits are valid, and invalid when not.
849VGJQF+VX7QR3J,true,false,true
849VGJQF+VX7QR3U,false,false,false
849VGJQF+VX7QR3JW,true,false,true
849VGJQF+VX7QR3JU,false,false,false