From 7f1bb18fd654b58eae56b1d02c4568d62ff226a5 Mon Sep 17 00:00:00 2001 From: Alexander Kiryukhin Date: Mon, 17 Aug 2020 13:19:06 +0300 Subject: [PATCH] initial --- .gitignore | 1 + go.mod | 8 +++++ go.sum | 49 ++++++++++++++++++++++++++++++ main.go | 45 ++++++++++++++++++++++++++++ map.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 191 insertions(+) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 map.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..59a005b --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module OsmStatic + +go 1.14 + +require ( + github.com/disintegration/imaging v1.6.2 + github.com/labstack/echo/v4 v4.1.16 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d8fca54 --- /dev/null +++ b/go.sum @@ -0,0 +1,49 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= +github.com/labstack/echo/v4 v4.1.16 h1:8swiwjE5Jkai3RPfZoahp8kjVCRNq+y7Q0hPji2Kz0o= +github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI= +github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= +github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/fasttemplate v1.1.0 h1:RZqt0yGBsps8NGvLSGW804QQqCUYYLsaOjTVHy1Ocw4= +github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw= +golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..349f41c --- /dev/null +++ b/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "github.com/labstack/echo/v4" + "log" + "strconv" +) + +func main() { + e := echo.New() + e.GET("/map", func(c echo.Context) error { + lat, err := strconv.ParseFloat(c.QueryParam("lat"), 64) + if err != nil { + return err + } + lon, err := strconv.ParseFloat(c.QueryParam("lon"), 64) + if err != nil { + return err + } + w, err := strconv.Atoi(c.QueryParam("w")) + if err != nil { + w = 800 + } + h, err := strconv.Atoi(c.QueryParam("h")) + if err != nil { + h = 800 + } + zoom, err := strconv.Atoi(c.QueryParam("zoom")) + if err != nil { + zoom = 16 + } + if zoom < 1 { + zoom = 1 + } + if zoom > 20 { + zoom = 20 + } + img, err := GetMapImage(lat, lon, zoom, w, h) + if err != nil { + return err + } + return c.Blob(200, "image/png", img) + }) + log.Fatal(e.Start(":8000")) +} diff --git a/map.go b/map.go new file mode 100644 index 0000000..baa9356 --- /dev/null +++ b/map.go @@ -0,0 +1,88 @@ +/* +Copyright © 2020 Alexander Kiryukhin +This file is part of OsmStatic project. +*/ +package main + +import ( + "bytes" + "fmt" + "image" + "image/color" + "image/png" + _ "image/png" + "io/ioutil" + "log" + "math" + "net/http" + "sync" + + "github.com/disintegration/imaging" +) + +const ( + tileAddr = `https://a.tile.openstreetmap.org/%d/%d/%d.png` + tw = 256 + th = 256 +) + +func GetMapImage(lat, lon float64, zoom, width, height int) ([]byte, error) { + x, y, dx, dy := getCoords(lat, lon, zoom) + dst := imaging.New(width, height, color.NRGBA{0, 255, 0, 255}) + wg := sync.WaitGroup{} + mu := sync.Mutex{} + cx := width/2 - tw/2 + cy := height/2 - th/2 + sx := width/tw + 2 + sy := height/th + 2 + di := int(dx*float64(tw)) - tw/2 + dj := int(dy*float64(th)) - th/2 + for i := -sx / 2; i <= sx/2; i++ { + for j := -sy / 2; j <= sy/2; j++ { + wg.Add(1) + go func(i, j int) { + defer wg.Done() + tile, err := getTile(x+i, y+j, zoom) + if err != nil { + log.Println(err) + return + } + img, err := png.Decode(bytes.NewReader(tile)) + if err != nil { + log.Println(err) + return + } + mu.Lock() + defer mu.Unlock() + tx := cx + i*tw - di + ty := cy + j*th - dj + dst = imaging.Paste(dst, img, image.Pt(tx, ty)) + }(int(i), int(j)) + } + } + wg.Wait() + + out := bytes.NewBuffer([]byte{}) + if err := imaging.Encode(out, dst, imaging.PNG); err != nil { + return nil, err + } + return out.Bytes(), nil +} + +func getCoords(lat, lon float64, zoom int) (int, int, float64, float64) { + x := (lon + 180.0) / 360.0 * (math.Exp2(float64(zoom))) + y := (1.0 - math.Log(math.Tan(lat*math.Pi/180.0)+1.0/math.Cos(lat*math.Pi/180.0))/math.Pi) / 2.0 * (math.Exp2(float64(zoom))) + dx := x - math.Floor(x) + dy := y - math.Floor(y) + return int(math.Floor(x)), int(math.Floor(y)), dx, dy +} + +func getTile(x, y, z int) ([]byte, error) { + tile := fmt.Sprintf(tileAddr, z, x, y) + resp, err := http.DefaultClient.Get(tile) + if err != nil { + return nil, err + } + defer resp.Body.Close() + return ioutil.ReadAll(resp.Body) +}