Ticket #481: geocode.py

File geocode.py, 2.4 KB (added by Olly Betts, 14 years ago)

prototype compact encoding in python

Line 
1#!/usr/bin/python
2
3def to_dms(angle):
4 m = 60 * (angle % 1)
5 s = 60 * (m % 1)
6 return (int(angle), int(m), s)
7
8def encode(lat, long):
9 if lat < -90 or lat > 90:
10 raise ValueError("latitude out of range")
11 if lat == -90:
12 # South Pole special case.
13 return b''
14 if lat == 90:
15 # North Pole special case.
16 return b'\xff\xff'
17 # Wrap longitude to range [0,360).
18 while long >= 360:
19 long -= 360
20 while long < 0:
21 long += 360
22 lat = to_dms(lat + 90)
23 long = to_dms(long)
24 result = bytearray()
25 dd = lat[0] * 360 + long[0]
26 result.append(dd >> 8)
27 result.append(dd & 255)
28 m1 = (lat[1] // 4) << 4 | (long[1] // 4)
29 result.append(m1)
30 ms = (lat[1] % 4) << 6 | (long[1] % 4) << 4
31 ms |= int(lat[2] // 15) << 2 | int(long[2] // 15)
32 result.append(ms)
33 s2 = int(lat[2] % 15) << 4 | int(long[2] % 15)
34 result.append(s2)
35 s3 = (int(lat[2] / 15) & 0x0f) << 4 | (int(long[2] / 15) & 0x0f);
36 result.append(s3)
37
38 # Remove trailing zeros.
39 while len(result) and result[-1] == 0:
40 result.pop()
41 return result
42
43def decode(value):
44 if len(value) == 0:
45 return (-90.0, 0.0)
46 if value == b'\xff\xff':
47 return (90.0, 0.0)
48 if len(value) == 1:
49 dd = 0
50 else:
51 dd = value[1]
52 dd |= (value[0] << 8)
53 lat = dd // 360;
54 long = dd % 360;
55 if len(value) > 2:
56 m1 = value[2]
57 lat_m = (m1 >> 4) * 4
58 long_m = (m1 & 15) * 4
59 if len(value) > 3:
60 ms = value[3]
61 lat_m += ms >> 6
62 long_m += (ms >> 4) & 3
63 lat_s = ((ms >> 2) & 3) * 15
64 long_s = (ms & 3) * 15
65 if len(value) > 4:
66 s2 = value[4]
67 lat_s += s2 >> 4
68 long_s += s2 & 15
69 if len(value) > 5:
70 s3 = value[5]
71 lat_s += ((s3 >> 4) + 0.5) / 16.0
72 long_s += ((s3 & 15) + 0.5) / 16.0
73 else:
74 lat_s += 0.5
75 long_s += 0.5
76 else:
77 lat_s += 7.5
78 long_s += 7.5
79 lat_m += lat_s / 60.0
80 long_m += long_s / 60.0
81 else:
82 lat_m += 2
83 long_m += 2
84 lat += lat_m / 60.0
85 long += long_m / 60.0
86 else:
87 lat += 0.5
88 long += 0.5
89 return (lat - 90, long)