1
+ # -*- coding: utf-8 -*-
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
+ #
16
+ #
17
+ # Convert locations to and from short codes.
18
+ #
19
+ # Open Location Codes are short, 10-11 character codes that can be used instead
20
+ # of street addresses. The codes can be generated and decoded offline, and use
21
+ # a reduced character set that minimises the chance of codes including words.
22
+ #
23
+ # Codes are able to be shortened relative to a nearby location. This means that
24
+ # in many cases, only four to seven characters of the code are needed.
25
+ # To recover the original code, the same location is not required, as long as
26
+ # a nearby location is provided.
27
+ #
28
+ # Codes represent rectangular areas rather than points, and the longer the
29
+ # code, the smaller the area. A 10 character code represents a 13.5x13.5
30
+ # meter area (at the equator. An 11 character code represents approximately
31
+ # a 2.8x3.5 meter area.
32
+ #
33
+ # Two encoding algorithms are used. The first 10 characters are pairs of
34
+ # characters, one for latitude and one for latitude, using base 20. Each pair
35
+ # reduces the area of the code by a factor of 400. Only even code lengths are
36
+ # sensible, since an odd-numbered length would have sides in a ratio of 20:1.
37
+ #
38
+ # At position 11, the algorithm changes so that each character selects one
39
+ # position from a 4x5 grid. This allows single-character refinements.
40
+ #
41
+ # Examples:
42
+ #
43
+ # Encode a location, default accuracy:
44
+ # var code = olc.encode(47.365590, 8.524997);
45
+ #
46
+ # Encode a location using one stage of additional refinement:
47
+ # var code = olc.encode(47.365590, 8.524997, 11);
48
+ #
49
+ # Decode a full code:
50
+ # var coord = olc.decode(code);
51
+ # var msg = 'Center is ' + coord.latitudeCenter + ',' + coord.longitudeCenter;
52
+ #
53
+ # Attempt to trim the first characters from a code:
54
+ # var shortCode = olc.shorten('8FVC9G8F+6X', 47.5, 8.5);
55
+ #
56
+ # Recover the full code from a short code:
57
+ # var code = olc.recoverNearest('9G8F+6X', 47.4, 8.6);
58
+ # var code = olc.recoverNearest('8F+6X', 47.4, 8.6);
59
+
1
60
import re
2
61
import math
3
62
@@ -218,11 +277,8 @@ def decode(code):
218
277
to find the nearest matching full code.
219
278
Returns:
220
279
The nearest full Open Location Code to the reference location that matches
221
- the short code. Note that the returned code may not have the same
222
- computed characters as the reference location. This is because it returns
223
- the nearest match, not necessarily the match within the same cell. If the
224
- passed code was not a valid short code, but was a valid full code, it is
225
- returned unchanged.
280
+ the short code. If the passed code was not a valid short code, but was a
281
+ valid full code, it is returned unchanged.
226
282
"""
227
283
def recoverNearest (shortcode , referenceLatitude , referenceLongitude ):
228
284
if not isShort (shortcode ):
@@ -238,11 +294,8 @@ def recoverNearest(shortcode, referenceLatitude, referenceLongitude):
238
294
resolution = pow (20 , 2 - (paddingLength / 2 ))
239
295
# Distance from the center to an edge (in degrees).
240
296
areaToEdge = resolution / 2.0
241
- # Now round down the reference latitude and longitude to the resolution.
242
- roundedLatitude = math .floor (referenceLatitude / resolution ) * resolution
243
- roundedLongitude = math .floor (referenceLongitude / resolution ) * resolution
244
297
# Use the reference location to pad the supplied short code and decode it.
245
- codeArea = decode (encode (roundedLatitude , roundedLongitude )[0 :paddingLength ] + shortcode )
298
+ codeArea = decode (encode (referenceLatitude , referenceLongitude )[0 :paddingLength ] + shortcode )
246
299
# How many degrees latitude is the code from the reference? If it is more
247
300
# than half the resolution, we need to move it east or west.
248
301
degreesDifference = codeArea .latitudeCenter - referenceLatitude
@@ -313,7 +366,7 @@ def shorten(code,latitude,longitude):
313
366
latitude: A latitude in signed decimal degrees.
314
367
"""
315
368
def clipLatitude (latitude ):
316
- return min (90 ,max (- 90 ,latitude ))
369
+ return min (90 , max (- 90 , latitude ))
317
370
318
371
"""
319
372
Compute the latitude precision value for a given code length. Lengths <=
@@ -323,7 +376,7 @@ def clipLatitude(latitude):
323
376
"""
324
377
def computeLatitutePrecision (codeLength ):
325
378
if codeLength <= 10 :
326
- return pow (20 ,math .floor ((codeLength / - 2 ) + 2 ))
379
+ return pow (20 , math .floor ((codeLength / - 2 ) + 2 ))
327
380
return pow (20 , - 3 ) / pow (GRID_ROWS_ , codeLength - 10 )
328
381
329
382
"""
@@ -359,16 +412,16 @@ def encodePairs(latitude, longitude, codeLength):
359
412
digitCount = 0
360
413
while digitCount < codeLength :
361
414
# Provides the value of digits in this place in decimal degrees.
362
- placeValue = PAIR_RESOLUTIONS_ [math .floor (digitCount / 2 )]
415
+ placeValue = PAIR_RESOLUTIONS_ [int ( math .floor (digitCount / 2 ) )]
363
416
# Do the latitude - gets the digit for this place and subtracts that for
364
417
# the next digit.
365
- digitValue = math .floor (adjustedLatitude / placeValue )
418
+ digitValue = int ( math .floor (adjustedLatitude / placeValue ) )
366
419
adjustedLatitude -= digitValue * placeValue
367
420
code += CODE_ALPHABET_ [digitValue ]
368
421
digitCount += 1
369
422
# And do the longitude - gets the digit for this place and subtracts that
370
423
# for the next digit.
371
- digitValue = math .floor (adjustedLongitude / placeValue )
424
+ digitValue = int ( math .floor (adjustedLongitude / placeValue ) )
372
425
adjustedLongitude -= digitValue * placeValue
373
426
code += CODE_ALPHABET_ [digitValue ]
374
427
digitCount += 1
@@ -401,8 +454,8 @@ def encodeGrid(latitude, longitude, codeLength):
401
454
adjustedLongitude = (longitude + LONGITUDE_MAX_ ) % lngPlaceValue
402
455
for i in range (codeLength ):
403
456
# Work out the row and column.
404
- row = math .floor (adjustedLatitude / (latPlaceValue / GRID_ROWS_ ))
405
- col = math .floor (adjustedLongitude / (lngPlaceValue / GRID_COLUMNS_ ))
457
+ row = int ( math .floor (adjustedLatitude / (latPlaceValue / GRID_ROWS_ ) ))
458
+ col = int ( math .floor (adjustedLongitude / (lngPlaceValue / GRID_COLUMNS_ ) ))
406
459
latPlaceValue /= GRID_ROWS_
407
460
lngPlaceValue /= GRID_COLUMNS_
408
461
adjustedLatitude -= row * latPlaceValue
@@ -492,7 +545,7 @@ def decodeGrid(code):
492
545
code_length: The number of significant characters that were in the code.
493
546
This excludes the separator.
494
547
"""
495
- class CodeArea :
548
+ class CodeArea ( object ) :
496
549
def __init__ (self ,latitudeLo , longitudeLo , latitudeHi , longitudeHi , codeLength ):
497
550
self .latitudeLo = latitudeLo
498
551
self .longitudeLo = longitudeLo
0 commit comments