Skip to content

Commit 309573d

Browse files
committed
Add calculation of max and min zoom for images
These changes: - replace the hard coded min/max zoom with values that are calculated based on the pixel density of the image and the geo bounds - add more implementations of functionality copied from globalmaptiles.py
1 parent 36ac6d5 commit 309573d

File tree

7 files changed

+94
-21
lines changed

7 files changed

+94
-21
lines changed

go.mod

-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@ module main
22

33
require (
44
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32
5-
github.com/gorilla/handlers v1.4.0 // indirect
65
github.com/gorilla/mux v1.7.0
76
github.com/h2non/bimg v1.0.19
87
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f
98
gonum.org/v1/gonum v0.0.0-20190330083134-779ef2ac207d
10-
gopkg.in/h2non/bimg.v1 v1.0.19
119
)

go.sum

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew=
22
github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
3-
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
4-
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
53
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
64
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
75
github.com/h2non/bimg v1.0.19 h1:lrKA2oi4DttnscGeb/oRiBIcRiAX33mmp3yQX8JzGIc=
@@ -10,14 +8,13 @@ golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2 h1:y102fOLFqhV41b+4GPiJoa0k/
108
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
119
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f h1:FO4MZ3N56GnxbqxGKqh+YTzUWQ2sDwtFQEZgLOxh9Jc=
1210
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
13-
golang.org/x/image v0.0.0-20190622003408-7e034cad6442 h1:KHkZ9SH+rcDwdj29lcYkks2agONXqNa8YkEGwGhY6Sg=
1411
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
1512
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
1613
gonum.org/v1/gonum v0.0.0-20190330083134-779ef2ac207d h1:ShJE9we+7oZ2ZWS32zNTOntaiKgC3zCnzvTbDLTGZhQ=
1714
gonum.org/v1/gonum v0.0.0-20190330083134-779ef2ac207d/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
15+
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc=
1816
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
17+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
1918
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
20-
gopkg.in/h2non/bimg.v1 v1.0.19 h1:Li7mgBrIvCHvShB4nyCcGJ2Z2rWR/95kgI/U2+U2eYw=
21-
gopkg.in/h2non/bimg.v1 v1.0.19/go.mod h1:PgsZL7dLwUbsGm1NYps320GxGgvQNTnecMCZqxV11So=
2219
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
2320
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

mapimage/goimage.go

