Skip to content

Commit 390d563

Browse files
authored
Add support for non-Web-Mercator coordinate systems. "Real" mercator (CrunchyData#60)
end up being very easy: just supply the alternate EPSG numbers (3395) as the planar bounds are the same as for web mercator. For other alternate systems you will need to also include the bounds of the inital level-zero tile.
1 parent b8face3 commit 390d563

File tree

11 files changed

+434
-81
lines changed

11 files changed

+434
-81
lines changed

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,37 @@ In general the defaults are fine, and the program autodetects things like the se
6565
```toml
6666
# Database connection
6767
DbConnection = "user=you host=localhost dbname=yourdb"
68+
6869
# Close pooled connections after this interval
6970
DbPoolMaxConnLifeTime = "1h"
71+
7072
# Hold no more than this number of connections in the database pool
7173
DbPoolMaxConns = 4
74+
7275
# Look to read html templates from this directory
7376
AssetsPath = "/usr/share/pg_tileserv/assets"
77+
7478
# Accept connections on this subnet (default accepts on all)
7579
HttpHost = "0.0.0.0"
80+
7681
# Accept connections on this port
7782
HttpPort = 7800
83+
HttpsPort = 7801
84+
85+
# HTTPS configuration
86+
# TLS server certificate full chain and private key
87+
# If you do not specify both, the TLS server will not be started
88+
TlsServerCertificateFile = "server.crt"
89+
TlsServerPrivateKeyFile = "server.key"
90+
```
91+
92+
For SSL support, you will need both a server private key and an authority certificate. For testing purposes you can generate a self-signed key/cert pair using `openssl`:
93+
94+
```bash
95+
openssl req -nodes -new -x509 -keyout server.key -out server.crt
96+
```
97+
98+
```toml
7899
# Advertise URLs relative to this server name
79100
# default is to looke this up from incoming request headers
80101
# UrlBase = "http://yourserver.com/"
@@ -88,11 +109,22 @@ MaxFeaturesPerTile = 10000
88109
DefaultMinZoom = 0
89110
# Advertise this maximum zoom level
90111
DefaultMaxZoom = 22
112+
91113
# Allow any page to consume these tiles
92114
CORSOrigins = ["*"]
115+
93116
# Output extra logging information?
94117
Debug = false
118+
119+
# Default CS is Web Mercator (EPSG:3857)
120+
[CoordinateSystem]
121+
SRID = 3857
122+
Xmin = -20037508.3427892
123+
Ymin = -20037508.3427892
124+
Xmax = 20037508.3427892
125+
Ymax = 20037508.3427892
95126
```
127+
You can use the **CoordinateSystem** block to output files in a system other than the default [Web Mercator](http://epsg.io/3857) projection. In order to view a map with multiple layers in a non-standard projection, you will have to ensure that all layers share the same projection, otherwise the layers will not line up.
96128

97129
# Operation
98130

bounds.go

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,74 +7,78 @@ import (
77

88
// Bounds represents a box in Web Mercator space
99
type Bounds struct {
10+
SRID int `json:"srid"`
1011
Xmin float64 `json:"xmin"`
1112
Ymin float64 `json:"ymin"`
1213
Xmax float64 `json:"xmax"`
1314
Ymax float64 `json:"ymax"`
1415
}
1516

1617
func (b *Bounds) String() string {
17-
return fmt.Sprintf("{Xmin:%g, Ymin:%g, Xmax:%g, Ymax:%g}",
18-
b.Xmin, b.Ymin, b.Xmax, b.Ymax)
18+
return fmt.Sprintf("{Xmin:%g, Ymin:%g, Xmax:%g, Ymax:%g, SRID:%d}",
19+
b.Xmin, b.Ymin, b.Xmax, b.Ymax, b.SRID)
1920
}
2021

2122
// SQL returns the SQL fragment to create this bounds in the database
2223
func (b *Bounds) SQL() string {
23-
return fmt.Sprintf("ST_MakeEnvelope(%g, %g, %g, %g, 3857)",
24+
return fmt.Sprintf("ST_MakeEnvelope(%g, %g, %g, %g, %d)",
2425
b.Xmin, b.Ymin,
25-
b.Xmax, b.Ymax)
26+
b.Xmax, b.Ymax, b.SRID)
2627
}
2728

2829
// Expand increases the size of this bounds in all directions, respecting
2930
// the limits of the Web Mercator plane
3031
func (b *Bounds) Expand(size float64) {
31-
worldMin := -0.5 * worldMercWidth
32-
worldMax := 0.5 * worldMercWidth
33-
b.Xmin = math.Max(b.Xmin-size, worldMin)
34-
b.Ymin = math.Max(b.Ymin-size, worldMin)
35-
b.Xmax = math.Min(b.Xmax+size, worldMax)
36-
b.Ymax = math.Min(b.Ymax+size, worldMax)
32+
serverBounds, _ := getServerBounds()
33+
b.Xmin = math.Max(b.Xmin-size, serverBounds.Xmin)
34+
b.Ymin = math.Max(b.Ymin-size, serverBounds.Ymin)
35+
b.Xmax = math.Min(b.Xmax+size, serverBounds.Xmax)
36+
b.Ymax = math.Min(b.Ymax+size, serverBounds.Ymax)
3737
return
3838
}
3939

40+
// func fromMercator(x float64, y float64) (lng float64, lat float64) {
41+
// // worldMercWidth is the width of the Web Mercator plane
42+
// worldMercWidth := 40075016.6855784
43+
// mercSize := worldMercWidth / 2.0
44+
// lng = x * 180.0 / mercSize
45+
// lat = 180.0 / math.Pi * (2.0*math.Atan(math.Exp((y/mercSize)*math.Pi)) - math.Pi/2.0)
46+
// return lng, lat
47+
// }
48+
4049
func (b *Bounds) sanitize() {
41-
if b.Ymin < -90 {
42-
b.Ymin = 90
43-
}
44-
if b.Ymax > 90 {
45-
b.Ymax = 90
46-
}
47-
if b.Xmin < -180 {
48-
b.Xmin = -180
49-
}
50-
if b.Xmax > 180 {
51-
b.Xmax = 180
50+
if b.SRID == 4326 {
51+
if b.Ymin < -90 {
52+
b.Ymin = 90
53+
}
54+
if b.Ymax > 90 {
55+
b.Ymax = 90
56+
}
57+
if b.Xmin < -180 {
58+
b.Xmin = -180
59+
}
60+
if b.Xmax > 180 {
61+
b.Xmax = 180
62+
}
5263
}
5364
return
5465
}
5566

56-
func fromMercator(x float64, y float64) (lng float64, lat float64) {
57-
mercSize := worldMercWidth / 2.0
58-
lng = x * 180.0 / mercSize
59-
lat = 180.0 / math.Pi * (2.0*math.Atan(math.Exp((y/mercSize)*math.Pi)) - math.Pi/2.0)
60-
return lng, lat
61-
}
62-
6367
// Json returns the bounds in array for form consumption
6468
// by Json formats that like it that way
65-
func (b *Bounds) Json() []float64 {
66-
s := make([]float64, 4)
67-
s[0], s[1] = fromMercator(b.Xmin, b.Ymin)
68-
s[2], s[3] = fromMercator(b.Xmax, b.Ymax)
69-
return s
70-
}
69+
// func (b *Bounds) Json() []float64 {
70+
// s := make([]float64, 4)
71+
// s[0], s[1] = fromMercator(b.Xmin, b.Ymin)
72+
// s[2], s[3] = fromMercator(b.Xmax, b.Ymax)
73+
// return s
74+
// }
7175

7276
// Center returns the center of the bounds in array format
7377
// for consumption by Json formats that like it that way
74-
func (b *Bounds) Center() []float64 {
75-
xc := (b.Xmin + b.Xmax) / 2.0
76-
yc := (b.Ymin + b.Ymax) / 2.0
77-
s := make([]float64, 2)
78-
s[0], s[1] = fromMercator(xc, yc)
79-
return s
80-
}
78+
// func (b *Bounds) Center() []float64 {
79+
// xc := (b.Xmin + b.Xmax) / 2.0
80+
// yc := (b.Ymin + b.Ymax) / 2.0
81+
// s := make([]float64, 2)
82+
// s[0], s[1] = fromMercator(xc, yc)
83+
// return s
84+
// }

config/pg_tileserv.toml.example

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,20 @@
5959

6060
# Output extra logging information?
6161
# Debug = false
62+
63+
# Default CS is Web Mercator (EPSG:3857)
64+
# [CoordinateSystem]
65+
# SRID = 3857
66+
# Xmin = -20037508.3427892
67+
# Ymin = -20037508.3427892
68+
# Xmax = 20037508.3427892
69+
# Ymax = 20037508.3427892
70+
71+
# "True" Mercator (EPSG:3395) is only a little different
72+
# [CoordinateSystem]
73+
# SRID = 3395
74+
# Xmin = -20037508.342789244
75+
# Ymin = -20037508.342789244
76+
# Xmax = 20037508.342789244
77+
# Ymax = 20037508.342789244
78+

go.mod

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ module github.com/CrunchyData/pg_tileserv
33
go 1.13
44

55
require (
6-
github.com/gorilla/handlers v1.4.2
7-
github.com/gorilla/mux v1.7.3
8-
github.com/jackc/pgconn v1.3.2
9-
github.com/jackc/pgtype v1.0.2
10-
github.com/jackc/pgx/v4 v4.1.2
11-
github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3
12-
github.com/sirupsen/logrus v1.4.2
13-
github.com/spf13/viper v1.6.1
14-
github.com/stretchr/testify v1.4.0
6+
github.com/Masterminds/sprig/v3 v3.1.0
7+
github.com/gorilla/handlers v1.5.1
8+
github.com/gorilla/mux v1.8.0
9+
github.com/jackc/pgconn v1.7.2
10+
github.com/jackc/pgtype v1.6.1
11+
github.com/jackc/pgx/v4 v4.9.2
12+
github.com/pborman/getopt/v2 v2.1.0
13+
github.com/sirupsen/logrus v1.7.0
14+
github.com/spf13/viper v1.7.1
15+
github.com/stretchr/testify v1.6.1
1516
github.com/theckman/httpforwarded v0.4.0
1617
)

0 commit comments

Comments
 (0)