-
Notifications
You must be signed in to change notification settings - Fork 0
/
projection.go
81 lines (71 loc) · 3.24 KB
/
projection.go
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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package flatsphere
import "math"
// A package of functionality for converting from spherical locations to planar coordinates, or from
// planar coordinates into spherical locations. Contains information specifying some characteristics
// of the planar space mapped to by the projection functions, which can differ between projections.
type Projection interface {
// Convert a location on the sphere (in radians) to a coordinate on the plane.
Project(lat float64, lon float64) (x float64, y float64)
// Convert a coordinate on the plane to a location in radians on the sphere.
Inverse(x float64, y float64) (lat float64, lon float64)
// Retrieve the planar bounds of the projection.
PlanarBounds() Bounds
}
// Compute both area distortion and angular distortion at a particular location on the sphere, for the given projection.
func DistortionAt(proj Projection, latitude float64, longitude float64) (area float64, angular float64) {
nudge := 1e-8
nudgedLat := latitude + nudge
// step to the side to avoid interruptions
pCx, pCy := proj.Project(nudgedLat, longitude)
// consider a point slightly east
pEx, pEy := proj.Project(nudgedLat, longitude+nudge/math.Cos(nudgedLat))
// consider a point slightly north
pNx, pNy := proj.Project(nudgedLat+nudge, longitude)
deltaA := (pEx-pCx)*(pNy-pCy) - (pEy-pCy)*(pNx-pCx)
areaDistortion := math.Log(math.Abs(deltaA / (nudge * nudge)))
if math.Abs(areaDistortion) > 25.0 {
areaDistortion = math.NaN()
}
s1ps2 := math.Hypot((pEx-pCx)+(pNy-pCy), (pEy-pCy)-(pNx-pCx))
s1ms2 := math.Hypot((pEx-pCx)-(pNy-pCy), (pEy-pCy)+(pNx-pCx))
angularDistortion := math.Abs(math.Log(math.Abs((s1ps2 - s1ms2) / (s1ps2 + s1ms2))))
if angularDistortion > 25.0 {
angularDistortion = math.NaN()
}
return areaDistortion, angularDistortion
}
// Compute the area distortion of a projection at a particular location.
func AreaDistortionAt(proj Projection, latitude float64, longitude float64) float64 {
nudge := 1e-8
nudgedLat := latitude + nudge
// step to the side to avoid interruptions
pCx, pCy := proj.Project(nudgedLat, longitude)
// consider a point slightly east
pEx, pEy := proj.Project(nudgedLat, longitude+nudge/math.Cos(nudgedLat))
// consider a point slightly north
pNx, pNy := proj.Project(nudgedLat+nudge, longitude)
deltaA := (pEx-pCx)*(pNy-pCy) - (pEy-pCy)*(pNx-pCx)
areaDistortion := math.Log(math.Abs(deltaA / (nudge * nudge)))
if math.Abs(areaDistortion) > 25.0 {
areaDistortion = math.NaN()
}
return areaDistortion
}
// Compute the angular distortion of a projection at a particular location.
func AngularDistortionAt(proj Projection, latitude float64, longitude float64) float64 {
nudge := 1e-8
nudgedLat := latitude + nudge
// step to the side to avoid interruptions
pCx, pCy := proj.Project(nudgedLat, longitude)
// consider a point slightly east
pEx, pEy := proj.Project(nudgedLat, longitude+nudge/math.Cos(nudgedLat))
// consider a point slightly north
pNx, pNy := proj.Project(nudgedLat+nudge, longitude)
s1ps2 := math.Hypot((pEx-pCx)+(pNy-pCy), (pEy-pCy)-(pNx-pCx))
s1ms2 := math.Hypot((pEx-pCx)-(pNy-pCy), (pEy-pCy)+(pNx-pCx))
angularDistortion := math.Abs(math.Log(math.Abs((s1ps2 - s1ms2) / (s1ps2 + s1ms2))))
if angularDistortion > 25.0 {
angularDistortion = math.NaN()
}
return angularDistortion
}