Skip to content

Commit 7d1b0d4

Browse files
authored
Merge pull request #789 from metaxasa/fix-linestring-mvt
Fix LineString feature encoding to use all points and add tests for validation
2 parents 653e7a0 + 698f06a commit 7d1b0d4

File tree

2 files changed

+88
-7
lines changed

2 files changed

+88
-7
lines changed

internal/server/mvt.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,14 @@ func mvtAddFeature(l *mvt.Layer, tileX, tileY, tileZ int, o mvtObj) {
5858
f = l.AddFeature(mvt.LineString)
5959
line := g.Base()
6060
npoints := line.NumPoints()
61-
if npoints > 0 {
62-
p := line.PointAt(0)
63-
f.MoveTo(mvt.LatLonXY(p.Y, p.X, tileX, tileY, tileZ))
64-
for i := 1; i < npoints; i++ {
65-
p := line.PointAt(0)
66-
f.LineTo(mvt.LatLonXY(p.Y, p.X, tileX, tileY, tileZ))
67-
}
61+
if npoints < 2 {
62+
return
63+
}
64+
p := line.PointAt(0)
65+
f.MoveTo(mvt.LatLonXY(p.Y, p.X, tileX, tileY, tileZ))
66+
for i := 1; i < npoints; i++ {
67+
p := line.PointAt(i)
68+
f.LineTo(mvt.LatLonXY(p.Y, p.X, tileX, tileY, tileZ))
6869
}
6970
f.AddTag("type", "linestring")
7071
case *geojson.Rect:

internal/server/mvt_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package server
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
7+
"github.com/tidwall/geojson"
8+
"github.com/tidwall/geojson/geometry"
9+
"github.com/tidwall/mvt"
10+
)
11+
12+
func ls(points []geometry.Point) *geojson.LineString {
13+
return geojson.NewLineString(geometry.NewLine(points, nil))
14+
}
15+
16+
// Ensure that LineString features are encoded using
17+
// all points in the geometry, not just the first one.
18+
func TestMVTAddFeatureLineStringUsesAllPoints(t *testing.T) {
19+
tileX, tileY, tileZ := 0, 0, 0
20+
21+
line := ls([]geometry.Point{
22+
{X: 1, Y: 1},
23+
{X: 2, Y: 2},
24+
{X: 3, Y: 3},
25+
})
26+
id := "line"
27+
28+
actual := mvtRender(tileX, tileY, tileZ, []mvtObj{{id: id, obj: line}})
29+
30+
var tile mvt.Tile
31+
layer := tile.AddLayer("tile38")
32+
layer.SetExtent(4096)
33+
34+
f := layer.AddFeature(mvt.LineString)
35+
series := line.Base()
36+
npoints := series.NumPoints()
37+
if npoints < 2 {
38+
t.Fatalf("expected at least two points, got %d", npoints)
39+
}
40+
p := series.PointAt(0)
41+
x, y := mvt.LatLonXY(p.Y, p.X, tileX, tileY, tileZ)
42+
f.MoveTo(x, y)
43+
for i := 1; i < npoints; i++ {
44+
p = series.PointAt(i)
45+
x, y = mvt.LatLonXY(p.Y, p.X, tileX, tileY, tileZ)
46+
f.LineTo(x, y)
47+
}
48+
f.AddTag("type", "linestring")
49+
f.AddTag("id", id)
50+
51+
expected := tile.Render()
52+
53+
if !bytes.Equal(actual, expected) {
54+
t.Fatalf("mvtAddFeature LineString encoding mismatch")
55+
}
56+
}
57+
58+
// LineStrings with fewer than two points should not
59+
// produce any geometry commands.
60+
func TestMVTAddFeatureLineStringTooShort(t *testing.T) {
61+
tileX, tileY, tileZ := 0, 0, 0
62+
63+
line := ls([]geometry.Point{
64+
{X: 1, Y: 1},
65+
})
66+
67+
actual := mvtRender(tileX, tileY, tileZ, []mvtObj{{id: "short", obj: line}})
68+
69+
var tile mvt.Tile
70+
layer := tile.AddLayer("tile38")
71+
layer.SetExtent(4096)
72+
_ = layer.AddFeature(mvt.LineString)
73+
74+
expected := tile.Render()
75+
76+
if !bytes.Equal(actual, expected) {
77+
t.Fatalf("mvtAddFeature LineString with <2 points should not encode geometry")
78+
}
79+
}
80+

0 commit comments

Comments
 (0)