Skip to content

Commit

Permalink
Add support for non-Web-Mercator coordinate systems. "Real" mercator (#…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
pramsey committed Nov 10, 2020
1 parent b8face3 commit 390d563
Show file tree
Hide file tree
Showing 11 changed files with 434 additions and 81 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,37 @@ In general the defaults are fine, and the program autodetects things like the se
```toml
# Database connection
DbConnection = "user=you host=localhost dbname=yourdb"

# Close pooled connections after this interval
DbPoolMaxConnLifeTime = "1h"

# Hold no more than this number of connections in the database pool
DbPoolMaxConns = 4

# Look to read html templates from this directory
AssetsPath = "/usr/share/pg_tileserv/assets"

# Accept connections on this subnet (default accepts on all)
HttpHost = "0.0.0.0"

# Accept connections on this port
HttpPort = 7800
HttpsPort = 7801

# HTTPS configuration
# TLS server certificate full chain and private key
# If you do not specify both, the TLS server will not be started
TlsServerCertificateFile = "server.crt"
TlsServerPrivateKeyFile = "server.key"
```

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`:

```bash
openssl req -nodes -new -x509 -keyout server.key -out server.crt
```

```toml
# Advertise URLs relative to this server name
# default is to looke this up from incoming request headers
# UrlBase = "http://yourserver.com/"
Expand All @@ -88,11 +109,22 @@ MaxFeaturesPerTile = 10000
DefaultMinZoom = 0
# Advertise this maximum zoom level
DefaultMaxZoom = 22

# Allow any page to consume these tiles
CORSOrigins = ["*"]

# Output extra logging information?
Debug = false

# Default CS is Web Mercator (EPSG:3857)
[CoordinateSystem]
SRID = 3857
Xmin = -20037508.3427892
Ymin = -20037508.3427892
Xmax = 20037508.3427892
Ymax = 20037508.3427892
```
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.

# Operation

Expand Down
86 changes: 45 additions & 41 deletions bounds.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,74 +7,78 @@ import (

// Bounds represents a box in Web Mercator space
type Bounds struct {
SRID int `json:"srid"`
Xmin float64 `json:"xmin"`
Ymin float64 `json:"ymin"`
Xmax float64 `json:"xmax"`
Ymax float64 `json:"ymax"`
}

func (b *Bounds) String() string {
return fmt.Sprintf("{Xmin:%g, Ymin:%g, Xmax:%g, Ymax:%g}",
b.Xmin, b.Ymin, b.Xmax, b.Ymax)
return fmt.Sprintf("{Xmin:%g, Ymin:%g, Xmax:%g, Ymax:%g, SRID:%d}",
b.Xmin, b.Ymin, b.Xmax, b.Ymax, b.SRID)
}

// SQL returns the SQL fragment to create this bounds in the database
func (b *Bounds) SQL() string {
return fmt.Sprintf("ST_MakeEnvelope(%g, %g, %g, %g, 3857)",
return fmt.Sprintf("ST_MakeEnvelope(%g, %g, %g, %g, %d)",
b.Xmin, b.Ymin,
b.Xmax, b.Ymax)
b.Xmax, b.Ymax, b.SRID)
}

// Expand increases the size of this bounds in all directions, respecting
// the limits of the Web Mercator plane
func (b *Bounds) Expand(size float64) {
worldMin := -0.5 * worldMercWidth
worldMax := 0.5 * worldMercWidth
b.Xmin = math.Max(b.Xmin-size, worldMin)
b.Ymin = math.Max(b.Ymin-size, worldMin)
b.Xmax = math.Min(b.Xmax+size, worldMax)
b.Ymax = math.Min(b.Ymax+size, worldMax)
serverBounds, _ := getServerBounds()
b.Xmin = math.Max(b.Xmin-size, serverBounds.Xmin)
b.Ymin = math.Max(b.Ymin-size, serverBounds.Ymin)
b.Xmax = math.Min(b.Xmax+size, serverBounds.Xmax)
b.Ymax = math.Min(b.Ymax+size, serverBounds.Ymax)
return
}

// func fromMercator(x float64, y float64) (lng float64, lat float64) {
// // worldMercWidth is the width of the Web Mercator plane
// worldMercWidth := 40075016.6855784
// mercSize := worldMercWidth / 2.0
// lng = x * 180.0 / mercSize
// lat = 180.0 / math.Pi * (2.0*math.Atan(math.Exp((y/mercSize)*math.Pi)) - math.Pi/2.0)
// return lng, lat
// }

func (b *Bounds) sanitize() {
if b.Ymin < -90 {
b.Ymin = 90
}
if b.Ymax > 90 {
b.Ymax = 90
}
if b.Xmin < -180 {
b.Xmin = -180
}
if b.Xmax > 180 {
b.Xmax = 180
if b.SRID == 4326 {
if b.Ymin < -90 {
b.Ymin = 90
}
if b.Ymax > 90 {
b.Ymax = 90
}
if b.Xmin < -180 {
b.Xmin = -180
}
if b.Xmax > 180 {
b.Xmax = 180
}
}
return
}

func fromMercator(x float64, y float64) (lng float64, lat float64) {
mercSize := worldMercWidth / 2.0
lng = x * 180.0 / mercSize
lat = 180.0 / math.Pi * (2.0*math.Atan(math.Exp((y/mercSize)*math.Pi)) - math.Pi/2.0)
return lng, lat
}

// Json returns the bounds in array for form consumption
// by Json formats that like it that way
func (b *Bounds) Json() []float64 {
s := make([]float64, 4)
s[0], s[1] = fromMercator(b.Xmin, b.Ymin)
s[2], s[3] = fromMercator(b.Xmax, b.Ymax)
return s
}
// func (b *Bounds) Json() []float64 {
// s := make([]float64, 4)
// s[0], s[1] = fromMercator(b.Xmin, b.Ymin)
// s[2], s[3] = fromMercator(b.Xmax, b.Ymax)
// return s
// }

// Center returns the center of the bounds in array format
// for consumption by Json formats that like it that way
func (b *Bounds) Center() []float64 {
xc := (b.Xmin + b.Xmax) / 2.0
yc := (b.Ymin + b.Ymax) / 2.0
s := make([]float64, 2)
s[0], s[1] = fromMercator(xc, yc)
return s
}
// func (b *Bounds) Center() []float64 {
// xc := (b.Xmin + b.Xmax) / 2.0
// yc := (b.Ymin + b.Ymax) / 2.0
// s := make([]float64, 2)
// s[0], s[1] = fromMercator(xc, yc)
// return s
// }
17 changes: 17 additions & 0 deletions config/pg_tileserv.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,20 @@

# Output extra logging information?
# Debug = false

# Default CS is Web Mercator (EPSG:3857)
# [CoordinateSystem]
# SRID = 3857
# Xmin = -20037508.3427892
# Ymin = -20037508.3427892
# Xmax = 20037508.3427892
# Ymax = 20037508.3427892

# "True" Mercator (EPSG:3395) is only a little different
# [CoordinateSystem]
# SRID = 3395
# Xmin = -20037508.342789244
# Ymin = -20037508.342789244
# Xmax = 20037508.342789244
# Ymax = 20037508.342789244

19 changes: 10 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ module github.com/CrunchyData/pg_tileserv
go 1.13

require (
github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.7.3
github.com/jackc/pgconn v1.3.2
github.com/jackc/pgtype v1.0.2
github.com/jackc/pgx/v4 v4.1.2
github.com/pborman/getopt v0.0.0-20190409184431-ee0cd42419d3
github.com/sirupsen/logrus v1.4.2
github.com/spf13/viper v1.6.1
github.com/stretchr/testify v1.4.0
github.com/Masterminds/sprig/v3 v3.1.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/jackc/pgconn v1.7.2
github.com/jackc/pgtype v1.6.1
github.com/jackc/pgx/v4 v4.9.2
github.com/pborman/getopt/v2 v2.1.0
github.com/sirupsen/logrus v1.7.0
github.com/spf13/viper v1.7.1
github.com/stretchr/testify v1.6.1
github.com/theckman/httpforwarded v0.4.0
)
Loading

0 comments on commit 390d563

Please sign in to comment.