Changeset 886
- Timestamp:
- 05/12/07 15:49:33 (5 years ago)
- Location:
- core/trunk/byCycle/model
- Files:
-
- 2 modified
-
glineenc.py (modified) (7 diffs)
-
route.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
core/trunk/byCycle/model/glineenc.py
r883 r886 1 def encode_pairs(pairs): 2 """Encode a set of lat/long pairs. 1 import math 3 2 4 ``pairs`` 5 A list of lat/long pairs ((lat, long), ...) 3 4 threshold = .00001 5 num_levels = 4 6 zoom_factor = 32 7 zoom_level_breaks = [] 8 for i in range(num_levels): 9 zoom_level_breaks.append(threshold * (zoom_factor ** (num_levels - i - 1))) 10 11 12 def encode_pairs(points): 13 """Encode a set of lat/long points. 14 15 ``points`` 16 A list of lat/long points ((lat, long), ...) 6 17 Note carefully that the order is latitude, longitude 7 18 8 19 return 9 An encoded string representing all pairs 20 - An encoded string representing points within our error 21 ``threshold``, 22 - An encoded string representing the maximum zoom level for each of 23 those points 10 24 11 25 Example:: … … 13 27 >>> pairs = ((38.5, -120.2), (43.252, -126.453), (40.7, -120.95)) 14 28 >>> encode_pairs(pairs) 15 '_p~iF~ps|U_c_\\\\fhde@~lqNwxq`@'29 ('_p~iF~ps|U_c_\\\\fhde@~lqNwxq`@', 'BBB') 16 30 17 31 """ 18 result = [] 32 encoded_points = [] 33 encoded_levels = [] 34 35 distances = douglas_peucker_distances(points) 36 points_of_interest = [] 37 for i, d in enumerate(distances): 38 if d is not None: 39 lat, long = points[i] 40 points_of_interest.append((lat, long, d)) 41 19 42 lat_prev, long_prev = 0, 0 20 for pair in pairs: 21 encoded_val, lat_prev = encode(pair[0], lat_prev) 22 result.append(encoded_val) 23 encoded_val, long_prev = encode(pair[1], long_prev) 24 result.append(encoded_val) 25 result = ''.join(result) 26 return result 43 for lat, long, d in points_of_interest: 44 encoded_lat, lat_prev = encode_lat_or_long(lat, lat_prev) 45 encoded_long, long_prev = encode_lat_or_long(long, long_prev) 46 encoded_points += [encoded_lat, encoded_long] 47 encoded_level = encode_unsigned(num_levels - compute_level(d) - 1) 48 encoded_levels.append(encoded_level) 27 49 28 def encode(x, prev_int): 50 encoded_points_str = ''.join(encoded_points) 51 encoded_levels_str = ''.join([str(l) for l in encoded_levels]) 52 return encoded_points_str, encoded_levels_str 53 54 def encode_lat_or_long(x, prev_int): 29 55 """Encode a single latitude or longitude. 30 56 … … 33 59 34 60 ``prev_int`` 35 The int value of the previous latitude or longitude61 The integer value of the previous latitude or longitude 36 62 37 63 Return the encoded value and its int value, which is used … … 40 66 41 67 >>> x = -179.9832104 42 >>> encoded_x, prev = encode (x, 0)68 >>> encoded_x, prev = encode_lat_or_long(x, 0) 43 69 >>> encoded_x 44 70 '`~oia@' … … 46 72 -17998321 47 73 >>> x = -120.2 48 >>> encode (x, prev)74 >>> encode_lat_or_long(x, prev) 49 75 ('al{kJ', -12020000) 50 76 51 77 """ 52 78 int_value = int(x * 1e5) 53 res = int_value - prev_int 54 res = res << 1 55 if res < 0: 56 res = ~res 57 chunk = res 58 res = [] 79 delta = int_value - prev_int 80 return encode_signed(delta), int_value 81 82 def encode_signed(n): 83 tmp = n << 1 84 if n < 0: 85 tmp = ~tmp 86 return encode_unsigned(tmp) 87 88 def encode_unsigned(n): 89 tmp = [] 59 90 # while there are more than 5 bits left (that aren't all 0)... 60 while chunk >= 32: # 32 == 0xf0 == 100000 61 res.append(chunk & 31) # 31 == 0x1f == 11111 62 chunk = chunk >> 5 63 res = [(c | 0x20) for c in res] 64 res.append(chunk) 65 res = [(i + 63) for i in res] 66 res = [chr(i) for i in res] 67 res = ''.join(res) 68 return res, int_value 91 while n >= 32: # 32 == 0xf0 == 100000 92 tmp.append(n & 31) # 31 == 0x1f == 11111 93 n = n >> 5 94 tmp = [(c | 0x20) for c in tmp] 95 tmp.append(n) 96 tmp = [(i + 63) for i in tmp] 97 tmp = [chr(i) for i in tmp] 98 tmp = ''.join(tmp) 99 return tmp 100 101 def douglas_peucker_distances(points): 102 distances = [None] * len(points) 103 distances[0] = threshold * (zoom_factor ** num_levels) 104 distances[-1] = distances[0] 105 106 if(len(points) < 3): 107 return distances 108 109 stack = [(0, len(points) - 1)] 110 while stack: 111 a, b = stack.pop() 112 max_dist = 0 113 for i in range(a + 1, b): 114 dist = distance(points[i], points[a], points[b]) 115 if dist > max_dist: 116 max_dist = dist 117 max_i = i 118 if max_dist > threshold: 119 distances[max_i] = max_dist 120 stack += [(a, max_i), (max_i, b)] 121 122 return distances 123 124 def distance(point, A, B): 125 """Compute distance of ``point`` from line ``A``, ``B``.""" 126 if A == B: 127 out = math.sqrt( 128 (B[0] - point[0]) ** 2 + 129 (B[1] - point[1]) ** 2 130 ) 131 else: 132 u = ( 133 (((point[0] - A[0]) * (B[0] - A[0])) + 134 ((point[1] - A[1]) * (B[1] - A[1]))) / 135 (((B[0] - A[0]) ** 2) + ((B[1] - A[1]) ** 2)) 136 ) 137 if u <= 0: 138 out = math.sqrt( 139 ((point[0] - A[0]) ** 2) + ((point[1] - A[1]) ** 2) 140 ) 141 elif u >= 1: 142 out = math.sqrt( 143 ((point[0] - B[0]) ** 2) + ((point[1] - B[1]) ** 2) 144 ) 145 elif 0 < u < 1: 146 out = math.sqrt( 147 ((((point[0] - A[0]) - (u * (B[0] - A[0]))) ** 2)) + 148 ((((point[1] - A[1]) - (u * (B[1] - A[1]))) ** 2)) 149 ) 150 return out 151 152 def compute_level(distance): 153 """Compute the appropriate zoom level of a point in terms of its 154 distance from the relevant segment in the DP algorithm.""" 155 if distance > threshold: 156 level = 0 157 while distance < zoom_level_breaks[level]: 158 level += 1 159 return level 69 160 70 161 def test_encode_negative(): 71 162 f = -179.9832104 72 assert encode (f, 0)[0] == '`~oia@'163 assert encode_lat_or_long(f, 0)[0] == '`~oia@' 73 164 74 165 f = -120.2 75 assert encode (f, 0)[0] == '~ps|U'166 assert encode_lat_or_long(f, 0)[0] == '~ps|U' 76 167 77 168 def test_encode_positive(): 78 169 f = 38.5 79 assert encode (f, 0)[0] == '_p~iF'170 assert encode_lat_or_long(f, 0)[0] == '_p~iF' 80 171 81 172 def test_encode_one_pair(): 82 173 pairs = [(38.5, -120.2)] 83 expected_encoding = '_p~iF~ps|U' 174 expected_encoding = '_p~iF~ps|U', 'B' 84 175 assert encode_pairs(pairs) == expected_encoding 85 176 … … 91 182 (40.7, -120.95), 92 183 ) 93 expected_encoding = '_p~iF~ps|U_ulLnnqC_mqNvxq`@~lqNwxq`@' 184 expected_encoding = '_p~iF~ps|U_ulLnnqC_mqNvxq`@~lqNwxq`@', 'BBBB' 94 185 assert encode_pairs(pairs) == expected_encoding 95 186 … … 99 190 (37.4619, -122.1819), 100 191 ) 101 expected_encoding = 'yzocFzynhVq}@n}@o}@nzD' 192 expected_encoding = 'yzocFzynhVq}@n}@o}@nzD', 'B@B' 102 193 assert encode_pairs(pairs) == expected_encoding -
core/trunk/byCycle/model/route.py
r883 r886 49 49 bounds = self.linestring_ll.envelope() 50 50 centroid = bounds.centroid() 51 google_points, google_levels = glineenc.encode_pairs(pairs) 51 52 route = { 52 53 'start': dict(self.start), … … 60 61 'directions': self.directions, 61 62 'distance': self.distance, 62 'google_points': g lineenc.encode_pairs(pairs),63 'google_levels': 'P' * len(pairs),63 'google_points': google_points, 64 'google_levels': google_levels, 64 65 } 65 66 route['start']['geocode'] = route['start']['geocode'].to_builtin()