1: /* ---------------------------------------------------------------- */
2: /* Decodes a Google encoded PolyLine string into latitude/longitude */
3: /* pairs */
4: /* ---------------------------------------------------------------- */
5: /* */
6: /* Originally by Ruurd J. Idenburg */
7: /* */
8: /* No copyright, no licence, no guarantees or warrantees, be it */
9: /* explicit, implicit or whatever. Usage is totally and completely */
10: /* at the users own risk, the author shall not be liable for any */
11: /* damages whatsoever, for any reason whatsoever. */
12: /* */
13: /* Please keep this comment block intact when modifying this code */
14: /* and add a note with date and a description. */
15: /* */
16: /* ---------------------------------------------------------------- */
17: /* Parameter(s): */
18: /* */
19: /* encodedPolyline - a polyline encoded in Google format. */
20: /* e.g. "_p~iF~ps|U_ulLnnqC_mqNvxq`@" */
21: /* */
22: /* Result: */
23: /* */
24: /* If invoked as a command latitude/longitude pairs to stdout, */
25: /* if invoked as a function latitude/longitude pairs into array. */
26: /* */
27: /* ---------------------------------------------------------------- */
28: /* 2013/12/13 - Initial version */
29: /* ---------------------------------------------------------------- */
30: --::routine decodeGString
31: parse source os how me
32: if how=="FUNCTION" then myResult = .array~new()
33: numeric digits 20
34:
35: parse arg encPoly
36: -- get rid of surrounding spaces
37: encPoly = encPoly~space(0)
38: -- get rid of surrounding quotes
39: if (encPoly~pos('"')=1 & encPoly~lastpos('"')=encPoly~length) then encPoly = encPoly~strip('B','"')
40: if (encPoly~pos("'")=1 & encPoly~lastpos("'")=encPoly~length) then encPoly = encPoly~strip('B',"'")
41: -- get rid of possibly escaped backslashes
42: --encPoly = encPoly~changestr('\\','\')
43: -- setup latitude and longitude
44: latitude = 0
45: longitude = 0
46: -- first position in encoded string
47: i = 1
48: do until i>=encPoly~length
49: -- first the latitude
50: result = '00000000'x
51: byte = 32
52: do j=1 by 1 while (byte>=32)
53: -- Convert each character to it's decimal value minus 63
54: byte = encPoly~subchar(i)~c2d-63
55: -- bitwise AND byte with '1F'x then shift left 5*(j-1) (i.e. multiply by 32**(j-1)
56: -- and OR into 4 byte result. That is: 5 bit chunks concatenated in reverse order.
57: -- The opposite of the encoding steps.
58: result = ((byte//32)*(32**(j-1)))~d2c(4)~bitor(result)
59: -- increment position in encoded string
60: i += 1
61: --if i>=1550 then trace ?i
62: end
63: -- encoding used 2's complement for negative values
64: -- if sign bit is not 0 then result should be negative
65: if result~bitand('00000001'x)~c2d\=0
66: then deltalatitude = -(result~c2d/2)~format(,0)/1e5
67: else deltalatitude = (result~c2d/2)~format(,0)/1e5
68: /*
69: if result~bitand('00000001'x)~c2d\=0
70: then testlatitude = latitude - ((result~c2d/2)~format(,0)/1e5)
71: else testlatitude = latitude + ((result~c2d/2)~format(,0)/1e5)
72: */
73: latitude += deltalatitude
74: -- now the longitude
75: result = '00000000'x
76: byte = 32
77: do j=1 by 1 while (byte>=32)
78: -- Convert each character to it's decimal value minus 63
79: byte = (encPoly~subchar(i)~c2d-63)
80: -- bitwise AND byte with '1F'x then shift left 5*(j-1) (i.e. multiply by 32**(j-1)
81: -- and OR into 4 byte result
82: result = ((byte//32)*(32**(j-1)))~d2c(4)~bitor(result)
83: -- increment position in encoded string
84: i += 1
85: end
86: -- if sign bit is not 0 then result should be negative
87: if result~bitand('00000001'x)~c2d\=0
88: then deltalongitude = -(result~c2d/2)~format(,0)/1e5
89: else deltalongitude = (result~c2d/2)~format(,0)/1e5
90: /*
91: if result~bitand('00000001'x)~c2d\=0
92: then testlongitude = longitude - (result~c2d/2)~format(,0)/1e5
93: else testlongitude = longitude + (result~c2d/2)~format(,0)/1e5
94: */
95: longitude += deltalongitude
96: if how=="COMMAND"
97: then say latitude longitude
98: else myResult~append(latitude longitude)
99: --if longitude==-74.88173 then trace ?i
100:
101: end
102: if how=="FUNCTION" then return myResult
103:
104: