-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathgeo3x3.sls
55 lines (52 loc) · 1.9 KB
/
geo3x3.sls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#!r6rs
(library (geo3x3)
(export encode decode)
(import (rnrs))
(define (encode lat lng level)
(assert (real? lat))
(assert (real? lng))
(assert (integer? level))
(assert (> level 0))
(call-with-string-output-port
(lambda(port)
(display (if (>= lng 0) "E" "W") port)
(let loop ((i 1)
(lng (exact (mod lng 180)))
(lat (+ (exact lat) 90))
(unit (/ 180 3)))
(when (< i level)
(let-values (((x xr) (div-and-mod lng unit))
((y yr) (div-and-mod lat unit)))
(display (+ x (* y 3) 1) port)
(loop (+ i 1) xr yr (/ unit 3))))))))
(define (digit->integer ch)
(- (char->integer ch)
(char->integer #\0)))
(define (decode code)
(assert (string? code))
(call-with-port (open-string-input-port code)
(lambda(port)
(let ((head (read-char port)))
(assert (or (char=? head #\W) (char=? head #\E)))
(let loop ((level 1)
(lng 0)
(lat 0)
(unit 180)
(ch (read-char port)))
(cond ((eof-object? ch)
(values (inexact (- lat (/ unit 2) 90))
(- (inexact (+ lng (/ unit 2)))
(if (char=? head #\W) 180 0))
level
(inexact unit)))
(else
(assert (char<=? #\1 ch #\9))
(let* ((n (- (digit->integer ch) 1)))
(let-values (((y x) (div-and-mod n 3))
((unit) (/ unit 3)))
(loop (+ level 1)
(+ lng (* x unit))
(+ lat (* y unit))
unit
(read-char port)))))))))))
)