summaryrefslogtreecommitdiff
path: root/vendor/github.com/felix
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/felix')
-rw-r--r--vendor/github.com/felix/go-staticmaps/.gitignore1
-rw-r--r--vendor/github.com/felix/go-staticmaps/LICENSE21
-rw-r--r--vendor/github.com/felix/go-staticmaps/README.md204
-rw-r--r--vendor/github.com/felix/go-staticmaps/area.go94
-rw-r--r--vendor/github.com/felix/go-staticmaps/color.go65
-rw-r--r--vendor/github.com/felix/go-staticmaps/context.go277
-rw-r--r--vendor/github.com/felix/go-staticmaps/create-static-map/create-static-map.go134
-rw-r--r--vendor/github.com/felix/go-staticmaps/map_object.go13
-rw-r--r--vendor/github.com/felix/go-staticmaps/marker.go125
-rw-r--r--vendor/github.com/felix/go-staticmaps/path.go103
-rw-r--r--vendor/github.com/felix/go-staticmaps/tile_fetcher.go153
-rw-r--r--vendor/github.com/felix/go-staticmaps/tile_provider.go142
-rw-r--r--vendor/github.com/felix/go-staticmaps/util.go18
13 files changed, 1350 insertions, 0 deletions
diff --git a/vendor/github.com/felix/go-staticmaps/.gitignore b/vendor/github.com/felix/go-staticmaps/.gitignore
new file mode 100644
index 0000000..e33609d
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/.gitignore
@@ -0,0 +1 @@
+*.png
diff --git a/vendor/github.com/felix/go-staticmaps/LICENSE b/vendor/github.com/felix/go-staticmaps/LICENSE
new file mode 100644
index 0000000..7417b3d
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 Florian Pigorsch
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/felix/go-staticmaps/README.md b/vendor/github.com/felix/go-staticmaps/README.md
new file mode 100644
index 0000000..19d94ea
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/README.md
@@ -0,0 +1,204 @@
+[![GoDoc](https://godoc.org/github.com/flopp/go-staticmaps?status.svg)](https://godoc.org/github.com/flopp/go-staticmaps)
+[![Go Report Card](https://goreportcard.com/badge/github.com/flopp/go-staticmaps)](https://goreportcard.com/report/flopp/go-staticmaps)
+[![License MIT](https://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)](https://github.com/flopp/go-staticmaps/)
+
+# go-staticmaps
+A go (golang) library and command line tool to render static map images using OpenStreetMap tiles.
+
+## What?
+go-staticmaps is a golang library that allows you to create nice static map images from OpenStreetMap tiles, along with markers of different size and color, as well as paths and colored areas.
+
+go-staticmaps comes with a command line tool called `create-static-map` for use in shell scripts, etc.
+
+![Static map of the Berlin Marathon](https://raw.githubusercontent.com/flopp/flopp.github.io/master/go-staticmaps/berlin-marathon.png)
+
+## How?
+
+### Installation
+
+Installing go-staticmaps is as easy as
+
+```bash
+go get -u github.com/flopp/go-staticmaps
+```
+
+### Library Usage
+
+Create a 400x300 pixel map with a red marker:
+
+```go
+import (
+ "image/color"
+
+ "github.com/flopp/go-staticmaps"
+ "github.com/fogleman/gg"
+ "github.com/golang/geo/s2"
+)
+
+func main() {
+ ctx := sm.NewContext()
+ ctx.SetSize(400, 300)
+ ctx.AddMarker(sm.NewMarker(s2.LatLngFromDegrees{52.514536, 13.350151}, color.RGBA{0xff, 0, 0, 0xff}, 16.0))
+
+ img, err := ctx.Render()
+ if err != nil {
+ panic(err)
+ }
+
+ if err := gg.SavePNG("my-map.png", img); err != nil {
+ panic(err)
+ }
+}
+```
+
+
+See [GoDoc](https://godoc.org/github.com/flopp/go-staticmaps/staticmaps) for a complete documentation and the source code of the [command line tool](https://github.com/flopp/go-staticmaps/blob/master/cmd/create-static-map/create-static-map.go) for an example how to use the package.
+
+
+### Command Line Usage
+
+ Usage:
+ create-static-map [OPTIONS]
+
+ Creates a static map
+
+ Application Options:
+ --width=PIXELS Width of the generated static map image (default: 512)
+ --height=PIXELS Height of the generated static map image (default: 512)
+ -o, --output=FILENAME Output file name (default: map.png)
+ -t, --type=MAPTYPE Select the map type; list possible map types with '--type list'
+ -c, --center=LATLNG Center coordinates (lat,lng) of the static map
+ -z, --zoom=ZOOMLEVEL Zoom factor
+ -m, --marker=MARKER Add a marker to the static map
+ -p, --path=PATH Add a path to the static map
+ -a, --area=AREA Add an area to the static map
+
+ Help Options:
+ -h, --help Show this help message
+
+### General
+The command line interface tries to resemble [Google's Static Maps API](https://developers.google.com/maps/documentation/static-maps/intro).
+If `--center` or `--zoom` are not given, *good* values are determined from the specified markers and paths.
+
+### Markers
+The `--marker` option defines one or more map markers of the same style. Use multiple `--marker` options to add markers of different styles.
+
+ --marker MARKER_STYLES|LATLNG|LATLNG|...
+
+`LATLNG` is a comma separated pair of latitude and longitude, e.g. `52.5153,13.3564`.
+
+`MARKER_STYLES` consists of a set of style descriptors separated by the pipe character `|`:
+
+- `color:COLOR` - where `COLOR` is either of the form `0xRRGGBB`, `0xRRGGBBAA`, or one of `black`, `blue`, `brown`, `green`, `orange`, `purple`, `red`, `yellow`, `white` (default: `red`)
+- `size:SIZE` - where `SIZE` is one of `mid`, `small`, `tiny`, or some number > 0 (default: `mid`)
+- `label:LABEL` - where `LABEL` is an alpha numeric character, i.e. `A`-`Z`, `a`-`z`, `0`-`9`; (default: no label)
+
+### Paths
+The `--path` option defines a path on the map. Use multiple `--path` options to add multiple paths to the map.
+
+ --path PATH_STYLES|LATLNG|LATLNG|...
+
+or
+
+ --path PATH_STYLES|gpx:my_gpx_file.gpx
+
+`PATH_STYLES` consists of a set of style descriptors separated by the pipe character `|`:
+
+- `color:COLOR` - where `COLOR` is either of the form `0xRRGGBB`, `0xRRGGBBAA`, or one of `black`, `blue`, `brown`, `green`, `orange`, `purple`, `red`, `yellow`, `white` (default: `red`)
+- `weight:WEIGHT` - where `WEIGHT` is the line width in pixels (defaut: `5`)
+
+### Areas
+The `--area` option defines a closed area on the map. Use multiple `--area` options to add multiple areas to the map.
+
+ --area AREA_STYLES|LATLNG|LATLNG|...
+
+`AREA_STYLES` consists of a set of style descriptors separated by the pipe character `|`:
+
+- `color:COLOR` - where `COLOR` is either of the form `0xRRGGBB`, `0xRRGGBBAA`, or one of `black`, `blue`, `brown`, `green`, `orange`, `purple`, `red`, `yellow`, `white` (default: `red`)
+- `weight:WEIGHT` - where `WEIGHT` is the line width in pixels (defaut: `5`)
+- `fill:COLOR` - where `COLOR` is either of the form `0xRRGGBB`, `0xRRGGBBAA`, or one of `black`, `blue`, `brown`, `green`, `orange`, `purple`, `red`, `yellow`, `white` (default: none)
+
+
+## Examples
+
+### Basic Maps
+
+Centered at "N 52.514536 E 13.350151" with zoom level 10:
+
+```bash
+$ create-static-map --width 600 --height 400 -o map1.png -c "52.514536,13.350151" -z 10
+```
+![Example 1](https://raw.githubusercontent.com/flopp/flopp.github.io/master/go-staticmaps/map1.png)
+
+A map with a marker at "N 52.514536 E 13.350151" with zoom level 14 (no need to specify the map's center - it is automatically computed from the marker(s)):
+
+```bash
+$ create-static-map --width 600 --height 400 -o map2.png -z 14 -m "52.514536,13.350151"
+```
+
+![Example 2](https://raw.githubusercontent.com/flopp/flopp.github.io/master/go-staticmaps/map2.png)
+
+A map with two markers (red and green). If there are more than two markers in the map, a *good* zoom level can be determined automatically:
+
+```bash
+$ create-static-map --width 600 --height 400 -o map3.png -m "red|52.514536,13.350151" -m "green|52.516285,13.377746"
+```
+
+![Example 3](https://raw.githubusercontent.com/flopp/flopp.github.io/master/go-staticmaps/map3.png)
+
+
+### Create a map of the Berlin Marathon
+
+ create-static-map --width 800 --height 600 \
+ --marker "color:green|52.5153,13.3564" \
+ --marker "color:red|52.5160,13.3711" \
+ --output "berlin-marathon.png" \
+ --path "color:blue|weight:2|gpx:berlin-marathon.gpx"
+
+![Static map of the Berlin Marathon](https://raw.githubusercontent.com/flopp/flopp.github.io/master/go-staticmaps/berlin-marathon.png)
+
+### Create a map of the US capitals
+
+ create-static-map --width 800 --height 400 \
+ --output "us-capitals.png" \
+ --marker "color:blue|size:tiny|32.3754,-86.2996|58.3637,-134.5721|33.4483,-112.0738|34.7244,-92.2789|\
+ 38.5737,-121.4871|39.7551,-104.9881|41.7665,-72.6732|39.1615,-75.5136|30.4382,-84.2806|33.7545,-84.3897|\
+ 21.2920,-157.8219|43.6021,-116.2125|39.8018,-89.6533|39.7670,-86.1563|41.5888,-93.6203|39.0474,-95.6815|\
+ 38.1894,-84.8715|30.4493,-91.1882|44.3294,-69.7323|38.9693,-76.5197|42.3589,-71.0568|42.7336,-84.5466|\
+ 44.9446,-93.1027|32.3122,-90.1780|38.5698,-92.1941|46.5911,-112.0205|40.8136,-96.7026|39.1501,-119.7519|\
+ 43.2314,-71.5597|40.2202,-74.7642|35.6816,-105.9381|42.6517,-73.7551|35.7797,-78.6434|46.8084,-100.7694|\
+ 39.9622,-83.0007|35.4931,-97.4591|44.9370,-123.0272|40.2740,-76.8849|41.8270,-71.4087|34.0007,-81.0353|\
+ 44.3776,-100.3177|36.1589,-86.7821|30.2687,-97.7452|40.7716,-111.8882|44.2627,-72.5716|37.5408,-77.4339|\
+ 47.0449,-122.9016|38.3533,-81.6354|43.0632,-89.4007|41.1389,-104.8165"
+
+![Static map of the US capitals](https://raw.githubusercontent.com/flopp/flopp.github.io/master/go-staticmaps/us-capitals.png)
+
+### Create a map of Australia
+...where the Northern Territory is highlighted and the capital Canberra is marked.
+
+ create-static-map --width 800 --height 600 \
+ --center="-26.284973,134.303764" \
+ --output "australia.png" \
+ --marker "color:blue|-35.305200,149.121574" \
+ --area "color:0x00FF00|fill:0x00FF007F|weight:2|-25.994024,129.013847|-25.994024,137.989677|-16.537670,138.011649|\
+ -14.834820,135.385917|-12.293236,137.033866|-11.174554,130.398124|-12.925791,130.167411|-14.866678,129.002860"
+
+![Static map of Australia](https://raw.githubusercontent.com/flopp/flopp.github.io/master/go-staticmaps/australia.png)
+
+## Acknowledgements
+Besides the go standard library, go-staticmaps uses
+
+- [OpenStreetMap](http://openstreetmap.org/), [Thunderforest](http://www.thunderforest.com/), [OpenTopoMap](http://www.opentopomap.org/), [Stamen](http://maps.stamen.com/) and [Carto](http://carto.com) as map tile providers
+- [Go Graphics](https://github.com/fogleman/gg) for 2D drawing
+- [S2 geometry library](https://github.com/golang/geo) for spherical geometry calculations
+- [appdirs](https://github.com/Wessie/appdirs) for platform specific system directories
+- [gpxgo](github.com/tkrajina/gpxgo) for loading GPX files
+- [go-coordsparser](https://github.com/flopp/go-coordsparser) for parsing geo coordinates
+
+## Contributors
+- [felix](https://github.com/felix): additional tile servers
+
+## License
+Copyright 2016 Florian Pigorsch & Contributors. All rights reserved.
+
+Use of this source code is governed by a MIT-style license that can be found in the LICENSE file.
diff --git a/vendor/github.com/felix/go-staticmaps/area.go b/vendor/github.com/felix/go-staticmaps/area.go
new file mode 100644
index 0000000..387105a
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/area.go
@@ -0,0 +1,94 @@
+// Copyright 2016 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 (
+ "image/color"
+ "strconv"
+ "strings"
+
+ "github.com/flopp/go-coordsparser"
+ "github.com/fogleman/gg"
+ "github.com/golang/geo/s2"
+)
+
+// Area represents a area or area on the map
+type Area struct {
+ MapObject
+ Positions []s2.LatLng
+ Color color.Color
+ Fill color.Color
+ Weight float64
+}
+
+// ParseAreaString parses a string and returns an area
+func ParseAreaString(s string) (*Area, error) {
+ area := new(Area)
+ area.Color = color.RGBA{0xff, 0, 0, 0xff}
+ area.Fill = color.Transparent
+ area.Weight = 5.0
+
+ for _, ss := range strings.Split(s, "|") {
+ if ok, suffix := hasPrefix(ss, "color:"); ok {
+ var err error
+ area.Color, err = ParseColorString(suffix)
+ if err != nil {
+ return nil, err
+ }
+ } else if ok, suffix := hasPrefix(ss, "fill:"); ok {
+ var err error
+ area.Fill, err = ParseColorString(suffix)
+ if err != nil {
+ return nil, err
+ }
+ } else if ok, suffix := hasPrefix(ss, "weight:"); ok {
+ var err error
+ area.Weight, err = strconv.ParseFloat(suffix, 64)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ lat, lng, err := coordsparser.Parse(ss)
+ if err != nil {
+ return nil, err
+ }
+ area.Positions = append(area.Positions, s2.LatLngFromDegrees(lat, lng))
+ }
+
+ }
+ return area, nil
+}
+
+func (p *Area) extraMarginPixels() float64 {
+ return 0.5 * p.Weight
+}
+
+func (p *Area) bounds() s2.Rect {
+ r := s2.EmptyRect()
+ for _, ll := range p.Positions {
+ r = r.AddPoint(ll)
+ }
+ return r
+}
+
+func (p *Area) draw(gc *gg.Context, trans *transformer) {
+ if len(p.Positions) <= 1 {
+ return
+ }
+
+ gc.ClearPath()
+ gc.SetLineWidth(p.Weight)
+ gc.SetLineCap(gg.LineCapRound)
+ gc.SetLineJoin(gg.LineJoinRound)
+ for _, ll := range p.Positions {
+ gc.LineTo(trans.ll2p(ll))
+ }
+ gc.ClosePath()
+ gc.SetColor(p.Fill)
+ gc.FillPreserve()
+ gc.SetColor(p.Color)
+ gc.Stroke()
+}
diff --git a/vendor/github.com/felix/go-staticmaps/color.go b/vendor/github.com/felix/go-staticmaps/color.go
new file mode 100644
index 0000000..ea73ffd
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/color.go
@@ -0,0 +1,65 @@
+// Copyright 2016 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/color"
+ "regexp"
+ "strings"
+)
+
+// ParseColorString parses hex color strings (i.e. `0xRRGGBB`, `#RRGGBB`, `0xRRGGBBAA`, `#RRGGBBAA`), and names colors (e.g. 'black', 'blue', ...)
+func ParseColorString(s string) (color.Color, error) {
+ s = strings.ToLower(strings.TrimSpace(s))
+
+ re := regexp.MustCompile(`^(0x|#)([A-Fa-f0-9]{6})$`)
+ matches := re.FindStringSubmatch(s)
+ if matches != nil {
+ var r, g, b int
+ fmt.Sscanf(matches[2], "%2x%2x%2x", &r, &g, &b)
+ return color.RGBA{uint8(r), uint8(g), uint8(b), 0xff}, nil
+ }
+
+ re = regexp.MustCompile(`^(0x|#)([A-Fa-f0-9]{8})$`)
+ matches = re.FindStringSubmatch(s)
+ if matches != nil {
+ var r, g, b, a int
+ fmt.Sscanf(matches[2], "%2x%2x%2x%2x", &r, &g, &b, &a)
+ rr := float64(r) * float64(a) / 256.0
+ gg := float64(g) * float64(a) / 256.0
+ bb := float64(b) * float64(a) / 256.0
+ return color.RGBA{uint8(rr), uint8(gg), uint8(bb), uint8(a)}, nil
+ }
+
+ switch s {
+ case "black":
+ return color.RGBA{0x00, 0x00, 0x00, 0xff}, nil
+ case "blue":
+ return color.RGBA{0x00, 0x00, 0xff, 0xff}, nil
+ case "brown":
+ return color.RGBA{0x96, 0x4b, 0x00, 0xff}, nil
+ case "green":
+ return color.RGBA{0x00, 0xff, 0x00, 0xff}, nil
+ case "orange":
+ return color.RGBA{0xff, 0x7f, 0x00, 0xff}, nil
+ case "purple":
+ return color.RGBA{0x7f, 0x00, 0x7f, 0xff}, nil
+ case "red":
+ return color.RGBA{0xff, 0x00, 0x00, 0xff}, nil
+ case "yellow":
+ return color.RGBA{0xff, 0xff, 0x00, 0xff}, nil
+ case "white":
+ return color.RGBA{0xff, 0xff, 0xff, 0xff}, nil
+ }
+ return color.Transparent, fmt.Errorf("Cannot parse color string: %s", s)
+}
+
+// Luminance computes the luminance (~ brightness) of the given color. Range: 0.0 for black to 1.0 for white.
+func Luminance(col color.Color) float64 {
+ r, g, b, _ := col.RGBA()
+ return (float64(r)*0.299 + float64(g)*0.587 + float64(b)*0.114) / float64(0xffff)
+}
diff --git a/vendor/github.com/felix/go-staticmaps/context.go b/vendor/github.com/felix/go-staticmaps/context.go
new file mode 100644
index 0000000..db6f9c2
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/context.go
@@ -0,0 +1,277 @@
+// Copyright 2016 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 (~ static maps) renders static map images from OSM tiles with markers, paths, and filled areas.
+package sm
+
+import (
+ "errors"
+ "image"
+ "image/draw"
+ "math"
+
+ "github.com/fogleman/gg"
+ "github.com/golang/geo/s2"
+)
+
+// Context holds all information about the map image that is to be rendered
+type Context struct {
+ width int
+ height int
+
+ hasZoom bool
+ zoom int
+
+ hasCenter bool
+ center s2.LatLng
+
+ markers []*Marker
+ paths []*Path
+ areas []*Area
+
+ tileProvider *TileProvider
+}
+
+// NewContext creates a new instance of Context
+func NewContext() *Context {
+ t := new(Context)
+ t.width = 512
+ t.height = 512
+ t.hasZoom = false
+ t.hasCenter = false
+ t.tileProvider = NewTileProviderOpenStreetMaps()
+ return t
+}
+
+// SetTileProvider sets the TileProvider to be used
+func (m *Context) SetTileProvider(t *TileProvider) {
+ m.tileProvider = t
+}
+
+// SetSize sets the size of the generated image
+func (m *Context) SetSize(width, height int) {
+ m.width = width
+ m.height = height
+}
+
+// SetZoom sets the zoom level
+func (m *Context) SetZoom(zoom int) {
+ m.zoom = zoom
+ m.hasZoom = true
+}
+
+// SetCenter sets the center coordinates
+func (m *Context) SetCenter(center s2.LatLng) {
+ m.center = center
+ m.hasCenter = true
+}
+
+// AddMarker adds a marker to the Context
+func (m *Context) AddMarker(marker *Marker) {
+ m.markers = append(m.markers, marker)
+}
+
+// ClearMarkers removes all markers from the Context
+func (m *Context) ClearMarkers() {
+ m.markers = nil
+}
+
+// AddPath adds a path to the Context
+func (m *Context) AddPath(path *Path) {
+ m.paths = append(m.paths, path)
+}
+
+// ClearPaths removes all paths from the Context
+func (m *Context) ClearPaths() {
+ m.paths = nil
+}
+
+// AddArea adds an area to the Context
+func (m *Context) AddArea(area *Area) {
+ m.areas = append(m.areas, area)
+}
+
+// ClearAreas removes all areas from the Context
+func (m *Context) ClearAreas() {
+ m.areas = nil
+}
+
+func (m *Context) determineBounds() s2.Rect {
+ r := s2.EmptyRect()
+ for _, marker := range m.markers {
+ r = r.Union(marker.bounds())
+ }
+ for _, path := range m.paths {
+ r = r.Union(path.bounds())
+ }
+ for _, area := range m.areas {
+ r = r.Union(area.bounds())
+ }
+ return r
+}
+
+func (m *Context) determineExtraMarginPixels() float64 {
+ p := 0.0
+ for _, marker := range m.markers {
+ if pp := marker.extraMarginPixels(); pp > p {
+ p = pp
+ }
+ }
+ for _, path := range m.paths {
+ if pp := path.extraMarginPixels(); pp > p {
+ p = pp
+ }
+ }
+ for _, area := range m.areas {
+ if pp := area.extraMarginPixels(); pp > p {
+ p = pp
+ }
+ }
+ return p
+}
+
+func (m *Context) determineZoom(bounds s2.Rect, center s2.LatLng) int {
+ b := bounds.AddPoint(center)
+ if b.IsEmpty() || b.IsPoint() {
+ return 15
+ }
+
+ tileSize := m.tileProvider.TileSize
+ margin := 4.0 + m.determineExtraMarginPixels()
+ w := (float64(m.width) - 2.0*margin) / float64(tileSize)
+ h := (float64(m.height) - 2.0*margin) / float64(tileSize)
+ minX := (b.Lo().Lng.Degrees() + 180.0) / 360.0
+ maxX := (b.Hi().Lng.Degrees() + 180.0) / 360.0
+ minY := (1.0 - math.Log(math.Tan(b.Lo().Lat.Radians())+(1.0/math.Cos(b.Lo().Lat.Radians())))/math.Pi) / 2.0
+ maxY := (1.0 - math.Log(math.Tan(b.Hi().Lat.Radians())+(1.0/math.Cos(b.Hi().Lat.Radians())))/math.Pi) / 2.0
+ dx := math.Abs(maxX - minX)
+ dy := math.Abs(maxY - minY)
+
+ zoom := 1
+ for zoom < 30 {
+ tiles := float64(uint(1) << uint(zoom))
+ if dx*tiles > w || dy*tiles > h {
+ return zoom - 1
+ }
+ zoom = zoom + 1
+ }
+
+ return 15
+}
+
+type transformer struct {
+ zoom int
+ tileSize int
+ pWidth, pHeight int
+ pCenterX, pCenterY int
+ tCountX, tCountY int
+ tCenterX, tCenterY float64
+ tOriginX, tOriginY int
+}
+
+func newTransformer(width int, height int, zoom int, llCenter s2.LatLng, tileSize int) *transformer {
+ t := new(transformer)
+ t.zoom = zoom
+ t.tileSize = tileSize
+ t.tCenterX, t.tCenterY = t.ll2t(llCenter)
+
+ ww := float64(width) / float64(tileSize)
+ hh := float64(height) / float64(tileSize)
+
+ t.tOriginX = int(math.Floor(t.tCenterX - 0.5*ww))
+ t.tOriginY = int(math.Floor(t.tCenterY - 0.5*hh))
+
+ t.tCountX = 1 + int(math.Floor(t.tCenterX+0.5*ww)) - t.tOriginX
+ t.tCountY = 1 + int(math.Floor(t.tCenterY+0.5*hh)) - t.tOriginY
+
+ t.pWidth = t.tCountX * tileSize
+ t.pHeight = t.tCountY * tileSize
+
+ t.pCenterX = int((t.tCenterX - float64(t.tOriginX)) * float64(tileSize))
+ t.pCenterY = int((t.tCenterY - float64(t.tOriginY)) * float64(tileSize))
+
+ return t
+}
+
+func (t *transformer) ll2t(ll s2.LatLng) (float64, float64) {
+ tiles := math.Exp2(float64(t.zoom))
+ x := tiles * (ll.Lng.Degrees() + 180.0) / 360.0
+ y := tiles * (1 - math.Log(math.Tan(ll.Lat.Radians())+(1.0/math.Cos(ll.Lat.Radians())))/math.Pi) / 2.0
+ return x, y
+}
+
+func (t *transformer) ll2p(ll s2.LatLng) (float64, float64) {
+ x, y := t.ll2t(ll)
+ x = float64(t.pCenterX) + (x-t.tCenterX)*float64(t.tileSize)
+ y = float64(t.pCenterY) + (y-t.tCenterY)*float64(t.tileSize)
+ return x, y
+}
+
+// Render actually renders the map image including all map objects (markers, paths, areas)
+func (m *Context) Render() (image.Image, error) {
+ bounds := m.determineBounds()
+
+ center := m.center
+ if !m.hasCenter {
+ if bounds.IsEmpty() {
+ return nil, errors.New("No center coordinates specified, cannot determine center from markers")
+ }
+ center = bounds.Center()
+ }
+
+ zoom := m.zoom
+ if !m.hasZoom {
+ zoom = m.determineZoom(bounds, center)
+ }
+
+ tileSize := m.tileProvider.TileSize
+ trans := newTransformer(m.width, m.height, zoom, center, tileSize)
+ img := image.NewRGBA(image.Rect(0, 0, trans.pWidth, trans.pHeight))
+ gc := gg.NewContextForRGBA(img)
+
+ // fetch and draw tiles to img
+ t := NewTileFetcher(m.tileProvider)
+ for xx := 0; xx < trans.tCountX; xx++ {
+ x := trans.tOriginX + xx
+ if x < 0 {
+ x = x + (1 << uint(zoom))
+ }
+ for yy := 0; yy < trans.tCountY; yy++ {
+ y := trans.tOriginY + yy
+ if tileImg, err := t.Fetch(zoom, x, y); err == nil {
+ gc.DrawImage(tileImg, xx*tileSize, yy*tileSize)
+ }
+ }
+ }
+
+ // draw map objects
+ for _, area := range m.areas {
+ area.draw(gc, trans)
+ }
+ for _, path := range m.paths {
+ path.draw(gc, trans)
+ }
+ for _, marker := range m.markers {
+ marker.draw(gc, trans)
+ }
+
+ // crop image
+ croppedImg := image.NewRGBA(image.Rect(0, 0, int(m.width), int(m.height)))
+ draw.Draw(croppedImg, image.Rect(0, 0, int(m.width), int(m.height)),
+ img, image.Point{trans.pCenterX - int(m.width)/2, trans.pCenterY - int(m.height)/2},
+ draw.Src)
+
+ // draw attribution
+ _, textHeight := gc.MeasureString(m.tileProvider.Attribution)
+ boxHeight := textHeight + 4.0
+ gc = gg.NewContextForRGBA(croppedImg)
+ gc.SetRGBA(0.0, 0.0, 0.0, 0.5)
+ gc.DrawRectangle(0.0, float64(m.height)-boxHeight, float64(m.width), boxHeight)
+ gc.Fill()
+ gc.SetRGBA(1.0, 1.0, 1.0, 0.75)
+ gc.DrawString(m.tileProvider.Attribution, 4.0, float64(m.height)-4.0)
+
+ return croppedImg, nil
+}
diff --git a/vendor/github.com/felix/go-staticmaps/create-static-map/create-static-map.go b/vendor/github.com/felix/go-staticmaps/create-static-map/create-static-map.go
new file mode 100644
index 0000000..7b8d429
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/create-static-map/create-static-map.go
@@ -0,0 +1,134 @@
+// Copyright 2016 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 main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "sort"
+
+ "github.com/flopp/go-coordsparser"
+ "github.com/flopp/go-staticmaps"
+ "github.com/fogleman/gg"
+ "github.com/golang/geo/s2"
+ "github.com/jessevdk/go-flags"
+)
+
+func getTileProviderOrExit(name string) *sm.TileProvider {
+ tileProviders := sm.GetTileProviders()
+ tp := tileProviders[name]
+ if tp != nil {
+ return tp
+ }
+
+ if name != "list" {
+ fmt.Println("Bad map type:", name)
+ }
+ fmt.Println("Possible map types (to be used with --type/-t):")
+ // print sorted keys
+ keys := make([]string, 0, len(tileProviders))
+ for k := range tileProviders {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ fmt.Println(k)
+ }
+ os.Exit(0)
+
+ return nil
+}
+
+func main() {
+ var opts struct {
+ // ClearCache bool `long:"clear-cache" description:"Clears the tile cache"`
+ Width int `long:"width" description:"Width of the generated static map image" value-name:"PIXELS" default:"512"`
+ Height int `long:"height" description:"Height of the generated static map image" value-name:"PIXELS" default:"512"`
+ Output string `short:"o" long:"output" description:"Output file name" value-name:"FILENAME" default:"map.png"`
+ Type string `short:"t" long:"type" description:"Select the map type; list possible map types with '--type list'" value-name:"MAPTYPE"`
+ Center string `short:"c" long:"center" description:"Center coordinates (lat,lng) of the static map" value-name:"LATLNG"`
+ Zoom int `short:"z" long:"zoom" description:"Zoom factor" value-name:"ZOOMLEVEL"`
+ Markers []string `short:"m" long:"marker" description:"Add a marker to the static map" value-name:"MARKER"`
+ Paths []string `short:"p" long:"path" description:"Add a path to the static map" value-name:"PATH"`
+ Areas []string `short:"a" long:"area" description:"Add an area to the static map" value-name:"AREA"`
+ }
+
+ parser := flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash)
+ parser.LongDescription = `Creates a static map`
+ _, err := parser.Parse()
+
+ if parser.FindOptionByLongName("help").IsSet() {
+ parser.WriteHelp(os.Stdout)
+ os.Exit(0)
+ }
+
+ ctx := sm.NewContext()
+
+ if parser.FindOptionByLongName("type").IsSet() {
+ tp := getTileProviderOrExit(opts.Type)
+ if tp != nil {
+ ctx.SetTileProvider(tp)
+ }
+ }
+
+ ctx.SetSize(opts.Width, opts.Height)
+
+ if parser.FindOptionByLongName("zoom").IsSet() {
+ ctx.SetZoom(opts.Zoom)
+ }
+
+ if parser.FindOptionByLongName("center").IsSet() {
+ lat, lng, err := coordsparser.Parse(opts.Center)
+ if err != nil {
+ log.Fatal(err)
+ } else {
+ ctx.SetCenter(s2.LatLngFromDegrees(lat, lng))
+ }
+ }
+
+ for _, markerString := range opts.Markers {
+ markers, err := sm.ParseMarkerString(markerString)
+ if err != nil {
+ log.Fatal(err)
+ } else {
+ for _, marker := range markers {
+ ctx.AddMarker(marker)
+ }
+ }
+ }
+
+ for _, pathString := range opts.Paths {
+ paths, err := sm.ParsePathString(pathString)
+ if err != nil {
+ log.Fatal(err)
+ } else {
+ for _, path := range paths {
+ ctx.AddPath(path)
+ }
+ }
+ }
+
+ for _, areaString := range opts.Areas {
+ area, err := sm.ParseAreaString(areaString)
+ if err != nil {
+ log.Fatal(err)
+ } else {
+ ctx.AddArea(area)
+ }
+ }
+
+ img, err := ctx.Render()
+ if err != nil {
+ log.Fatal(err)
+ return
+ }
+
+ if err = gg.SavePNG(opts.Output, img); err != nil {
+ log.Fatal(err)
+ return
+ }
+}
diff --git a/vendor/github.com/felix/go-staticmaps/map_object.go b/vendor/github.com/felix/go-staticmaps/map_object.go
new file mode 100644
index 0000000..d174b51
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/map_object.go
@@ -0,0 +1,13 @@
+package sm
+
+import (
+ "github.com/fogleman/gg"
+ "github.com/golang/geo/s2"
+)
+
+// MapObject is the interface for all objects on the map
+type MapObject interface {
+ bounds() s2.Rect
+ extraMarginPixels() float64
+ draw(dc *gg.Context, trans *transformer)
+}
diff --git a/vendor/github.com/felix/go-staticmaps/marker.go b/vendor/github.com/felix/go-staticmaps/marker.go
new file mode 100644
index 0000000..6e88984
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/marker.go
@@ -0,0 +1,125 @@
+// Copyright 2016 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/color"
+ "math"
+ "strconv"
+ "strings"
+
+ "github.com/flopp/go-coordsparser"
+ "github.com/fogleman/gg"
+ "github.com/golang/geo/s2"
+)
+
+// Marker represents a marker on the map
+type Marker struct {
+ MapObject
+ Position s2.LatLng
+ Color color.Color
+ Size float64
+ Label string
+}
+
+// NewMarker creates a new Marker
+func NewMarker(pos s2.LatLng, col color.Color, size float64) *Marker {
+ m := new(Marker)
+ m.Position = pos
+ m.Color = col
+ m.Size = size
+ m.Label = ""
+ return m
+}
+
+func parseSizeString(s string) (float64, error) {
+ switch {
+ case s == "mid":
+ return 16.0, nil
+ case s == "small":
+ return 12.0, nil
+ case s == "tiny":
+ return 8.0, nil
+ }
+
+ if ss, err := strconv.ParseFloat(s, 64); err != nil && ss > 0 {
+ return ss, nil
+ }
+
+ return 0.0, fmt.Errorf("Cannot parse size string: %s", s)
+}
+
+// ParseMarkerString parses a string and returns an array of markers
+func ParseMarkerString(s string) ([]*Marker, error) {
+ markers := make([]*Marker, 0, 0)
+
+ var color color.Color = color.RGBA{0xff, 0, 0, 0xff}
+ size := 16.0
+ label := ""
+
+ for _, ss := range strings.Split(s, "|") {
+ if ok, suffix := hasPrefix(ss, "color:"); ok {
+ var err error
+ color, err = ParseColorString(suffix)
+ if err != nil {
+ return nil, err
+ }
+ } else if ok, suffix := hasPrefix(ss, "label:"); ok {
+ label = suffix
+ } else if ok, suffix := hasPrefix(ss, "size:"); ok {
+ var err error
+ size, err = parseSizeString(suffix)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ lat, lng, err := coordsparser.Parse(ss)
+ if err != nil {
+ return nil, err
+ }
+ m := NewMarker(s2.LatLngFromDegrees(lat, lng), color, size)
+ m.Label = label
+ markers = append(markers, m)
+ }
+ }
+ return markers, nil
+}
+
+func (m *Marker) extraMarginPixels() float64 {
+ return 1.0 + 1.5*m.Size
+}
+
+func (m *Marker) bounds() s2.Rect {
+ r := s2.EmptyRect()
+ r = r.AddPoint(m.Position)
+ return r
+}
+
+func (m *Marker) draw(gc *gg.Context, trans *transformer) {
+ gc.ClearPath()
+ gc.SetLineJoin(gg.LineJoinRound)
+ gc.SetLineWidth(1.0)
+
+ radius := 0.5 * m.Size
+ x, y := trans.ll2p(m.Position)
+ gc.DrawArc(x, y-m.Size, radius, (90.0+60.0)*math.Pi/180.0, (360.0+90.0-60.0)*math.Pi/180.0)
+ gc.LineTo(x, y)
+ gc.ClosePath()
+ gc.SetColor(m.Color)
+ gc.FillPreserve()
+ gc.SetRGB(0, 0, 0)
+ gc.Stroke()
+
+ if m.Label != "" {
+ if Luminance(m.Color) >= 0.5 {
+ gc.SetColor(color.RGBA{0x00, 0x00, 0x00, 0xff})
+ } else {
+ gc.SetColor(color.RGBA{0xff, 0xff, 0xff, 0xff})
+ }
+ gc.DrawStringAnchored(m.Label, x, y-m.Size, 0.5, 0.5)
+ }
+}
diff --git a/vendor/github.com/felix/go-staticmaps/path.go b/vendor/github.com/felix/go-staticmaps/path.go
new file mode 100644
index 0000000..1c580e6
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/path.go
@@ -0,0 +1,103 @@
+// Copyright 2016 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 (
+ "image/color"
+ "strconv"
+ "strings"
+
+ "github.com/flopp/go-coordsparser"
+ "github.com/fogleman/gg"
+ "github.com/golang/geo/s2"
+ "github.com/tkrajina/gpxgo/gpx"
+)
+
+// Path represents a path or area on the map
+type Path struct {
+ MapObject
+ Positions []s2.LatLng
+ Color color.Color
+ Weight float64
+}
+
+// ParsePathString parses a string and returns a path
+func ParsePathString(s string) ([]*Path, error) {
+ paths := make([]*Path, 0, 0)
+ currentPath := new(Path)
+ currentPath.Color = color.RGBA{0xff, 0, 0, 0xff}
+ currentPath.Weight = 5.0
+
+ for _, ss := range strings.Split(s, "|") {
+ if ok, suffix := hasPrefix(ss, "color:"); ok {
+ var err error
+ if currentPath.Color, err = ParseColorString(suffix); err != nil {
+ return nil, err
+ }
+ } else if ok, suffix := hasPrefix(ss, "weight:"); ok {
+ var err error
+ if currentPath.Weight, err = strconv.ParseFloat(suffix, 64); err != nil {
+ return nil, err
+ }
+ } else if ok, suffix := hasPrefix(ss, "gpx:"); ok {
+ gpxData, err := gpx.ParseFile(suffix)
+ if err != nil {
+ return nil, err
+ }
+ for _, trk := range gpxData.Tracks {
+ for _, seg := range trk.Segments {
+ p := new(Path)
+ p.Color = currentPath.Color
+ p.Weight = currentPath.Weight
+ for _, pt := range seg.Points {
+ p.Positions = append(p.Positions, s2.LatLngFromDegrees(pt.GetLatitude(), pt.GetLongitude()))
+ }
+ if len(p.Positions) > 0 {
+ paths = append(paths, p)
+ }
+ }
+ }
+ } else {
+ lat, lng, err := coordsparser.Parse(ss)
+ if err != nil {
+ return nil, err
+ }
+ currentPath.Positions = append(currentPath.Positions, s2.LatLngFromDegrees(lat, lng))
+ }
+ }
+ if len(currentPath.Positions) > 0 {
+ paths = append(paths, currentPath)
+ }
+ return paths, nil
+}
+
+func (p *Path) extraMarginPixels() float64 {
+ return 0.5 * p.Weight
+}
+
+func (p *Path) bounds() s2.Rect {
+ r := s2.EmptyRect()
+ for _, ll := range p.Positions {
+ r = r.AddPoint(ll)
+ }
+ return r
+}
+
+func (p *Path) draw(gc *gg.Context, trans *transformer) {
+ if len(p.Positions) <= 1 {
+ return
+ }
+
+ gc.ClearPath()
+ gc.SetLineWidth(p.Weight)
+ gc.SetLineCap(gg.LineCapRound)
+ gc.SetLineJoin(gg.LineJoinRound)
+ for _, ll := range p.Positions {
+ gc.LineTo(trans.ll2p(ll))
+ }
+ gc.SetColor(p.Color)
+ gc.Stroke()
+}
diff --git a/vendor/github.com/felix/go-staticmaps/tile_fetcher.go b/vendor/github.com/felix/go-staticmaps/tile_fetcher.go
new file mode 100644
index 0000000..e02a71f
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/tile_fetcher.go
@@ -0,0 +1,153 @@
+// Copyright 2016 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 (
+ "bytes"
+ "fmt"
+ "image"
+ _ "image/jpeg" // to be able to decode jpegs
+ _ "image/png" // to be able to decode pngs
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "path/filepath"
+
+ "github.com/Wessie/appdirs"
+)
+
+// TileFetcher downloads map tile images from a TileProvider
+type TileFetcher struct {
+ tileProvider *TileProvider
+ cacheDir string
+ useCaching bool
+}
+
+// NewTileFetcher creates a new Tilefetcher struct
+func NewTileFetcher(tileProvider *TileProvider) *TileFetcher {
+ t := new(TileFetcher)
+ t.tileProvider = tileProvider
+ app := appdirs.New("go-staticmaps", "flopp.net", "0.1")
+ t.cacheDir = fmt.Sprintf("%s/%s", app.UserCache(), tileProvider.Name)
+ t.useCaching = true
+ return t
+}
+
+func (t *TileFetcher) url(zoom, x, y int) string {
+ shard := ""
+ ss := len(t.tileProvider.Shards)
+ if len(t.tileProvider.Shards) > 0 {
+ shard = t.tileProvider.Shards[(x+y)%ss]
+ }
+ return t.tileProvider.getURL(shard, zoom, x, y)
+}
+
+func (t *TileFetcher) cacheFileName(zoom int, x, y int) string {
+ return fmt.Sprintf("%s/%d/%d/%d", t.cacheDir, zoom, x, y)
+}
+
+// ToggleCaching enables/disables caching
+func (t *TileFetcher) ToggleCaching(enabled bool) {
+ t.useCaching = enabled
+}
+
+// Fetch download (or retrieves from the cache) a tile image for the specified zoom level and tile coordinates
+func (t *TileFetcher) Fetch(zoom, x, y int) (image.Image, error) {
+ if t.useCaching {
+ fileName := t.cacheFileName(zoom, x, y)
+ cachedImg, err := t.loadCache(fileName)
+ if err == nil {
+ return cachedImg, nil
+ }
+ }
+
+ url := t.url(zoom, x, y)
+ data, err := t.download(url)
+ if err != nil {
+ return nil, err
+ }
+
+ img, _, err := image.Decode(bytes.NewBuffer(data))
+ if err != nil {
+ return nil, err
+ }
+
+ if t.useCaching {
+ fileName := t.cacheFileName(zoom, x, y)
+ if err := t.storeCache(fileName, data); err != nil {
+ log.Printf("Failed to store map tile as '%s': %s", fileName, err)
+ }
+ }
+
+ return img, nil
+}
+
+func (t *TileFetcher) download(url string) ([]byte, error) {
+ resp, err := http.Get(url)
+ defer resp.Body.Close()
+
+ if err != nil {
+ return nil, err
+ }
+
+ contents, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ return contents, nil
+}
+
+func (t *TileFetcher) loadCache(fileName string) (image.Image, error) {
+ file, err := os.Open(fileName)
+ if err != nil {
+ return nil, err
+ }
+ defer file.Close()
+
+ img, _, err := image.Decode(file)
+ if err != nil {
+ return nil, err
+ }
+
+ return img, nil
+}
+
+func (t *TileFetcher) createCacheDir(path string) error {
+ src, err := os.Stat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return os.MkdirAll(path, 0777)
+ }
+ return err
+ }
+ if src.IsDir() {
+ return nil
+ }
+ return fmt.Errorf("File exists but is not a directory: %s", path)
+}
+
+func (t *TileFetcher) storeCache(fileName string, data []byte) error {
+ dir, _ := filepath.Split(fileName)
+
+ if err := t.createCacheDir(dir); err != nil {
+ return err
+ }
+
+ file, err := os.Create(fileName)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ if _, err = io.Copy(file, bytes.NewBuffer(data)); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/felix/go-staticmaps/tile_provider.go b/vendor/github.com/felix/go-staticmaps/tile_provider.go
new file mode 100644
index 0000000..2848e28
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/tile_provider.go
@@ -0,0 +1,142 @@
+// Copyright 2016 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"
+
+// TileProvider encapsulates all infos about a map tile provider service (name, url scheme, attribution, etc.)
+type TileProvider struct {
+ Name string
+ Attribution string
+ TileSize int
+ URLPattern string // "%[1]s" => shard, "%[2]d" => zoom, "%[3]d" => x, "%[4]d" => y
+ Shards []string
+}
+
+func (t *TileProvider) getURL(shard string, zoom, x, y int) string {
+ return fmt.Sprintf(t.URLPattern, shard, zoom, x, y)
+}
+
+// NewTileProviderOpenStreetMaps creates a TileProvider struct for OSM's tile service
+func NewTileProviderOpenStreetMaps() *TileProvider {
+ t := new(TileProvider)
+ t.Name = "osm"
+ t.Attribution = "Maps and Data (c) openstreetmaps.org and contributors, ODbL"
+ t.TileSize = 256
+ t.URLPattern = "http://%[1]s.tile.openstreemaps.org/%[2]d/%[3]d/%[4]d.png"
+ t.Shards = []string{"a", "b", "c"}
+ return t
+}
+
+func newTileProviderThunderforest(name string) *TileProvider {
+ t := new(TileProvider)
+ t.Name = fmt.Sprintf("thunderforest-%s", name)
+ t.Attribution = "Maps (c) Thundeforest; Data (c) OSM and contributors, ODbL"
+ t.TileSize = 256
+ t.URLPattern = "https://%[1]s.tile.thunderforest.com/" + name + "/%[2]d/%[3]d/%[4]d.png"
+ t.Shards = []string{"a", "b", "c"}
+ return t
+}
+
+// NewTileProviderThunderforestLandscape creates a TileProvider struct for thundeforests's 'landscape' tile service
+func NewTileProviderThunderforestLandscape() *TileProvider {
+ return newTileProviderThunderforest("landscape")
+}
+
+// NewTileProviderThunderforestOutdoors creates a TileProvider struct for thundeforests's 'outdoors' tile service
+func NewTileProviderThunderforestOutdoors() *TileProvider {
+ return newTileProviderThunderforest("outdoors")
+}
+
+// NewTileProviderThunderforestTransport creates a TileProvider struct for thundeforests's 'transport' tile service
+func NewTileProviderThunderforestTransport() *TileProvider {
+ return newTileProviderThunderforest("transport")
+}
+
+// NewTileProviderStamenToner creates a TileProvider struct for stamens' 'toner' tile service
+func NewTileProviderStamenToner() *TileProvider {
+ t := new(TileProvider)
+ t.Name = "stamen-toner"
+ t.Attribution = "Maps (c) Stamen; Data (c) OSM and contributors, ODbL"
+ t.TileSize = 256
+ t.URLPattern = "http://%[1]s.tile.stamen.com/toner/%[2]d/%[3]d/%[4]d.png"
+ t.Shards = []string{"a", "b", "c", "d"}
+ return t
+}
+
+// NewTileProviderOpenTopoMap creates a TileProvider struct for opentopomaps's tile service
+func NewTileProviderOpenTopoMap() *TileProvider {
+ t := new(TileProvider)
+ t.Name = "opentopomap"
+ t.Attribution = "Maps (c) OpenTopoMap [CC-BY-SA]; Data (c) OSM and contributors [ODbL]; Data (c) SRTM"
+ t.TileSize = 256
+ t.URLPattern = "http://%[1]s.tile.opentopomap.org/%[2]d/%[3]d/%[4]d.png"
+ t.Shards = []string{"a", "b", "c"}
+ return t
+}
+
+func NewTileProviderWikimedia() *TileProvider {
+ t := new(TileProvider)
+ t.Name = "wikimedia"
+ t.Attribution = "Map (c) Wikimedia; Data (c) OSM and contributers, ODbL."
+ t.TileSize = 256
+ t.URLPattern = "https://maps.wikimedia.org/osm-intl/%[2]d/%[3]d/%[4]d.png"
+ t.Shards = []string{}
+ return t
+}
+
+func NewTileProviderOpenCycleMap() *TileProvider {
+ t := new(TileProvider)
+ t.Name = "cycle"
+ t.Attribution = "Maps and Data (c) openstreetmaps.org and contributors, ODbL"
+ t.TileSize = 256
+ t.URLPattern = "http://%[1]s.tile.opencyclemap.org/cycle/%[2]d/%[3]d/%[4]d.png"
+ t.Shards = []string{"a", "b"}
+ return t
+}
+
+func newTileProviderCarto(name string) *TileProvider {
+ t := new(TileProvider)
+ t.Name = fmt.Sprintf("carto-%s", name)
+ t.Attribution = "Map (c) Carto [CC BY 3.0] Data (c) OSM and contributers, ODbL."
+ t.TileSize = 256
+ t.URLPattern = "https://cartodb-basemaps-%[1]s.global.ssl.fastly.net/" + name + "_all/%[2]d/%[3]d/%[4]d.png"
+ t.Shards = []string{"a", "b", "c", "d"}
+ return t
+}
+
+func NewTileProviderCartoLight() *TileProvider {
+ return newTileProviderCarto("light")
+}
+
+func NewTileProviderCartoDark() *TileProvider {
+ return newTileProviderCarto("dark")
+}
+
+// GetTileProviders returns a map of all available TileProviders
+func GetTileProviders() map[string]*TileProvider {
+ m := make(map[string]*TileProvider)
+
+ list := []*TileProvider{
+ NewTileProviderOpenStreetMaps(),
+ NewTileProviderOpenCycleMap(),
+ NewTileProviderThunderforestLandscape(),
+ NewTileProviderThunderforestOutdoors(),
+ NewTileProviderThunderforestTransport(),
+ NewTileProviderStamenToner(),
+ NewTileProviderOpenTopoMap(),
+ NewTileProviderOpenStreetMaps(),
+ NewTileProviderOpenCycleMap(),
+ NewTileProviderCartoLight(),
+ NewTileProviderCartoDark(),
+ }
+
+ for _, tp := range list {
+ m[tp.Name] = tp
+ }
+
+ return m
+}
diff --git a/vendor/github.com/felix/go-staticmaps/util.go b/vendor/github.com/felix/go-staticmaps/util.go
new file mode 100644
index 0000000..3f5d4ad
--- /dev/null
+++ b/vendor/github.com/felix/go-staticmaps/util.go
@@ -0,0 +1,18 @@
+// Copyright 2016 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 (
+ "strings"
+)
+
+// hasPrefix checks if 's' has prefix 'prefix'; returns 'true' and the remainder on success, and 'false', 's' otherwise.
+func hasPrefix(s string, prefix string) (bool, string) {
+ if strings.HasPrefix(s, prefix) {
+ return true, strings.TrimPrefix(s, prefix)
+ }
+ return false, s
+}