From 79a46b5d2d7718ffdf117a38bb6ea68b74c56ad9 Mon Sep 17 00:00:00 2001 From: flopp Date: Sat, 28 Jan 2017 17:33:19 +0100 Subject: [PATCH] fix setting of bounding box --- README.md | 5 ++- bbox.go | 53 ++++++++++++++++++++++++++ context.go | 27 ++++++++++--- create-static-map/create-static-map.go | 28 ++++++++------ 4 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 bbox.go diff --git a/README.md b/README.md index 349f397..a4314da 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,10 @@ See [GoDoc](https://godoc.org/github.com/flopp/go-staticmaps) for a complete doc -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 - -b, --bbox=LATLNG|LATLNG Set the bounding box (the given coordinates pair must be opposite corners of a rectangle) + -b, --bbox=NW_LATLNG|SE_LATLNG + Set the bounding box (NW_LATLNG = north-western point of the + bounding box, SW_LATLNG = southe-western point of the bounding + box) -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 diff --git a/bbox.go b/bbox.go new file mode 100644 index 0000000..c32d06b --- /dev/null +++ b/bbox.go @@ -0,0 +1,53 @@ +// Copyright 2016, 2017 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" + "math" + + "github.com/golang/geo/s1" + "github.com/golang/geo/s2" +) + +// CreateBBox creates a bounding box from a north-western point +// (lat/lng in degrees) and a south-eastern point (lat/lng in degrees). +// Note that you can create a bounding box wrapping over the antimeridian at +// lng=+-/180° by nwlng > selng. +func CreateBBox(nwlat float64, nwlng float64, selat float64, selng float64) (*s2.Rect, error) { + if nwlat < -90 || nwlat > 90 { + return nil, fmt.Errorf("Out of range nwlat (%f) must be in [-90, 90]", nwlat) + } + if nwlng < -180 || nwlng > 180 { + return nil, fmt.Errorf("Out of range nwlng (%f) must be in [-180, 180]", nwlng) + } + + if selat < -90 || selat > 90 { + return nil, fmt.Errorf("Out of range selat (%f) must be in [-90, 90]", selat) + } + if selng < -180 || selng > 180 { + return nil, fmt.Errorf("Out of range selng (%f) must be in [-180, 180]", selng) + } + + if nwlat == selat { + return nil, fmt.Errorf("nwlat and selat must not be equal") + } + if nwlng == selng { + return nil, fmt.Errorf("nwlng and selng must not be equal") + } + + bbox := new(s2.Rect) + if selat < nwlat { + bbox.Lat.Lo = selat * math.Pi / 180.0 + bbox.Lat.Hi = nwlat * math.Pi / 180.0 + } else { + bbox.Lat.Lo = nwlat * math.Pi / 180.0 + bbox.Lat.Hi = selat * math.Pi / 180.0 + } + bbox.Lng = s1.IntervalFromEndpoints(nwlng*math.Pi/180.0, selng*math.Pi/180.0) + + return bbox, nil +} diff --git a/context.go b/context.go index 913e778..e8201dd 100644 --- a/context.go +++ b/context.go @@ -157,7 +157,14 @@ func (m *Context) determineZoom(bounds s2.Rect, center s2.LatLng) int { 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) + + dx := maxX - minX + for dx < 0 { + dx = dx + 1 + } + for dx > 1 { + dx = dx - 1 + } dy := math.Abs(maxY - minY) zoom := 1 @@ -236,6 +243,9 @@ func (t *transformer) ll2t(ll s2.LatLng) (float64, float64) { func (t *transformer) ll2p(ll s2.LatLng) (float64, float64) { x, y := t.ll2t(ll) + if x < float64(t.tOriginX) { + x = x + math.Exp2(float64(t.zoom)) + } x = float64(t.pCenterX) + (x-t.tCenterX)*float64(t.tileSize) y = float64(t.pCenterY) + (y-t.tCenterY)*float64(t.tileSize) return x, y @@ -255,17 +265,24 @@ func (m *Context) Render() (image.Image, error) { // fetch and draw tiles to img t := NewTileFetcher(m.tileProvider) + tiles := (1 << uint(zoom)) for xx := 0; xx < trans.tCountX; xx++ { x := trans.tOriginX + xx if x < 0 { - x = x + (1 << uint(zoom)) + x = x + tiles + } else if x >= tiles { + x = x - tiles } 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) + if y < 0 || y >= tiles { + log.Printf("Skipping out of bounds tile %d/%d", x, y) } else { - log.Printf("Error downloading tile file: %s", err) + if tileImg, err := t.Fetch(zoom, x, y); err == nil { + gc.DrawImage(tileImg, xx*tileSize, yy*tileSize) + } else { + log.Printf("Error downloading tile file: %s", err) + } } } } diff --git a/create-static-map/create-static-map.go b/create-static-map/create-static-map.go index f3da3fc..b0bf2c6 100644 --- a/create-static-map/create-static-map.go +++ b/create-static-map/create-static-map.go @@ -55,26 +55,30 @@ func handleCenterOption(ctx *sm.Context, parameter string) { func handleBboxOption(ctx *sm.Context, parameter string) { pair := strings.Split(parameter, "|") if len(pair) != 2 { - log.Fatalf("Bad LATLNG|LATLNG pair: %s", parameter) + log.Fatalf("Bad NW|SE coordinates pair: %s", parameter) } - bbox := s2.EmptyRect() - - lat, lng, err := coordsparser.Parse(pair[0]) + var err error + var nwlat float64 + var nwlng float64 + var selat float64 + var selng float64 + nwlat, nwlng, err = coordsparser.Parse(pair[0]) if err != nil { log.Fatal(err) - } else { - bbox = bbox.AddPoint(s2.LatLngFromDegrees(lat, lng)) } - - lat, lng, err = coordsparser.Parse(pair[1]) + selat, selng, err = coordsparser.Parse(pair[1]) if err != nil { log.Fatal(err) - } else { - bbox = bbox.AddPoint(s2.LatLngFromDegrees(lat, lng)) } - ctx.SetBoundingBox(bbox) + var bbox s2.Rect + bbox, err = sm.CreateBBox(nwlat, nwlng, selat, selng) + if err != nil { + log.Fatal(err) + } + + ctx.SetBoundingBox(*bbox) } func handleMarkersOption(ctx *sm.Context, parameters []string) { @@ -124,7 +128,7 @@ func main() { 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"` - BBox string `short:"b" long:"bbox" description:"Bounding box of the static map" value-name:"LATLNG|LATLNG"` + BBox string `short:"b" long:"bbox" description:"Bounding box of the static map" value-name:"nwLATLNG|seLATLNG"` 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"`