-
Notifications
You must be signed in to change notification settings - Fork 71
/
image_marker.go
127 lines (110 loc) · 3.14 KB
/
image_marker.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2021 Florian Pigorsch. All rights reserved.
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package sm
import (
"fmt"
"image"
_ "image/jpeg" // to be able to decode jpegs
_ "image/png" // to be able to decode pngs
"log"
"os"
"strconv"
"strings"
"github.com/flopp/go-coordsparser"
"github.com/fogleman/gg"
"github.com/golang/geo/s2"
)
// ImageMarker represents an image marker on the map
type ImageMarker struct {
MapObject
Position s2.LatLng
Img image.Image
OffsetX float64
OffsetY float64
}
// NewImageMarker creates a new ImageMarker
func NewImageMarker(pos s2.LatLng, img image.Image, offsetX, offsetY float64) *ImageMarker {
m := new(ImageMarker)
m.Position = pos
m.Img = img
m.OffsetX = offsetX
m.OffsetY = offsetY
return m
}
// ParseImageMarkerString parses a string and returns an array of image markers
func ParseImageMarkerString(s string) ([]*ImageMarker, error) {
markers := make([]*ImageMarker, 0)
var img image.Image = nil
offsetX := 0.0
offsetY := 0.0
for _, ss := range strings.Split(s, "|") {
if ok, suffix := hasPrefix(ss, "image:"); ok {
file, err := os.Open(suffix)
if err != nil {
return nil, err
}
defer file.Close()
img, _, err = image.Decode(file)
if err != nil {
return nil, err
}
} else if ok, suffix := hasPrefix(ss, "offsetx:"); ok {
var err error
offsetX, err = strconv.ParseFloat(suffix, 64)
if err != nil {
return nil, err
}
} else if ok, suffix := hasPrefix(ss, "offsety:"); ok {
var err error
offsetY, err = strconv.ParseFloat(suffix, 64)
if err != nil {
return nil, err
}
} else {
lat, lng, err := coordsparser.Parse(ss)
if err != nil {
return nil, err
}
if img == nil {
return nil, fmt.Errorf("cannot create an ImageMarker without an image: %s", s)
}
m := NewImageMarker(s2.LatLngFromDegrees(lat, lng), img, offsetX, offsetY)
markers = append(markers, m)
}
}
return markers, nil
}
// SetImage sets the marker's image
func (m *ImageMarker) SetImage(img image.Image) {
m.Img = img
}
// SetOffsetX sets the marker's x offset
func (m *ImageMarker) SetOffsetX(offset float64) {
m.OffsetX = offset
}
// SetOffsetY sets the marker's y offset
func (m *ImageMarker) SetOffsetY(offset float64) {
m.OffsetY = offset
}
// ExtraMarginPixels return the marker's left, top, right, bottom pixel extent.
func (m *ImageMarker) ExtraMarginPixels() (float64, float64, float64, float64) {
size := m.Img.Bounds().Size()
return m.OffsetX, m.OffsetY, float64(size.X) - m.OffsetX, float64(size.Y) - m.OffsetY
}
// Bounds returns single point rect containing the marker's geographical position.
func (m *ImageMarker) Bounds() s2.Rect {
r := s2.EmptyRect()
r = r.AddPoint(m.Position)
return r
}
// Draw draws the object in the given graphical context.
func (m *ImageMarker) Draw(gc *gg.Context, trans *Transformer) {
if !CanDisplay(m.Position) {
log.Printf("ImageMarker coordinates not displayable: %f/%f", m.Position.Lat.Degrees(), m.Position.Lng.Degrees())
return
}
x, y := trans.LatLngToXY(m.Position)
gc.DrawImage(m.Img, int(x-m.OffsetX), int(y-m.OffsetY))
}