-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathhelpers.go
78 lines (68 loc) · 2.02 KB
/
helpers.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
package triangolatte
import (
"encoding/json"
"io/ioutil"
"math"
)
// polygonArea calculates real area of the polygon.
func polygonArea(data []Point) float64 {
area := 0.0
for i, j := 0, len(data)-1; i < len(data); i++ {
area += data[i].X*data[j].Y - data[i].Y*data[j].X
j = i
}
return math.Abs(area / 2)
}
// trianglesArea calculates summed area of all triangles.
func trianglesArea(t []float64) float64 {
trianglesArea := 0.0
for i := 0; i < len(t); i += 6 {
trianglesArea += math.Abs((t[i]*(t[i+3]-t[i+5]) + t[i+2]*(t[i+5]-t[i+1]) + t[i+4]*(t[i+1]-t[i+3])) / 2)
}
return trianglesArea
}
// deviation calculates difference between real area and the one from
// triangulation. Used as a helper function.
func deviation(data []Point, holes [][]Point, t []float64) (
actual,
calculated,
deviation float64,
) {
calculated = trianglesArea(t)
actual = polygonArea(data)
for _, h := range holes {
actual -= polygonArea(h)
}
deviation = math.Abs(calculated - actual)
return
}
// loadPointsFromFile takes file name and returns array of arrays of points.
func loadPointsFromFile(fileName string) ([][]Point, error) {
data, err := ioutil.ReadFile(fileName)
if err != nil {
return nil, err
}
polygons := make([][][]float64, 0)
json.Unmarshal([]byte(data), &polygons)
points := make([][]Point, len(polygons))
for i := range polygons {
points[i] = make([]Point, len(polygons[i]))
for j := range polygons[i] {
points[i][j] = Point{polygons[i][j][0], polygons[i][j][1]}
}
}
return points, nil
}
// Origin shift comes from the circumference of the Earth in meters (6378137).
const originShift = 2.0 * math.Pi * 6378137 / 2.0
// degreesToMeters converts longitude and latitude using WGS84 Geodetic Datum to
// meters with Spherical Mercator projection, known officially under EPSG:3857
// codename.
//
// X is longitude, Y is latitude.
func degreesToMeters(point Point) Point {
return Point{
point.X * originShift / 180.0,
math.Log(math.Tan((90.0+point.Y)*math.Pi/360.0)) / (math.Pi / 180.0) * originShift / 180.0,
}
}