diff --git a/.travis.yml b/.travis.yml index 7ccfdad9..a7ceeb42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,15 +7,15 @@ git: matrix: include: + - go: "1.13.x" + env: CGO_ENABLED=0 - go: "1.12.x" env: CGO_ENABLED=0 - go: "1.11.x" env: CGO_ENABLED=0 - - go: "1.10.x" - env: CGO_ENABLED=0 + - go: "1.13.x" - go: "1.12.x" - go: "1.11.x" - - go: "1.10.x" script: - bash ci/go_test_multi_package_coverprofile.sh --coveralls diff --git a/cmd/.gitignore b/cmd/.gitignore new file mode 100644 index 00000000..be1c5a42 --- /dev/null +++ b/cmd/.gitignore @@ -0,0 +1 @@ +_output diff --git a/cmd/README.md b/cmd/README.md new file mode 100644 index 00000000..5873ef37 --- /dev/null +++ b/cmd/README.md @@ -0,0 +1,16 @@ +A small utility to break down a given wkt and z/x/y into various parts for the makevalid algo. + +This tool is very much a work in progress. + +#Quick Start: + +``` +$ cmd z/x/y input.wkt +``` + +Options: + +* simplify [true] -- simplify the geom +* tag -- create an additional directory for the output files +* buffer [64] -- buffer to expand the tile boundry by +* extent [4096] -- the extent of mvt tile. diff --git a/cmd/main.go b/cmd/main.go new file mode 100644 index 00000000..b226142d --- /dev/null +++ b/cmd/main.go @@ -0,0 +1,310 @@ +package main + +import ( + "context" + "flag" + "fmt" + "log" + "math" + "os" + "strconv" + "strings" + + "github.com/go-spatial/geom/winding" + + "github.com/go-spatial/geom/planar/clip" + + "github.com/go-spatial/geom/cmp" + "github.com/go-spatial/geom/planar" + + "github.com/go-spatial/geom/planar/makevalid" + "github.com/go-spatial/geom/planar/makevalid/hitmap" + "github.com/go-spatial/geom/planar/makevalid/walker" + "github.com/go-spatial/geom/planar/simplify" + "github.com/go-spatial/geom/planar/triangulate/delaunay" + + "github.com/go-spatial/geom" + "github.com/go-spatial/geom/encoding/mvt" + "github.com/go-spatial/geom/encoding/wkt" + "github.com/go-spatial/geom/slippy" +) + +var simplifyGeo = flag.Bool("simplify", true, "simplify the wkt before running makevalid") +var tag = flag.String("tag", "", "place in an additional directory") +var buffer = flag.Int("buffer", 64, "Buffer to place around the tile") +var help = flag.Bool("help", false, "print this message") +var mvtExtent = flag.Float64("extent", 4096, "extent of the mvt tile") + +func usage() { + fmt.Fprintf( + os.Stderr, + "%v takes input wkt file and z/x/y slippy tile and outputs triangles that make up the location\nusage %[1]v\n\t$ %[1]v [options] z/x/y input.wkt \noptions:\n", + os.Args[0], + ) + flag.PrintDefaults() + os.Exit(1) +} + +func readInputWKT(filename string) (geom.Geometry, error) { + file, err := os.Open(filename) + if err != nil { + return nil, err + } + defer file.Close() + return wkt.Decode(file) +} + +type outfile struct { + tile *slippy.Tile + format string +} +type outfilefile struct { + tag string + *os.File +} + +func (of outfile) NewFile(item string) *outfilefile { + f, err := os.Create(fmt.Sprintf(of.format, item)) + if err != nil { + fmt.Fprintf(os.Stderr, "unable to open %v file: %v", item, err) + os.Exit(2) + } + return &outfilefile{File: f, tag: item} +} + +func (off *outfilefile) WriteWKTGeom(geos ...geom.Geometry) *outfilefile { + for _, g := range geos { + if err := wkt.Encode(off, g); err != nil { + log.Printf("failed to encode geo: %v: %v", off.tag, err) + return off + } + off.WriteString("\n") + } + return off +} + +func newOutFile(tile *slippy.Tile, tag string) outfile { + path := fmt.Sprintf("%v/%v/%v", tile.Z, tile.X, tile.Y) + if tag != "" { + path = fmt.Sprintf("%v/%v", path, tag) + } + + os.MkdirAll(path, os.ModePerm) + return outfile{ + tile: tile, + format: fmt.Sprintf("%v/%%v.wkt", path), + } +} + +func main() { + flag.Parse() + if len(flag.Args()) < 2 || *help { + usage() + } + if *help { + usage() + return + } + parts := strings.Split(flag.Args()[0], "/") + if len(parts) < 3 { + fmt.Fprintf(os.Stderr, "invalid first parameters expected slippy tile\n Got %v\n", flag.Args()[1]) + usage() + } + + z, err := strconv.ParseUint(parts[0], 10, 64) + if err != nil { + fmt.Fprintf(os.Stderr, "Unabled to parse z: %v", err) + usage() + } + x, err := strconv.ParseUint(parts[1], 10, 64) + if err != nil { + fmt.Fprintf(os.Stderr, "Unabled to parse x: %v", err) + usage() + } + y, err := strconv.ParseUint(parts[2], 10, 64) + if err != nil { + fmt.Fprintf(os.Stderr, "Unabled to parse y: %v", err) + usage() + } + tile := slippy.NewTile(uint(z), uint(x), uint(y)) + fileTemplate := newOutFile(tile, *tag) + geo, err := readInputWKT(flag.Args()[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "Unabled to parse/open `%v` : %v", os.Args, err) + usage() + } + ctx := context.Background() + /* + plywkt, err := wkt.EncodeString(geo) + if err != nil { + panic(err) + } + fmt.Printf("Polygon:\n%v\n", plywkt) + */ + order := winding.Order{} + + var clipRegion *geom.Extent + { + webs := slippy.Pixels2Webs(tile.Z, uint(*buffer)) + clipRegion = tile.Extent3857().ExpandBy(webs) + } + + if *simplifyGeo { + simp := simplify.DouglasPeucker{ + Tolerance: slippy.Pixels2Webs(tile.Z, 10.0), + } + + var err error + geo, err = planar.Simplify(ctx, simp, geo) + if err != nil { + fmt.Fprintf(os.Stderr, "Unabled to simplify geo : %v", err) + usage() + } + sgeofile := fileTemplate.NewFile("simplified_geo") + sgeofile.WriteWKTGeom(geo) + sgeofile.Close() + } + + var hm planar.HitMapper + { + hm, err = hitmap.New(clipRegion, geo) + if err != nil { + fmt.Fprintf(os.Stderr, "Unabled to create hm for geo : %v", err) + usage() + } + } + + { + mv := makevalid.Makevalid{ + Hitmap: hm, + Clipper: clip.Default, + Order: order, + } + + mkvgeo, _, err := mv.Makevalid(ctx, geo, clipRegion) + if err != nil { + log.Printf("Got error using original makevalid: %v", err) + + } else { + mvgeoFile := fileTemplate.NewFile("original_makevalid") + mvgeoFile.WriteWKTGeom(mkvgeo) + mvgeoFile.Close() + if mvtgeo := mvt.PrepareGeo(mkvgeo, tile.Extent3857(), *mvtExtent); mvtgeo != nil { + mvtgeof := fileTemplate.NewFile("original_mvt_geo") + mvtgeof.WriteWKTGeom(mvtgeo) + mvtgeof.Close() + } + } + } + + var mp geom.MultiPolygon + switch g := geo.(type) { + case geom.MultiPolygon: + mp = g + case *geom.MultiPolygon: + if g == nil { + return + } + mp = *g + case geom.Polygon: + mp = geom.MultiPolygon{g} + case *geom.Polygon: + if g == nil { + return + } + mp = geom.MultiPolygon{*g} + default: + fmt.Fprintf(os.Stderr, "Unsupported geometry type: %t", geo) + usage() + } + + segs, err := makevalid.Destructure(context.Background(), cmp.HiCMP, clipRegion, &mp) + if err != nil { + log.Printf("Destructure returned err %v", err) + return + } + if len(segs) == 0 { + log.Printf("Step 1a: Segments are zero.") + return + } + triangulator := delaunay.GeomConstrained{ + Constraints: segs, + } + allTriangles, err := triangulator.Triangles(ctx, false) + if err != nil { + log.Printf("triangulator returned err %v", err) + return + } + + sofile := fileTemplate.NewFile("outside_triangles_makevalid_steps") + sifile := fileTemplate.NewFile("inside_triangles_makevalid_steps") + defer sofile.Close() + defer sifile.Close() + + sifile.WriteWKTGeom(clipRegion) + sofile.WriteWKTGeom(clipRegion) + + var outsideTriangles, insideTriangles []geom.Triangle + { + inTrisFile := fileTemplate.NewFile("inside_triangles") + outTrisFile := fileTemplate.NewFile("outside_triangles") + fmt.Printf("Tagging triangles: %v\n#", len(allTriangles)) + numTri := len(allTriangles) + size := int(math.Log10(float64(numTri))) + + for i := range allTriangles { + center := allTriangles[i].Center() + lbl := hm.LabelFor(center) + if lbl == planar.Outside { + sofile.WriteWKTGeom(center, allTriangles[i]) + outTrisFile.WriteWKTGeom(allTriangles[i]) + outsideTriangles = append(outsideTriangles, allTriangles[i]) + fmt.Printf("\rTagging triangle: % *d of %d as outside", size+1, i+1, numTri) + continue + } + sifile.WriteWKTGeom(center, allTriangles[i]) + inTrisFile.WriteWKTGeom(allTriangles[i]) + insideTriangles = append(insideTriangles, allTriangles[i]) + fmt.Printf("\rTagging triangle: % *d of %d as inside", size+1, i+1, numTri) + } + inTrisFile.Close() + outTrisFile.Close() + } + + ringFile := fileTemplate.NewFile("ring_from_inside_triangles") + polygonFile := fileTemplate.NewFile("polygon_from_ring") + + var newMp geom.MultiPolygon + triWalker := walker.New(insideTriangles) + seen := make(map[int]bool, len(insideTriangles)) + for i := range insideTriangles { + if seen[i] { + continue + } + seen[i] = true + ring := triWalker.RingForTriangle(ctx, i, seen) + ringFile.WriteWKTGeom(geom.LineString(ring)) + ply := order.RectifyPolygon(walker.PolygonForRing(ctx, ring)) + polygonFile.WriteWKTGeom(geom.Polygon(ply)) + newMp = append(newMp, ply) + } + ringFile.Close() + polygonFile.Close() + + { + mvtgeo := mvt.PrepareGeo(newMp, tile.Extent3857(), *mvtExtent) + if mvtgeo != nil { + mvtgeof := fileTemplate.NewFile("mvt_geo") + mvtgeof.WriteWKTGeom(mvtgeo) + mvtgeof.Close() + } + } + + /* + triangles, err := makevalid.InsideTrianglesForMultiPolygon(context.Background(), extent, &mp, hm) + if err != nil { + fmt.Fprintf(os.Stderr, "unable to get triangles", err) + os.Exit(1) + } + */ +} diff --git a/encoding/mvt/feature.go b/encoding/mvt/feature.go index 87fce79e..0f0acbe7 100644 --- a/encoding/mvt/feature.go +++ b/encoding/mvt/feature.go @@ -8,6 +8,7 @@ import ( "github.com/go-spatial/geom" vectorTile "github.com/go-spatial/geom/encoding/mvt/vector_tile" "github.com/go-spatial/geom/encoding/wkt" + "github.com/go-spatial/geom/winding" ) var ( @@ -147,20 +148,29 @@ func NewCursor() *cursor { return &cursor{} } -// GetDeltaPointAndUpdate assumes the Point is in WebMercator. +// GetDeltaPointAndUpdate returns the delta of for the given point from the current +// cursor position func (c *cursor) GetDeltaPointAndUpdate(p geom.Point) (dx, dy int64) { - var ix, iy int64 - var tx, ty = p.X(), p.Y() - - ix, iy = int64(tx), int64(ty) - // compute our point delta - dx = ix - int64(c.x) - dy = iy - int64(c.y) - - // update our cursor - c.x = ix - c.y = iy - return dx, dy + delta := c.moveCursorPoints([2]int64{int64(p.X()), int64(p.Y())}) + return delta[0][0], delta[0][1] +} + +func (c *cursor) moveCursorPoints(pts ...[2]int64) (deltas [][2]int64) { + deltas = make([][2]int64, len(pts)) + for i := range pts { + deltas[i][0] = pts[i][0] - c.x + deltas[i][1] = pts[i][1] - c.y + c.x, c.y = pts[i][0], pts[i][1] + } + return deltas +} + +func (c *cursor) encodeZigZagPt(pts [][2]int64) []uint32 { + g := make([]uint32, 0, (2 * len(pts))) + for _, dp := range pts { + g = append(g, encodeZigZag(dp[0]), encodeZigZag(dp[1])) + } + return g } func (c *cursor) encodeCmd(cmd uint32, points [][2]float64) []uint32 { @@ -182,6 +192,81 @@ func (c *cursor) encodeCmd(cmd uint32, points [][2]float64) []uint32 { return g } +func (c *cursor) encodeLinearRing(order winding.Order, wo winding.Winding, ring [][2]float64) []uint32 { + + iring := make([][2]int64, len(ring)) + for i := range iring { + // the process of truncating the float can cause the winding order to flip! + iring[i][0], iring[i][1] = int64(ring[i][0]), int64(ring[i][1]) + } + ringWinding := order.OfInt64Points(iring...) + + if ringWinding.IsColinear() { + return []uint32{} + } + + if ringWinding != wo { + if debug { + log.Printf("(0) RING WKT:\n%v", wkt.MustEncode(geom.LineString(ring))) + log.Printf("(1) winding order: \n\tpts: %v\n\two : %v", ringWinding, wo) + } + // need to reverse the points in the ring + for i := len(iring)/2 - 1; i >= 0; i-- { + opp := len(iring) - 1 - i + iring[i], iring[opp] = iring[opp], iring[i] + } + if debug { + log.Printf("(2) RING WKT:\n%v", wkt.MustEncode(geom.LineString(ring))) + log.Printf("(2) winding order: \n\tpts: %v\n\two : %v", ringWinding, wo) + } + } + + deltas := c.moveCursorPoints(iring...) + + // 3 is for the three commands that it takes to describe a ring: move to, line to, and close + g := make([]uint32, 0, (2*len(iring))+3) + + // move to first point + g = append(g, + uint32(NewCommand(cmdMoveTo, 1)), + encodeZigZag(deltas[0][0]), + encodeZigZag(deltas[0][1]), + ) + + // line to each of the other points + g = append(g, uint32(NewCommand(cmdLineTo, len(deltas)-1))) + g = append(g, c.encodeZigZagPt(deltas[1:])...) + + // Close path + g = append(g, uint32(NewCommand(cmdClosePath, 1))) + + return g +} + +func (c *cursor) encodePolygon(geo geom.Polygon) []uint32 { + var ( + order winding.Order + g []uint32 + ) + lines := geo.LinearRings() + for i := range lines { + // bail if number of points is less then or equal two + if len(lines[i]) <= 2 { + if i != 0 { + continue + } + return g + } + // when we flip the y our rotation gets inverted + wo := winding.CounterClockwise + if i == 0 { + wo = winding.Clockwise + } + g = append(g, c.encodeLinearRing(order, wo, lines[i])...) + } + return g +} + // MoveTo encodes a move to command for the given points func (c *cursor) MoveTo(points ...[2]float64) []uint32 { return c.encodeCmd(uint32(NewCommand(cmdMoveTo, len(points))), points) @@ -231,26 +316,13 @@ func encodeGeometry(ctx context.Context, geometry geom.Geometry) (g []uint32, vt return g, vectorTile.Tile_LINESTRING, nil case geom.Polygon: - // TODO: Right now c.ScaleGeo() never returns a Polygon, so this is dead code. - lines := t.LinearRings() - for _, l := range lines { - points := geom.LineString(l).Verticies() - g = append(g, c.MoveTo(points[0])...) - g = append(g, c.LineTo(points[1:]...)...) - g = append(g, c.ClosePath()) - } + g = append(g, c.encodePolygon(t)...) return g, vectorTile.Tile_POLYGON, nil case geom.MultiPolygon: polygons := t.Polygons() for _, p := range polygons { - lines := geom.Polygon(p).LinearRings() - for _, l := range lines { - points := geom.LineString(l).Verticies() - g = append(g, c.MoveTo(points[0])...) - g = append(g, c.LineTo(points[1:]...)...) - g = append(g, c.ClosePath()) - } + g = append(g, c.encodePolygon(p)...) } return g, vectorTile.Tile_POLYGON, nil @@ -261,13 +333,7 @@ func encodeGeometry(ctx context.Context, geometry geom.Geometry) (g []uint32, vt polygons := t.Polygons() for _, p := range polygons { - lines := geom.Polygon(p).LinearRings() - for _, l := range lines { - points := geom.LineString(l).Verticies() - g = append(g, c.MoveTo(points[0])...) - g = append(g, c.LineTo(points[1:]...)...) - g = append(g, c.ClosePath()) - } + g = append(g, c.encodePolygon(p)...) } return g, vectorTile.Tile_POLYGON, nil diff --git a/encoding/mvt/feature_test.go b/encoding/mvt/feature_test.go new file mode 100644 index 00000000..a5499ca9 --- /dev/null +++ b/encoding/mvt/feature_test.go @@ -0,0 +1,104 @@ +package mvt + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "math" + "os" + "path/filepath" + "testing" + + "github.com/go-spatial/geom/testing/must" + + "github.com/go-spatial/geom" + "github.com/go-spatial/geom/encoding/wkt" +) + +var dumpSolution = flag.Bool("dump.solution", false, "Dump the solution to the test") + +func TestEncodePolygon(t *testing.T) { + type tcase struct { + x, y int64 + Polygon geom.Polygon + g []uint32 + } + fn := func(tc tcase) func(*testing.T) { + return func(t *testing.T) { + c := cursor{ + x: tc.x, + y: tc.y, + } + g := c.encodePolygon(tc.Polygon) + if len(g) != len(tc.g) { + t.Errorf("g length, expected %v, got %v", len(tc.g), len(g)) + if *dumpSolution { + dumpFilename := filepath.Join("testdata", "dump", t.Name()+".json") + dumpDir := filepath.Dir(dumpFilename) + os.MkdirAll(dumpDir, os.ModePerm) + t.Logf("dumping got to %v", dumpFilename) + f, err := os.Create(dumpFilename) + if err != nil { + t.Logf("unable to create dumpfile: %v", err) + return + } + bytes, err := json.Marshal(g) + if err != nil { + t.Logf("failed to marshal to json: %v", err) + } + _, err = f.Write(bytes) + if err != nil { + t.Logf("failed to write to dumpfile: %v", err) + } + } + return + } + for i := range tc.g { + // calculate the amount of padding needed to format the numbers + gl := int(math.Log10(float64(g[i]))) + 1 + tcl := int(math.Log10(float64(tc.g[i]))) + 1 + if gl < tcl { + gl = tcl + } + if tc.g[i] != g[i] { + t.Errorf("value not correct for %d, expected %0*d got %0*d", i, gl, tc.g[i], gl, g[i]) + } + } + } + } + + tests := map[string]tcase{} + + testForFile := func(file string) { + + var sol []uint32 + filename := filepath.Join("testdata", file) + f, err := ioutil.ReadFile(filename + ".wkt") + if err != nil { + panic(fmt.Sprintf("error opening file (%v.wkt): %v", filename, err)) + } + poly := must.AsPolygon(must.Decode(wkt.DecodeBytes(f))) + + if info, err := os.Stat(filename + ".json"); !(os.IsNotExist(err) || info.IsDir()) { + f, err = ioutil.ReadFile(filename + ".json") + if err != nil { + panic(fmt.Sprintf("error opening file (%v.json): %v", filename, err)) + } + if err = json.Unmarshal(f, &sol); err != nil { + panic(fmt.Sprintf("error un-marshaling file (%v.json): %v", filename, err)) + } + } + + tests[file] = tcase{ + Polygon: poly, + g: sol, + } + } + for _, file := range []string{"florida_keys"} { + testForFile(file) + } + for name, tc := range tests { + t.Run(name, fn(tc)) + } +} diff --git a/encoding/mvt/prepare.go b/encoding/mvt/prepare.go index bd9f7b81..ab970bf6 100644 --- a/encoding/mvt/prepare.go +++ b/encoding/mvt/prepare.go @@ -3,6 +3,10 @@ package mvt import ( "log" + "github.com/go-spatial/geom/cmp" + + "github.com/go-spatial/geom/winding" + "github.com/go-spatial/geom" ) @@ -86,13 +90,22 @@ func preparelinestr(g geom.LineString, tile *geom.Extent, pixelExtent float64) ( pts := g // If the linestring if len(pts) < 2 { - // Not enought points to make a line. + // Not enough points to make a line. return nil } - ls = make(geom.LineString, len(pts)) + ls = make(geom.LineString, 0, len(pts)) for i := 0; i < len(pts); i++ { - ls[i] = preparept(pts[i], tile, pixelExtent) + npt := preparept(pts[i], tile, pixelExtent) + + if i != 0 && cmp.HiCMP.GeomPointEqual(ls[len(ls)-1], npt) { + // skip points that are equivalent due to precision truncation + continue + } + ls = append(ls, preparept(pts[i], tile, pixelExtent)) + } + if len(ls) < 2 { + return nil } return ls @@ -107,17 +120,31 @@ func preparePolygon(g geom.Polygon, tile *geom.Extent, pixelExtent float64) (p g } for _, line := range lines.LineStrings() { + + if len(line) < 2 { + if debug { + // skip lines that have been reduced to less than 2 points. + log.Println("skipping line 2", line, len(line)) + } + continue + } ln := preparelinestr(line, tile, pixelExtent) + if cmp.HiCMP.GeomPointEqual(ln[0], ln[len(ln)-1]) { + // first and last is the same, need to remove the last point. + ln = ln[:len(ln)-1] + } if len(ln) < 2 { if debug { - // skip lines that have been reduced to less then 2 points. + // skip lines that have been reduced to less than 2 points. log.Println("skipping line 2", line, len(ln)) } continue } - // TODO: check the last and first point to make sure - // they are not the same, per the mvt spec p = append(p, ln) } - return p + + order := winding.Order{ + YPositiveDown: false, + } + return geom.Polygon(order.RectifyPolygon([][][2]float64(p))) } diff --git a/encoding/mvt/prepare_internal_test.go b/encoding/mvt/prepare_internal_test.go index 859cf41d..cfc5e6bd 100644 --- a/encoding/mvt/prepare_internal_test.go +++ b/encoding/mvt/prepare_internal_test.go @@ -10,8 +10,8 @@ import ( func TestPrepareLinestring(t *testing.T) { type tcase struct { - in geom.LineString - out geom.LineString + in geom.LineString + out geom.LineString tile geom.Extent } @@ -33,28 +33,38 @@ func TestPrepareLinestring(t *testing.T) { tests := map[string]tcase{ "duplicate pt simple line": { - in: geom.LineString{{9.0, 4090.0}, {9.0, 4090.0}}, - out: geom.LineString{{9.0, 6.0}, {9.0, 6.0}}, + in: geom.LineString{{9.0, 4090.0}, {9.0, 4090.0}}, + out: geom.LineString{}, + tile: geom.Extent{0.0, 0.0, 4096.0, 4096.0}, + }, + "triplicate pt simple line": { + in: geom.LineString{{9.0, 4090.0}, {9.0, 4090.0}, {9.0, 4090.0}}, + out: geom.LineString{}, + tile: geom.Extent{0.0, 0.0, 4096.0, 4096.0}, + }, + "triplicate pt simple line1": { + in: geom.LineString{{9.0, 4090.0}, {9.0, 4090.0}, {9.0, 4090.0}, {11.0, 4091.0}}, + out: geom.LineString{{9.0, 6.0}, {11.0, 5.0}}, tile: geom.Extent{0.0, 0.0, 4096.0, 4096.0}, }, "simple line": { - in: geom.LineString{{9.0, 4090.0}, {11.0, 4091.0}}, - out: geom.LineString{{9.0, 6.0}, {11.0, 5.0}}, + in: geom.LineString{{9.0, 4090.0}, {11.0, 4091.0}}, + out: geom.LineString{{9.0, 6.0}, {11.0, 5.0}}, tile: geom.Extent{0.0, 0.0, 4096.0, 4096.0}, }, "edge line": { - in: geom.LineString{{0.0, 0.0}, {4096.0, 20.0}}, - out: geom.LineString{{0.0, 4096.0}, {4096.0, 4076.0}}, + in: geom.LineString{{0.0, 0.0}, {4096.0, 20.0}}, + out: geom.LineString{{0.0, 4096.0}, {4096.0, 4076.0}}, tile: geom.Extent{0.0, 0.0, 4096.0, 4096.0}, }, "simple line 3pt": { - in: geom.LineString{{9.0, 4090.0}, {11.0, 4090.0}, {11.0, 4076.0}}, - out: geom.LineString{{9.0, 6.0}, {11.0, 6.0}, {11.0, 20.0}}, + in: geom.LineString{{9.0, 4090.0}, {11.0, 4090.0}, {11.0, 4076.0}}, + out: geom.LineString{{9.0, 6.0}, {11.0, 6.0}, {11.0, 20.0}}, tile: geom.Extent{0.0, 0.0, 4096.0, 4096.0}, }, - "scale" : { - in: geom.LineString{{100.0, 100.0}, {300.0, 300.0}}, - out: geom.LineString{{1024.0, 3072.0}, {3072.0, 1024.0}}, + "scale": { + in: geom.LineString{{100.0, 100.0}, {300.0, 300.0}}, + out: geom.LineString{{1024.0, 3072.0}, {3072.0, 1024.0}}, tile: geom.Extent{0.0, 0.0, 400.0, 400.0}, }, } diff --git a/encoding/mvt/testdata/florida_keys.json b/encoding/mvt/testdata/florida_keys.json new file mode 100644 index 00000000..90d8eb5c --- /dev/null +++ b/encoding/mvt/testdata/florida_keys.json @@ -0,0 +1 @@ +[9,17550335,5116426,1698,10426,548,1142,2419,4248,14015,806,608,2094,1038,2228,3115,2066,1920,3442,7630,2843,4046,1521,1548,1847,1116,0,1646,6612,889,7112,7201,24324,8657,3126,2211,1902,3075,4430,3797,5110,3465,3894,2055,5318,1613,13398,2299,4096,626,99,1615,218,3345,117,1615,2292,1136,878,656,1504,2397,2084,4597,1612,2103,2012,1525,3986,2083,1730,1467,1730,957,2192,39,2328,236,2112,137,7610,3119,3460,967,11034,821,1938,1025,436,2377,180,2727,1178,2063,1840,467,5706,68,733,361,731,899,2336,2199,2764,1063,2880,665,2364,829,444,147,3290,1154,2110,2287,2954,6313,4238,4045,1214,1631,1468,4387,4004,7103,1786,2313,2636,937,2682,1895,10226,10555,762,1981,3778,6971,1548,1697,2674,400,1268,2402,4856,6970,1422,2547,1930,2313,2554,2411,1938,915,5472,58,2400,1601,930,2043,45730,0,3273,2826,2355,3710,1521,410,3079,1503,1894,4100,3542,4316,4068,2774,3478,545,7746,6561,832,1963,1424,6061,788,1267,312,229,994984,0,0,118038,2769,1461,5381,1055,2353,518,1485,1126,1105,1118,1195,528,8423,1792,3841,1040,2137,1576,508,2284,4086,3174,1277,1704,89,1118,1368,2410,1040,3116,387,2588,44,2186,2348,1970,3812,5057,1894,1213,3398,461,17,500,1286,1088,1794,1128,1522,578,1576,127,3316,1107,1856,263,624,231,0,1152884,1291479,0,0,130193,464,295,6622,9147,4416,824,3528,544,7174,3115,5314,71,5024,2352,4558,3224,3058,1412,2612,1620,1738,1154,830,2014,2814,2290,578,3114,3246,2746,2726,5608,4132,2768,513,2644,5357,3346,9257,1694,1540,3236,6070,6968,1304,3076,1720,10544,4240,3055,3914,4921,2880,5367,1134,4441,4210,2545,18356,7269,4620,1228,10264,2547,11350,1993,7324,257,3000,4508,4604,2334,6956,3151,4240,781,7924,3300,10710,1513,7062,2192,7084,3216,4512,638,14132,244,3424,1460,2102,2780,1514,3216,1982,2750,3506,1480,518,4625,1115,5081,605,5121,3976,8811,174,4775,1867,4013,4121,1763,1601,640,3769,3252,2081,1218,2863,506,14547,831,13263,3079,30583,6161,12395,5,46759,12009,4021,667,4157,1337,6749,5833,4365,1335,3905,2603,4751,2395,3889,2799,2077,1757,4663,411,2095,1049,9091,880,8875,3150,5397,5372,9677,5962,741,766,0,993617,418,751,1740,3363,977,813,1179,340,0,21529,15,9,77114,1073226,122,1738,1785,272,224,246,1086,606,1116,860,578,708,901,180,1521,523,731,99,395,254,789,633,375,969,283,1521,29,1693,1938,307,1968,15,9,34280,1107493,98,3850,3838,4412,616,72,1349,2509,3611,913,2623,2581,3111,1413,361,1142,812,726,1076,579,1008,2101,382,443,1596,15,9,55614,10999,138,834,1143,1658,1231,1620,1155,1378,1153,515,879,1160,145,444,644,18,598,480,68,598,304,381,2143,2155,791,2227,1340,1937,1508,543,2112,915,1380,189,822,15,9,79052,70285,90,706,271,588,1239,898,967,770,70,706,350,190,1541,72,643,959,643,487,341,4511,2606,235,1816,15,9,24187,16134,66,2446,1054,5980,975,3586,77,1973,2489,7119,1289,1539,2051,308,4275,2907,7734,15,9,611876,456628,50,1840,356,660,1109,64,2653,1095,3109,1495,859,1385,3862,15,9,41194,33249,154,3460,1682,5128,1278,11206,3314,8316,109,2836,1245,4990,3621,2235,3787,1431,3095,2245,1769,4711,216,0,1521,1386,1849,4011,59,5345,1722,2681,3510,4021,1847,7355,69,3949,1403,831,5568,15,9,425637,451148,82,2792,580,3488,1354,2444,194,1918,773,347,1353,4013,1739,4359,0,2791,2125,2441,385,173,1932,15,9,229995,25525,114,1306,1114,1694,792,1358,120,2554,219,3498,240,2636,1624,1712,2248,616,109,1185,2779,2201,2585,2689,1193,3423,9,1983,220,4077,80,15,9,79196,91317,194,5308,4020,5046,2190,3262,570,7528,2790,3388,380,9522,379,9448,1742,3480,59,3098,1101,5344,3249,8516,1969,2427,2949,23327,10947,5379,150,7111,3130,1285,2049,2555,2927,3097,1869,2933,1070,3369,1958,4311,450,4113,109,2789,290,3649,4170,15,9,54291,678229,42,3470,4021,4030,3697,3190,4265,5345,137,5651,5960,15,9,10907,26428,66,4874,3985,3514,5951,2828,10325,9203,7722,1666,3230,2471,3624,3959,3112,2717,1686,15,9,13895,9517,90,814,980,980,9,1658,997,1638,58,1632,1038,996,127,651,997,3551,3591,1593,891,0,1224,2155,2378,15,9,1550,21250,114,1340,351,3306,3663,1306,871,1810,2105,1442,2701,435,1849,1511,177,1005,1078,163,1890,433,980,3069,2408,671,1108,2009,2222,553,1038,15,9,54869,25300,170,1738,786,1804,1980,1006,1980,81,930,752,452,2672,1803,2510,2989,1630,3215,253,1889,1485,900,823,3362,1575,2942,859,39,517,1409,659,931,851,2813,625,439,831,744,1187,304,1983,411,1221,570,15,9,103030,297830,74,797,722,172,1444,2928,446,1294,1207,769,1403,1313,1443,1231,495,723,684,1303,702,15,9,21289,21502,34,3470,1375,1239,1513,1041,108,1975,1258,15,9,145156,68868,50,2546,446,1024,1209,1205,2569,1321,458,1575,1716,987,476,15,9,166217,15488,1122,1566,1648,3198,2123,1252,674,180,1786,63,1162,136,2292,633,1112,43,1092,1928,2174,2266,1202,6024,2026,2492,1926,888,2066,1448,5998,834,1916,7628,536,2880,1142,2248,1948,778,1530,480,1888,1332,2970,3344,2812,9194,3866,2518,3328,6224,3480,2074,3289,1632,3905,1848,3259,2736,1359,1494,1341,2119,2881,13741,11481,5453,3037,6847,1271,0,1647,3950,327,1656,1815,977,2055,3939,953,869,961,2320,2193,5472,3513,3532,1548,1204,2679,569,4405,3659,6935,741,3153,1169,2599,3159,1745,4140,1169,3532,3174,6912,14158,4638,5300,2194,3516,886,4794,254,6166,798,5780,2626,3566,4412,693,3326,4887,2700,6115,2482,4369,2826,3463,1594,3693,726,4297,424,8057,1142,5147,262,2133,261,2795,1141,4681,261,2519,724,1347,3126,4619,716,2319,715,2875,1565,1941,1559,1209,723,713,2291,1069,4845,117,4347,1813,807,6155,7782,5570,4612,2102,4466,861,1884,3459,1357,9213,1140,4101,3803,8665,2971,1535,5525,1744,734,3059,4032,3337,1304,3583,325,3265,1259,3583,1601,3047,1359,1711,6993,2445,5317,2296,4845,3604,5643,1524,3832,4671,71,2137,2101,3155,1657,0,3695,5176,6603,1770,6557,3020,1123,4168,4764,129,6994,1090,5325,632,5363,7684,10120,6992,7402,4468,1050,5160,3187,3445,4367,1417,11793,127,3179,633,2707,1167,2591,743,2853,724,1801,1950,1349,2914,3251,16380,289,6156,1376,2686,3259,1122,117,2706,952,3332,0,2976,2527,2826,3071,1846,1757,1606,1432,2054,0,1646,4347,2740,13895,5586,15,9,6975,24234,210,2038,238,2782,773,2482,99,1050,2314,2210,824,12230,8414,1052,448,3624,2126,2300,766,9122,0,823,2473,1339,1221,3913,1163,1829,29,959,826,1123,426,2299,1221,1539,2303,2147,6673,2273,2841,2889,2103,11331,5709,4003,505,1449,1806,1141,3238,451,3416,15,9,6351,16540,114,5790,1132,5762,2742,4602,1282,2354,3337,3287,119,1385,2055,164,3089,1340,3229,3205,806,5635,835,3315,30,2417,1024,2581,2006,887,2146,15,9,29678,22642,58,3208,1392,6558,796,1540,127,933,1799,2579,3569,4159,1977,3649,1918,15,9,18924,2386,154,4902,2456,4148,2984,4186,1900,4458,1124,3586,279,1550,853,1794,1541,1258,1959,35,2157,1719,1341,2283,746,2373,1462,1909,806,3941,267,2335,915,4375,4721,4267,2933,2879,656,1031,2426,15,9,225320,54272,66,1722,936,1594,2229,706,1275,280,1691,110,3087,1413,1163,2309,1016,1285,3166,15,9,59120,59661,98,2030,3039,1558,3437,2120,3209,2636,2085,2392,1191,2146,1639,1930,3417,4185,40,2525,1232,9377,12102,2073,3578,71,3060,15,9,31934,43493,74,5498,3899,12874,29541,1385,1505,3343,3450,4103,8648,3639,5584,2735,7272,2301,3930,859,2540,15,9,173990,157127,58,9576,2725,8280,4413,3552,5537,8007,2606,9367,1896,7889,2932,3615,5816,15,9,85409,34970,354,6568,2016,1034,544,425,2174,1477,2206,228,1354,2355,1582,1847,2810,453,3126,1768,2590,2744,543,1920,782,1450,1068,1360,346,1720,799,1160,1275,1956,3037,2466,2451,2716,1463,3488,731,4730,197,751,1027,399,791,587,691,13262,16369,10546,6147,2392,809,3488,7547,8370,6025,20346,5649,1665,1657,3187,3417,5091,1394,9965,5500,11305,868,4219,2194,1848,5066,4131,2906,4211,3912,3859,2194,3141,2223,7727,8262,8325,6226,9403,3104,11015,1017,15,9,152412,8454,354,2274,2432,1740,2848,924,3532,217,4450,1350,355,1124,701,996,1007,942,1247,13064,21723,3026,1905,4012,4625,3724,5513,2156,4673,2708,16425,2674,4205,3894,4343,4802,13441,3297,3632,795,1115,2383,2219,382,5724,8425,7166,444,5330,2997,762,2717,1096,1403,1816,1032,2962,4511,3606,1683,3852,1395,10916,4565,11612,2145,1138,1457,533,1585,1205,2545,889,1522,11696,1267,3510,2571,533,924,1058,1394,840,2789,890,1829,1739,1775,2599,2735,1661,15,9,48260,95639,114,1874,4712,2030,3846,1196,3924,181,5760,1467,6512,2517,5782,8370,12233,333,2505,1748,2227,580,5265,18,10707,1812,11669,12311,3460,1657,4080,15,9,136303,226807,42,960,431,598,4031,243,2083,825,283,831,606,15,9,2573,18542,34,379,1822,1450,2369,99,2125,1385,912,15,9,120252,211020,418,1042,2150,1386,1970,1758,1942,1376,0,2228,3497,6270,3095,2282,3339,5733,818,1855,690,1520,2807,2292,2393,2664,1399,2636,138,2718,1811,4240,3605,2030,1181,2508,609,3598,315,2274,718,1477,2602,397,10728,3768,7269,6314,4433,18980,7169,8172,6391,14430,16251,949,1239,1223,2361,1005,1199,2692,2459,1910,6217,1124,7317,308,9469,433,2565,1331,1061,2745,884,1285,1682,1621,8210,823,569,2209,1061,1449,6294,6359,11374,2309,9880,2109,3386,7509,9234,2309,2196,2789,1358,25455,5082,5535,3496,2853,2344,15897,10120,3487,1448,15,9,189898,141867,58,6468,6890,7936,6124,6288,8078,1149,6771,6369,9951,8279,9449,6865,5265,15,9,300711,76243,18,1070,1585,1793,1116,15,9,1231,4109,98,1314,439,1358,997,217,1488,572,2944,2084,3755,868,1633,770,3091,1601,1819,2771,77,1847,1976,1305,3228,271,1888,15,9,15543,44248,66,1322,2537,434,1517,852,1419,1160,3007,633,1341,1703,2086,1565,3624,769,3468,15,9,5001,21494,50,554,1166,1004,803,834,1959,17,1627,1485,145,977,1608,15,9,463903,87947,594,3098,1995,2808,2541,3470,1739,3642,87,2510,1282,2138,1856,2482,1722,3824,1124,3116,233,2700,1085,2526,1445,844,1017,2064,3225,952,683,1912,508,3206,2258,1668,518,2426,1093,7148,4711,2582,899,2882,1584,1830,2034,2164,224,3906,3841,1694,2931,488,2959,597,3253,4809,10815,688,2315,2538,3955,3443,125,2643,1045,4693,3603,1052,4298,1431,1954,2391,741,1793,3867,598,741,952,1581,162,1699,1711,1043,1285,322,833,1142,723,1464,2735,3780,1067,2256,1367,2168,2763,2140,3169,1523,4783,1026,4763,2286,3099,2296,559,2090,878,2540,1304,2688,652,2520,1059,1730,2407,1154,4257,1222,1122,2061,436,2071,353,2071,1203,2003,1521,4926,1377,0,2255,3429,3641,967,3395,1436,1495,3850,1927,2864,3841,3118,2817,4008,1134,5534,1649,1622,15,9,17809,24502,490,2890,3102,1902,3944,706,3906,1385,7538,1704,1194,779,2722,2445,4142,3370,529,3452,1173,2728,2143,1104,3387,1267,2211,2409,2417,1539,2995,1332,3943,1956,841,5490,792,2656,849,1540,2153,1014,2445,1594,1799,3306,323,2907,1790,888,1528,988,1320,1142,1116,1276,970,1668,2917,2220,1457,2182,362,1668,2516,1776,4119,2419,1779,4049,909,3043,1535,2574,695,1912,1407,1620,1585,1632,1241,2354,801,4584,957,2320,1515,5009,10063,3323,4047,2445,2482,1015,467,2561,703,979,489,713,1848,589,1008,1739,2074,949,4830,4701,1682,3741,1935,1940,6073,2871,1292,7827,4704,1603,1330,1521,3580,7101,5086,2155,3718,15,9,56329,53310,362,4384,1214,7864,165,7156,2852,3108,148,1766,2999,4440,2480,5688,1469,5600,3655,4166,4065,2138,2987,1940,3557,1440,3759,870,7991,1024,2507,4746,5345,1894,47,3088,1203,2754,391,3713,3701,5325,1488,10853,7148,4853,950,5381,0,5615,1174,5563,4438,4712,2996,2119,3996,4519,2352,2501,2017,279,2243,859,2497,1467,1555,2073,616,1395,2556,107,3008,1024,1880,1984,861,54,4194,3533,4782,5217,2292,4981,3193,1131,1244,1005,284,1069,47,1349,302,15,9,26115,4930,74,470,736,562,606,434,980,192,1864,652,900,1466,115,1532,323,914,294,6221,6419,15,9,58467,28942,370,2082,989,762,4776,2030,510,2364,1117,1748,47,2428,402,9874,2049,5418,3473,6268,499,6334,500,5606,479,5428,334,3532,2864,3054,3296,3958,1580,5056,519,5334,1511,4530,2529,2556,3511,815,334,2083,1148,996,3245,14894,15345,834,2115,669,2381,1603,28,2001,1010,1803,520,21415,0,192,2264,779,2324,1829,1088,2971,1499,4337,1931,6033,821,10081,224,5073,1540,6095,4294,9195,1724,6431,2060,3913,2676,3208,2658,3425,3816,4537,3443,3613,1969,579,8180,15,9,14693,500,98,3098,901,2092,294,272,1784,498,688,1596,805,127,1509,1639,2667,569,1509,4057,1391,2001,58,425,1550,53,3962,15,9,19576,12066,34,454,557,380,873,1123,979,841,1118,15,9,2953,6506,186,3434,147,4530,2825,3976,5101,344,1697,1583,509,1567,1158,200,892,471,668,1375,78,1983,2150,1413,126,190,1462,561,472,615,539,379,1049,397,37,597,538,1051,125,233,422,498,1314,289,962,1323,638,461,628,15,9,61024,490010,1306,4620,2122,4240,2582,1848,2152,688,3410,1630,307,2066,1645,1830,537,2392,1496,1730,1834,390,2272,1611,2772,2916,4218,3570,129,3008,3249,1286,5103,261,4207,825,3687,1429,3297,2039,3099,3903,2749,659,597,444,2411,1068,2141,1630,895,5998,3826,3298,956,1812,1944,561,5420,4330,2091,36,4403,1159,5141,662,4321,3686,2271,2102,3088,518,5400,1059,4722,2138,955,2318,1385,1994,607,1158,1276,135,3518,1637,2442,2247,1952,1929,2134,279,1454,508,3708,227,1526,1357,1824,3477,3210,1367,1796,5145,4227,1421,3988,1739,3670,3097,1596,379,1844,652,4200,2002,7352,3406,3592,4874,4042,3416,4882,915,6048,2110,1498,5816,1148,1196,1478,680,3096,3044,5972,688,3416,2002,230,787,1918,1793,2568,923,2158,462,1938,1196,3418,1712,3238,2012,1458,1740,3088,489,6908,2083,11040,2399,7792,4647,10206,2989,9400,2582,5436,3752,209,8090,1561,3370,1441,2726,2581,1522,2743,1848,2201,3696,879,3398,1440,3278,2704,3408,1662,3822,1681,2836,2081,3126,1681,3016,2141,2400,3401,3315,3841,559,4333,1756,4029,3660,2901,2797,9699,897,6047,1332,2699,4076,629,3344,2007,2908,3667,13544,33789,9838,14799,3696,4001,3786,1735,2682,1615,8244,8267,2066,3509,234,4407,361,5999,895,5631,1331,3337,1285,4663,1802,5987,4884,10397,1068,8631,2037,6271,5163,3841,8379,1293,3423,1073,2327,2467,1947,2785,2263,2009,6759,895,1747,2107,2582,5351,2663,2725,8125,5617,4021,1223,7745,59,2661,1221,8769,6441,1123,1967,454,2137,742,1977,164,1797,1359,1669,2145,537,2119,756,1901,1472,1421,1648,2537,6720,1421,8352,2327,7100,5181,3004,6839,2984,1493,7224,1432,16662,4013,3145,2743,3265,3397,2567,5879,1043,4447,1184,27873,15898,13325,12380,4239,5082,2771,5560,15,9,224804,493156,90,878,525,752,364,444,1053,99,2147,146,707,652,467,689,413,1973,790,307,1306,354,1378,643,1460,15,9,31634,52037,58,3008,2792,2284,2032,1748,72,525,1709,2345,2205,3967,2061,551,81,15,9,4139,14399,138,3188,1518,752,717,1360,444,498,787,99,1131,126,919,788,1233,272,1555,697,5689,595,777,1169,868,1096,5216,1647,3922,877,656,1177,20,2627,1849,507,860,15,9,55857,3061,66,5970,5023,1240,1465,959,1889,6775,7515,1268,5536,1139,3446,1595,3264,53,4862,15,9,6876,60021,74,1822,1140,978,1754,924,39,1486,4095,1395,2923,741,90,797,1282,1239,938,1059,1220,15,9,73887,75173,74,2818,523,2174,2503,8326,14995,370,2231,2725,270,2807,3308,3569,6538,4537,5060,1521,3078,15,9,107,204740,154,6730,1286,996,1185,887,2277,726,728,1196,1186,2436,1986,644,739,2001,2441,769,1457,17,1083,1051,1793,823,2633,1413,2145,1439,61,469,710,525,952,3053,3748,1003,2108,453,2126,15,9,137248,33009,186,960,121,1068,770,1278,1316,1794,546,2120,393,1476,1093,344,919,107,243,417,192,813,112,199,383,508,425,54,181,453,101,225,2933,554,2883,1251,1031,867,109,887,19,1947,1010,923,2754,1087,1840,1313,1276,15,9,10708,4563,18,3272,60,5697,1213,15,9,159985,113148,1186,660,366,1604,366,8018,5262,10082,1860,20854,293,20510,4693,11706,1055,5108,4042,11860,5585,9412,7109,40820,40005,4638,3163,5220,1683,7364,495,1901,2737,2997,921,7265,254,3260,6741,4612,5451,5788,3627,13608,2541,6124,3039,10690,7809,8172,4525,2608,2277,2012,3239,1666,4555,36,4027,2951,1751,707,1729,53,11089,762,4055,2038,2639,2962,1597,3506,969,2853,5773,343,1849,508,2699,1086,1697,1106,1211,498,1263,244,2011,300,959,389,979,1829,2051,1775,1495,1847,907,3967,829,462,1052,1060,3718,7229,867,6865,3901,6087,5505,4963,5665,2101,6139,1965,18959,336,4701,2337,13961,1124,19949,797,17863,7999,7733,5869,3100,5163,7032,3667,7736,1395,5118,3577,3226,16279,3588,4473,6018,3606,30,4040,1392,3298,2582,2500,6130,2736,756,3242,374,2692,1352,8144,9340,5218,4400,5706,2422,1447,2028,887,2050,453,2342,107,2968,895,1716,1875,1474,1703,1836,361,2686,1386,2798,2074,2110,1922,2364,832,3646,97,6548,625,3202,3777,3740,7066,10492,279,2396,1947,2982,2936,17590,2418,1398,1866,2378,1558,2964,246,1246,245,4766,616,1732,1396,1032,1594,688,1096,730,2256,3898,978,4486,1593,3666,7889,2106,5209,2432,20617,3048,3913,2462,2499,4226,2681,6112,1014,1520,254,2028,615,2168,2527,3316,1139,2666,787,1218,1169,404,1041,951,1085,1337,1321,659,4539,426,3505,1430,1557,2586,1304,3904,3685,8450,10137,17018,6069,7210,3767,2742,4855,1838,4953,152,4121,2275,3859,1379,5281,852,13089,4348,4031,508,8831,20,2627,832,6285,4226,3941,1768,4075,650,17609,1341,7057,2619,4691,121,15,9,217592,96485,98,508,1264,534,800,480,373,300,59,73,1012,480,2652,2638,6602,244,184,544,2197,227,2825,4881,8533,561,566,15,9,45450,236381,802,2444,774,2616,579,2792,967,3572,4588,6132,80,3462,461,2572,1303,2435,3815,1077,3795,73,4215,544,5177,3498,4636,2490,2317,2002,4757,2020,2617,4304,1203,28264,21935,8172,4661,10328,2485,10300,431,3706,1011,3532,2835,11488,16051,13462,13249,13896,10421,6686,4411,2890,3403,1196,4681,1875,20843,949,3937,217,2149,897,2567,2037,1569,2119,969,1149,767,779,4727,980,4375,2826,6293,870,4055,869,11711,1177,4961,5235,8443,1177,3413,561,17175,780,9433,2826,7913,7391,3278,3849,7806,2419,8996,3069,6832,3687,2684,9727,3992,4131,2604,4691,5458,580,2266,3622,270,21842,3733,1468,660,1032,1576,924,1896,1142,1668,3652,3704,1068,2176,598,3404,179,5644,1821,1279,2553,3933,2345,2255,1349,2776,244,6290,1930,11210,1258,4116,616,980,1306,1598,6396,5958,1068,1748,1722,14038,73,5252,3985,11314,6991,6014,7999,4104,7001,5586,18373,27044,5633,4670,8451,3126,17827,3970,9177,4712,13443,12846,8749,2638,4855,522,9203,2318,4249,532,4791,1253,7817,4383,3359,582,5562,5818,3116,9672,957,12412,2441,192,5929,388,15,9,230302,212901,522,4638,5542,1848,788,3344,407,1476,1087,5980,5741,5796,2261,2674,1495,2446,2929,1730,15615,1322,4601,2174,2577,3570,3277,3298,3873,2680,7645,6180,11385,12502,18165,3994,3241,8706,4761,4150,3509,5516,11609,1332,1877,2474,1669,9756,10759,1712,3613,3688,14111,10101,3366,4591,398,5217,427,10073,2053,3515,1935,3895,3445,5507,535,5959,3992,2535,5004,4828,2442,3270,884,4748,2294,4384,3198,2228,3634,4286,117,1984,6636,959,7958,4601,3866,6505,1432,4591,3618,11895,19510,1755,6904,4275,6348,979,3304,1339,7784,3777,5844,5761,3414,7345,578,870,2570,180,2948,333,3098,715,2928,1195,2998,1131,1116,1531,758,9827,8648,7175,3628,1947,1386,1503,2084,215,1864,15,9,267046,172855,202,3788,4790,2546,7556,932,8450,1041,7480,100,5856,2446,3542,3878,2174,4348,1758,1232,1012,1214,1340,1322,794,1486,645,3334,6003,534,595,444,2539,2030,3423,570,1597,135,2213,1221,4811,299,2201,9113,15887,669,2796,2843,5481,225,2141,14649,1663,15,9,181728,207995,50,12502,1330,4348,1329,0,1801,19829,4007,9375,196,4365,7268,15,9,61444,118359,74,3798,540,5062,1269,5060,2355,2164,3255,1445,357,9395,2900,4157,1270,4521,726,541,1266,15,9,13205,2525,34,2714,1988,2714,1809,3077,5963,3979,723,15,9,103569,20086,18,761,1964,107,530,15,9,56465,38144,346,362,796,164,826,290,884,2446,148,3714,1298,1440,226,2664,767,6314,4185,2228,589,4838,431,2192,629,6224,5109,680,2063,254,4253,588,1767,788,225,2718,354,906,127,470,707,1052,2739,4348,1503,7990,559,4666,1217,1657,3282,4946,1207,13290,5235,0,8523,17447,4103,2309,952,200,3978,4085,747,5789,1785,16441,4300,2291,1906,3641,4026,1231,2827,2661,2395,2645,1295,1213,530,1286,5224,35,2750,1937,1178,14495,21578,15,9,16696,146243,842,1006,2370,2338,664,8778,713,1876,880,6722,5990,180,1538,2363,1752,0,1478,4358,2800,1576,646,1303,392,1015,440,669,872,181,1586,4476,1762,6540,4016,5146,784,1196,782,2438,3390,2944,2086,235,3026,851,3322,46,2184,4104,1666,6088,648,5508,1352,2400,3822,924,5820,2554,2804,3914,1138,4902,852,8822,3294,6126,5658,2082,7806,3351,9712,6131,4552,15825,274,7057,3554,3341,3218,380,904,2690,4358,1468,1392,1622,924,1748,588,1421,1572,3143,5026,7366,2149,1756,1001,744,2682,1648,2060,1994,944,1830,745,1350,1010,606,344,942,138,0,1806,1819,512,751,510,597,864,1377,1552,11488,127,5490,884,5960,2406,236,931,100,775,316,745,870,707,5253,9347,2499,2327,107,2426,779,1924,1457,1356,2065,726,770,3279,1838,3151,2420,1529,2572,1530,1504,3533,2038,18017,1224,3699,2844,6187,3821,931,1603,4079,787,5285,1395,4499,2173,2783,3205,3245,3387,2713,2699,1137,2555,2145,7391,14433,11621,9657,2055,1037,2355,175,13533,5561,5561,1213,3407,3123,5561,8955,1793,1977,5887,5185,2245,1057,5045,781,3967,2123,7175,6935,279,2172,15] \ No newline at end of file diff --git a/encoding/mvt/testdata/florida_keys.wkt b/encoding/mvt/testdata/florida_keys.wkt new file mode 100644 index 00000000..2b1faf82 --- /dev/null +++ b/encoding/mvt/testdata/florida_keys.wkt @@ -0,0 +1 @@ +POLYGON ((-8775168.968 2558213.49,-8769955.397 2558487.828,-8769384.667 2557277.834,-8767260.284 2550269.422,-8766857.149 2550573.01,-8765810.811 2551092.061,-8764696.529 2549534.957,-8763663.78 2550494.664,-8761942.531 2554309.553,-8763364.826 2556332.433,-8764125.799 2557106.384,-8765049.838 2557664.827,-8765049.838 2558487.828,-8761743.229 2558042.031,-8758187.492 2554441.792,-8746025.511 2550112.733,-8744462.798 2549006.162,-8743511.582 2547468.834,-8741296.607 2545569.401,-8738741.912 2543836.6,-8736794.183 2542808.751,-8734135.307 2542001.2,-8727436.026 2540851.118,-8725388.646 2541164.324,-8725438.471 2540356.851,-8725329.761 2538683.304,-8725388.646 2537875.951,-8724242.656 2538443.541,-8723803.285 2538771.382,-8723051.371 2537572.592,-8722009.563 2535273.11,-8721203.294 2534221.324,-8720197.722 2533458.208,-8718204.698 2532416.318,-8717339.544 2531682.631,-8716474.39 2531203.306,-8715378.226 2531183.742,-8714214.118 2531301.126,-8713158.721 2531232.652,-8709353.856 2529672.492,-8707623.548 2529188.333,-8702106.493 2528777.543,-8701137.158 2528264.069,-8700919.738 2527075.804,-8700829.145 2525711.602,-8700240.297 2524679.967,-8699320.788 2524445.291,-8696467.139 2524479.514,-8696834.037 2524298.62,-8697200.935 2523848.837,-8696032.297 2522748.875,-8694650.769 2522216.03,-8693210.355 2521883.622,-8692028.129 2521468.121,-8691806.179 2521394.798,-8690161.934 2521971.612,-8689106.536 2520827.78,-8687629.886 2517670.421,-8685510.033 2515647.282,-8684903.066 2514831.254,-8684169.271 2512637.455,-8682167.187 2509085.956,-8681274.855 2507928.337,-8679956.741 2507459.451,-8678615.979 2506511.949,-8673502.059 2501233.274,-8673121.572 2500242.178,-8671232.728 2496756.712,-8670458.166 2495907.42,-8669121.934 2496107.537,-8668487.789 2497308.286,-8666059.923 2500793.865,-8665348.776 2499519.642,-8664383.97 2498362.672,-8663106.623 2497156.967,-8662137.288 2496698.138,-8659401.409 2496727.425,-8658201.064 2495926.943,-8657736.644 2494904.603,-8634871.518 2494904.603,-8636508.802 2496317.417,-8637686.498 2498172.292,-8638447.471 2498377.316,-8639987.536 2497625.571,-8639040.849 2499675.863,-8637269.775 2501833.818,-8635235.984 2503220.52,-8633496.617 2502947.077,-8629623.807 2499666.1,-8629207.084 2498684.858,-8628495.936 2495653.617,-8628101.861 2495019.125,-8627945.006 2494904.603,-8130453.824 2494904.603,-8130453.824 2553923.177,-8131838.701 2553192.911,-8134529.285 2552664.001,-8135706.981 2552923.556,-8136449.836 2553486.757,-8137002.447 2554045.079,-8137600.355 2554309.553,-8141812.884 2555205.86,-8143733.435 2555725.054,-8144802.421 2556513.672,-8144548.764 2557655.029,-8142505.913 2559242.282,-8143144.587 2560094.758,-8143189.883 2560653.3,-8142505.913 2561858.639,-8141985.009 2563416.888,-8142179.782 2564710.64,-8142157.134 2565803.545,-8140983.967 2566788.692,-8139077.005 2564259.775,-8138130.318 2563652.108,-8136431.717 2563421.789,-8136440.777 2563671.71,-8135797.573 2564215.67,-8134900.712 2564779.25,-8134139.739 2565068.399,-8133351.588 2565004.688,-8131693.754 2564450.901,-8130765.186 2564318.583,-8130453.824 2564202.043,-8130453.824 3140644.618,-8776193.838 3140644.618,-8776193.838 3075547.049,-8775961.649 3075399.267,-8772650.51 3070825.006,-8770442.165 3071237.922,-8768678.048 3071509.442,-8765091.331 3069951.52,-8762434.545 3069915.6,-8759922.52 3071091.853,-8757643.751 3072703.669,-8756114.274 3073409.584,-8754808.993 3074219.854,-8753939.752 3074796.834,-8753524.834 3075803.942,-8752117.717 3076948.806,-8751828.312 3078505.973,-8750205.639 3079878.117,-8748842.852 3082682.504,-8746776.845 3084066.74,-8747033.878 3085388.715,-8749712.607 3087061.925,-8754341.86 3087908.741,-8753571.827 3089526.45,-8750536.994 3093010.985,-8749884.732 3094548.105,-8749024.107 3099820.221,-8746904.254 3098292.678,-8744947.466 3095831.702,-8743507.052 3093147.949,-8742940.852 3090926.248,-8740835.059 3089653.908,-8731657.79 3086018.16,-8729347.088 3086632.221,-8724215.479 3085358.307,-8718540.713 3084361.789,-8714878.095 3084232.789,-8713378.985 3086486.919,-8711076.286 3087653.252,-8707598.126 3086077.047,-8705478.208 3085686.41,-8701516.312 3087336.427,-8696161.536 3086579.792,-8692630.566 3087675.481,-8689088.418 3089283.021,-8686832.676 3089602.523,-8679766.498 3089724.239,-8678054.308 3090454.561,-8677003.441 3091844.306,-8676246.997 3093452.319,-8675255.014 3094827.137,-8673502.059 3095567.87,-8673243.871 3093254.478,-8673801.012 3090713.226,-8674104.496 3088152.146,-8672116 3083746.141,-8672029.938 3081358.648,-8672963.036 3079351.638,-8675024.005 3078469.86,-8675825.744 3078789.119,-8677710.058 3080415.926,-8678751.867 3081024.126,-8680183.221 3081277.551,-8687457.761 3080861.937,-8694089.098 3079321.231,-8709381.615 3076240.508,-8715579.838 3076237.369,-8738959.332 3070232.435,-8740970.476 3069898.175,-8743049.563 3069229.679,-8746424.116 3066312.971,-8748607.384 3065644.643,-8750560.112 3064342.466,-8752936.432 3063144.096,-8754881.709 3061744.762,-8755920.268 3060865.953,-8758252.114 3060659.851,-8759300.13 3060134.89,-8763846.03 3060574.547,-8768284.448 3062149.144,-8770983.867 3064835.824,-8775822.756 3067816.184,-8776193.838 3068199.965,-8776193.838 2571390.308,-8775984.296 2571014.211,-8775114.613 2569332.699,-8775603.81 2568925.828,-8776193.838 2569095.715,-8776193.838 2558330.7,-8775168.968 2558213.49),(-8737636.689 3094943.826,-8736767.005 3094050.932,-8736631.117 3094162.541,-8736508.818 3094705.377,-8736205.335 3095263.455,-8735775.022 3095552.649,-8735421.713 3095101.103,-8735331.121 3094340.102,-8735593.838 3093974.836,-8735643.664 3093776.987,-8735516.835 3093381.299,-8735833.907 3093193.604,-8736318.575 3093051.567,-8737079.548 3093036.349,-8737926.583 3094005.274,-8738080.59 3094989.487,-8737636.689 3094943.826),(-8720940.577 2541242.626,-8719015.496 2543161.149,-8716809.58 2543469.504,-8716773.343 2542794.068,-8718028.043 2540988.145,-8718485.533 2539676.647,-8719776.469 2538120.599,-8720483.087 2537939.559,-8719912.357 2538345.679,-8719549.989 2538883.926,-8719839.884 2539387.935,-8720890.751 2539578.778,-8721112.702 2540376.426,-8720940.577 2541242.626),(-8693305.477 2534876.848,-8692888.754 2534304.486,-8692059.837 2533688.118,-8691249.038 2533110.905,-8690560.538 2532533.711,-8690818.726 2532093.492,-8690238.937 2532020.123,-8690016.986 2532342.948,-8690007.927 2532641.322,-8689767.858 2532675.562,-8689468.905 2532827.197,-8689659.148 2531755.998,-8690737.193 2531359.819,-8691851.475 2532029.906,-8692820.81 2532783.174,-8693092.586 2533839.762,-8693550.076 2534529.515,-8693645.197 2534940.445,-8693305.477 2534876.848),(-8654119.893 2499797.912,-8653766.584 2499661.218,-8653472.16 2499041.223,-8653023.729 2498557.935,-8652638.713 2498592.107,-8652285.404 2498767.846,-8652190.283 2497996.558,-8652154.046 2497674.385,-8652634.184 2497352.217,-8652878.782 2497181.373,-8655134.524 2498484.711,-8655252.293 2499392.713,-8654119.893 2499797.912),(-8667346.33 2507459.451,-8666123.337 2507986.949,-8663133.8 2507498.524,-8661340.078 2507459.451,-8662327.531 2506214.034,-8665887.798 2505569.383,-8666657.83 2504543.852,-8666503.824 2502405.086,-8667957.826 2506272.639,-8667346.33 2507459.451),(-8362019.47 2734586.194,-8361099.961 2734764.479,-8360769.3 2734209.821,-8360737.592 2732882.682,-8361285.674 2731327.893,-8362033.059 2730897.134,-8362726.088 2732828.212,-8362019.47 2734586.194),(-8342129.989 2716203.908,-8340399.681 2717044.85,-8337835.926 2717683.006,-8332232.809 2719340.354,-8328074.635 2719285.931,-8326656.869 2718662.552,-8324161.059 2716851.924,-8325279.871 2714957.417,-8325995.548 2713409.332,-8327118.889 2712524.073,-8329474.282 2712632.873,-8329474.282 2711871.289,-8328781.253 2710946.556,-8330787.866 2710916.886,-8333460.331 2711777.329,-8334801.093 2713532.975,-8336812.236 2712608.146,-8340490.273 2712573.528,-8342465.179 2711871.289,-8342881.903 2714655.701,-8342129.989 2716203.908),(-8555700.186 2940229.844,-8554304.551 2940519.828,-8552560.007 2941196.482,-8551338.827 2941293.149,-8550379.328 2940906.484,-8550553.782 2940229.844,-8552560.007 2939359.923,-8554740.687 2939359.923,-8556136.322 2938296.756,-8557357.502 2938103.461,-8557444.73 2939069.96,-8555700.186 2940229.844),(-8672442.132 2926306.36,-8671789.869 2926863.009,-8670942.834 2927259.196,-8670263.393 2927319.377,-8668986.046 2927209.045,-8667237.619 2927329.407,-8665919.505 2928141.877,-8665063.411 2929265.365,-8664755.398 2929210.192,-8665348.776 2927820.896,-8666449.469 2926527.011,-8667794.76 2925930.257,-8669506.95 2925925.243,-8670498.933 2926035.565,-8672537.253 2926075.683,-8672442.132 2926306.36),(-8632939.476 2880416.638,-8630285.129 2882426.535,-8627762.141 2883521.592,-8626131.484 2883806.62,-8622367.385 2885201.835,-8620673.314 2885391.874,-8615912.703 2885201.835,-8611188.328 2886072.034,-8609448.961 2886042.026,-8607899.838 2885491.895,-8605227.372 2883866.627,-8600969.547 2882881.549,-8602183.48 2881406.554,-8613847.205 2875932.833,-8616537.788 2876007.802,-8620093.525 2877572.242,-8620736.729 2876547.591,-8622014.076 2875083.21,-8623563.2 2874148.68,-8625030.791 2874683.404,-8626715.803 2875662.948,-8628871.893 2875887.852,-8630928.332 2875832.875,-8632323.45 2875977.815,-8634148.879 2878062.099,-8632939.476 2880416.638),(-8661294.782 2538947.538,-8659559.945 2536936.533,-8657544.272 2535087.208,-8655949.852 2532954.375,-8658622.317 2532885.895,-8661448.788 2535865.074,-8661294.782 2538947.538),(-8666902.429 2549079.605,-8664465.503 2547086.972,-8662708.018 2544110.703,-8661294.782 2538947.538,-8665896.857 2542808.751,-8665063.411 2544423.97,-8666299.992 2546235.157,-8668279.428 2547791.955,-8669638.308 2548634.057,-8666902.429 2549079.605),(-8676586.717 2543875.757,-8676179.053 2544365.232,-8675689.856 2544360.337,-8674860.939 2543861.073,-8674041.081 2543890.441,-8673225.753 2544409.285,-8672727.497 2544345.653,-8673053.628 2543846.389,-8674829.232 2542050.141,-8675626.442 2541604.78,-8675626.442 2542216.543,-8676704.487 2543405.875,-8676586.717 2543875.757),(-8675929.925 2554030.386,-8675259.544 2553854.072,-8673606.239 2552022.475,-8672953.977 2551586.643,-8672048.056 2550533.837,-8671327.85 2549182.425,-8671545.271 2548257.064,-8672301.714 2548168.938,-8672804.5 2548707.498,-8672886.033 2549652.469,-8673103.454 2550142.112,-8674638.989 2551346.695,-8674974.179 2551900.049,-8675979.751 2553011.708,-8676256.056 2553530.834,-8675929.925 2554030.386),(-8703691.854 2566180.933,-8702822.17 2566573.033,-8701920.779 2567563.127,-8701417.994 2568553.28,-8701458.76 2569018.966,-8701082.803 2569244.461,-8699746.571 2568342.5,-8698491.871 2566847.509,-8697676.543 2565239.93,-8697803.372 2564294.08,-8698546.226 2564744.945,-8698958.42 2566425.995,-8699746.571 2567896.44,-8700176.883 2567876.833,-8700435.07 2567171.004,-8700765.731 2566705.369,-8701191.514 2565298.742,-8701504.056 2565078.201,-8701920.779 2565450.671,-8702514.157 2565602.602,-8703506.14 2565396.761,-8704117.636 2565681.019,-8703691.854 2566180.933),(-8652602.476 2714596.348,-8653001.081 2714957.417,-8652915.019 2715679.578,-8651451.958 2715902.169,-8650804.225 2715298.708,-8651189.241 2714596.348,-8651846.033 2713874.236,-8652462.059 2713626.945,-8652824.427 2713968.208,-8653476.69 2714319.37,-8652602.476 2714596.348),(-8664121.254 2725070.67,-8662386.416 2724382.725,-8663006.971 2723625.524,-8663527.876 2723679.962,-8664515.329 2724308.488,-8664121.254 2725070.67),(-8591937.521 2758742.414,-8590664.703 2758965.614,-8590152.858 2758360.502,-8590755.295 2757075.958,-8591416.617 2757304.093,-8592204.768 2758162.11,-8592698.494 2758400.181,-8591937.521 2758742.414),(-8675807.626 2766144.418,-8675024.005 2766968.182,-8673425.055 2765906.229,-8672799.97 2766243.664,-8672709.378 2767136.91,-8672741.085 2767717.547,-8672673.141 2768863.997,-8672990.214 2769419.881,-8673012.862 2769965.859,-8672048.056 2771052.907,-8670915.656 2771653.547,-8667903.471 2772666.247,-8666657.83 2773629.366,-8666213.929 2774662.055,-8665489.193 2777661.212,-8665072.47 2778619.674,-8661258.545 2778887.855,-8659818.132 2779458.997,-8658694.791 2780432.471,-8658305.245 2781197.385,-8658065.176 2782141.163,-8657399.325 2783626.487,-8655727.902 2785032.46,-8651130.356 2786965.259,-8649871.127 2788629.945,-8646759.29 2790369.36,-8645722.012 2788724.366,-8644906.683 2786771.471,-8643982.644 2785141.763,-8642614.705 2784461.113,-8641867.32 2783790.428,-8642927.247 2782349.795,-8649798.653 2776608.462,-8652525.473 2775089.052,-8655949.852 2774453.525,-8655949.852 2773629.366,-8653974.946 2773465.532,-8653146.029 2772557.031,-8653635.226 2771529.446,-8655605.602 2771052.907,-8656040.444 2770571.42,-8654880.866 2769474.478,-8652144.987 2767717.547,-8650378.442 2768491.764,-8649776.005 2767151.798,-8650061.37 2764948.548,-8651891.329 2761480.549,-8652262.756 2759903.087,-8652847.075 2758603.536,-8654427.906 2757730.616,-8652357.878 2757145.39,-8650591.333 2758732.494,-8647135.247 2765811.947,-8644816.091 2768461.985,-8643719.928 2770219,-8643276.027 2772616.603,-8643149.198 2775699.777,-8642750.593 2778589.876,-8641437.008 2780372.868,-8639231.092 2780025.194,-8637568.728 2777581.757,-8636218.907 2774523.035,-8634977.796 2772338.601,-8633564.561 2770606.166,-8632767.351 2768759.771,-8632404.983 2766610.881,-8632192.091 2762581.89,-8631621.361 2760007.254,-8631490.003 2758940.814,-8631621.361 2757542.151,-8632192.091 2755201.407,-8632323.45 2753941.914,-8631961.082 2753267.581,-8630398.369 2750957.22,-8630040.53 2749797.21,-8630398.369 2748359.709,-8631181.99 2747388.231,-8631961.082 2746783.567,-8632323.45 2746426.726,-8633469.439 2745891.481,-8635892.776 2745832.01,-8638066.985 2744925.111,-8638470.119 2741847.992,-8634579.191 2744632.734,-8632273.624 2745683.334,-8630040.53 2745252.183,-8629098.373 2743522.742,-8629777.814 2738915.13,-8629207.084 2736864.433,-8631109.517 2732531.108,-8632595.226 2731763.615,-8635358.283 2732635.094,-8634991.385 2731105.085,-8632975.712 2729436.604,-8632323.45 2727644.544,-8632486.515 2726011.076,-8633116.13 2724219.404,-8633917.869 2722695.158,-8634597.31 2721839.071,-8638094.162 2720616.877,-8640753.038 2721764.846,-8643176.375 2723566.138,-8645998.317 2724328.284,-8644082.296 2721992.47,-8644118.533 2720923.654,-8645169.4 2719345.301,-8645998.317 2719345.301,-8647846.395 2721933.09,-8651148.474 2722818.874,-8654427.906 2724328.284,-8654989.577 2726412.002,-8652607.006 2726347.655,-8649110.154 2726892.138,-8651773.559 2727208.936,-8654455.084 2731050.622,-8649395.518 2734546.575,-8645694.834 2736780.232,-8645169.4 2739360.969,-8646763.82 2737637.128,-8648947.088 2736928.823,-8654844.629 2736864.433,-8656434.519 2736547.441,-8657788.87 2735963.004,-8659084.336 2735591.55,-8660511.161 2735953.098,-8661412.552 2736928.823,-8662087.462 2738385.094,-8663713.589 2746575.409,-8663858.537 2749653.454,-8663170.037 2750996.88,-8664800.694 2751557.088,-8664859.579 2752910.593,-8664383.97 2754576.606,-8664383.97 2756064.268,-8665647.729 2757477.677,-8667183.264 2758400.181,-8668062.007 2759203.697,-8667346.33 2760230.471,-8667346.33 2761053.924,-8669520.539 2762423.133,-8676468.948 2765216.495,-8675807.626 2766144.418),(-8679956.741 2777333.461,-8678937.581 2777452.643,-8677546.993 2777065.307,-8676305.882 2777015.649,-8675780.448 2778172.715,-8674675.225 2778584.91,-8668560.263 2782791.906,-8668034.829 2783015.45,-8666222.989 2784078.57,-8665072.47 2784461.113,-8660511.161 2784461.113,-8660923.355 2783224.094,-8661593.736 2782613.073,-8663550.524 2782031.88,-8664465.503 2782016.978,-8664945.641 2782429.275,-8665507.312 2782642.878,-8666657.83 2782031.88,-8667427.863 2780879.494,-8668501.378 2777542.029,-8669638.308 2776121.837,-8671083.251 2775069.191,-8676749.783 2772214.495,-8678751.867 2771961.321,-8679476.603 2772864.823,-8680047.333 2774483.315,-8680273.813 2776191.354,-8679956.741 2777333.461),(-8683449.064 2784461.113,-8680554.648 2785027.491,-8677673.822 2786398.81,-8675372.784 2787039.794,-8674195.088 2785370.31,-8675839.333 2785310.688,-8676532.362 2784282.261,-8676450.829 2782737.262,-8675780.448 2781122.879,-8677383.927 2781525.217,-8680201.339 2781107.978,-8681859.174 2781122.879,-8683068.577 2781634.496,-8684359.514 2782637.911,-8684803.415 2783710.941,-8683449.064 2784461.113),(-8669964.44 2795031.956,-8668360.961 2795727.987,-8665081.529 2796125.732,-8664311.497 2796061.098,-8664778.046 2795161.217,-8666068.982 2793376.524,-8668148.069 2792387.327,-8669973.499 2793346.698,-8669964.44 2795031.956),(-8660511.161 2794539.782,-8658060.646 2795767.761,-8655986.089 2797259.363,-8653893.413 2798209.092,-8651664.849 2798771.001,-8649871.127 2798631.765,-8649096.565 2798204.12,-8648199.704 2797433.393,-8647570.089 2796453.88,-8647588.207 2795374.996,-8648448.832 2794703.838,-8649590.291 2795076.7,-8650777.047 2795807.535,-8651732.793 2796210.254,-8653703.17 2796076.013,-8654871.807 2795618.608,-8657059.604 2793257.221,-8659193.047 2791790.856,-8660633.46 2792118.912,-8661149.835 2793331.785,-8660511.161 2794539.782),(-8548489.582 2820467.382,-8547628.958 2820935.485,-8546831.748 2819820.029,-8546478.439 2819182.661,-8546338.021 2818336.199,-8546283.666 2816792.77,-8546990.284 2816210.29,-8548145.332 2816718.092,-8548788.536 2818301.346,-8548489.582 2820467.382),(-8519228.355 2788470.923,-8518213.724 2786950.352,-8517434.633 2785231.194,-8516374.706 2783626.487,-8515056.592 2782583.268,-8513860.777 2781987.174,-8512787.262 2781167.583,-8511822.456 2779458.997,-8513915.132 2779478.863,-8515178.891 2780094.728,-8519867.029 2786145.405,-8520904.308 2787934.234,-8520940.545 2789464.84,-8519228.355 2788470.923),(-8504973.699 2767717.547,-8502224.23 2765767.287,-8495787.666 2750996.88,-8496480.696 2750243.357,-8498152.118 2751968.581,-8500204.028 2756292.388,-8502024.928 2759084.655,-8503392.868 2762720.804,-8504543.386 2764685.569,-8504973.699 2765955.851,-8504973.699 2767717.547),(-8417978.169 2687391.391,-8413190.38 2686028.656,-8409050.324 2683821.862,-8407274.72 2681052.692,-8411278.888 2682355.771,-8415962.496 2683303.532,-8419907.779 2684769.71,-8421715.09 2687677.778,-8417978.169 2687391.391),(-8464420.175 2705162.016,-8461136.214 2706170.451,-8460619.839 2706442.344,-8460832.73 2707529.962,-8461571.055 2708632.488,-8461457.815 2709309.862,-8462635.512 2710100.992,-8463559.551 2711505.345,-8463786.031 2713068.081,-8462902.758 2714363.884,-8461530.289 2714091.856,-8460570.013 2714482.589,-8459845.277 2715016.771,-8459165.837 2715189.89,-8458305.213 2714789.247,-8457725.423 2714151.207,-8456747.03 2712632.873,-8455514.978 2711406.443,-8454156.097 2710674.586,-8452412.201 2710308.67,-8450047.749 2710209.775,-8450423.706 2709695.533,-8450623.008 2709299.973,-8450917.432 2708953.866,-8444286.095 2700768.159,-8439013.639 2697694.661,-8437817.824 2697289.517,-8436073.927 2693515.258,-8431888.576 2690502.418,-8421715.09 2687677.778,-8422548.537 2686848.258,-8424142.957 2685139.978,-8426688.593 2685836.105,-8431671.155 2688586.349,-8437324.098 2689020.901,-8439434.892 2690117.21,-8438510.853 2692650.86,-8440576.352 2694103.075,-8442682.616 2696059.327,-8444612.227 2697156.119,-8446183.998 2696044.506,-8450047.749 2700175.155,-8454210.453 2703288.671,-8458912.179 2704840.714,-8464420.175 2704331.588,-8464420.175 2705162.016),(-8388214.156 2708558.324,-8387077.226 2709774.646,-8386207.543 2711198.75,-8385745.523 2712964.224,-8385854.234 2715189.89,-8385179.323 2715011.825,-8384617.652 2714660.648,-8384119.396 2714156.153,-8383648.318 2713532.975,-8377116.632 2702670.862,-8375603.745 2701717.011,-8373597.132 2699404.283,-8371735.465 2696647.237,-8370657.42 2694310.545,-8369303.069 2686097.777,-8367966.837 2683994.643,-8366019.108 2681822.681,-8363618.419 2675101.332,-8365267.194 2676917.102,-8365665.799 2676359.52,-8366857.084 2675249.349,-8366666.841 2678111.28,-8370879.371 2681694.347,-8370657.42 2684359.956,-8372156.718 2684740.088,-8373515.599 2685288.087,-8374217.687 2686196.523,-8373701.312 2687677.778,-8375957.054 2689480.157,-8376799.56 2691406.21,-8377497.119 2696864.622,-8379780.038 2702670.862,-8380853.554 2703239.246,-8381582.819 2702972.35,-8382375.5 2702369.379,-8383648.318 2701924.58,-8382887.345 2707772.215,-8383521.489 2709527.419,-8384807.896 2709260.417,-8384345.876 2709789.48,-8383648.318 2710209.775,-8385043.435 2710654.807,-8385958.415 2709784.535,-8386846.216 2708484.162,-8388214.156 2707653.56,-8388214.156 2708558.324),(-8364084.968 2659833.276,-8363147.34 2662189.61,-8362132.71 2664112.398,-8361534.802 2666074.863,-8361625.394 2668954.892,-8362359.19 2672210.338,-8363618.419 2675101.332,-8359433.067 2668984.483,-8359600.662 2667731.803,-8358726.449 2666617.294,-8358436.555 2663984.205,-8358427.496 2658630.593,-8357521.575 2652795.892,-8363677.304 2654525.386,-8364506.221 2656565.539,-8364084.968 2659833.276),(-8432658.608 2543161.149,-8432178.47 2542945.794,-8431879.516 2540929.419,-8432001.816 2539887.067,-8432414.009 2539745.156,-8432830.733 2540048.554,-8432658.608 2543161.149),(-8434117.14 2549319.52,-8434307.383 2550230.25,-8433582.647 2549045.331,-8433632.472 2547982.893,-8434325.501 2548438.216,-8434117.14 2549319.52),(-8374199.569 2653948.867,-8373678.664 2655023.08,-8372985.635 2656008.66,-8372106.893 2656979.514,-8371418.393 2656979.514,-8370304.111 2655230.047,-8367169.627 2653682.789,-8366028.167 2652012.507,-8368895.405 2652421.439,-8369823.973 2652766.33,-8369063 2651362.178,-8367917.011 2650165.051,-8366585.308 2649465.535,-8365267.194 2649534.5,-8363908.314 2648628.127,-8361788.46 2646825.383,-8360773.829 2646234.363,-8359519.13 2645929.011,-8357720.878 2645771.413,-8356583.948 2646130.937,-8357322.273 2647431.201,-8357521.575 2652795.892,-8355637.261 2649160.123,-8352480.129 2646943.59,-8342990.613 2643358.373,-8338904.912 2640162.877,-8331689.257 2632036.636,-8332164.865 2631416.629,-8332776.361 2630235.728,-8333279.147 2629635.469,-8331933.855 2628405.5,-8330978.109 2625296.551,-8330416.439 2621637.405,-8330262.432 2616902.386,-8330479.853 2615619.298,-8331145.705 2615088.395,-8332518.174 2615530.813,-8333161.377 2616371.441,-8333972.176 2620476.88,-8334384.37 2620191.678,-8335489.593 2619660.627,-8336214.329 2622807.85,-8339394.109 2628494.055,-8340549.158 2633434.199,-8341604.555 2635127.182,-8345359.595 2639744.407,-8346514.643 2640842.298,-8347909.76 2641521.747,-8360637.941 2644062.549,-8363405.528 2645810.812,-8364832.352 2646982.992,-8372781.803 2652042.068,-8374525.7 2652766.33,-8374199.569 2653948.867),(-8279576.19 2581832.893,-8276342.054 2585277.124,-8272374.123 2588339.264,-8269230.579 2592378.816,-8269805.839 2588992.004,-8272990.149 2584016.119,-8277130.205 2579291.881,-8280563.643 2576658.076,-8279576.19 2581832.893),(-8430919.241 2538536.51,-8430384.748 2537743.842,-8431281.609 2538301.641,-8430919.241 2538536.51),(-8431897.635 2536246.682,-8431240.842 2536026.523,-8430561.402 2535527.505,-8430670.113 2536271.144,-8430384.748 2537743.842,-8429342.939 2535865.074,-8428908.098 2535048.071,-8428523.082 2533502.233,-8429324.821 2532592.408,-8430710.879 2532553.277,-8431634.918 2533541.367,-8432287.18 2535155.698,-8432423.069 2536099.909,-8431897.635 2536246.682),(-8440195.865 2558223.288,-8439534.543 2556954.53,-8439317.122 2556195.281,-8438891.34 2555485.047,-8438311.551 2553981.409,-8438628.623 2553310.449,-8439480.188 2554353.633,-8440263.809 2556165.892,-8440648.825 2557899.966,-8440195.865 2558223.288),(-8443149.165 2568646.416,-8442872.86 2569229.755,-8442370.074 2568827.788,-8441953.351 2567847.423,-8441962.41 2567033.763,-8442705.264 2566960.241,-8443194.461 2567764.094,-8443149.165 2568646.416),(-8675146.304 2523790.171,-8673597.18 2522792.872,-8672193.004 2521521.891,-8670458.166 2520651.812,-8668637.266 2520607.821,-8667382.567 2521248.153,-8666313.581 2522176.923,-8665072.47 2523037.303,-8663160.978 2523599.506,-8661602.795 2523482.175,-8660252.974 2522939.53,-8658989.215 2522216.03,-8658567.962 2521707.644,-8657535.213 2520094.594,-8657059.604 2519752.452,-8656103.858 2520006.614,-8654500.38 2521135.727,-8653666.933 2521394.798,-8652453 2520847.332,-8648879.144 2518491.473,-8647588.207 2518041.844,-8646147.794 2518833.59,-8645232.814 2519850.206,-8644150.24 2519962.624,-8642197.981 2518041.844,-8641350.946 2516575.746,-8641106.347 2515095.115,-8641405.301 2513468.036,-8643810.52 2508060.214,-8643466.27 2506902.665,-8642197.981 2504924.756,-8643919.23 2504861.272,-8645241.874 2504338.753,-8647588.207 2502536.92,-8647062.774 2504685.469,-8647778.451 2505662.172,-8648974.265 2505291.018,-8649871.127 2503357.244,-8649572.173 2502986.14,-8649096.565 2502195.131,-8649015.032 2501345.569,-8649871.127 2500823.158,-8650514.33 2500984.274,-8650931.053 2501555.514,-8651293.422 2502287.902,-8652661.361 2504177.606,-8653195.854 2505305.669,-8653879.824 2506389.852,-8655261.353 2507459.451,-8656846.713 2506697.538,-8659238.343 2507210.36,-8661620.913 2508353.277,-8663170.037 2509501.155,-8663450.872 2510546.524,-8663011.501 2511816.685,-8662359.238 2513160.227,-8662033.107 2514420.811,-8662563.071 2515285.684,-8663767.945 2515862.29,-8665896.857 2516473.124,-8665335.187 2515442.05,-8665117.766 2514406.152,-8665294.42 2513370.318,-8665896.857 2512368.746,-8666657.83 2514831.254,-8667346.33 2514831.254,-8668474.201 2513116.255,-8670295.101 2512632.569,-8671993.701 2513350.775,-8672741.085 2515275.911,-8673705.891 2516707.69,-8675626.442 2518266.657,-8677035.148 2520270.556,-8676468.948 2523037.303,-8677293.335 2523848.837,-8675146.304 2523790.171),(-8686198.532 2536099.909,-8684753.589 2537650.877,-8683802.373 2539622.819,-8683449.064 2541575.416,-8684142.093 2545344.225,-8683290.528 2545941.438,-8683680.074 2547302.381,-8684903.066 2549373.379,-8683218.054 2549108.982,-8681492.276 2548521.448,-8680128.866 2547449.252,-8679576.254 2545755.419,-8680210.399 2544649.134,-8681415.273 2543440.137,-8682185.305 2541942.47,-8681519.454 2539970.257,-8680541.06 2539549.418,-8677796.121 2539945.789,-8676468.948 2539520.057,-8675698.915 2538443.541,-8675191.6 2537220.31,-8674394.39 2536320.069,-8672741.085 2536158.618,-8674195.088 2537053.958,-8673751.187 2537817.236,-8673257.46 2538477.793,-8672686.73 2539035.616,-8672048.056 2539520.057,-8671214.61 2538061.883,-8670104.857 2537332.844,-8669013.223 2537513.877,-8668179.777 2538771.382,-8667291.975 2536711.472,-8668501.378 2535821.043,-8670526.11 2535366.062,-8672048.056 2534598.002,-8670761.65 2534250.675,-8669805.904 2533546.258,-8668995.105 2532753.825,-8668179.777 2532132.622,-8667002.08 2531731.542,-8664710.102 2531252.216,-8663550.524 2530494.126,-8666055.393 2525462.244,-8667717.757 2523438.176,-8668940.75 2524679.967,-8669448.065 2524445.291,-8670729.942 2524093.283,-8671219.139 2523848.837,-8671576.978 2524772.86,-8671871.402 2525276.45,-8672741.085 2526313.011,-8673216.694 2528728.64,-8675567.557 2529569.79,-8677438.282 2528601.493,-8676468.948 2525564.92,-8677904.831 2526210.33,-8681818.407 2528562.371,-8682620.147 2529227.457,-8683381.12 2531017.449,-8686932.327 2533560.933,-8688010.373 2535419.876,-8686198.532 2536099.909),(-8716175.436 2562074.237,-8713983.109 2562681.847,-8710051.414 2562598.544,-8706473.029 2564024.547,-8704919.376 2564098.055,-8704036.103 2562598.544,-8701816.599 2563838.327,-8698972.009 2563103.267,-8696172.715 2561275.557,-8694089.098 2559242.282,-8693020.112 2557748.105,-8692050.777 2555969.962,-8691330.571 2554089.157,-8690895.729 2550093.147,-8690383.884 2548839.693,-8688010.373 2546166.622,-8687063.686 2546142.146,-8685519.092 2545540.03,-8684142.093 2545344.225,-8685999.23 2543493.977,-8688662.635 2544237.967,-8694089.098 2547811.539,-8696516.965 2548286.44,-8699207.548 2548286.44,-8702015.901 2548873.966,-8704797.077 2551092.061,-8702441.684 2552590.542,-8703501.61 2554588.726,-8705761.882 2555764.239,-8707012.052 2554755.252,-8707152.469 2553633.682,-8707582.782 2552384.86,-8708316.577 2551606.23,-8709353.856 2551914.74,-8710051.414 2553192.911,-8710105.77 2554696.478,-8709593.925 2555636.888,-8708601.942 2555205.86,-8708574.764 2557302.327,-8710341.309 2559693.011,-8712950.36 2560839.485,-8715441.64 2559242.282,-8716007.841 2559864.487,-8716510.627 2560006.569,-8717045.119 2559982.072,-8717720.03 2560133.953,-8716175.436 2562074.237),(-8730778.872 2562598.544,-8730543.332 2562966.059,-8730262.497 2563269.877,-8730045.076 2563759.919,-8729949.955 2564691.037,-8729623.823 2565141.912,-8728890.028 2565083.102,-8728124.525 2564921.374,-8727667.035 2565068.399,-8730778.872 2561858.639,-8730778.872 2562598.544),(-8760012.921 2576329.493,-8758971.113 2575834.178,-8758590.626 2578222.614,-8757575.995 2578477.663,-8756393.769 2577918.523,-8755519.556 2577894,-8754305.623 2578095.091,-8749368.357 2577070.041,-8746659.655 2575333.974,-8743525.171 2575083.878,-8740358.979 2575333.974,-8737555.156 2575093.686,-8734841.924 2575260.416,-8733075.38 2576692.406,-8731548.904 2578340.328,-8729569.468 2579130.015,-8727041.95 2578870.052,-8724374.015 2578114.71,-8722109.214 2576849.344,-8720831.866 2575093.686,-8721239.531 2575260.416,-8722281.339 2575834.178,-8721783.083 2574211.022,-8714336.418 2566538.724,-8713919.694 2565480.077,-8714254.885 2564289.179,-8715056.624 2564303.881,-8716057.666 2564808.655,-8716959.057 2565068.399,-8727667.035 2565068.399,-8727571.914 2566200.538,-8727961.46 2567362.163,-8728876.439 2567906.243,-8730362.148 2567156.299,-8732531.828 2566190.736,-8735548.542 2565779.04,-8740589.989 2565891.765,-8743126.566 2566661.257,-8746174.988 2568808.18,-8750772.534 2569670.949,-8753988.551 2570700.447,-8755945.339 2572038.889,-8754341.86 2573367.632,-8756054.049 2575275.128,-8758323.38 2573553.959,-8760130.691 2572568.412,-8760420.585 2576658.076,-8760012.921 2576329.493),(-8767767.599 2576908.196,-8766218.475 2576457.002,-8765172.137 2576604.129,-8765036.249 2577496.729,-8764787.121 2577840.049,-8763989.911 2577437.875,-8764053.326 2576682.598,-8764873.184 2575348.686,-8765158.548 2574593.504,-8767187.81 2573897.198,-8768188.852 2573926.619,-8768401.743 2574701.385,-8768428.921 2576682.598,-8767767.599 2576908.196),(-8758640.452 2582715.961,-8758413.972 2582436.318,-8758223.728 2581999.691,-8758785.399 2581509.113,-8759206.652 2582068.373,-8758640.452 2582715.961),(-8760683.302 2585321.286,-8758966.583 2585247.683,-8756701.782 2583834.582,-8754713.287 2581283.452,-8754541.162 2580434.798,-8755333.842 2580179.72,-8756117.463 2580758.557,-8756017.812 2581204.962,-8756253.352 2581538.548,-8756941.851 2581577.793,-8757933.834 2582652.182,-8758640.452 2582715.961,-8758545.33 2583446.981,-8758826.165 2583682.484,-8759134.178 2583412.637,-8759324.422 2582887.674,-8759523.724 2582868.05,-8759822.678 2583137.888,-8760348.112 2583074.108,-8760465.881 2583285.074,-8760216.753 2583942.523,-8760361.7 2584423.359,-8761023.022 2584742.289,-8761254.032 2585056.319,-8760683.302 2585321.286),(-8730742.635 2830061.369,-8728432.538 2831122.756,-8726312.685 2832413.461,-8725388.646 2833489.963,-8725044.396 2835194.579,-8724229.068 2835040.059,-8723196.319 2834217.641,-8722281.339 2833948.496,-8721085.524 2834696.133,-8720220.37 2835613.285,-8720025.597 2836749.833,-8720831.866 2838135.737,-8719373.335 2840244.747,-8717588.672 2840179.927,-8716084.844 2838554.525,-8715441.64 2836002.094,-8715572.999 2833898.654,-8715985.193 2832054.644,-8716700.87 2830405.191,-8717720.03 2828855.564,-8719672.288 2827480.464,-8720002.949 2827181.546,-8719780.999 2825975.968,-8719246.506 2824904.975,-8718431.178 2824456.675,-8715432.581 2826369.514,-8713783.806 2826847.761,-8712877.886 2827819.246,-8713158.721 2830529.766,-8710993.572 2829483.368,-8710975.453 2827281.185,-8711555.242 2824710.71,-8711224.581 2822549.056,-8709381.033 2821413.562,-8708330.166 2822957.456,-8708071.979 2825657.153,-8708601.942 2828018.532,-8707532.956 2827540.249,-8706373.378 2826847.761,-8705376.866 2826543.873,-8704797.077 2827181.546,-8704865.021 2828940.267,-8705684.879 2830161.027,-8706808.22 2831137.706,-8707773.025 2832204.15,-8707913.443 2832931.767,-8707659.785 2834785.852,-8707773.025 2835548.485,-8708452.465 2836460.703,-8710191.832 2838065.94,-8710875.802 2838963.352,-8713448.616 2836849.534,-8714159.763 2838843.694,-8715029.447 2840678.551,-8716578.57 2841476.384,-8716768.814 2842398.931,-8716442.682 2844498.555,-8715441.64 2848174.841,-8713738.51 2849970.908,-8711301.585 2851991.736,-8709593.925 2854432.057,-8710051.414 2857456.803,-8708996.017 2858205.595,-8706088.013 2858779.695,-8705490.106 2859518.567,-8705150.385 2861066.323,-8703628.439 2864052.44,-8703284.19 2865760.484,-8702283.148 2865875.359,-8702677.223 2866834.353,-8703574.084 2868118.101,-8704036.103 2869197.133,-8703805.094 2870166.329,-8703207.186 2871875.064,-8702351.092 2873494.043,-8701345.52 2874223.64,-8700475.837 2875767.903,-8700720.435 2879221.826,-8701762.243 2884741.75,-8702962.588 2888637.914,-8705286.273 2893740.966,-8706781.042 2898440.309,-8705490.106 2901158.493,-8703614.851 2901053.361,-8699569.916 2900272.401,-8697884.904 2899551.551,-8696521.494 2898260.115,-8695760.521 2896888.712,-8694836.482 2895787.676,-8692988.405 2895347.285,-8691289.804 2896067.932,-8689650.089 2897419.24,-8687946.958 2898250.105,-8686035.466 2897409.23,-8684617.701 2896368.213,-8683054.988 2895527.443,-8681546.631 2894456.532,-8680346.287 2892755.241,-8682004.121 2890834.015,-8682284.956 2888667.927,-8681406.213 2886652.194,-8679576.254 2885201.835,-8680975.901 2880351.646,-8681424.332 2877327.319,-8680758.48 2875977.815,-8678720.16 2875662.948,-8677048.737 2874658.416,-8675594.735 2872824.444,-8668822.98 2855929.381,-8663903.833 2848529.049,-8662055.755 2846528.633,-8660162.382 2845660.704,-8658821.62 2844852.677,-8654699.682 2840718.442,-8653666.933 2838963.352,-8653549.163 2836759.803,-8653730.347 2833759.1,-8654178.778 2830943.362,-8654844.629 2829274.098,-8655487.833 2826942.416,-8654586.442 2823948.618,-8652144.987 2818749.466,-8651610.494 2814433.117,-8652629.654 2811297.429,-8655211.527 2809376.514,-8659401.409 2808729.628,-8661113.598 2808192.235,-8662277.706 2806958.293,-8663251.57 2805565.251,-8664383.97 2804560.35,-8667763.053 2804112.642,-8668637.266 2803058.093,-8667346.33 2800382.251,-8668678.033 2799019.64,-8672741.085 2796210.254,-8674752.229 2795598.721,-8678625.038 2795568.891,-8679956.741 2794957.383,-8684341.395 2791736.181,-8684903.066 2790752.058,-8684676.586 2789683.511,-8684305.159 2788694.549,-8684223.626 2787795.095,-8684903.066 2786960.29,-8685976.582 2786691.97,-8687036.508 2787069.607,-8687987.725 2787805.034,-8688698.872 2788629.945,-8689967.161 2791989.677,-8690678.308 2796165.507,-8691842.416 2799715.85,-8694433.348 2801217.78,-8697853.197 2802709.909,-8698600.581 2806321.458,-8697884.904 2814652.141,-8699891.518 2813079.218,-8701263.987 2811446.733,-8702962.588 2810162.767,-8705902.299 2809640.253,-8708126.334 2810232.436,-8722063.918 2818181.849,-8728726.962 2824371.998,-8730846.816 2826912.524,-8732232.874 2829692.642,-8730742.635 2830061.369),(-8619830.808 3076270.721,-8619391.437 3076007.252,-8619015.48 3076189.653,-8618793.529 3075662.724,-8618843.355 3074588.659,-8618770.882 3074234.033,-8618444.75 3074000.998,-8618789 3073793.296,-8619776.453 3074188.439,-8619930.46 3074841.969,-8619753.805 3075530.995,-8620075.407 3076260.587,-8619830.808 3076270.721),(-8604258.038 3050241.249,-8602754.21 3051637.194,-8601612.75 3052653.892,-8600738.537 3052689.301,-8601001.254 3051834.458,-8602174.421 3050731.838,-8604158.387 3049700.104,-8604434.692 3049659.645,-8604258.038 3050241.249),(-8606504.72 3042459.826,-8604910.3 3043218.064,-8604534.343 3042859.159,-8603854.903 3043081.578,-8603605.775 3042687.293,-8603655.601 3042121.159,-8603592.186 3041661.192,-8603198.111 3041044.555,-8603062.223 3040266.216,-8603411.002 3037421.087,-8603709.956 3037032.011,-8604294.275 3037466.565,-8603746.193 3040074.165,-8604570.58 3042035.23,-8605009.952 3042363.785,-8605598.8 3042373.895,-8606912.384 3041448.904,-8607166.042 3041878.537,-8606504.72 3042459.826),(-8635095.566 3040347.081,-8632110.558 3037835.441,-8631490.003 3037102.751,-8631970.141 3036157.889,-8635358.283 3032399.267,-8634724.139 3035167.619,-8635294.868 3036890.531,-8636092.078 3038522.687,-8636119.256 3040953.579,-8635095.566 3040347.081),(-8632681.288 3010942.339,-8631770.838 3011512.295,-8631281.641 3012389.97,-8630819.622 3012369.793,-8630076.767 3010321.969,-8630774.326 3008859.415,-8631145.753 3008904.802,-8631544.358 3009545.284,-8632164.914 3010014.316,-8632694.877 3010624.585,-8632681.288 3010942.339),(-8669638.308 2973037.445,-8668229.602 2972775.853,-8667142.498 2971523.293,-8662979.794 2964025.262,-8662794.08 2962909.182,-8664157.49 2963044.917,-8665561.667 2964698.973,-8667346.33 2967967.412,-8669615.66 2970497.18,-8670376.633 2972036.377,-8669638.308 2973037.445),(-8670430.989 3074406.279,-8667065.495 3075049.687,-8666567.238 3074456.94,-8667011.139 3073317.112,-8666648.771 3073681.847,-8666050.864 3074274.561,-8664832.401 3075267.54,-8664510.799 3074897.698,-8665511.841 3073676.781,-8665896.857 3072947.321,-8665905.917 3072405.315,-8666431.35 3071508.772,-8666843.544 3070191.918,-8667550.162 3069118.266,-8668270.369 3069087.881,-8668505.908 3069442.379,-8668768.625 3069918.433,-8670295.101 3071792.418,-8670797.886 3072846.01,-8671024.367 3073909.811,-8670430.989 3074406.279),(-8602400.901 3057404.497,-8601920.763 3057343.776,-8601386.27 3057728.344,-8600747.596 3058386.182,-8599850.735 3058659.446,-8598790.808 3058462.088,-8598052.483 3057915.572,-8597880.359 3057455.098,-8597934.714 3057333.656,-8598143.076 3057429.797,-8598550.74 3057485.458,-8598650.391 3057293.176,-8598396.733 3057080.657,-8598369.556 3056989.578,-8598596.036 3056938.979,-8598709.276 3055471.686,-8598432.97 3054029.837,-8599058.055 3053513.842,-8599492.897 3053458.197,-8599936.798 3053448.079,-8600910.662 3053953.954,-8601372.682 3055330.024,-8601916.234 3056250.851,-8602573.026 3056888.38,-8602400.901 3057404.497),(-8597219.037 3054606.559,-8595583.851 3054636.914,-8598432.97 3054029.837,-8597219.037 3054606.559),(-8678425.736 3110603.991,-8678095.075 3110786.838,-8677293.335 3110969.687,-8673284.638 3113600.946,-8668243.191 3114530.64,-8657816.048 3114383.307,-8647561.03 3112036.355,-8641708.784 3111508.09,-8639154.089 3113529.825,-8633224.84 3110736.047,-8628518.584 3107181.13,-8608108.199 3087178.55,-8605789.043 3085596.598,-8603179.993 3084754.991,-8599497.426 3084506.574,-8600448.643 3083137.825,-8601947.941 3082676.535,-8605580.681 3082803.261,-8603950.025 3079432.724,-8601644.458 3076706.468,-8598750.042 3074892.632,-8591946.58 3073621.057,-8588884.57 3072101.396,-8583539.64 3068196.61,-8579453.939 3065933.235,-8578149.414 3064794.088,-8577143.842 3063174.125,-8576310.395 3060896.362,-8576292.277 3058882.11,-8577768.927 3058006.656,-8578122.236 3057141.376,-8578149.414 3051596.73,-8577768.927 3049568.614,-8576749.767 3048248.722,-8575268.587 3047449.766,-8573515.631 3046964.346,-8574942.456 3044077.448,-8575114.581 3043152.348,-8574860.923 3041802.719,-8574317.371 3040953.579,-8573764.759 3040347.081,-8573515.631 3039715.339,-8573393.332 3038709.664,-8573243.855 3038229.593,-8573438.628 3037739.431,-8574353.607 3036713.683,-8575241.409 3035965.893,-8576165.448 3035511.175,-8578149.414 3035096.888,-8577918.404 3035622.327,-8577388.441 3037481.724,-8581003.063 3037047.169,-8584436.501 3035096.888,-8587480.393 3032343.703,-8589962.615 3029510.239,-8591013.482 3026440.02,-8591996.406 3016960.795,-8591828.811 3014609.617,-8592997.448 3007628.966,-8592435.777 2997653.069,-8592834.382 2988721.396,-8596834.021 2984854.213,-8599769.202 2986404.991,-8602351.075 2989920.028,-8604185.564 2993788.554,-8604883.123 2996347.988,-8606672.315 2997960.46,-8614812.01 2999754.546,-8617049.633 3002763.664,-8615246.851 3002778.787,-8613226.649 3003474.451,-8611577.874 3004765.047,-8610327.704 3007830.672,-8608959.764 3008208.878,-8607338.167 3008395.463,-8605992.875 3009071.224,-8601920.763 3013741.896,-8599311.713 3015941.568,-8596458.064 3017152.539,-8597182.8 3018166.805,-8597626.701 3019191.235,-8597853.181 3020362.102,-8597907.536 3021846.009,-8598355.967 3022704.12,-8599293.594 3023441.126,-8600145.159 3024359.913,-8600326.344 3025702.86,-8599633.314 3027101.476,-8598596.036 3028156.838,-8597635.76 3029338.532,-8597219.037 3031161.763,-8597268.862 3034435.066,-8597581.405 3036036.628,-8599470.249 3037906.185,-8595937.159 3043152.348,-8596077.577 3044350.44,-8597051.441 3045841.876,-8595583.851 3054636.914,-8594374.447 3055335.083,-8593441.349 3056524.074,-8592662.257 3058006.656,-8592539.958 3058629.083,-8592662.257 3061012.772,-8592354.244 3061878.286,-8591656.686 3062394.583,-8590859.476 3062738.791,-8590311.394 3063103.256,-8589183.523 3065052.287,-8588694.326 3067295.268,-8589491.536 3069128.394,-8593436.819 3070181.789,-8596041.34 3071397.341,-8606350.714 3072921.993,-8608307.502 3074152.977,-8609557.672 3076265.654,-8610898.434 3079321.231,-8610391.118 3080081.427,-8610264.29 3081095.085,-8610572.302 3082179.778,-8611836.061 3083837.391,-8612406.791 3085170.718,-8612800.867 3085779.122,-8613385.185 3085981.929,-8613906.089 3085505.337,-8614449.642 3084836.107,-8615110.963 3084506.574,-8617380.294 3084719.502,-8619133.25 3085434.357,-8619912.341 3086727.27,-8619260.078 3088679.539,-8621103.626 3092904.458,-8626172.251 3101413.913,-8629207.084 3105018.148,-8631091.398 3106389.014,-8633519.265 3107308.076,-8635996.957 3107384.244,-8638057.925 3106246.844,-8639987.536 3105556.324,-8642628.294 3105982.818,-8649173.568 3108156.104,-8651189.241 3108410.015,-8655605.602 3108420.171,-8656919.187 3108836.595,-8660062.73 3110949.371,-8662033.107 3111833.174,-8664071.428 3112158.265,-8672876.974 3111487.773,-8676405.533 3110177.358,-8678751.867 3110116.411,-8678425.736 3110603.991),(-8569955.364 3061873.225,-8569701.707 3062505.944,-8569434.46 3062905.836,-8569194.391 3062718.543,-8569044.914 3062688.172,-8569081.151 3063194.373,-8568841.082 3064520.707,-8567522.968 3067821.888,-8567400.669 3067913.036,-8567128.893 3066814.238,-8567242.133 3065401.622,-8569683.588 3061134.245,-8569964.423 3061417.685,-8569955.364 3061873.225),(-8547239.149 2943226.629,-8546017.969 2943613.355,-8544709.561 2943323.31,-8543313.926 2942839.913,-8541527.584 2945133.695,-8538461.044 2945173.864,-8536730.736 2944942.893,-8535444.329 2944290.168,-8536662.792 2942382.367,-8537201.815 2940484.852,-8537238.051 2938376.787,-8536966.275 2935787.289,-8535217.849 2938105.772,-8533972.209 2936946.485,-8532971.167 2934567.973,-8531961.065 2933258.449,-8529809.505 2932656.408,-8515677.147 2921688.48,-8511591.447 2919357.521,-8506427.701 2918114.492,-8501277.544 2917898.977,-8499424.937 2917392.781,-8497658.392 2915974.52,-8491914.857 2907948.601,-8485183.869 2901323.703,-8478235.46 2896112.974,-8474892.614 2893906.093,-8473447.671 2892204.865,-8472849.763 2889863.489,-8473787.391 2879441.785,-8474262.999 2877472.273,-8474371.71 2876397.647,-8474820.14 2875113.196,-8475839.301 2874328.585,-8476899.227 2873843.845,-8477474.487 2873459.063,-8477864.033 2871095.617,-8477374.836 2868907.385,-8475961.6 2865760.484,-8475526.758 2863732.827,-8475961.6 2857876.122,-8476550.448 2855395.318,-8479168.558 2851173.393,-8479757.406 2849466.99,-8480038.241 2840878.006,-8479648.696 2836161.609,-8478235.46 2832204.15,-8481931.615 2833843.829,-8483856.696 2837746.874,-8485066.099 2842244.338,-8486601.634 2845660.704,-8488445.182 2847002.523,-8493309.974 2848998.012,-8495375.473 2850300.21,-8497721.806 2853029.698,-8497431.912 2854162.555,-8495620.071 2854297.305,-8484699.202 2852430.865,-8483965.406 2852760.22,-8483449.031 2853548.706,-8482987.012 2854496.938,-8482416.282 2855330.434,-8480590.853 2857182.255,-8480056.36 2858270.492,-8479757.406 2859972.892,-8479847.998 2862794.005,-8480758.448 2862154.839,-8482035.796 2860187.578,-8483208.963 2859059.264,-8483883.873 2860447.202,-8483761.574 2863592.999,-8482796.769 2869197.133,-8482167.154 2871255.5,-8481859.141 2871745.153,-8481206.879 2872544.621,-8478008.98 2875523.009,-8477474.487 2876397.647,-8476613.863 2883416.583,-8476650.099 2886042.026,-8478643.124 2891699.537,-8482139.977 2894706.738,-8486139.615 2896758.586,-8489640.997 2899551.551,-8498827.029 2913073.268,-8501644.441 2915408.255,-8505870.56 2916971.799,-8514784.816 2918956.533,-8519373.302 2921312.494,-8526095.231 2927735.636,-8530470.826 2929054.705,-8532898.693 2929315.523,-8537500.768 2930474.213,-8539625.151 2930740.073,-8542021.311 2930113.053,-8545930.357 2927921.202,-8547610.839 2928212.092,-8544829.664 2931121.313,-8543271.481 2935957.901,-8543750.062 2942163.184,-8544971.242 2942259.858,-8547936.967 2942453.207,-8547239.149 2943226.629),(-8432785.437 2836002.094,-8430466.281 2838773.894,-8429542.242 2839167.77,-8427870.819 2838963.352,-8427132.494 2838419.913,-8424142.957 2835548.485,-8421244.012 2834417.011,-8419907.779 2833669.387,-8418684.787 2832204.15,-8417819.633 2824396.903,-8417158.311 2822095.845,-8416071.206 2820806.008,-8414286.543 2819167.723,-8412637.768 2817230.889,-8411297.006 2813407.727,-8408207.818 2807714.568,-8401956.968 2798631.765,-8399959.413 2797010.753,-8395606.466 2794629.267,-8393531.909 2792874.461,-8390773.381 2787069.607,-8390107.53 2786130.499,-8388870.948 2785295.783,-8383992.567 2779915.926,-8383136.473 2778108.156,-8381292.925 2771052.907,-8386343.431 2772735.748,-8388639.939 2772934.326,-8391248.989 2772720.855,-8396285.906 2771693.259,-8398043.392 2770725.296,-8399991.121 2769002.966,-8402745.118 2768734.955,-8405725.596 2770730.26,-8406993.885 2773232.196,-8404579.607 2774453.525,-8402944.421 2774895.412,-8400570.91 2776042.39,-8398378.582 2777641.348,-8397264.3 2779458.997,-8395121.799 2779399.399,-8394129.816 2782717.392,-8394609.954 2786696.938,-8396910.991 2788629.945,-8400163.245 2789345.567,-8402459.753 2791154.646,-8408407.12 2800909.425,-8409285.863 2804361.367,-8411423.835 2807535.447,-8411913.032 2809187.421,-8412583.413 2813079.218,-8414472.257 2816001.2,-8417353.084 2817708.851,-8421026.591 2817997.627,-8420591.749 2819282.248,-8420501.157 2820756.21,-8420668.752 2822305.017,-8421026.591 2823769.307,-8421624.498 2825268.606,-8422190.698 2825826.522,-8422956.201 2826205.12,-8427870.819 2830529.766,-8431458.263 2832343.691,-8432432.128 2833036.427,-8433184.042 2834078.084,-8433292.752 2835010.152,-8432785.437 2836002.094),(-8299769.154 2748582.761,-8297875.78 2750977.05,-8296602.962 2754755.118,-8296136.413 2758980.494,-8296657.317 2762720.804,-8296607.492 2765648.195,-8295384.499 2767419.782,-8293445.83 2768506.653,-8291271.621 2769385.138,-8290655.595 2769891.406,-8290048.629 2770561.493,-8289387.307 2770958.594,-8288644.452 2770635.948,-8286977.559 2767633.18,-8286710.312 2767335.416,-8286488.362 2766065.021,-8285473.731 2764353.129,-8285188.366 2763554.31,-8285256.31 2762447.939,-8285867.806 2760041.976,-8286017.283 2758940.814,-8290574.062 2750996.88,-8290909.253 2752394.958,-8292331.548 2749653.454,-8292444.788 2748582.761,-8299769.154 2747750.05,-8299769.154 2748582.761),(-8208905.344 2643752.314,-8202654.494 2644417.111,-8200480.285 2643752.314,-8200480.285 2642851.187,-8210395.583 2640847.221,-8215083.721 2640945.691,-8217266.989 2644579.621,-8208905.344 2643752.314),(-8186544.488 2585399.951,-8184645.477 2585669.589,-8182114.598 2585034.498,-8179584.973 2583856.852,-8178502.309 2582228.948,-8179225.517 2582049.048,-8183923.915 2583499.749,-8186002.843 2584134.048,-8188263.06 2584497.175,-8188534.094 2585130.129,-8186544.488 2585399.951),(-8195137.984 2583867.224,-8193780.592 2584861.354,-8192423.725 2583956.872,-8193962.556 2580974.241,-8195952.947 2580612.887,-8195137.984 2583867.224),(-8247737.619 2590655.873,-8248118.106 2591637.585,-8248172.461 2591902.657,-8247737.619 2590655.873),(-8276405.468 2610974.475,-8276224.284 2611372.551,-8276142.752 2611785.381,-8275997.804 2612227.71,-8274774.812 2612301.433,-8272917.675 2612950.207,-8272197.468 2613063.254,-8270865.766 2612679.882,-8267708.633 2610586.237,-8266594.351 2610291.379,-8264175.544 2610075.153,-8263079.38 2609760.647,-8259967.544 2607205.513,-8259627.824 2606173.745,-8259500.995 2604046.541,-8259206.571 2603162.333,-8258812.496 2603049.355,-8257453.615 2603226.191,-8257000.655 2603162.333,-8256765.116 2602808.664,-8256239.682 2601438.265,-8254065.473 2600686.805,-8250070.364 2600406.858,-8247737.619 2599797.867,-8248566.536 2601438.265,-8246093.374 2600834.148,-8239448.448 2598216.559,-8239448.448 2593954.656,-8248172.461 2591902.657,-8249327.51 2592378.816,-8249227.858 2594367.05,-8251270.709 2593993.932,-8254165.124 2593100.444,-8262386.351 2595250.787,-8263532.341 2596203.311,-8265353.24 2598216.559,-8265969.266 2596802.349,-8267300.969 2595604.295,-8268623.613 2594956.203,-8269230.579 2595221.328,-8268587.376 2597833.532,-8268605.494 2599208.542,-8269574.829 2599797.867,-8276822.192 2610586.237,-8276405.468 2610974.475),(-8268474.136 2537464.949,-8267971.35 2538649.052,-8266802.713 2538981.79,-8262413.529 2538624.586,-8261475.901 2539064.976,-8258114.937 2542059.93,-8258024.345 2542828.329,-8259206.571 2543704.444,-8259206.571 2544443.549,-8257027.832 2545843.533,-8256239.682 2546166.622,-8256891.944 2546362.437,-8257399.26 2546582.732,-8257734.45 2547018.434,-8257825.042 2547811.539,-8255587.419 2548692.81,-8252317.047 2550700.323,-8249744.233 2551092.061,-8249146.326 2551483.808,-8247927.863 2553178.218,-8246455.742 2554221.395,-8246573.512 2555734.85,-8246999.294 2557395.4,-8246976.646 2558487.828,-8244924.737 2559320.669,-8241880.844 2559644.018,-8239126.847 2560320.132,-8237926.502 2562231.037,-8237464.483 2565141.912,-8236187.135 2566543.626,-8234230.347 2567112.186,-8231779.833 2567538.619,-8227368.001 2569185.636,-8224305.99 2572014.374,-8223264.182 2575917.547,-8224940.134 2580773.273,-8228006.675 2583049.577,-8235919.889 2583186.95,-8239448.448 2584963.091,-8241119.871 2586572.576,-8240929.628 2587024.045,-8239584.336 2589203.046,-8238850.541 2589899.995,-8238039.742 2590361.371,-8237165.529 2590655.873,-8237876.677 2591441.238,-8239448.448 2593954.656,-8235765.882 2592879.534,-8234887.139 2592378.816,-8234515.712 2593719.007,-8233691.325 2594749.997,-8232694.812 2595221.328,-8231779.833 2594848.19,-8231104.922 2595353.893,-8230801.439 2595525.737,-8230330.36 2595594.475,-8230330.36 2596497.917,-8231240.81 2596753.247,-8231616.767 2597008.581,-8231915.721 2597440.693,-8232604.22 2598216.559,-8226860.685 2598152.72,-8224115.747 2598594.684,-8221135.269 2599797.867,-8221017.499 2599331.316,-8220967.674 2598943.352,-8220809.137 2598570.13,-8220374.296 2598216.559,-8223001.465 2593542.272,-8224251.635 2592378.816,-8224305.99 2593591.365,-8224695.536 2594553.613,-8225424.802 2595231.148,-8226457.551 2595594.475,-8226072.535 2593954.656,-8225153.025 2592378.816,-8223943.622 2591613.042,-8222657.215 2592378.816,-8221905.301 2590611.698,-8220886.141 2581602.322,-8220274.644 2579752.963,-8218852.35 2576658.076,-8220763.841 2576192.177,-8221565.581 2574152.18,-8221959.656 2571509.382,-8222657.215 2569259.167,-8223744.319 2567867.029,-8225347.798 2566244.649,-8227041.869 2564887.068,-8228391.691 2564318.583,-8229669.038 2563245.376,-8233365.193 2556028.741,-8239176.672 2551199.79,-8240204.892 2550680.736,-8241382.588 2550592.597,-8248149.813 2547811.539,-8250930.989 2547204.468,-8252634.119 2545642.829,-8255415.294 2541164.324,-8256312.155 2540175.787,-8259256.396 2537582.377,-8260379.738 2537053.958,-8262902.726 2536662.546,-8264886.691 2535600.889,-8268474.136 2532132.622,-8268614.553 2533218.519,-8268474.136 2537464.949)) \ No newline at end of file diff --git a/encoding/wkt/wkt.go b/encoding/wkt/wkt.go index ad38a7f8..0a1a9280 100644 --- a/encoding/wkt/wkt.go +++ b/encoding/wkt/wkt.go @@ -45,3 +45,10 @@ func DecodeBytes(b []byte) (geo geom.Geometry, err error) { func DecodeString(s string) (geo geom.Geometry, err error) { return Decode(strings.NewReader(s)) } + +func MustDecode(geo geom.Geometry, err error) geom.Geometry { + if err != nil { + panic(err) + } + return geo +} diff --git a/planar/makevalid/hitmap/polygon_hitmap.go b/planar/makevalid/hitmap/polygon_hitmap.go index e9e58b09..5fb180d4 100644 --- a/planar/makevalid/hitmap/polygon_hitmap.go +++ b/planar/makevalid/hitmap/polygon_hitmap.go @@ -5,6 +5,8 @@ import ( "math/big" "sort" + "github.com/go-spatial/geom/encoding/wkt" + "github.com/go-spatial/geom" "github.com/go-spatial/geom/planar" ) @@ -39,10 +41,11 @@ func NewFromPolygons(clipbox *geom.Extent, plys ...[][][2]float64) (*PolygonHM, for i := range plys { log.Printf("[% 3v] Polygons Rings:[% 3v]", i, len(plys[i])) for j := range plys[i] { - log.Printf("\t[%v]Ring: %v", j, plys[i][j]) + log.Printf("\t[%v]Ring: %v", j, wkt.MustEncode(geom.LineString(plys[i][j]))) } } } + for i := range plys { if len(plys[i]) == 0 { continue @@ -63,10 +66,8 @@ func NewFromPolygons(clipbox *geom.Extent, plys ...[][][2]float64) (*PolygonHM, } for j := range plys[i][1:] { if len(plys[i][j+1]) == 0 { - if debug { - log.Println("got an invalid linestring") - } - return nil, geom.ErrInvalidLineString + // Empty cutout skip + continue } // plys we assume the first ring is inside, and all other rings are outside. ring := NewRing(plys[i][j+1], planar.Outside) diff --git a/planar/makevalid/makevalid.go b/planar/makevalid/makevalid.go index b911feee..41a6333b 100644 --- a/planar/makevalid/makevalid.go +++ b/planar/makevalid/makevalid.go @@ -7,6 +7,7 @@ import ( "sort" "github.com/go-spatial/geom/encoding/wkt" + "github.com/go-spatial/geom/winding" "github.com/go-spatial/geom" pkgcmp "github.com/go-spatial/geom/cmp" @@ -23,6 +24,7 @@ type Makevalid struct { // Used to clip geometries that are not Polygon and MultiPolygons Clipper planar.Clipper CMP pkgcmp.Compare + Order winding.Order } // asSegments calls the AsSegments functions and flattens the array of segments that are returned. @@ -163,40 +165,22 @@ func unique(segs []geom.Line) { } func (mv *Makevalid) makevalidPolygon(ctx context.Context, clipbox *geom.Extent, multipolygon *geom.MultiPolygon) (*geom.MultiPolygon, error) { - if debug { - log.Printf("*Step 1 : Destructure the geometry into segments w/ the clipbox applied.") - } - segs, err := Destructure(ctx, cmp, clipbox, multipolygon) + hm, err := hitmap.NewFromPolygons(nil, (*multipolygon)...) if err != nil { - if debug { - log.Printf("Destructure returned err %v", err) - } return nil, err } - if len(segs) == 0 { - if debug { - log.Printf("Step 1a: Segments are zero.") - log.Printf("\t multiPolygon: %+v", multipolygon) - log.Printf("\n clipbox: %+v", clipbox) - } - return nil, nil - } - if debug { - log.Printf("Step 2 : Convert segments to linestrings to use in triangulation.") - log.Printf("Step 2a: %v", wkt.MustEncode(segs)) - } - hm, err := hitmap.NewFromPolygons(nil, (*multipolygon)...) + triangles, err := InsideTrianglesForMultiPolygon(ctx, clipbox, multipolygon, hm) if err != nil { return nil, err } - triangles, err := InsideTrianglesForSegments(ctx, segs, hm) if debug { log.Printf("Step 5 : generate multipolygon from triangles") } if len(triangles) == 0 { return nil, nil } + triWalker := walker.New(triangles) mplygs := triWalker.MultiPolygon(ctx) diff --git a/planar/makevalid/makevalid_test.go b/planar/makevalid/makevalid_test.go index 58d68b7a..0b37007d 100644 --- a/planar/makevalid/makevalid_test.go +++ b/planar/makevalid/makevalid_test.go @@ -10,10 +10,10 @@ import ( "github.com/go-spatial/geom/encoding/wkt" "github.com/go-spatial/geom/slippy" + "github.com/go-spatial/geom/winding" "github.com/go-spatial/geom" "github.com/go-spatial/geom/planar/makevalid/hitmap" - "github.com/go-spatial/geom/windingorder" ) var runAll bool @@ -48,6 +48,8 @@ func checkMakeValid(tb testing.TB) { skip string } + order := winding.Order{} + fn := func(tc tcase) func(testing.TB) { return func(t testing.TB) { if tc.skip != "" && !runAll { @@ -89,14 +91,14 @@ func checkMakeValid(tb testing.TB) { if !geom.IsEmpty(tc.ExpectedMultiPolygon) { for p, ply := range tc.ExpectedMultiPolygon.Polygons() { for l, ln := range ply { - t.Logf("expected windorder %v:%v: %v", p, l, windingorder.OfPoints(ln...)) + t.Logf("expected windorder %v:%v: %v", p, l, order.OfPoints(ln...)) } } } if !geom.IsEmpty(mp) { for p, ply := range mp.Polygons() { for l, ln := range ply { - t.Logf("got windorder %v:%v: %v", p, l, windingorder.OfPoints(ln...)) + t.Logf("got windorder %v:%v: %v", p, l, order.OfPoints(ln...)) } } } diff --git a/planar/makevalid/triangulate.go b/planar/makevalid/triangulate.go index 7b8a925e..d1536dfa 100644 --- a/planar/makevalid/triangulate.go +++ b/planar/makevalid/triangulate.go @@ -12,6 +12,7 @@ import ( "github.com/go-spatial/geom/planar" ) +// InsideTrianglesForSegments returns triangles that are painted as as inside triangles func InsideTrianglesForSegments(ctx context.Context, segs []geom.Line, hm planar.HitMapper) ([]geom.Triangle, error) { if debug { log.Printf("Step 3 : generate triangles") @@ -50,3 +51,34 @@ func InsideTrianglesForSegments(ctx context.Context, segs []geom.Line, hm planar return triangles, nil } + +// InsideTrianglesForMultiPolygon returns triangles that are painted as inside triangles for the multipolygon +func InsideTrianglesForMultiPolygon(ctx context.Context, clipbox *geom.Extent, multipolygon *geom.MultiPolygon, hm planar.HitMapper) ([]geom.Triangle, error) { + segs, err := Destructure(ctx, cmp, clipbox, multipolygon) + if err != nil { + if debug { + log.Printf("Destructure returned err %v", err) + } + return nil, err + } + if len(segs) == 0 { + if debug { + log.Printf("Step 1a: Segments are zero.") + log.Printf("\t multiPolygon: %+v", multipolygon) + log.Printf("\n clipbox: %+v", clipbox) + } + return nil, nil + } + if debug { + log.Printf("Step 2 : Convert segments(%v) to linestrings to use in triangulation.", len(segs)) + log.Printf("Step 2a: %v", wkt.MustEncode(segs)) + } + triangles, err := InsideTrianglesForSegments(ctx, segs, hm) + if err != nil { + return nil, err + } + if len(triangles) == 0 { + return nil, nil + } + return triangles, nil +} diff --git a/planar/makevalid/walker/walker.go b/planar/makevalid/walker/walker.go index d32e287c..8ce460d3 100644 --- a/planar/makevalid/walker/walker.go +++ b/planar/makevalid/walker/walker.go @@ -4,7 +4,7 @@ import ( "context" "log" - "github.com/go-spatial/geom/windingorder" + "github.com/go-spatial/geom/winding" "github.com/go-spatial/geom/encoding/wkt" @@ -58,6 +58,7 @@ func New(triangles []geom.Triangle) *Walker { type Walker struct { Triangles []geom.Triangle edgeMap map[[2][2]float64][]int + Order winding.Order } // EdgeMap returns a copy of the edgemap @@ -107,39 +108,7 @@ func (w *Walker) MultiPolygon(ctx context.Context) (mplyg geom.MultiPolygon) { func (w *Walker) PolygonForTriangle(ctx context.Context, idx int, seen map[int]bool) (plyg [][][2]float64) { // Get the external ring for the given triangle. plyg4r := PolygonForRing(ctx, w.RingForTriangle(ctx, idx, seen)) - - reverse := func(idx int) { - for i := len(plyg[idx])/2 - 1; i >= 0; i-- { - opp := len(plyg[idx]) - 1 - i - plyg[idx][i], plyg[idx][opp] = plyg[idx][opp], plyg[idx][i] - } - } - - plyg = make([][][2]float64, 0, len(plyg4r)) - // Let's make sure each of the rings have the correct windingorder. - - for i := range plyg4r { - - wo := windingorder.OfPoints(plyg4r[i]...) - - // Drop collinear rings - if wo == windingorder.Colinear { - if i == 0 { - return nil - } - continue - } - - plyg = append(plyg, plyg4r[i]) - - if (i == 0 && wo != windingorder.Clockwise) || (i != 0 && wo != windingorder.CounterClockwise) { - // 0 ring should be clockwise. - // all others should be conterclockwise - // reverse the ring. - reverse(len(plyg) - 1) - } - } - return plyg + return w.Order.RectifyPolygon(plyg4r) } // RingForTriangle will walk the set of triangles starting at the given triangle index. As it walks the triangles it will diff --git a/planar/triangulate/delaunay/quadedge/edge.go b/planar/triangulate/delaunay/quadedge/edge.go index 94013bc3..aa6787b1 100644 --- a/planar/triangulate/delaunay/quadedge/edge.go +++ b/planar/triangulate/delaunay/quadedge/edge.go @@ -7,7 +7,7 @@ import ( "github.com/go-spatial/geom" "github.com/go-spatial/geom/planar/intersect" - "github.com/go-spatial/geom/windingorder" + "github.com/go-spatial/geom/winding" ) const ( @@ -245,7 +245,7 @@ func (e *Edge) IsEqual(e1 *Edge) bool { // Validate check to se if the edges in the edges are correctly // oriented -func Validate(e *Edge) (err1 error) { +func Validate(e *Edge, order winding.Order) (err1 error) { const radius = 10 var err ErrInvalid @@ -342,7 +342,7 @@ func Validate(e *Edge) (err1 error) { // All points are colinear to each other. // Need to check winding order with original point // not enough information just using the outer points, we need to include the origin - if !windingorder.OfGeomPoints(append(points, orig)...).IsCounterClockwise() { + if !order.OfGeomPoints(append(points, orig)...).IsCounterClockwise() { err = append(err, fmt.Sprintf("1. expected all points to be counter-clockwise: %v:%v\n%v", wkt.MustEncode(orig), diff --git a/planar/triangulate/delaunay/quadedge/edge_test.go b/planar/triangulate/delaunay/quadedge/edge_test.go index 8601c233..db9acd9b 100644 --- a/planar/triangulate/delaunay/quadedge/edge_test.go +++ b/planar/triangulate/delaunay/quadedge/edge_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/go-spatial/geom" + "github.com/go-spatial/geom/winding" ) func TestFindONextDest(t *testing.T) { @@ -101,11 +102,14 @@ func TestValidate(t *testing.T) { edge *Edge err ErrInvalid } + order := winding.Order{ + YPositiveDown: true, + } //const debug = true fn := func(tc tcase) func(*testing.T) { return func(t *testing.T) { - e := Validate(tc.edge) + e := Validate(tc.edge, order) err, _ := e.(ErrInvalid) if len(err) != len(tc.err) { t.Errorf("len(error), expected %v got %v", len(tc.err), len(err)) @@ -291,7 +295,6 @@ func TestValidate(t *testing.T) { geom.Point{368, 117}, ), err: ErrInvalid{ - "expected all points to be counter-clockwise: MULTIPOINT (384 112,384 112,372 114,376 119,368 117)", "found self interstion for vertics POINT (376 119) and POINT (384 112)", }, }, diff --git a/planar/triangulate/delaunay/quadedge/resolve_edge_test.go b/planar/triangulate/delaunay/quadedge/resolve_edge_test.go index 4c363b24..6741db08 100644 --- a/planar/triangulate/delaunay/quadedge/resolve_edge_test.go +++ b/planar/triangulate/delaunay/quadedge/resolve_edge_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/go-spatial/geom" + "github.com/go-spatial/geom/winding" ) func findEdgeWithDest(e *Edge, dest geom.Point) *Edge { @@ -29,6 +30,9 @@ func TestResolveEdge(t *testing.T) { err error noValidation bool } + order := winding.Order{ + YPositiveDown: true, + } fn := func(tc tcase) func(*testing.T) { @@ -39,7 +43,7 @@ func TestResolveEdge(t *testing.T) { ) // Validate our test case if !tc.noValidation { - if err := Validate(edge); err != nil { + if err := Validate(edge, order); err != nil { if e, ok := err.(ErrInvalid); ok { for i, estr := range e { t.Logf("err %03v: %v", i, estr) diff --git a/planar/triangulate/delaunay/quadedge/topo.go b/planar/triangulate/delaunay/quadedge/topo.go index 9591bbc5..bbc38cc0 100644 --- a/planar/triangulate/delaunay/quadedge/topo.go +++ b/planar/triangulate/delaunay/quadedge/topo.go @@ -3,6 +3,8 @@ package quadedge import ( "log" + "github.com/go-spatial/geom/winding" + "github.com/go-spatial/geom/planar" "github.com/go-spatial/geom" @@ -38,7 +40,7 @@ func Splice(a, b *Edge) { // origin of b, in such a way that all three have the same // left face after the connection is complete. // Additionally, the data pointers of the new edge are set. -func Connect(a, b *Edge) *Edge { +func Connect(a, b *Edge, order winding.Order) *Edge { //const debug = true if debug { log.Printf("\n\n\tConnect\n\n") @@ -60,7 +62,7 @@ func Connect(a, b *Edge) *Edge { Splice(e.Sym(), bb) if debug { log.Printf("\n\n\tvalidate e:\n%v\n", e.DumpAllEdges()) - if err := Validate(e); err != nil { + if err := Validate(e, order); err != nil { if err1, ok := err.(ErrInvalid); ok { for i, estr := range err1 { log.Printf("err: %03v : %v", i, estr) @@ -69,7 +71,7 @@ func Connect(a, b *Edge) *Edge { log.Printf("Vertex Edges: %v", e.DumpAllEdges()) } log.Printf("\n\n\tvalidate a:\n%v\n", a.DumpAllEdges()) - if err := Validate(a); err != nil { + if err := Validate(a, order); err != nil { if err1, ok := err.(ErrInvalid); ok { for i, estr := range err1 { log.Printf("err: %03v : %v", i, estr) @@ -78,7 +80,7 @@ func Connect(a, b *Edge) *Edge { log.Printf("Vertex Edges: %v", e.DumpAllEdges()) } log.Printf("\n\n\tvalidate b:\n%v\n", b.DumpAllEdges()) - if err := Validate(b); err != nil { + if err := Validate(b, order); err != nil { if err1, ok := err.(ErrInvalid); ok { for i, estr := range err1 { log.Printf("err: %03v : %v", i, estr) diff --git a/planar/triangulate/delaunay/quadedge/topo_test.go b/planar/triangulate/delaunay/quadedge/topo_test.go index 4a5fcb62..07743f16 100644 --- a/planar/triangulate/delaunay/quadedge/topo_test.go +++ b/planar/triangulate/delaunay/quadedge/topo_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/go-spatial/geom" + "github.com/go-spatial/geom/winding" ) func TestSplice(t *testing.T) { @@ -13,10 +14,13 @@ func TestSplice(t *testing.T) { b *Edge err ErrInvalid } + order := winding.Order{ + YPositiveDown: true, + } fn := func(tc tcase) (string, func(*testing.T)) { return tc.Desc, func(t *testing.T) { var err error - if err = Validate(tc.a); err != nil { + if err = Validate(tc.a, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -25,7 +29,7 @@ func TestSplice(t *testing.T) { t.Errorf("validate on a: expected nil got %v", err) return } - if err = Validate(tc.b); err != nil { + if err = Validate(tc.b, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -41,7 +45,7 @@ func TestSplice(t *testing.T) { Splice(tc.a.Sym(), tc.b) - if err := Validate(tc.a); err != nil { + if err := Validate(tc.a, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -50,7 +54,7 @@ func TestSplice(t *testing.T) { } t.Errorf("after splice validate on a: expected nil got %v", err) } - if err := Validate(tc.b); err != nil { + if err := Validate(tc.b, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -96,10 +100,14 @@ func TestConnect(t *testing.T) { err ErrInvalid } + order := winding.Order{ + YPositiveDown: true, + } + fn := func(tc tcase) (string, func(*testing.T)) { return tc.Name, func(t *testing.T) { var err error - if err = Validate(tc.a); err != nil { + if err = Validate(tc.a, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -108,7 +116,7 @@ func TestConnect(t *testing.T) { t.Errorf("validate on a: expected nil got %v", err) return } - if err = Validate(tc.b); err != nil { + if err = Validate(tc.b, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -122,9 +130,9 @@ func TestConnect(t *testing.T) { tc.b, _ = ResolveEdge(tc.b, *tc.a.Orig()) t.Logf("Connecting a:%v to b: %v", wkt.MustEncode(tc.a.AsLine()), wkt.MustEncode(tc.b.AsLine())) - e := Connect(tc.a, tc.b) + e := Connect(tc.a, tc.b, order) - if err = Validate(tc.a); err != nil { + if err = Validate(tc.a, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -133,7 +141,7 @@ func TestConnect(t *testing.T) { t.Errorf("validate on a: expected nil got %v", err) return } - if err = Validate(tc.b); err != nil { + if err = Validate(tc.b, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) @@ -142,7 +150,7 @@ func TestConnect(t *testing.T) { t.Errorf("validate on b: expected nil got %v", err) return } - if err = Validate(e); err != nil { + if err = Validate(e, order); err != nil { if verr, ok := err.(ErrInvalid); ok { for i, estr := range verr { t.Logf("%03v: %v", i, estr) diff --git a/planar/triangulate/delaunay/subdivision/geom.go b/planar/triangulate/delaunay/subdivision/geom.go index 92e3d31a..c192fe12 100644 --- a/planar/triangulate/delaunay/subdivision/geom.go +++ b/planar/triangulate/delaunay/subdivision/geom.go @@ -8,6 +8,7 @@ import ( "github.com/go-spatial/geom" "github.com/go-spatial/geom/planar" "github.com/go-spatial/geom/planar/triangulate/delaunay/quadedge" + "github.com/go-spatial/geom/winding" ) // AsGeom returns a geom based Triangle @@ -22,7 +23,7 @@ func (t Triangle) AsGeom() (tri geom.Triangle) { // NewSubdivisionFromGeomLines returns a new subdivision made up of the given geom lines. // it is assume that all line are connected. If lines are disjointed that it is undefined // which disjointed subdivision will be returned -func NewSubdivisionFromGeomLines(lines []geom.Line) *Subdivision { +func NewSubdivisionFromGeomLines(lines []geom.Line, order winding.Order) *Subdivision { lines = planar.NormalizeUniqueLines(lines) var ( @@ -71,7 +72,7 @@ func NewSubdivisionFromGeomLines(lines []geom.Line) *Subdivision { switch { case oe != nil && de != nil: - eq = quadedge.Connect(oe.Sym(), de) + eq = quadedge.Connect(oe.Sym(), de, order) case oe != nil && de == nil: quadedge.Splice(oe, eq) diff --git a/planar/triangulate/delaunay/subdivision/geom_test.go b/planar/triangulate/delaunay/subdivision/geom_test.go index 6c6ea82f..942abb9b 100644 --- a/planar/triangulate/delaunay/subdivision/geom_test.go +++ b/planar/triangulate/delaunay/subdivision/geom_test.go @@ -6,6 +6,7 @@ import ( "github.com/go-spatial/geom" "github.com/go-spatial/geom/planar/triangulate/delaunay/test/must" + "github.com/go-spatial/geom/winding" ) func TestNewSubdivisionFromGeomLines(t *testing.T) { @@ -15,6 +16,10 @@ func TestNewSubdivisionFromGeomLines(t *testing.T) { Skip string } + order := winding.Order{ + YPositiveDown: true, + } + fn := func(tc tcase) func(*testing.T) { return func(t *testing.T) { @@ -22,7 +27,7 @@ func TestNewSubdivisionFromGeomLines(t *testing.T) { t.Skip(tc.Skip) return } - sd := NewSubdivisionFromGeomLines(tc.Lines) + sd := NewSubdivisionFromGeomLines(tc.Lines, order) if sd == nil { t.Errorf("subdivision, expected not nil, got nil") return diff --git a/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon.go b/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon.go index ce7c165e..220491c7 100644 --- a/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon.go +++ b/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon.go @@ -7,10 +7,10 @@ import ( "github.com/go-spatial/geom" "github.com/go-spatial/geom/encoding/wkt" "github.com/go-spatial/geom/planar" - "github.com/go-spatial/geom/windingorder" + "github.com/go-spatial/geom/winding" ) -func triangulateSubRings(oPoints []geom.Point) (points []geom.Point, edges []geom.Line, err error) { +func triangulateSubRings(oPoints []geom.Point, order winding.Order) (points []geom.Point, edges []geom.Line, err error) { if debug { log.Printf("Step-1: starting points(%v): %v", len(oPoints), wkt.MustEncode(oPoints)) @@ -46,7 +46,7 @@ func triangulateSubRings(oPoints []geom.Point) (points []geom.Point, edges []geo // , but logically we should drop them. To drop them, uncomment the guard // and modify test `multiple duplicated points` //if len(npts) > 2 { - newEdges, err := Triangulate(npts) + newEdges, err := Triangulate(npts, order) if err != nil { return nil, nil, err } @@ -72,14 +72,14 @@ func triangulateSubRings(oPoints []geom.Point) (points []geom.Point, edges []geo // Triangulate will return triangulated edges for the given polygon. The edges are not // guaranteed to be unique or normalized. -func Triangulate(oPoints []geom.Point) (edges []geom.Line, err error) { +func Triangulate(oPoints []geom.Point, order winding.Order) (edges []geom.Line, err error) { if debug { log.Printf("opoints:\n%v", wkt.MustEncode(oPoints)) } var points []geom.Point - points, edges, err = triangulateSubRings(oPoints) + points, edges, err = triangulateSubRings(oPoints, order) if err != nil { return nil, err } @@ -99,7 +99,7 @@ func Triangulate(oPoints []geom.Point) (edges []geom.Line, err error) { }, nil } - if windingorder.OfGeomPoints(points...).IsColinear() { + if order.OfGeomPoints(points...).IsColinear() { if debug { log.Printf("Step 0: colinear starting points(%v): %v", len(points), wkt.MustEncode(points)) } @@ -133,7 +133,7 @@ func Triangulate(oPoints []geom.Point) (edges []geom.Line, err error) { for i, candidate := range points[1:pe] { d := planar.PointDistance(cpoint, candidate) - cln := windingorder.OfGeomPoints(points[ps], points[i+1], points[pe]) + cln := order.OfGeomPoints(points[ps], points[i+1], points[pe]) if debug { log.Printf("colin: %v -- %v %v %v", cln, points[ps], points[i+1], points[pe]) log.Printf("%v distance: %v < %v : %v / %v", i+1, d, dist, d < dist, cln) @@ -193,7 +193,7 @@ func Triangulate(oPoints []geom.Point) (edges []geom.Line, err error) { log.Printf("p2: %v, len(points):%v", p2, len(points)) } - p2IsCol := windingorder.OfGeomPoints(points[ps], points[p2], points[pe]).IsColinear() + p2IsCol := order.OfGeomPoints(points[ps], points[p2], points[pe]).IsColinear() if !p2IsCol && circle.ContainsPoint(points[p2]) { // we need to "flip" our edge from p1 to p2. // a ← pe @@ -300,7 +300,7 @@ func Triangulate(oPoints []geom.Point) (edges []geom.Line, err error) { } } // We now need to triangulate the pseudo-polygon - newEdges, err := Triangulate(ply) + newEdges, err := Triangulate(ply, order) if err != nil { log.Printf("Called Self(%v) with\n%v\n", len(ply), wkt.MustEncode(ply)) return nil, err @@ -325,7 +325,7 @@ func Triangulate(oPoints []geom.Point) (edges []geom.Line, err error) { } } // We now need to triangulate the pseudo-polygon - newEdges, err = Triangulate(ply) + newEdges, err = Triangulate(ply, order) if err != nil { if debug { log.Printf("Called Self(%v) with\n%v\n", len(ply), wkt.MustEncode(ply)) diff --git a/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon_test.go b/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon_test.go index daa1522c..114f5af7 100644 --- a/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon_test.go +++ b/planar/triangulate/delaunay/subdivision/pseudopolygon/pseudo_polygon_test.go @@ -8,6 +8,8 @@ import ( "strings" "testing" + "github.com/go-spatial/geom/winding" + "github.com/go-spatial/geom/planar/triangulate/delaunay/test/must" "github.com/go-spatial/geom" @@ -29,10 +31,13 @@ func TestTriangulate(t *testing.T) { edges []geom.Line err error } + order := winding.Order{ + YPositiveDown: true, + } fn := func(tc tcase) func(t *testing.T) { return func(t *testing.T) { - edges, err := Triangulate(tc.points) + edges, err := Triangulate(tc.points, order) if tc.err != nil { if tc.err != err { @@ -321,11 +326,14 @@ func TestTriangulateSubRings(t *testing.T) { edges []geom.Line err error } + order := winding.Order{ + YPositiveDown: true, + } fn := func(tc tcase) func(*testing.T) { return func(t *testing.T) { - points, edges, err := triangulateSubRings(tc.opoints) + points, edges, err := triangulateSubRings(tc.opoints, order) if tc.err != err { t.Errorf("error, expected %v got %v", tc.err, err) return diff --git a/planar/triangulate/delaunay/subdivision/subdivision.go b/planar/triangulate/delaunay/subdivision/subdivision.go index 46173f1b..9cec3752 100644 --- a/planar/triangulate/delaunay/subdivision/subdivision.go +++ b/planar/triangulate/delaunay/subdivision/subdivision.go @@ -8,6 +8,7 @@ import ( "sync" "github.com/go-spatial/geom/planar/intersect" + "github.com/go-spatial/geom/winding" "github.com/gdey/errors" @@ -28,6 +29,7 @@ type Subdivision struct { vertexIndexLock sync.RWMutex vertexIndexCache VertexIndex + Order winding.Order } // New initialize a subdivision to the triangle defined by the points a,b,c. @@ -235,7 +237,7 @@ func (sd *Subdivision) InsertSite(x geom.Point) bool { ) } - base = quadedge.Connect(e, base.Sym()) + base = quadedge.Connect(e, base.Sym(), sd.Order) // reset e e = base.OPrev() if debug { @@ -255,7 +257,7 @@ func (sd *Subdivision) InsertSite(x geom.Point) bool { wkt.MustEncode(base.Sym().AsLine()), ) } - base = quadedge.Connect(e, base.Sym()) + base = quadedge.Connect(e, base.Sym(), sd.Order) e = base.OPrev() if debug { count++ @@ -379,7 +381,7 @@ func (sd *Subdivision) Validate(ctx context.Context) error { if err := sd.WalkAllEdges(func(e *quadedge.Edge) error { l := e.AsLine() - if err := quadedge.Validate(e); err != nil { + if err := quadedge.Validate(e, sd.Order); err != nil { if verr, ok := err.(quadedge.ErrInvalid); ok { wktStr, wktErr := wkt.EncodeString(l) if wktErr != nil { diff --git a/planar/triangulate/delaunay/subdivision/subdivision_constrained.go b/planar/triangulate/delaunay/subdivision/subdivision_constrained.go index 07dece1b..f5197f2b 100644 --- a/planar/triangulate/delaunay/subdivision/subdivision_constrained.go +++ b/planar/triangulate/delaunay/subdivision/subdivision_constrained.go @@ -13,6 +13,7 @@ import ( "github.com/go-spatial/geom/internal/debugger" "github.com/go-spatial/geom/planar/triangulate/delaunay/quadedge" "github.com/go-spatial/geom/planar/triangulate/delaunay/subdivision/pseudopolygon" + "github.com/go-spatial/geom/winding" ) func roundGeomPoint(pt geom.Point) geom.Point { @@ -137,6 +138,7 @@ testcase: pppc := PseudoPolygonPointCollector{ Start: start, End: end, + Order: sd.Order, } for i, e := range removalList { @@ -283,7 +285,7 @@ func (sd *Subdivision) insertEdge(vertexIndex VertexIndex, start, end geom.Point return ErrInvalidEndVertex } - newEdge := quadedge.Connect(from.ONext().Sym(), to) + newEdge := quadedge.Connect(from.ONext().Sym(), to, sd.Order) if debug { log.Printf("Connected : %v -> %v", from.ONext().Sym().AsLine(), to.AsLine()) @@ -300,6 +302,7 @@ type PseudoPolygonPointCollector struct { seen map[geom.Point]bool Start geom.Point End geom.Point + Order winding.Order } // AddEdge will attempt to add the origin and dest points of the edge to the lower @@ -394,7 +397,7 @@ func (pppc *PseudoPolygonPointCollector) Edges(upper bool) ([]geom.Line, error) return []geom.Line{pppc.SharedLine()}, nil } - return pseudopolygon.Triangulate(pts) + return pseudopolygon.Triangulate(pts, pppc.Order) } func (pppc *PseudoPolygonPointCollector) debugRecord(ctx context.Context) { diff --git a/planar/triangulate/delaunay/subdivision/testdb.go b/planar/triangulate/delaunay/subdivision/testdb.go index edec971d..60913f05 100644 --- a/planar/triangulate/delaunay/subdivision/testdb.go +++ b/planar/triangulate/delaunay/subdivision/testdb.go @@ -14,6 +14,8 @@ import ( "fmt" "log" + "github.com/go-spatial/geom/winding" + "github.com/go-spatial/geom/planar" "github.com/gdey/errors" @@ -429,11 +431,19 @@ func (db *TestDB) Get(id int64) (*Subdivision, error) { if err != nil { return nil, err } + order, err := db.Order(id) + if err != nil { + return nil, err + } - sd := NewSubdivisionFromGeomLines(lines) + sd := NewSubdivisionFromGeomLines(lines, order) return sd, nil } +func (db *TestDB) Order(_ int64) (winding.Order, error) { + return winding.Order{}, nil +} + // SubdivisionFrom will create a new subdivsion that is a subsection of // another subdivision that is described by the points func (db *TestDB) SubdivisionFrom(id int64, name, description string, pts ...geom.Point) (int64, error) { diff --git a/testing/dynamic_geoms_test.go b/testing/dynamic_geoms_test.go index d6e3bcf6..a13b57ea 100644 --- a/testing/dynamic_geoms_test.go +++ b/testing/dynamic_geoms_test.go @@ -6,7 +6,7 @@ import ( "github.com/go-spatial/geom" "github.com/go-spatial/geom/cmp" - "github.com/go-spatial/geom/windingorder" + "github.com/go-spatial/geom/winding" ) func TestBoxPolygon(t *testing.T) { @@ -14,12 +14,13 @@ func TestBoxPolygon(t *testing.T) { dim float64 res geom.Polygon } + order := winding.Order{} fn := func(tc tcase) func(*testing.T) { return func(t *testing.T) { got := BoxPolygon(tc.dim) - wo := windingorder.OfPoints(got[0]...) + wo := order.OfPoints(got[0]...) if !wo.IsClockwise() { t.Error("winding order of box not clockwise") } @@ -30,12 +31,12 @@ func TestBoxPolygon(t *testing.T) { } } - tcases := map[string]tcase { - "dim 1" : { + tcases := map[string]tcase{ + "dim 1": { dim: 1.0, res: geom.Polygon{{{0, 0}, {1.0, 0}, {1.0, 1.0}, {0, 1.0}}}, }, - "dim -1" : { + "dim -1": { dim: -1.0, res: geom.Polygon{{{0, 0}, {-1.0, 0}, {-1.0, -1.0}, {0, -1.0}}}, }, @@ -49,11 +50,11 @@ func TestBoxPolygon(t *testing.T) { func TestSinLineString(t *testing.T) { type tcase struct { amp, start, end float64 - points int - out geom.LineString + points int + out geom.LineString } - fn := func (tc tcase) func(t *testing.T) { + fn := func(tc tcase) func(t *testing.T) { return func(t *testing.T) { out := SinLineString(tc.amp, tc.start, tc.end, tc.points) @@ -64,12 +65,12 @@ func TestSinLineString(t *testing.T) { } tcases := map[string]tcase{ - "amp 10" : { - amp: 10, - start: 0, - end: math.Pi * 2, + "amp 10": { + amp: 10, + start: 0, + end: math.Pi * 2, points: 5, - out: geom.LineString{{0, 0}, {math.Pi/2, 10}, {math.Pi, 0}, {3*math.Pi/2, -10}, {2*math.Pi, 0}}, + out: geom.LineString{{0, 0}, {math.Pi / 2, 10}, {math.Pi, 0}, {3 * math.Pi / 2, -10}, {2 * math.Pi, 0}}, }, } diff --git a/testing/must/decode.go b/testing/must/decode.go new file mode 100644 index 00000000..561b33bc --- /dev/null +++ b/testing/must/decode.go @@ -0,0 +1,79 @@ +// Package must provides helpers to decode wkt geometries to be used in tests +package must + +import ( + "fmt" + + "github.com/go-spatial/geom" +) + +// Decode will panic if err is not nil otherwise return the geometry +func Decode(g geom.Geometry, err error) geom.Geometry { + if err != nil { + panic(fmt.Sprintf("got error decoding geometry: %v", err)) + } + return g +} + +// AsPolygon will panic if g is not a geom.Polygon +func AsPolygon(g geom.Geometry) geom.Polygon { + p, ok := g.(geom.Polygon) + if !ok { + panic(fmt.Sprintf("expected polygon, not %t", g)) + } + return p +} + +// AsMultiPolygon will panic if g is not a geom.MultiPolygon or geom.Polygon +// if it is a geom.Polygon, it will return a multipolygon containing just that polygon +func AsMultiPolygon(g geom.Geometry) geom.MultiPolygon { + switch mp := g.(type) { + case geom.Polygon: + return geom.MultiPolygon{mp} + case geom.MultiPolygon: + return mp + default: + panic(fmt.Sprintf("expected multi-polygon, not %t", g)) + } +} + +// AsLines will panic if g can not be coerced into a set of lines +func AsLines(g geom.Geometry) (segs []geom.Line) { + var err error + switch geo := g.(type) { + case geom.LineString: + segs, err = geo.AsSegments() + if err != nil { + panic(err) + } + case geom.MultiLineString: + s, err := geo.AsSegments() + if err != nil { + panic(err) + } + for i := range s { + segs = append(segs, s[i]...) + } + case geom.Polygon: + s, err := geo.AsSegments() + if err != nil { + panic(err) + } + for i := range s { + segs = append(segs, s[i]...) + } + case geom.MultiPolygon: + s, err := geo.AsSegments() + if err != nil { + panic(err) + } + for i := range s { + for j := range s[i] { + segs = append(segs, s[i][j]...) + } + } + default: + panic("geometry not supported for AsLines") + } + return segs +} diff --git a/windingorder/debug.go b/winding/debug.go similarity index 50% rename from windingorder/debug.go rename to winding/debug.go index 16af6b81..68382947 100644 --- a/windingorder/debug.go +++ b/winding/debug.go @@ -1,3 +1,3 @@ -package windingorder +package winding const debug = false diff --git a/winding/winding.go b/winding/winding.go new file mode 100644 index 00000000..9e21cf12 --- /dev/null +++ b/winding/winding.go @@ -0,0 +1,200 @@ +// Package winding provides primitives for determining the winding order of a +// set of points +package winding + +import ( + "log" + + "github.com/go-spatial/geom" +) + +// Winding is the clockwise direction of a set of points. +type Winding uint8 + +const ( + + // Clockwise indicates that the winding order is in the clockwise direction + Clockwise Winding = 0 + // Colinear indicates that the points are colinear to each other + Colinear Winding = 1 + // CounterClockwise indicates that the winding order is in the counter clockwise direction + CounterClockwise Winding = 2 + + // Collinear alternative spelling of Colinear + Collinear = Colinear +) + +// String implements the stringer interface +func (w Winding) String() string { + switch w { + case Clockwise: + return "clockwise" + case Colinear: + return "colinear" + case CounterClockwise: + return "counter clockwise" + default: + return "unknown" + } +} + +// IsClockwise checks if winding is clockwise +func (w Winding) IsClockwise() bool { return w == Clockwise } + +// IsCounterClockwise checks if winding is counter clockwise +func (w Winding) IsCounterClockwise() bool { return w == CounterClockwise } + +// IsColinear check if the points are colinear +func (w Winding) IsColinear() bool { return w == Colinear } + +// Not returns the inverse of the winding, clockwise <-> counter-clockwise, colinear is it's own +// inverse +func (w Winding) Not() Winding { + switch w { + case Clockwise: + return CounterClockwise + case CounterClockwise: + return Clockwise + default: + return w + } +} + +// Orient will take the points and calculate the Orientation of the points. by +// summing the normal vectors. It will return 0 of the given points are colinear +// or 1, or -1 for clockwise and counter clockwise depending on the direction of +// the y axis. If the y axis increase as you go up on the graph then clockwise will +// be -1, otherwise it will be 1; vice versa for counter-clockwise. +func Orient(pts ...[2]float64) int8 { + if len(pts) < 3 { + return 0 + } + var ( + sum = 0.0 + dop = 0.0 + li = len(pts) - 1 + ) + + if debug { + log.Printf("pts: %v", pts) + } + for i := range pts { + dop = (pts[li][0] * pts[i][1]) - (pts[i][0] * pts[li][1]) + sum += dop + if debug { + log.Printf("sum(%v,%v): %g -- %g", li, i, sum, dop) + } + li = i + } + switch { + case sum == 0: + return 0 + case sum < 0: + return -1 + default: + return 1 + } +} + +// Orientation returns the orientation of the set of the points given the +// direction of the positive values of the y axis +func Orientation(yPositiveDown bool, pts ...[2]float64) Winding { + mul := int8(1) + if yPositiveDown { + mul = -1 + } + switch mul * Orient(pts...) { + case 0: + return Colinear + case 1: + return Clockwise + default: // -1 + return CounterClockwise + } +} + +// Order configures how the orientation of a set of points is determined +type Order struct { + YPositiveDown bool +} + +// OfPoints returns the winding of the given points +func (order Order) OfPoints(pts ...[2]float64) Winding { + return Orientation(order.YPositiveDown, pts...) +} + +// OfInt64Points returns the winding of the given int64 points +func (order Order) OfInt64Points(ipts ...[2]int64) Winding { + pts := make([][2]float64, len(ipts)) + for i := range ipts { + pts[i] = [2]float64{ + float64(ipts[i][0]), + float64(ipts[i][1]), + } + } + return Orientation(order.YPositiveDown, pts...) +} + +// OfGeomPoints returns the winding of the given geom points +func (order Order) OfGeomPoints(points ...geom.Point) Winding { + pts := make([][2]float64, len(points)) + for i := range points { + pts[i] = [2]float64(points[i]) + } + return order.OfPoints(pts...) +} + +// RectifyPolygon will make sure that the rings are of the correct orientation, if not it will reverse them +// Colinear rings are dropped +func (order Order) RectifyPolygon(plyg2r [][][2]float64) [][][2]float64 { + plyg := make([][][2]float64, 0, len(plyg2r)) + reverse := func(idx int) { + for i := len(plyg[idx])/2 - 1; i >= 0; i-- { + opp := len(plyg[idx]) - 1 - i + plyg[idx][i], plyg[idx][opp] = plyg[idx][opp], plyg[idx][i] + } + } + + // Let's make sure each of the rings have the correct windingorder. + + for i := range plyg2r { + + wo := order.OfPoints(plyg2r[i]...) + + // Drop collinear rings + if wo.IsColinear() { + if i == 0 { + return nil + } + continue + } + + plyg = append(plyg, plyg2r[i]) + + if (i == 0 && wo.IsCounterClockwise()) || (i != 0 && wo.IsClockwise()) { + // 0 ring should be clockwise. + // all others should be conterclockwise + // reverse the ring. + reverse(len(plyg) - 1) + } + } + return plyg +} + +// Clockwise returns a clockwise winding +func (Order) Clockwise() Winding { return Clockwise } + +// CounterClockwise returns a counter clockwise winding +func (Order) CounterClockwise() Winding { return CounterClockwise } + +// Colinear returns a colinear winding +func (Order) Colinear() Winding { return Colinear } + +// Collinear is a alias for colinear +func (Order) Collinear() Winding { return Colinear } + +// OfPoints returns the winding order of the given points +func OfPoints(pts ...[2]float64) Winding { return Order{}.OfPoints(pts...) } + +// OfGeomPoints is the same as OfPoints, just a convenience to unwrap geom.Point +func OfGeomPoints(points ...geom.Point) Winding { return Order{}.OfGeomPoints(points...) } diff --git a/windingorder/windingorder_test.go b/winding/winding_test.go similarity index 69% rename from windingorder/windingorder_test.go rename to winding/winding_test.go index 4ee14887..a6c4c751 100644 --- a/windingorder/windingorder_test.go +++ b/winding/winding_test.go @@ -1,15 +1,40 @@ -package windingorder +package winding import ( "testing" + "github.com/go-spatial/geom/cmp" + "github.com/go-spatial/geom" "github.com/go-spatial/geom/encoding/wkt" + "github.com/go-spatial/geom/testing/must" ) +func TestHelperMethods(t *testing.T) { + order := Order{} + val := order.Clockwise() + if val != Clockwise { + t.Errorf("clockwise, expected clockwise got %v", val) + } + val = order.CounterClockwise() + if val != CounterClockwise { + t.Errorf("counter clockwise, expected counter clockwise got %v", val) + } + + val = order.Colinear() + if val != Colinear { + t.Errorf("colinear, expected colinear got %v", val) + } + val = order.Collinear() + if val != Colinear { + t.Errorf("collinear, expected colinear got %v", val) + } + +} + func TestAttributeMethods(t *testing.T) { - fn := func(val WindingOrder) func(*testing.T) { + fn := func(val Winding) func(*testing.T) { return func(t *testing.T) { var ( @@ -66,7 +91,7 @@ func TestAttributeMethods(t *testing.T) { } } } - tests := []WindingOrder{Clockwise, CounterClockwise, Colinear, 3} + tests := []Winding{Clockwise, CounterClockwise, Colinear, 3} for i := range tests { t.Run(tests[i].String(), fn(tests[i])) } @@ -76,12 +101,28 @@ func TestOfPoints(t *testing.T) { type tcase struct { Desc string pts [][2]float64 - order WindingOrder + order Winding + } + order := Order{ + YPositiveDown: false, } fn := func(tc tcase) func(*testing.T) { return func(t *testing.T) { - got := OfPoints(tc.pts...) + got := order.OfPoints(tc.pts...) + if got != tc.order { + t.Errorf("order.OfPoints, expected %v got %v", tc.order, got) + for i := range tc.pts { + str, err := wkt.EncodeString(geom.Point(tc.pts[i])) + if err != nil { + panic(err) + } + t.Logf("%03v:%v", i, str) + } + return + } + + got = OfPoints(tc.pts...) if got != tc.order { t.Errorf("OfPoints, expected %v got %v", tc.order, got) for i := range tc.pts { @@ -99,13 +140,18 @@ func TestOfPoints(t *testing.T) { points[i] = geom.Point(tc.pts[i]) } + got = order.OfGeomPoints(points...) + if got != tc.order { + t.Errorf("order.OfGeomPoints, expected %v got %v", tc.order, got) + } + got = OfGeomPoints(points...) if got != tc.order { t.Errorf("OfGeomPoints, expected %v got %v", tc.order, got) } // Test with yPostiveDown set to false - got = Orientation(false, tc.pts...) + got = Orientation(!order.YPositiveDown, tc.pts...) if got != tc.order.Not() { t.Errorf("Orientation y-false, expected %v got %v", tc.order.Not(), got) } @@ -235,3 +281,32 @@ func TestOfPoints(t *testing.T) { t.Run(tests[i].Desc, fn(tests[i])) } } + +func TestRectifyPolygon(t *testing.T) { + type tcase struct { + Polygon geom.Polygon + Expected geom.Polygon + } + var order Order + fn := func(tc tcase) func(*testing.T) { + return func(t *testing.T) { + got := order.RectifyPolygon([][][2]float64(tc.Polygon)) + if !cmp.PolygonEqual(got, [][][2]float64(tc.Expected)) { + t.Errorf("polygon, expected: %v got %v", wkt.MustEncode(tc.Expected), wkt.MustEncode(geom.Polygon(got))) + } + } + } + + tests := map[string]tcase{ + "#1": { + Polygon: must.AsPolygon(must.Decode(wkt.DecodeString(`POLYGON((0 0,0 10,10 0,0 0),(1 1,2 1,1 2,1 1),(1 1,1 2,1 3,1 1))`))), + Expected: must.AsPolygon(must.Decode(wkt.DecodeString(`POLYGON((0 0,10 0,0 10,0 0),(1 1,1 2,2 1,1 1))`))), + }, + "#2": { + Polygon: must.AsPolygon(must.Decode(wkt.DecodeString(`POLYGON((1 1,1 2,1 3,1 1))`))), + }, + } + for name, tc := range tests { + t.Run(name, fn(tc)) + } +} diff --git a/windingorder/windingorder.go b/windingorder/windingorder.go deleted file mode 100644 index 7544e0eb..00000000 --- a/windingorder/windingorder.go +++ /dev/null @@ -1,128 +0,0 @@ -// Package windingorder provides primitives for determining the winding order of a -// set of points -package windingorder - -import ( - "log" - - "github.com/go-spatial/geom" -) - -// WindingOrder is the clockwise direction of a set of points. -type WindingOrder uint8 - -const ( - - // Clockwise indicates that the winding order is in the clockwise direction - Clockwise WindingOrder = 0 - // Colinear indicates that the points are colinear to each other - Colinear WindingOrder = 1 - // CounterClockwise indicates that the winding order is in the counter clockwise direction - CounterClockwise WindingOrder = 2 - - // Collinear alternative spelling of Colinear - Collinear = Colinear -) - -// String implements the stringer interface -func (w WindingOrder) String() string { - switch w { - case Clockwise: - return "clockwise" - case Colinear: - return "colinear" - case CounterClockwise: - return "counter clockwise" - default: - return "unknown" - } -} - -// IsClockwise checks if winding is clockwise -func (w WindingOrder) IsClockwise() bool { return w == Clockwise } - -// IsCounterClockwise checks if winding is counter clockwise -func (w WindingOrder) IsCounterClockwise() bool { return w == CounterClockwise } - -// IsColinear check if the points are colinear -func (w WindingOrder) IsColinear() bool { return w == Colinear } - -// Not returns the inverse of the winding, clockwise <-> counter-clockwise, colinear is it's own -// inverse -func (w WindingOrder) Not() WindingOrder { - switch w { - case Clockwise: - return CounterClockwise - case CounterClockwise: - return Clockwise - default: - return w - } -} - -// Orient will take the points and calculate the Orientation of the points. by -// summing the normal vectors. It will return 0 of the given points are colinear -// or 1, or -1 for clockwise and counter clockwise depending on the direction of -// the y axis. If the y axis increase as you go up on the graph then clockwise will -// be -1, otherwise it will be 1; vice versa for counter-clockwise. -func Orient(pts ...[2]float64) int8 { - if len(pts) < 3 { - return 0 - } - var ( - sum = 0.0 - dop = 0.0 - li = len(pts) - 1 - ) - - if debug { - log.Printf("pts: %v", pts) - } - for i := range pts { - dop = (pts[li][0] * pts[i][1]) - (pts[i][0] * pts[li][1]) - sum += dop - if debug { - log.Printf("sum(%v,%v): %g -- %g", li, i, sum, dop) - } - li = i - } - switch { - case sum == 0: - return 0 - case sum < 0: - return -1 - default: - return 1 - } -} - -// Orientation returns the clockwise orientation of the set of the points given the -// direction of the positive values of the y axis -func Orientation(yPositiveDown bool, pts ...[2]float64) WindingOrder { - mul := int8(1) - if !yPositiveDown { - mul = -1 - } - switch mul * Orient(pts...) { - case 0: - return Colinear - case 1: - return Clockwise - default: // -1 - return CounterClockwise - } -} - -// OfPoints returns the winding order of the given points -func OfPoints(pts ...[2]float64) WindingOrder { - return Orientation(true, pts...) -} - -// OfGeomPoints is the same as OfPoints, just a convenience to unwrap geom.Point -func OfGeomPoints(points ...geom.Point) WindingOrder { - pts := make([][2]float64, len(points)) - for i := range points { - pts[i] = [2]float64(points[i]) - } - return OfPoints(pts...) -}