tidwall 6257ddba78 Faster point in polygon / GeoJSON updates
The big change is that the GeoJSON package has been completely
rewritten to fix a few of geometry calculation bugs, increase
performance, and to better follow the GeoJSON spec RFC 7946.

GeoJSON updates

- A LineString now requires at least two points.
- All json members, even foreign, now persist with the object.
- The bbox member persists too but is no longer used for geometry
  calculations. This is change in behavior. Previously Tile38 would
  treat the bbox as the object's physical rectangle.
- Corrections to geometry intersects and within calculations.

Faster spatial queries

- The performance of Point-in-polygon and object intersect operations
  are greatly improved for complex polygons and line strings. It went
  from O(n) to roughly O(log n).
- The same for all collection types with many children, including
  FeatureCollection, GeometryCollection, MultiPoint, MultiLineString,
  and MultiPolygon.

Codebase changes

- The pkg directory has been renamed to internal
- The GeoJSON internal package has been moved to a seperate repo at
  https://github.com/tidwall/geojson. It's now vendored.

Please look out for higher memory usage for datasets using complex
shapes. A complex shape is one that has 64 or more points. For these
shapes it's expected that there will be increase of least 54 bytes per
point.
2018-10-13 04:30:48 -07:00

113 lines
2.2 KiB
Go

package geojson
import (
"encoding/json"
"fmt"
"math/rand"
"testing"
"time"
"github.com/tidwall/geojson/geometry"
"github.com/tidwall/pretty"
)
func init() {
seed := time.Now().UnixNano()
println(seed)
rand.Seed(seed)
}
func R(minX, minY, maxX, maxY float64) geometry.Rect {
return geometry.Rect{
Min: geometry.Point{X: minX, Y: minY},
Max: geometry.Point{X: maxX, Y: maxY},
}
}
func P(x, y float64) geometry.Point {
return geometry.Point{X: x, Y: y}
}
func PO(x, y float64) *Point {
return NewPoint(P(x, y))
}
func RO(minX, minY, maxX, maxY float64) *Rect {
return NewRect(R(minX, minY, maxX, maxY))
}
func LO(points []geometry.Point) *LineString {
return NewLineString(geometry.NewLine(points, geometry.DefaultIndex))
}
func PPO(exterior []geometry.Point, holes [][]geometry.Point) *Polygon {
return NewPolygon(geometry.NewPoly(exterior, holes, geometry.DefaultIndex))
}
func expectJSON(t testing.TB, data string, expect interface{}) Object {
if t != nil {
t.Helper()
}
return expectJSONOpts(t, data, expect, nil)
}
func expectJSONOpts(t testing.TB, data string, expect interface{}, opts *ParseOptions) Object {
if t != nil {
t.Helper()
}
var exerr error
var exstr string
switch expect := expect.(type) {
case string:
exstr = expect
case error:
exerr = expect
case nil:
exstr = data
}
obj, err := Parse(data, opts)
if err != exerr {
if t == nil {
panic(fmt.Sprintf("expected '%v', got '%v'", exerr, err))
} else {
t.Fatalf("expected '%v', got '%v'", exerr, err)
}
}
if exstr != "" {
if cleanJSON(exstr) != cleanJSON(string(obj.AppendJSON(nil))) {
if t == nil {
panic("json mismatch")
} else {
t.Fatal("json mismatch")
}
}
}
return obj
}
func expect(t testing.TB, what bool) {
if t != nil {
t.Helper()
}
if !what {
if t == nil {
panic("exception failure")
} else {
t.Fatal("expection failure")
}
}
}
func cleanJSON(data string) string {
var v interface{}
if err := json.Unmarshal([]byte(data), &v); err != nil {
println(string(data))
panic(err)
}
dst, err := json.Marshal(v)
if err != nil {
panic(err)
}
opts := *pretty.DefaultOptions
opts.Width = 99999999
return string(pretty.PrettyOptions(dst, &opts))
}