aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Kiryukhin <a.kiryukhin@mail.ru>2020-08-17 13:19:06 +0300
committerAlexander Kiryukhin <a.kiryukhin@mail.ru>2020-08-17 13:19:06 +0300
commit7f1bb18fd654b58eae56b1d02c4568d62ff226a5 (patch)
tree5d3b8eccdc23d55d6f63f843a5438af87251d74a
initial
-rw-r--r--.gitignore1
-rw-r--r--go.mod8
-rw-r--r--go.sum49
-rw-r--r--main.go45
-rw-r--r--map.go88
5 files changed, 191 insertions, 0 deletions
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 <ak@bytechain.ru>
+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)
+}