...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package s2
16
17 import (
18 "fmt"
19 "math"
20
21 "github.com/golang/geo/r3"
22 "github.com/golang/geo/s1"
23 )
24
25 const (
26 northPoleLat = s1.Angle(math.Pi/2) * s1.Radian
27 southPoleLat = -northPoleLat
28 )
29
30
31 type LatLng struct {
32 Lat, Lng s1.Angle
33 }
34
35
36 func LatLngFromDegrees(lat, lng float64) LatLng {
37 return LatLng{s1.Angle(lat) * s1.Degree, s1.Angle(lng) * s1.Degree}
38 }
39
40
41 func (ll LatLng) IsValid() bool {
42 return math.Abs(ll.Lat.Radians()) <= math.Pi/2 && math.Abs(ll.Lng.Radians()) <= math.Pi
43 }
44
45
46
47 func (ll LatLng) Normalized() LatLng {
48 lat := ll.Lat
49 if lat > northPoleLat {
50 lat = northPoleLat
51 } else if lat < southPoleLat {
52 lat = southPoleLat
53 }
54 lng := s1.Angle(math.Remainder(ll.Lng.Radians(), 2*math.Pi)) * s1.Radian
55 return LatLng{lat, lng}
56 }
57
58 func (ll LatLng) String() string { return fmt.Sprintf("[%v, %v]", ll.Lat, ll.Lng) }
59
60
61 func (ll LatLng) Distance(ll2 LatLng) s1.Angle {
62
63 lat1, lat2 := ll.Lat.Radians(), ll2.Lat.Radians()
64 lng1, lng2 := ll.Lng.Radians(), ll2.Lng.Radians()
65 dlat := math.Sin(0.5 * (lat2 - lat1))
66 dlng := math.Sin(0.5 * (lng2 - lng1))
67 x := dlat*dlat + dlng*dlng*math.Cos(lat1)*math.Cos(lat2)
68 return s1.Angle(2*math.Atan2(math.Sqrt(x), math.Sqrt(math.Max(0, 1-x)))) * s1.Radian
69 }
70
71
72
73
74 func latitude(p Point) s1.Angle {
75 return s1.Angle(math.Atan2(p.Z, math.Sqrt(p.X*p.X+p.Y*p.Y))) * s1.Radian
76 }
77
78 func longitude(p Point) s1.Angle {
79 return s1.Angle(math.Atan2(p.Y, p.X)) * s1.Radian
80 }
81
82
83
84
85 func PointFromLatLng(ll LatLng) Point {
86 phi := ll.Lat.Radians()
87 theta := ll.Lng.Radians()
88 cosphi := math.Cos(phi)
89 return Point{r3.Vector{math.Cos(theta) * cosphi, math.Sin(theta) * cosphi, math.Sin(phi)}}
90 }
91
92
93 func LatLngFromPoint(p Point) LatLng {
94 return LatLng{latitude(p), longitude(p)}
95 }
96
97
98
99 func (ll LatLng) ApproxEqual(other LatLng) bool {
100 return ll.Lat.ApproxEqual(other.Lat) && ll.Lng.ApproxEqual(other.Lng)
101 }
102
View as plain text