+9-6
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,7 @@ func NewImageInfo(
2929
id,
3030
text string,
3131
referencePoints []MapImagePair,
32-
minZoom int,
33-
maxZoom int,
3432
contents *os.File) MapImage {
35-
//image, err := png.Decode(bytes.NewReader(fileContents))
3633
image, _, err := image.Decode(contents)
3734
if err != nil {
3835
panic(0)
@@ -52,26 +49,32 @@ func NewImageInfo(
5249
panic(0)
5350
}
5451

55-
return &goImage{
52+
i := goImage{
5653
id: id,
5754
text: text,
58-
minZoom: minZoom,
59-
maxZoom: maxZoom,
55+
minZoom: 0,
56+
maxZoom: 0,
6057
referencePoints: referencePoints,
6158
contents: contents,
6259
image: image,
6360
toGeo: &toGeo,
6461
toPixel: &toPixel,
6562
}
6663

64+
i.minZoom = calculateMinZoom(&i)
65+
i.maxZoom = calculateMaxZoom(&i)
66+
67+
return &i
6768
}
6869

6970
func (i goImage) Id() string {
7071
return i.id
7172
}
73+
7274
func (i goImage) Text() string {
7375
return i.text
7476
}
77+
7578
func (i goImage) GeoBounds() [2]LatLng {
7679
imageSize := i.PixelBounds()
7780

mapimage/libvips.go

+6-7
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,7 @@ func NewVIPSImageInfo(
3434
id,
3535
text string,
3636
referencePoints []MapImagePair,
37-
minZoom int,
38-
maxZoom int,
3937
contents *os.File) MapImage {
40-
//image, err := png.Decode(bytes.NewReader(fileContents))
4138
imageConfig, format, err := image.DecodeConfig(contents)
4239
if err != nil {
4340
panic(0)
@@ -64,11 +61,11 @@ func NewVIPSImageInfo(
6461
panic(0)
6562
}
6663

67-
return &libvipsImage{
64+
i := libvipsImage{
6865
id: id,
6966
text: text,
70-
minZoom: minZoom,
71-
maxZoom: maxZoom,
67+
minZoom: 0,
68+
maxZoom: 0,
7269
//referencePoints: referencePoints,
7370
contents: contents,
7471
fileBuf: buf,
@@ -77,7 +74,9 @@ func NewVIPSImageInfo(
7774
toGeo: &toGeo,
7875
toPixel: &toPixel,
7976
}
80-
77+
i.minZoom = calculateMinZoom(&i)
78+
i.maxZoom = calculateMaxZoom(&i)
79+
return &i
8180
}
8281

8382
func (i libvipsImage) Id() string {

mapimage/main.go

+43
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"github.com/gorilla/mux"
77
"io"
8+
"math"
89
"net/http"
910
"strconv"
1011
"strings"
@@ -18,9 +19,12 @@ type MapImage interface {
1819
Text() string
1920
GeoBounds() [2]LatLng
2021
PixelBounds() [2]LatLng
22+
// The zoom where whole image is on a single tile?
2123
MinZoom() int
24+
// The zoom where image is being stretched by more than half?
2225
MaxZoom() int
2326
//ReferencePoints() []MapImagePair
27+
GeoFromPixel(p LatLng) LatLng
2428
}
2529

2630
type MapImagesSource interface {
@@ -56,6 +60,45 @@ func max(a, b int) int {
5660
return b
5761
}
5862

63+
func calculateMinZoom(i MapImage) int {
64+
// The zoom where whole image is on a single tile?
65+
geoBounds := i.GeoBounds()
66+
geoBoundsMin := geoBounds[0]
67+
geoBoundsMax := geoBounds[1]
68+
69+
for z := 20; z > 0; z-- {
70+
minX, minY := LatLonToPixels(geoBoundsMin.Lat, geoBoundsMin.Lng, z)
71+
maxX, maxY := LatLonToPixels(geoBoundsMax.Lat, geoBoundsMax.Lng, z)
72+
if math.Abs(minX-maxX) < 256 {
73+
return z
74+
}
75+
if math.Abs(minY-maxY) < 256 {
76+
return z
77+
}
78+
}
79+
80+
return 0
81+
}
82+
83+
func calculateMaxZoom(i MapImage) int {
84+
// The zoom where tiles start to stretch (i.e. pixel density limit)
85+
singleTileMin := i.GeoFromPixel(LatLng{Lat: 0, Lng: 0})
86+
singleTileMax := i.GeoFromPixel(LatLng{Lat: 256, Lng: 256})
87+
88+
for z := 0; z < 21; z++ {
89+
minX, minY := LatLonToPixels(singleTileMin.Lat, singleTileMin.Lng, z)
90+
maxX, maxY := LatLonToPixels(singleTileMax.Lat, singleTileMax.Lng, z)
91+
if math.Abs(minX-maxX) > 256 {
92+
return z
93+
}
94+
if math.Abs(minY-maxY) > 256 {
95+
return z
96+
}
97+
}
98+
99+
return 20
100+
}
101+
59102
type ApiRepresentation struct {
60103
Id string `json:"id"`
61104
Text string `json:"text"`

mapimage/maptile.go

+28-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ type TileBounds struct {
1212
}
1313

1414
const tileSize int64 = 256
15+
const originShift float64 = 2.0 * math.Pi * 6378137.0 / 2.0
1516

1617
func Resolution(zoom int64) float64 {
1718
//"Resolution (meters/pixel) for given zoom level (measured at Equator)"
@@ -22,7 +23,6 @@ func Resolution(zoom int64) float64 {
2223

2324
func PixelsToMeters(px, py, zoom int64) (float64, float64) {
2425
//"Converts pixel coordinates in given zoom level of pyramid to EPSG:900913"
25-
originShift := 2.0 * math.Pi * 6378137.0 / 2.0
2626

2727
res := Resolution(zoom)
2828
mx := float64(px)*res - originShift
@@ -36,6 +36,33 @@ func (b *TileBounds) FromTile(tx, ty, zoom int64) {
3636
b.maxX, b.maxY = PixelsToMeters((tx+1)*tileSize, (ty+1)*tileSize, zoom)
3737
}
3838

39+
func LatLonToMeters(lat, lon float64) (mx, my float64) {
40+
// "Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:900913"
41+
42+
mx = lon * originShift / 180.0
43+
my = math.Log(math.Tan((90+lat)*math.Pi/360.0)) / (math.Pi / 180.0)
44+
my = my * originShift / 180.0
45+
return mx, my
46+
}
47+
48+
func MetersToPixels(mx, my float64, zoom int64) (px, py float64) {
49+
// "Converts EPSG:900913 to pyramid pixel coordinates in given zoom level"
50+
51+
res := Resolution(zoom)
52+
px = (mx + originShift) / float64(res)
53+
py = (my + originShift) / float64(res)
54+
return px, py
55+
}
56+
57+
func LatLonToPixels(lat, lon float64, zoom int) (px, py float64) {
58+
// "Converts lat/lon to pixel coordinates in given zoom of the EPSG:4326 pyramid"
59+
60+
res := 180.0 / 256.0 / math.Pow(2, float64(zoom))
61+
px = (180.0 + lat) / res
62+
py = (90.0 + lon) / res
63+
return px, py
64+
}
65+
3966
func MetersToLatLon(mx, my float64) (float64, float64) {
4067
//"Converts XY point from Spherical Mercator EPSG:900913 to lat/lon in WGS84 Datum"
4168

serverd.go

+6
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"log"
1414
"main/mapimage"
1515
"net/http"
16+
_ "net/http/pprof"
1617
"os"
1718
)
1819

@@ -79,6 +80,7 @@ func init() {
7980
loadedImage.ReferencePoints,
8081
20, 0,
8182
f)
83+
log.Printf(" >> MinZoom: %v MaxZoom: %v\n", mi.MinZoom(), mi.MaxZoom())
8284
}
8385
maps.images = append(maps.images, mi)
8486
}
@@ -116,6 +118,10 @@ func main() {
116118

117119
router.PathPrefix("/").Handler(http.FileServer(http.Dir("./ui/build")))
118120

121+
go func() {
122+
log.Println(http.ListenAndServe("localhost:6060", nil))
123+
}()
124+
119125
log.Fatal(http.ListenAndServe(":8000", router))
120126

121127
}

0 commit comments

Comments
 (0)