-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathkml.go
90 lines (73 loc) · 2.18 KB
/
kml.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
82
83
84
85
86
87
88
89
90
package heatmap
import (
"archive/zip"
"errors"
"fmt"
"image"
"image/color"
"image/png"
"io"
)
const kmlStart = `<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Folder>`
const kmlOverlay = `
<GroundOverlay>
<Icon>
<href>%s</href>
</Icon>
<LatLonBox>
<north>%2.16f</north>
<south>%2.16f</south>
<east>%2.16f</east>
<west>%2.16f</west>
<rotation>0</rotation>
</LatLonBox>
</GroundOverlay>`
const kmlEnd = `</Folder></kml>`
const kml = kmlStart + kmlOverlay + kmlEnd
// KML generates a heatmap for geographical data and the kml required to render it.
func KML(size image.Rectangle, points []DataPoint, dotSize int, opacity uint8,
scheme []color.Color, imgurl string, out io.Writer) (image.Image, error) {
limits := findLimits(points)
if !limits.inRange(-180, 180, -90, 90) {
return nil, errors.New("limits out of range")
}
mapimg := Heatmap(size, points, dotSize, opacity, scheme)
adjustedLimits := adjustLimits(limits, size, dotSize)
_, err := fmt.Fprintf(out, kml, imgurl,
adjustedLimits.Max.Y(),
adjustedLimits.Min.Y(),
adjustedLimits.Max.X(),
adjustedLimits.Min.X())
return mapimg, err
}
func must(err error) {
if err != nil {
panic(err)
}
}
// KMZ generates a heatmap for geographical data as a kmz.
func KMZ(size image.Rectangle, points []DataPoint, dotSize int, opacity uint8,
scheme []color.Color, out io.Writer) error {
z := zip.NewWriter(out)
defer z.Close()
dockml, err := z.Create("doc.kml")
must(err) // no known condition can cause failure here
img, err := KML(size, points, dotSize, opacity, scheme,
"heatmap.png", dockml)
if err != nil {
return err
}
imgf, err := z.Create("heatmap.png")
must(err) // Can't induce failure here, either
return png.Encode(imgf, img)
}
func adjustLimits(limits limits, size image.Rectangle, dotSize int) (rv limits) {
halfdot := float64(dotSize) / 2.0
offx := (halfdot / float64(size.Dx()-dotSize)) * float64(limits.Dx())
offy := (halfdot / float64(size.Dy()-dotSize)) * float64(limits.Dy())
rv.Min = P(limits.Min.X()-offx, limits.Min.Y()-offy)
rv.Max = P(limits.Max.X()+offx, limits.Max.Y()+offy)
return
}