Skip to content

Commit 446e536

Browse files
committed
expose C++ integer encoding and conversion functions
1 parent d47385e commit 446e536

2 files changed

Lines changed: 81 additions & 72 deletions

File tree

cpp/openlocationcode.cc

Lines changed: 75 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,78 @@ const int64_t kLongitudeMaxDegrees = 180;
4747
const int kPositionLUT['X' - 'C' + 1] = {8, -1, -1, 9, 10, 11, -1, 12,
4848
-1, -1, 13, -1, -1, 14, 15, 16,
4949
-1, -1, -1, 17, 18, 19};
50+
51+
int64_t latitudeToInteger(double latitude) {
52+
int64_t lat = round(latitude * kGridLatPrecisionInverse);
53+
lat += kLatitudeMaxDegrees * kGridLatPrecisionInverse;
54+
if (lat < 0) {
55+
lat = 0;
56+
} else if (lat >= 2 * kLatitudeMaxDegrees * kGridLatPrecisionInverse) {
57+
lat = 2 * kLatitudeMaxDegrees * kGridLatPrecisionInverse - 1;
58+
}
59+
return lat;
60+
}
61+
62+
int64_t longitudeToInteger(double longitude) {
63+
int64_t lng = round(longitude * kGridLngPrecisionInverse);
64+
lng += kLongitudeMaxDegrees * kGridLngPrecisionInverse;
65+
if (lng <= 0) {
66+
lng = lng % (2 * kLongitudeMaxDegrees * kGridLngPrecisionInverse) +
67+
2 * kLongitudeMaxDegrees * kGridLngPrecisionInverse;
68+
} else if (lng >= 2 * kLongitudeMaxDegrees * kGridLngPrecisionInverse) {
69+
lng = lng % (2 * kLongitudeMaxDegrees * kGridLngPrecisionInverse);
70+
}
71+
return lng;
72+
}
73+
74+
std::string encodeIntegers(int64_t lat_val, int64_t lng_val,
75+
size_t code_length) {
76+
// Reserve characters for the code digits and the separator.
77+
std::string code = "1234567890abcdef";
78+
// Add the separator character.
79+
code[internal::kSeparatorPosition] = internal::kSeparator;
80+
81+
// Compute the grid part of the code if necessary.
82+
if (code_length > internal::kPairCodeLength) {
83+
for (size_t i = internal::kGridCodeLength; i >= 1; i--) {
84+
int lat_digit = lat_val % internal::kGridRows;
85+
int lng_digit = lng_val % internal::kGridColumns;
86+
code[internal::kSeparatorPosition + 2 + i] =
87+
internal::kAlphabet[lat_digit * internal::kGridColumns + lng_digit];
88+
lat_val /= internal::kGridRows;
89+
lng_val /= internal::kGridColumns;
90+
}
91+
} else {
92+
lat_val /= pow(internal::kGridRows, internal::kGridCodeLength);
93+
lng_val /= pow(internal::kGridColumns, internal::kGridCodeLength);
94+
}
95+
96+
// Add the pair after the separator.
97+
code[internal::kSeparatorPosition + 1] =
98+
internal::kAlphabet[lat_val % internal::kEncodingBase];
99+
code[internal::kSeparatorPosition + 2] =
100+
internal::kAlphabet[lng_val % internal::kEncodingBase];
101+
lat_val /= internal::kEncodingBase;
102+
lng_val /= internal::kEncodingBase;
103+
104+
// Compute the pair section before the separator in reverse order.
105+
// Even indices contain latitude and odd contain longitude.
106+
for (int i = (internal::kPairCodeLength / 2 + 1); i >= 0; i -= 2) {
107+
code[i] = internal::kAlphabet[lat_val % internal::kEncodingBase];
108+
code[i + 1] = internal::kAlphabet[lng_val % internal::kEncodingBase];
109+
lat_val /= internal::kEncodingBase;
110+
lng_val /= internal::kEncodingBase;
111+
}
112+
// Replace digits with padding if necessary.
113+
if (code_length < internal::kSeparatorPosition) {
114+
for (size_t i = code_length; i < internal::kSeparatorPosition; i++) {
115+
code[i] = internal::kPaddingCharacter;
116+
}
117+
code_length = internal::kSeparatorPosition;
118+
}
119+
// Return the code up to and including the separator.
120+
return code.substr(0, code_length + 1);
121+
}
50122
} // namespace internal
51123

