Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
gdey committed May 3, 2017
1 parent 576ece0 commit 73a38ae
Show file tree
Hide file tree
Showing 26 changed files with 1,258 additions and 41 deletions.
8 changes: 8 additions & 0 deletions basic/line.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ func (Line) basicType() {}
func (Line) String() string { return "Line" }
func (l Line) Direction() maths.WindingOrder { return maths.WindingOrderOfLine(l) }

func (l Line) AsPts() []maths.Pt {
var line []maths.Pt
for _, p := range l {
line = append(line, p.AsPt())
}
return line
}

// Contains tells you weather the given point is contained by the Linestring.
// This assumes the linestring is a connected linestring.
func (l Line) Contains(pt Point) bool {
Expand Down
3 changes: 3 additions & 0 deletions bounding_box.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ type BoundingBox struct {
Minx, Miny, Maxx, Maxy float64
// Epsilon is the tolerance for the simplification function.
Epsilon float64
// X,Y,Z are just for debug and display purposes.
X, Y, Z int
HasXYZ bool
}
2 changes: 1 addition & 1 deletion cmd/printwkb/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ func main() {
panic(fmt.Sprintf("Failed while creating connection pool: %v", err))
}
sql := fmt.Sprintf(
`SELECT ST_AsBinary("%v") AS "geometry" from %v WHERE "%[1]v" && ST_MakeEnvelope(%[3]v,%v,%v,%v,%v)`,
`SELECT ST_AsBinary("%v") AS "geometry" from "%v" WHERE "%[1]v" && ST_MakeEnvelope(%[3]v,%v,%v,%v,%v)`,
provider.geoField,
provider.table,
minPt.X(),
Expand Down
4 changes: 2 additions & 2 deletions maths/clip/clip.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ func LineString(line tegola.LineString, min, max maths.Pt, extant int) (ls []bas
emin := maths.Pt{min.X - float64(extant), min.Y - float64(extant)}
emax := maths.Pt{max.X + float64(extant), max.Y + float64(extant)}
r := region.New(maths.Clockwise, emin, emax)
// I don't think this makes sense for a unconnected pollygon
// I don't think this makes sense for a unconnected polygon
// Linestrings are not connected. So, for these we just need to walk each point and see if it's within the clipping rectangle.
// When we enter the clipping rectangle, we need to calculate the interaction point, and start a new line.
// When we leave the clipping rectangle, we need to calculated the interaction point, and stop the line.
Expand Down Expand Up @@ -672,7 +672,7 @@ func Polygon(polygon tegola.Polygon, min, max maths.Pt, extant int) (p []basic.P
}
func Geometry(geo tegola.Geometry, min, max maths.Pt) (basic.Geometry, error) {
// log.Println("Clipping Geometry")
var extant = 0
var extant = 2
switch g := geo.(type) {

case tegola.Point:
Expand Down
8 changes: 4 additions & 4 deletions maths/douglaspeucker.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package maths

func DouglasPeucker(points []Pt, tolerence float64) []Pt {
if tolerence <= 0 || len(points) <= 2 {
func DouglasPeucker(points []Pt, tolerence float64, simplify bool) []Pt {
if tolerence <= 0 || len(points) <= 2 || !simplify {
return points
}

Expand All @@ -19,8 +19,8 @@ func DouglasPeucker(points []Pt, tolerence float64) []Pt {
}
}
if dmax > epsilon {
rec1 := DouglasPeucker(points[0:idx], epsilon)
rec2 := DouglasPeucker(points[idx:len(points)-1], epsilon)
rec1 := DouglasPeucker(points[0:idx], epsilon, simplify)
rec2 := DouglasPeucker(points[idx:len(points)-1], epsilon, simplify)

newpts := append(rec1, rec2...)
return newpts
Expand Down
18 changes: 18 additions & 0 deletions maths/douglaspeucker_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package maths

import (
"testing"

"github.com/gdey/tbltest"
)

func TestDouglasPeucker(t *testing.T) {
type testcase struct {
line []Pt
simplify bool
tolerance float64
expectedLine []Pt
}
tests := tbltest.Cases()
tests.Run(nil)
}
112 changes: 80 additions & 32 deletions mvt/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,18 @@ var (
ErrNilGeometryType = fmt.Errorf("Nil geometry passed")
)

var EnableClipping = false

func init() {
if os.Getenv("TEGOLA_CLIPPING") == "mvt" {
log.Println("Clipping has been enabled.")
EnableClipping = true
}
}

// TODO: Need to put in validation for the Geometry, at current the system
// does not check to make sure that the geometry is following the rules as
// laided out by the spec. It just assumes the user is good.
// laid out by the spec. It just assumes the user is good.

// Feature describes a feature of a Layer. A layer will contain multiple features
// each of which has a geometry describing the interesting thing, and the metadata
Expand Down Expand Up @@ -272,7 +281,7 @@ Restart:
}

func bubbleSplitter(ls basic.Line) basic.MultiLine {
//return basic.MultiLine{ls}
return basic.MultiLine{ls}

seen := make(map[string][]int)
key := func(x, y float64) string {
Expand Down Expand Up @@ -308,6 +317,44 @@ func bubbleSplitter(ls basic.Line) basic.MultiLine {

}

func simplifyLineString(g tegola.LineString, tolerance float64) basic.Line {
line := basic.CloneLine(g)
if len(line) <= 4 || maths.DistOfLine(g) < tolerance {
return line
}
return basic.NewLineFromPt(maths.DouglasPeucker(line.AsPts(), tolerance, true)...)
}

func simplifyPolygon(g tegola.Polygon, tolerance float64) basic.Polygon {

lines := g.Sublines()
if len(lines) == 0 {
return nil
}

// HMMJ
sqTolerance := tolerance * tolerance

// First lets look the first line, then we will simplify the other lines.
area := maths.AreaOfPolygonLineString(lines[0])
if area < sqTolerance {
return basic.ClonePolygon(g)
}
var poly basic.Polygon
poly = append(poly, basic.NewLineFromPt(maths.DouglasPeucker(basic.CloneLine(lines[0]).AsPts(), sqTolerance, true)...))
for i := 1; i < len(lines); i++ {
area := maths.AreaOfPolygonLineString(lines[0])
l := basic.CloneLine(lines[i])
if area < sqTolerance {
// don't simplify the internal line
poly = append(poly, l)
continue
}
poly = append(poly, basic.NewLineFromPt(maths.DouglasPeucker(l.AsPts(), sqTolerance, true)...))
}
return poly
}

func (c *cursor) scalelinestr(g tegola.LineString, polygon bool) basic.MultiLine {

var ls basic.Line
Expand All @@ -324,8 +371,8 @@ func (c *cursor) scalelinestr(g tegola.LineString, polygon bool) basic.MultiLine
ls = append(ls, npt)
lpt = npt
}
var multiline basic.MultiLine
//return bubbleSplitter(ls)
// var multiline basic.MultiLine
return bubbleSplitter(ls)

//return bubbleSplitter(cleanLine(ls))
/*
Expand All @@ -343,38 +390,34 @@ func (c *cursor) scalelinestr(g tegola.LineString, polygon bool) basic.MultiLine
}
}
*/
lines := bubbleSplitter(cleanLine(ls))
for i := range lines {
ln := lines[i]
/*
lines := bubbleSplitter(cleanLine(ls))
for i := range lines {
simplify := true
if len(ln) <= 4 {
simplify = false
}
simplify := true
if len(lines[i]) <= 4 {
simplify = false
}
if polygon {
sqTolerance := c.tile.Epsilon * c.tile.Epsilon
area := maths.AreaOfPolygonLineString(ln)
simplify = simplify && area < sqTolerance
} else {
dist := maths.DistOfLine(ln)
simplify = simplify && dist < c.tile.Epsilon
}
if polygon {
sqTolerance := c.tile.Epsilon * c.tile.Epsilon
area := maths.AreaOfPolygonLineString(lines[i])
simplify = simplify && area < sqTolerance
} else {
dist := maths.DistOfLine(lines[i])
simplify = simplify && dist < c.tile.Epsilon
}
if !simplify {
multiline = append(multiline, ln)
continue
}
if !simplify {
multiline = append(multiline, lines[i])
continue
}
var line []maths.Pt
for _, p := range ln {
line = append(line, p.AsPt())
nls := basic.NewLineFromPt(maths.DouglasPeucker(lines[i].AsPts(), c.tile.Epsilon, simplify)...)
multiline = append(multiline, nls)
}

nls := basic.NewLineFromPt(maths.DouglasPeucker(line, c.tile.Epsilon)...)
multiline = append(multiline, nls)
}
return multiline
return multiline
*/

}

Expand Down Expand Up @@ -423,19 +466,24 @@ func (c *cursor) ScaleGeo(geo tegola.Geometry) basic.Geometry {
}
return mp
case tegola.LineString:
// return c.scalelinestr(simplifyLineString(g, c.tile.Epsilon), false)
return c.scalelinestr(g, false)
case tegola.MultiLine:
var ml basic.MultiLine
for _, l := range g.Lines() {
//ml = append(ml, c.scalelinestr(simplifyLineString(l, c.tile.Epsilon), false)...)
ml = append(ml, c.scalelinestr(l, false)...)
}
return ml
case tegola.Polygon:
//return c.scalePolygon(simplifyPolygon(g, c.tile.Epsilon))
return c.scalePolygon(g)

case tegola.MultiPolygon:
var mp basic.MultiPolygon
for _, p := range g.Polygons() {

// nmp := c.scalePolygon(simplifyPolygon(p, c.tile.Epsilon))
nmp := c.scalePolygon(p)
mp = append(mp, nmp...)
}
Expand Down Expand Up @@ -530,7 +578,7 @@ func encodeGeometry(geom tegola.Geometry, extent tegola.BoundingBox, layerExtent

geo := c.ScaleGeo(geom)

if os.Getenv("TEGOLA_CLIPPING") == "mvt" {
if EnableClipping {
geo, err = c.ClipGeo(geo)
if geo == nil {
return []uint32{}, -1, nil
Expand Down
5 changes: 5 additions & 0 deletions mvt/tile.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mvt

import (
"fmt"
"log"

"github.com/terranodo/tegola"
"github.com/terranodo/tegola/mvt/vector_tile"
Expand All @@ -17,6 +18,10 @@ func (t *Tile) AddLayers(layers ...*Layer) error {
// Need to make sure that all layer names are unique.
for i := range layers {
nl := layers[i]
if nl == nil {
log.Printf("Got a nil layer for %v", i)
continue
}
for i, l := range t.layers {
if l.Name == nl.Name {
return fmt.Errorf("Layer %v, already is named %v, new layer not added.", i, l.Name)
Expand Down
11 changes: 10 additions & 1 deletion provider/postgis/postgis.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,8 @@ func (p Provider) MVTLayer(layerName string, tile tegola.Tile, tags map[string]i
}
case plyr.IDFieldName:
switch aval := v.(type) {
case float64:
gid = uint64(aval)
case int64:
gid = uint64(aval)
case uint64:
Expand All @@ -446,8 +448,15 @@ func (p Provider) MVTLayer(layerName string, tile tegola.Tile, tags map[string]i
gid = uint64(aval)
case uint32:
gid = uint64(aval)
case string:
var err error
gid, err = strconv.ParseUint(aval, 10, 64)
if err != nil {
return nil, err
}

default:
return nil, fmt.Errorf("Unable to convert geometry ID field (%v) into a uint64 for layer (%v)", plyr.IDFieldName, layerName)
return nil, fmt.Errorf("Unable to convert geometry ID field (%v [%T]) into a uint64 for layer (%v)", plyr.IDFieldName, v, layerName)
}
default:
if vals[i] == nil {
Expand Down
11 changes: 11 additions & 0 deletions server/handle_map_layer_zxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"strings"
"sync"

"time"

"github.com/dimfeld/httptreemux"
"github.com/golang/protobuf/proto"
"github.com/terranodo/tegola"
Expand Down Expand Up @@ -188,13 +190,22 @@ func (req HandleMapLayerZXY) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}

// generate our vector tile
start := time.Now()
vtile, err := mvtTile.VTile(tile.BoundingBox())
if err != nil {
elapsed := time.Since(start)
if DisplayTiming {
log.Printf("Generate with error tile for maps/%v/%v/%v/%v/%v [%s]", req.mapName, req.layerName, tile.Z, tile.X, tile.Y, elapsed)
}
errMsg := fmt.Sprintf("Error Getting VTile: %v", err.Error())
log.Println(errMsg)
http.Error(w, errMsg, http.StatusBadRequest)
return
}
elapsed := time.Since(start)
if DisplayTiming {
log.Printf("Generate tile for maps/%v/%v/%v/%v/%v [%s]", req.mapName, req.layerName, tile.Z, tile.X, tile.Y, elapsed)
}

// marshal our tile into a protocol buffer
var pbyte []byte
Expand Down
Loading

0 comments on commit 73a38ae

Please sign in to comment.