52124
namespace {
@@ -129,78 +201,9 @@ std::string Encode(const LatLng &location, size_t code_length) {
129201
code_length = code_length + 1;
130202
}
131203
// Convert latitude and longitude into integer values.
132-
int64_t lat_val =
133-
round(location.latitude * internal::kGridLatPrecisionInverse);
134-
int64_t lng_val =
135-
round(location.longitude * internal::kGridLngPrecisionInverse);
136-
137-
// Adjust latitude and longitude so that they are normalized/clipped.
138-
lat_val += internal::kLatitudeMaxDegrees * internal::kGridLatPrecisionInverse;
139-
if (lat_val < 0) {
140-
lat_val = 0;
141-
} else if (lat_val >= 2 * internal::kLatitudeMaxDegrees *
142-
internal::kGridLatPrecisionInverse) {
143-
lat_val =
144-
2 * internal::kLatitudeMaxDegrees * internal::kGridLatPrecisionInverse -
145-
1;
146-
}
147-
lng_val +=
148-
internal::kLongitudeMaxDegrees * internal::kGridLngPrecisionInverse;
149-
if (lng_val <= 0) {
150-
lng_val =
151-
lng_val % (2 * internal::kLongitudeMaxDegrees *
152-
internal::kGridLngPrecisionInverse) +
153-
2 * internal::kLongitudeMaxDegrees * internal::kGridLngPrecisionInverse;
154-
} else if (lng_val >= 2 * internal::kLongitudeMaxDegrees *
155-
internal::kGridLngPrecisionInverse) {
156-
lng_val = lng_val % (2 * internal::kLongitudeMaxDegrees *
157-
internal::kGridLngPrecisionInverse);
158-
}
159-
// Reserve characters for the code digits and the separator.
160-
std::string code = "1234567890abcdef";
161-
// Add the separator character.
162-
code[internal::kSeparatorPosition] = internal::kSeparator;
163-
164-
// Compute the grid part of the code if necessary.
165-
if (code_length > internal::kPairCodeLength) {
166-
for (size_t i = internal::kGridCodeLength; i >= 1; i--) {
167-
int lat_digit = lat_val % internal::kGridRows;
168-
int lng_digit = lng_val % internal::kGridColumns;
169-
code[internal::kSeparatorPosition + 2 + i] =
170-
internal::kAlphabet[lat_digit * internal::kGridColumns + lng_digit];
171-
lat_val /= internal::kGridRows;
172-
lng_val /= internal::kGridColumns;
173-
}
174-
} else {
175-
lat_val /= pow(internal::kGridRows, internal::kGridCodeLength);
176-
lng_val /= pow(internal::kGridColumns, internal::kGridCodeLength);
177-
}
178-
179-
// Add the pair after the separator.
180-
code[internal::kSeparatorPosition + 1] =
181-
internal::kAlphabet[lat_val % internal::kEncodingBase];
182-
code[internal::kSeparatorPosition + 2] =
183-
internal::kAlphabet[lng_val % internal::kEncodingBase];
184-
lat_val /= internal::kEncodingBase;
185-
lng_val /= internal::kEncodingBase;
186-
187-
// Compute the pair section before the separator in reverse order.
188-
// Even indices contain latitude and odd contain longitude.
189-
for (int i = (internal::kPairCodeLength / 2 + 1); i >= 0; i -= 2) {
190-
code[i] = internal::kAlphabet[lat_val % internal::kEncodingBase];
191-
code[i + 1] = internal::kAlphabet[lng_val % internal::kEncodingBase];
192-
lat_val /= internal::kEncodingBase;
193-
lng_val /= internal::kEncodingBase;
194-
}
195-
// Replace digits with padding if necessary.
196-
if (code_length < internal::kSeparatorPosition) {
197-
for (size_t i = code_length; i < internal::kSeparatorPosition; i++) {
198-
code[i] = internal::kPaddingCharacter;
199-
}
200-
code_length = internal::kSeparatorPosition;
201-
}
202-
// Return the code up to and including the separator.
203-
return code.substr(0, code_length + 1);
204+
int64_t lat_val = internal::latitudeToInteger(location.latitude);
205+
int64_t lng_val = internal::longitudeToInteger(location.longitude);
206+
return internal::encodeIntegers(lat_val, lng_val, code_length);
204207
}
205208

206209
std::string Encode(const LatLng &location) {

cpp/openlocationcode.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ extern const size_t kInitialExponent;
106106
// Size of the initial grid in degrees. This is the size of the area represented
107107
// by a 10 character code, and is kEncodingBase ^ (2 - kPairCodeLength / 2).
108108
extern const double kGridSizeDegrees;
109+
// Internal method to convert latitude in degrees to the integer value for encoding.
110+
int64_t latitudeToInteger(double latitude);
111+
// Internal method to convert longitude in degrees to the integer value for encoding.
112+
int64_t longitudeToInteger(double longitude);
113+
// Internal method to encode using the integer values to avoid floating-point precision errors.
114+
std::string encodeIntegers(int64_t latitude, int64_t longitude, size_t code_length);
109115
} // namespace internal
110116

111117
} // namespace openlocationcode

0 commit comments

Comments
 (0)