From 7cc4008442b80f953f33fb6ea791588afe824232 Mon Sep 17 00:00:00 2001 From: tidwall Date: Sun, 21 Oct 2018 19:08:56 -0700 Subject: [PATCH] Added multiple indexing kinds --- Gopkg.lock | 4 +- internal/clip/linestring.go | 2 +- internal/clip/polygon.go | 2 +- internal/clip/rect.go | 2 +- internal/controller/controller.go | 30 +- internal/controller/fence.go | 2 +- vendor/github.com/tidwall/geojson/circle.go | 8 +- .../tidwall/geojson/geometry/geometry_test.go | 2 +- .../tidwall/geojson/geometry/issue_test.go | 18 +- .../tidwall/geojson/geometry/line.go | 4 +- .../tidwall/geojson/geometry/line_test.go | 42 +- .../geojson/geometry/pip_bench_test.go | 8 +- .../tidwall/geojson/geometry/point_test.go | 12 +- .../tidwall/geojson/geometry/poly.go | 10 +- .../tidwall/geojson/geometry/poly_test.go | 32 +- .../tidwall/geojson/geometry/quadtree.go | 255 ++++++++++++ .../tidwall/geojson/geometry/rect_test.go | 8 +- .../tidwall/geojson/geometry/ring.go | 4 +- .../tidwall/geojson/geometry/ring_test.go | 94 ++--- .../tidwall/geojson/geometry/rtree.go | 384 ++++++++++++++++++ .../tidwall/geojson/geometry/series.go | 194 ++++++--- .../tidwall/geojson/geometry/series_test.go | 78 ++-- .../github.com/tidwall/geojson/linestring.go | 3 +- .../tidwall/geojson/multilinestring.go | 3 +- .../tidwall/geojson/multipolygon.go | 3 +- vendor/github.com/tidwall/geojson/object.go | 19 +- .../github.com/tidwall/geojson/object_test.go | 4 +- vendor/github.com/tidwall/geojson/polygon.go | 3 +- 28 files changed, 1000 insertions(+), 230 deletions(-) create mode 100644 vendor/github.com/tidwall/geojson/geometry/quadtree.go create mode 100644 vendor/github.com/tidwall/geojson/geometry/rtree.go diff --git a/Gopkg.lock b/Gopkg.lock index adf5e1ed..de312eda 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -227,7 +227,7 @@ [[projects]] branch = "master" - digest = "1:c27e7d5bfc68a4ad2166d1ae909917013a985ba4c8b5255b91bd253bf3ab5730" + digest = "1:9fcbc64769ddda5230be91f192aa87aa8233f9776053108c1c89e1263f2c4a98" name = "github.com/tidwall/geojson" packages = [ ".", @@ -235,7 +235,7 @@ "geometry", ] pruneopts = "" - revision = "5302514a34feb71743bf597938742b51831ba289" + revision = "2d2f7893c3d92f36cef52047d457573ed44d6f04" [[projects]] digest = "1:3ddca2bd5496c6922a2a9e636530e178a43c2a534ea6634211acdc7d10222794" diff --git a/internal/clip/linestring.go b/internal/clip/linestring.go index 211d375e..5cc06964 100644 --- a/internal/clip/linestring.go +++ b/internal/clip/linestring.go @@ -34,7 +34,7 @@ func clipLineString( var children []*geometry.Line for _, points := range newPoints { children = append(children, - geometry.NewLine(points, geometry.DefaultIndex)) + geometry.NewLine(points, nil)) } if len(children) == 1 { return geojson.NewLineString(children[0]) diff --git a/internal/clip/polygon.go b/internal/clip/polygon.go index 1d7849e4..25de61d7 100644 --- a/internal/clip/polygon.go +++ b/internal/clip/polygon.go @@ -30,7 +30,7 @@ func clipPolygon( holes = newPoints[1:] } newPoly := geojson.NewPolygon( - geometry.NewPoly(exterior, holes, geometry.DefaultIndex), + geometry.NewPoly(exterior, holes, nil), ) if newPoly.Empty() { return geojson.NewMultiPolygon(nil) diff --git a/internal/clip/rect.go b/internal/clip/rect.go index 3568d2fc..b3944824 100644 --- a/internal/clip/rect.go +++ b/internal/clip/rect.go @@ -11,7 +11,7 @@ func clipRect(rect *geojson.Rect, clipper geojson.Object) geojson.Object { for i := 0; i < len(points); i++ { points[i] = base.PointAt(i) } - poly := geometry.NewPoly(points, nil, geometry.DefaultIndex) + poly := geometry.NewPoly(points, nil, nil) gPoly := geojson.NewPolygon(poly) return Clip(gPoly, clipper) } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 7540472d..280f67d7 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -19,6 +19,7 @@ import ( "github.com/tidwall/buntdb" "github.com/tidwall/geojson" + "github.com/tidwall/geojson/geometry" "github.com/tidwall/resp" "github.com/tidwall/tile38/core" "github.com/tidwall/tile38/internal/collection" @@ -174,8 +175,33 @@ func ListenAndServeEx(host string, port int, dir string, ln *net.Listener, http if err == nil { c.geomParseOpts.IndexChildren = int(n) } - log.Debugf("geom indexing: %d", c.geomParseOpts.IndexGeometry) - log.Debugf("multi indexing: %d", c.geomParseOpts.IndexChildren) + indexKind := os.Getenv("T38IDXGEOMKIND") + switch indexKind { + default: + log.Errorf("Unknown index kind: %s", indexKind) + case "": + case "None": + c.geomParseOpts.IndexGeometryKind = geometry.None + case "RTree": + c.geomParseOpts.IndexGeometryKind = geometry.RTree + case "RTreeCompressed": + c.geomParseOpts.IndexGeometryKind = geometry.RTreeCompressed + case "QuadTree": + c.geomParseOpts.IndexGeometryKind = geometry.QuadTree + case "QuadTreeCompressed": + c.geomParseOpts.IndexGeometryKind = geometry.QuadTreeCompressed + } + if c.geomParseOpts.IndexGeometryKind == geometry.None { + log.Debugf("Geom indexing: %s", + c.geomParseOpts.IndexGeometryKind, + ) + } else { + log.Debugf("Geom indexing: %s (%d points)", + c.geomParseOpts.IndexGeometryKind, + c.geomParseOpts.IndexGeometry, + ) + } + log.Debugf("Multi indexing: RTree (%d points)", c.geomParseOpts.IndexChildren) // load the queue before the aof qdb, err := buntdb.Open(core.QueueFileName) diff --git a/internal/controller/fence.go b/internal/controller/fence.go index b4d3aa44..ef433f43 100644 --- a/internal/controller/fence.go +++ b/internal/controller/fence.go @@ -131,7 +131,7 @@ func fenceMatch( []geometry.Point{ details.oldObj.Center(), details.obj.Center(), - }, geometry.DefaultIndex)) + }, nil)) temp := false if fence.cmd == "within" { // because we are testing if the line croses the area we need to use diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index a4df8572..8f528351 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -37,12 +37,12 @@ func NewCircle(center geometry.Point, meters float64, steps int) *Circle { points = append(points, geometry.Point{X: lon, Y: lat}) i++ } - // TODO: account for the pole and antimerdian. In most cases only a polygon - // is needed, but when the circle bounds passes the 90/180 lines, we need - // to create a multipolygon + // TODO: account for the pole and antimerdian. In most cases only a + // polygon is needed, but when the circle bounds passes the 90/180 + // lines, we need to create a multipolygon points = append(points, points[0]) g.Object = NewPolygon( - geometry.NewPoly(points, nil, geometry.DefaultIndex), + geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), ) } return g diff --git a/vendor/github.com/tidwall/geojson/geometry/geometry_test.go b/vendor/github.com/tidwall/geojson/geometry/geometry_test.go index 22573d93..735da79e 100644 --- a/vendor/github.com/tidwall/geojson/geometry/geometry_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/geometry_test.go @@ -30,7 +30,7 @@ func P(x, y float64) Point { return Point{x, y} } func L(points ...Point) *Line { - return NewLine(points, DefaultIndex) + return NewLine(points, DefaultIndexOptions) } var ( diff --git a/vendor/github.com/tidwall/geojson/geometry/issue_test.go b/vendor/github.com/tidwall/geojson/geometry/issue_test.go index d20dbd59..39c29150 100644 --- a/vendor/github.com/tidwall/geojson/geometry/issue_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/issue_test.go @@ -30,10 +30,10 @@ func TestIssue362(t *testing.T) { {-122.44850635528563, 37.73885397998102}, {-122.4475622177124, 37.7359013302630}, } - expect(t, !NewPoly(shape, nil, DefaultIndex).ContainsPoly( - NewPoly(box, nil, DefaultIndex), + expect(t, !NewPoly(shape, nil, DefaultIndexOptions).ContainsPoly( + NewPoly(box, nil, DefaultIndexOptions), )) - expect(t, !NewPoly(shape, nil, DefaultIndex).ContainsRect(rect)) + expect(t, !NewPoly(shape, nil, DefaultIndexOptions).ContainsRect(rect)) } func TestIssue245(t *testing.T) { @@ -61,7 +61,7 @@ func TestIssue245(t *testing.T) { {113.825694, 23.341791}, {113.825695, 23.341794}, {113.825695, 23.341796}, {113.825695, 23.341799}, {113.825695, 23.341801}, {113.825695, 23.341804}, {113.825695, 23.341806}, {113.825695, 23.341809}, {113.825695, 23.341811}, {113.825695, 23.341814}, {113.825695, 23.341816}, {113.825695, 23.341819}, {113.825696, 23.341821}, {113.825696, 23.341824}, {113.825696, 23.341826}, {113.825696, 23.341829}, {113.825696, 23.341831}, {113.825696, 23.341834}, {113.825696, 23.341836}, {113.825696, 23.341839}, {113.825696, 23.341841}, {113.825696, 23.341844}, {113.825696, 23.341846}, {113.825697, 23.341849}, {113.825697, 23.341851}, {113.825697, 23.341854}, {113.825696, 23.341856}, {113.825639, 23.342752}, {113.825909, 23.343038}, {113.826124, 23.34317}, {113.826246, 23.343207}, {113.826544, 23.343462}, {113.826663, 23.343725}, {113.826921, 23.344028}, {113.826946, 23.344045}, {113.827411, 23.344775}, {113.827452, 23.345071}, {113.827433, 23.345444}, {113.827373, 23.345688}, {113.827847, 23.346486}, {113.827867, 23.346492}, {113.828217, 23.346555}, {113.828812, 23.346578}, {113.829478, 23.346804}, {113.829926, 23.347127}, {113.830393, 23.34749}, {113.830756, 23.347827}, {113.83112, 23.348231}, {113.832415, 23.349689}, {113.833006, 23.350048}, {113.834533, 23.350448}, {113.835235, 23.350919}, {113.835526, 23.35132}, {113.836805, 23.353126}, {113.836931, 23.353474}, {113.837019, 23.35471}, {113.837041, 23.354934}, {113.837129, 23.355633}, {113.837135, 23.355731}, {113.837148, 23.35729}, {113.837124, 23.357391}, {113.837093, 23.357543}, {113.837116, 23.357842}, {113.837231, 23.358547}, {113.837488, 23.359569}, {113.837398, 23.359954}, {113.838019, 23.360873}, {113.838056, 23.360928}, {113.840391, 23.36073}, - }, nil, DefaultIndex) + }, nil, DefaultIndexOptions) expect(t, poly.ContainsPoint(P(113.837019, 23.35471))) expect(t, !poly.ContainsPoint(P(114.837019, 23.35471))) } @@ -75,12 +75,12 @@ func TestIssue313(t *testing.T) { {-122.300208, 47.52478}, {-122.300139, 47.524907}, {-122.300088, 47.525001}, {-122.299756, 47.526019}, {-122.299746, 47.526257}, {-122.299776, 47.526614}, {-122.299862, 47.526967}, {-122.29989, 47.52709}, {-122.300272, 47.52798}, {-122.300916, 47.529034}, {-122.301367, 47.529248}, {-122.301578, 47.529347}, {-122.303344, 47.530249}, {-122.305076, 47.531051}, {-122.305114, 47.531303}, {-122.305172, 47.531678}, {-122.307104, 47.531709}, {-122.307306, 47.531712}, {-122.30843, 47.531733}, {-122.308924, 47.531741}, {-122.309177, 47.531745}, {-122.313285, 47.531774}, {-122.31681, 47.53177}, {-122.317958, 47.531767}, {-122.31803, 47.531765}, {-122.318264, 47.531766}, {-122.318263, 47.531643}, {-122.318258, 47.530963}, {-122.318256, 47.530464}, {-122.318249, 47.529776}, {-122.318245, 47.529455}, {-122.318244, 47.529438}, {-122.31822, 47.529438}, {-122.318118, 47.529438}, {-122.318016, 47.529437}, {-122.317914, 47.529437}, {-122.317812, 47.529437}, {-122.31771, 47.529436}, {-122.317576, 47.529436}, {-122.317575, 47.529413}, {-122.317568, 47.529169}, {-122.317575, 47.529026}, {-122.31759, 47.528825}, {-122.317599, 47.528549}, {-122.317554, 47.52821}, {-122.317483, 47.528171}, {-122.314898, 47.527369}, {-122.314718, 47.527316}, {-122.312833, 47.526819}, {-122.312645, 47.526777}, {-122.311887, 47.526583}, {-122.311836, 47.526557}, {-122.311724, 47.526485}, {-122.311609, 47.526363}, {-122.311428, 47.526182}, {-122.311084, 47.525758}, {-122.310315, 47.525051}, {-122.310148, 47.524907}, {-122.309972, 47.524754}, {-122.309856, 47.524584}, {-122.309703, 47.524299}, {-122.309637, 47.52412}, {-122.309595, 47.524004}, {-122.309533, 47.523704}, {-122.309521, 47.523466}, {-122.309518, 47.5234}, {-122.309549, 47.523097}, {-122.309619, 47.522756}, {-122.309667, 47.522187}, {-122.309671, 47.522145}, {-122.309758, 47.522145}, {-122.310126, 47.522145}, {-122.310995, 47.522146}, {-122.313361, 47.522133}, {-122.313516, 47.522154}, {-122.313666, 47.522183}, {-122.314266, 47.522183}, {-122.314889, 47.522191}, {-122.314984, 47.522197}, {-122.315112, 47.52221}, {-122.31586, 47.522206}, {-122.316023, 47.522218}, {-122.317656, 47.522222}, {-122.317641, 47.521828}, {-122.317611, 47.521011}, {-122.317593, 47.520549}, {-122.317588, 47.520393}, {-122.317578, 47.520107}, {-122.317571, 47.51995}, {-122.317567, 47.519832}, {-122.317544, 47.519205}, {-122.31753, 47.518832}, {-122.317526, 47.518725}, {-122.318131, 47.518727}, {-122.318413, 47.518724}, {-122.318601, 47.518722}, {-122.320136, 47.518714}, {-122.320343, 47.518714}, {-122.321292, 47.518716}, {-122.321607, 47.518714}, {-122.323154, 47.518686}, {-122.32323, 47.518684}, {-122.323438, 47.518685}, {-122.323858, 47.518686}, {-122.324073, 47.518686}, {-122.324135, 47.518686}, {-122.32451, 47.518687}, {-122.3251, 47.518674}, {-122.325879, 47.518691}, {-122.325881, 47.520232}, {-122.325876, 47.52092}, {-122.327899, 47.520921}, {-122.329592, 47.520913}, {-122.330073, 47.520906}, {-122.330599, 47.520902}, {-122.330779, 47.520901}, {-122.330906, 47.520902}, {-122.33063, 47.520513}, {-122.329917, 47.519564}, {-122.329914, 47.519549}, {-122.329852, 47.519245}, {-122.329836, 47.519168}, {-122.32969, 47.518457}, {-122.329611, 47.518302}, {-122.329556, 47.518195}, {-122.329518, 47.518122}, {-122.329369, 47.517833}, {-122.329357, 47.517809}, {-122.329308, 47.51753}, {-122.329256, 47.517381}, {-122.329238, 47.517329}, {-122.329227, 47.517281}, {-122.329215, 47.517225}, {-122.329207, 47.517184}, {-122.3292, 47.51717}, {-122.329177, 47.517126}, {-122.328849, 47.516755}, {-122.328713, 47.516593}, {-122.328639, 47.516505}, {-122.327326, 47.513997}, {-122.328184, 47.513994}, {-122.328565, 47.513999}, {-122.330079, 47.513997}, {-122.330273, 47.513999}, {-122.330289, 47.514029}, {-122.330586, 47.514539}, {-122.33097, 47.514944}, {-122.331153, 47.515121}, {-122.331182, 47.515149}, {-122.331385, 47.515132}, {-122.331405, 47.515098}, {-122.332616, 47.514882}, {-122.333497, 47.514725}, {-122.333555, 47.514742}, {-122.333512, 47.514531}, {-122.334036, 47.514522}, {-122.334357, 47.514523}, {-122.334353, 47.514499}, {-122.334252, 47.513897}, {-122.335707, 47.513923}, {-122.336507, 47.513914}, {-122.336645, 47.513907}, {-122.33704, 47.513893}, {-122.337124, 47.515023}, {-122.337275, 47.515858}, {-122.33739, 47.516502}, {-122.337408, 47.516602}, {-122.337469, 47.516944}, {-122.33748, 47.517005}, {-122.337492, 47.517073}, {-122.337521, 47.517257}, {-122.337537, 47.517256}, {-122.33793, 47.517258}, {-122.339915, 47.517269}, {-122.340134, 47.517277}, {-122.340448, 47.51724}, {-122.34075, 47.51722}, {-122.341437, 47.517276}, {-122.34161, 47.517281}, {-122.342878, 47.517287}, {-122.343873, 47.517293}, {-122.344151, 47.517294}, {-122.344639, 47.517299}, {-122.345426, 47.517302}, {-122.346699, 47.517309}, {-122.347972, 47.517317}, {-122.348017, 47.517317}, {-122.349246, 47.517324}, {-122.350655, 47.517332}, {-122.351735, 47.517339}, {-122.351778, 47.517339}, {-122.352909, 47.517361}, {-122.353404, 47.51737}, {-122.354037, 47.517374}, {-122.355167, 47.51738}, {-122.356112, 47.517386}, {-122.356513, 47.517382}, {-122.357859, 47.51736}, {-122.358228, 47.517353}, {-122.358557, 47.517347}, {-122.358564, 47.515528}, {-122.359181, 47.515528}, {-122.360495, 47.515528}, {-122.360536, 47.51682}, {-122.360542, 47.51736}, {-122.361127, 47.517362}, {-122.361851, 47.517361}, {-122.36262, 47.517361}, {-122.363226, 47.517362}, {-122.36457, 47.517362}, {-122.365915, 47.517361}, {-122.36728, 47.517377}, {-122.367695, 47.517381}, {-122.368662, 47.517393}, {-122.3714, 47.517424}, {-122.371316, 47.516653}, {-122.371272, 47.516076}, {-122.371274, 47.516024}, {-122.371263, 47.515745}, {-122.371152, 47.514459}, {-122.371104, 47.513705}, {-122.37108, 47.513335}, {-122.37102, 47.512548}, {-122.371, 47.51229}, {-122.370984, 47.512047}, {-122.370888, 47.510038}, {-122.37086, 47.509458}, {-122.370877, 47.508199}, {-122.370862, 47.508017}, {-122.370714, 47.507259}, {-122.37053, 47.506664}, {-122.370465, 47.506409}, {-122.370464, 47.506398}, {-122.370394, 47.505821}, {-122.370404, 47.505686}, {-122.370449, 47.505503}, {-122.370474, 47.505402}, {-122.37054, 47.505135}, {-122.37055, 47.50452}, {-122.370561, 47.503866}, {-122.370596, 47.503683}, {-122.370694, 47.503511}, {-122.370919, 47.503241}, {-122.371413, 47.502778}, {-122.372051, 47.502182}, {-122.372257, 47.502014}, {-122.373121, 47.501378}, {-122.3738, 47.500834}, {-122.373923, 47.500697}, {-122.373972, 47.500581}, {-122.374059, 47.499917}, {-122.374133, 47.499617}, {-122.374278, 47.499221}, {-122.37485, 47.497659}, {-122.37492, 47.497497}, {-122.375024, 47.49732}, {-122.375068, 47.497248}, {-122.375208, 47.497032}, {-122.375312, 47.496869}, {-122.375652, 47.496434}, {-122.380128, 47.493203}, {-122.38181, 47.491912}, {-122.399237, 47.48522}, {-122.407658, 47.48215}, {-122.409315, 47.485945}, {-122.409341, 47.485999}, {-122.409371, 47.486053}, {-122.415446, 47.497105}, {-122.416946, 47.499846}, {-122.418072, 47.501568}, {-122.423326, 47.508282}, {-122.42629, 47.512069}, {-122.430797, 47.516605}, {-122.436093, 47.521938}, {-122.436484, 47.522337}, {-122.439282, 47.525625}, {-122.441558, 47.529092}, {-122.442968, 47.532037}, {-122.443244, 47.53264}, {-122.443323, 47.532812}, {-122.444449, 47.536414}, {-122.445032, 47.540187}, {-122.445031, 47.541851}, {-122.445031, 47.54253}, {-122.444867, 47.542661}, {-122.444636, 47.543295}, {-122.444778, 47.544416}, {-122.444372, 47.54783}, {-122.443864, 47.551798}, {-122.443888, 47.553717}, {-122.444013, 47.554485}, {-122.444297, 47.555565}, {-122.444622, 47.55646}, {-122.444772, 47.556877}, {-122.445159, 47.557759}, {-122.445723, 47.558828}, {-122.447001, 47.560745}, {-122.44849, 47.562978}, {-122.450247, 47.565615}, {-122.450834, 47.566373}, {-122.451683, 47.567468}, {-122.452447, 47.568371}, {-122.453062, 47.569097}, {-122.453249, 47.569399}, {-122.453374, 47.569604}, {-122.453994, 47.57091}, {-122.454134, 47.571318}, {-122.45448, 47.572328}, {-122.454766, 47.573685}, {-122.454787, 47.57397}, {-122.454847, 47.574757}, {-122.454781, 47.576186}, {-122.454746, 47.576391}, {-122.454726, 47.576591}, {-122.454627, 47.577209}, {-122.4541, 47.579662}, {-122.453582, 47.581237}, {-122.453158, 47.582208}, {-122.451696, 47.585085}, {-122.451383, 47.585702}, {-122.450513, 47.587416}, {-122.449692, 47.588963}, {-122.448332, 47.591253}, {-122.447883, 47.592297}, {-122.447569, 47.593313}, {-122.447305, 47.594455}, {-122.447157, 47.595574}, {-122.446984, 47.597612}, {-122.446947, 47.5981}, {-122.446859, 47.599162}, {-122.446558, 47.602772}, {-122.446203, 47.607035}, {-122.446063, 47.607998}, {-122.446503, 47.611494}, {-122.446853, 47.61242}, {-122.447298, 47.613069}, {-122.447711, 47.614209}, {-122.447908, 47.614741}, {-122.448321, 47.615696}, {-122.448615, 47.616382}, {-122.448642, 47.616446}, {-122.44867, 47.61651}, {-122.449203, 47.617523}, {-122.449543, 47.618171}, {-122.45005, 47.619022}, {-122.451403, 47.620957}, {-122.453006, 47.622876}, {-122.453763, 47.623782}, {-122.454252, 47.624636}, {-122.454908, 47.626561}, {-122.454985, 47.627192}, {-122.45491, 47.627647}, {-122.454567, 47.629007}, {-122.454372, 47.629669}, {-122.454199, 47.630258}, {-122.454069, 47.630696}, {-122.453871, 47.631371}, {-122.453682, 47.632013}, {-122.453522, 47.632556}, {-122.453067, 47.634524}, {-122.45284, 47.636087}, {-122.452694, 47.638749}, {-122.452675, 47.63911}, {-122.452686, 47.642348}, {-122.452812, 47.643798}, {-122.453181, 47.646248}, {-122.453251, 47.646713}, {-122.453391, 47.647654}, {-122.454105, 47.651119}, {-122.454282, 47.652018}, {-122.454346, 47.652662}, {-122.454405, 47.653253}, {-122.455216, 47.655316}, {-122.456059, 47.657707}, {-122.456757, 47.659683}, {-122.457251, 47.661335}, {-122.458099, 47.663906}, {-122.458569, 47.665605}, {-122.459375, 47.669161}, {-122.45962, 47.671118}, {-122.459737, 47.67212}, {-122.459774, 47.672418}, - }, nil, DefaultIndex) + }, nil, DefaultIndexOptions) bounds := []*Poly{ - NewPoly([]Point{{-114.2399485999843, 42.681876499955926}, {-114.23997050001262, 42.67824680037998}, {-114.23627140565759, 42.678233981038666}, {-114.23504369971833, 42.67822970021946}, {-114.23503067863831, 42.67578671168899}, {-114.23543512533203, 42.67583999946153}, {-114.23594982495554, 42.676124423371455}, {-114.23672596666609, 42.67625624813994}, {-114.23685805764039, 42.676776002285635}, {-114.23663532665391, 42.677055424446124}, {-114.23671287282251, 42.67747314961749}, {-114.23681394047848, 42.677805126285634}, {-114.23706193209075, 42.67813127497741}, {-114.23784992168157, 42.678186635769315}, {-114.23838959806322, 42.67813118119811}, {-114.23875417123647, 42.67791953618522}, {-114.23912485834349, 42.67784524816636}, {-114.23952718950476, 42.67769791345572}, {-114.23999116575574, 42.677386626685646}, {-114.24048944148089, 42.67724527831817}, {-114.241314164082, 42.67699656963459}, {-114.24195248087176, 42.676729402854455}, {-114.24240805338327, 42.67645818447628}, {-114.24311814376759, 42.67608562786248}, {-114.24355505557568, 42.67596026910592}, {-114.24477528843009, 42.67578037408335}, {-114.24521195320149, 42.675790315723084}, {-114.24576310286596, 42.67606342521258}, {-114.2467516503271, 42.676300425443266}, {-114.2474970507903, 42.676777404382534}, {-114.24910805618318, 42.67760249691951}, {-114.24971203666782, 42.67767705336001}, {-114.25014930420876, 42.67756278302376}, {-114.25107740672941, 42.677654319638556}, {-114.25187256038463, 42.677646259180754}, {-114.25216885710465, 42.677753657678224}, {-114.25223329954821, 42.678306700105715}, {-114.25279040055142, 42.678712300300425}, {-114.25345425195313, 42.678693062516}, {-114.25372209992645, 42.67868529937817}, {-114.25422830058905, 42.67839869989619}, {-114.25469089972272, 42.67851959990614}, {-114.25525630026085, 42.67839799985663}, {-114.2563918004244, 42.678740799683624}, {-114.25714179936351, 42.67950249986307}, {-114.25712530000669, 42.6819502000424}, {-114.25711160069862, 42.68397369991884}, {-114.25465699999884, 42.68442620019711}, {-114.25229229999773, 42.684861999674204}, {-114.24974329893801, 42.68533019969429}, {-114.2486267002264, 42.685511500004914}, {-114.24862660051338, 42.68554050010786}, {-114.24483440027073, 42.68552580030558}, {-114.24131170000318, 42.68551210025312}, {-114.24115469964434, 42.685511400293755}, {-114.2399323000535, 42.68459820015348}, {-114.2399485999843, 42.681876499955926}}, nil, DefaultIndex), - NewPoly([]Point{{-114.24970880003785, 42.69640819992281}, {-114.24970389972798, 42.692787600018605}, {-114.25460269953487, 42.69281529997132}, {-114.25950169966605, 42.69284299991165}, {-114.25951680034598, 42.69646220021525}, {-114.2546128001919, 42.69643530009867}, {-114.24970880003785, 42.69640819992281}}, nil, DefaultIndex), - NewPoly([]Point{{-122.50865178071805, 47.61633533468668}, {-122.50746427348945, 47.6148250023897}, {-122.50762759349631, 47.61480254865959}, {-122.50778991457659, 47.61477700108817}, {-122.50795111006781, 47.61474837844346}, {-122.50811105151087, 47.61471670312629}, {-122.51010371333871, 47.61430140449804}, {-122.51016786562644, 47.6142883120613}, {-122.51041138093365, 47.61424362213619}, {-122.51040948099681, 47.61458176413451}, {-122.51040824760994, 47.614801121949036}, {-122.5104030903819, 47.61571858749849}, {-122.51039374700463, 47.61572085227092}, {-122.51038431649077, 47.61572294324917}, {-122.51037480423024, 47.61572485861667}, {-122.51036521830783, 47.61572659716236}, {-122.51026191115182, 47.615750784801655}, {-122.51015949332798, 47.615776646785115}, {-122.51007599582063, 47.61579915156894}, {-122.50999317294806, 47.6158227693494}, {-122.5099449262308, 47.615836900530496}, {-122.50989743499666, 47.61585215743006}, {-122.50985075673788, 47.6158685200638}, {-122.50980494714995, 47.61588596844757}, {-122.50976006103016, 47.61590448380809}, {-122.50971615497232, 47.61592404192218}, {-122.50967327838381, 47.61594461977769}, {-122.50963148606186, 47.61596619133478}, {-122.50959082651548, 47.61598873297563}, {-122.50955135094863, 47.6160122150271}, {-122.50951310517539, 47.61603661144916}, {-122.50947613500989, 47.61606189135753}, {-122.50944048716445, 47.61608802386794}, {-122.50940620296163, 47.616114978095965}, {-122.50939632239182, 47.61612695102005}, {-122.50938583635751, 47.616138685960564}, {-122.50937475743511, 47.61615016959558}, {-122.50936310089598, 47.6161613886031}, {-122.50935087841822, 47.61617232905581}, {-122.50933810527319, 47.61618297763166}, {-122.50932479673226, 47.61619332161441}, {-122.50931096896512, 47.616203350104364}, {-122.50929663724307, 47.61621305038511}, {-122.50928181953245, 47.61622241034595}, {-122.50926653379958, 47.6162314184816}, {-122.50925079801074, 47.61624006570906}, {-122.50923462923394, 47.6162483411286}, {-122.50921804992707, 47.61625623444614}, {-122.50920107715808, 47.61626373657857}, {-122.50918373158828, 47.61627083844286}, {-122.50916603387886, 47.61627753156154}, {-122.50914800648772, 47.616283808668186}, {-122.50912966917784, 47.61628966128524}, {-122.50911104350872, 47.61629508275189}, {-122.50909215373491, 47.616300066407184}, {-122.50907301961938, 47.61630460740689}, {-122.50905366631491, 47.61630869909014}, {-122.50903411627938, 47.61631233782372}, {-122.50901439107238, 47.61631551815777}, {-122.50899451584671, 47.61631823645919}, {-122.5089745139586, 47.61632049030575}, {-122.50895440966254, 47.61632227606429}, {-122.50893422541641, 47.61632359312931}, {-122.50891398637307, 47.61632443726198}, {-122.50889371678699, 47.616324809673436}, {-122.50887343911609, 47.61632470915263}, {-122.50885317941147, 47.61632413630507}, {-122.50883296102938, 47.616323091130724}, {-122.508812807326, 47.6163215748407}, {-122.50879274345411, 47.61631958985712}, {-122.50877279276996, 47.61631713860209}, {-122.50875901261351, 47.61631791309698}, {-122.50874528006777, 47.616319003081905}, {-122.50873160950579, 47.616320408556895}, {-122.5087180179955, 47.61632212588859}, {-122.50870451991005, 47.616324155682584}, {-122.50869113231737, 47.61632649430547}, {-122.50867786959051, 47.616329139335114}, {-122.50866474700086, 47.61633208713811}, {-122.50865178071805, 47.61633533468668}}, nil, DefaultIndex), + NewPoly([]Point{{-114.2399485999843, 42.681876499955926}, {-114.23997050001262, 42.67824680037998}, {-114.23627140565759, 42.678233981038666}, {-114.23504369971833, 42.67822970021946}, {-114.23503067863831, 42.67578671168899}, {-114.23543512533203, 42.67583999946153}, {-114.23594982495554, 42.676124423371455}, {-114.23672596666609, 42.67625624813994}, {-114.23685805764039, 42.676776002285635}, {-114.23663532665391, 42.677055424446124}, {-114.23671287282251, 42.67747314961749}, {-114.23681394047848, 42.677805126285634}, {-114.23706193209075, 42.67813127497741}, {-114.23784992168157, 42.678186635769315}, {-114.23838959806322, 42.67813118119811}, {-114.23875417123647, 42.67791953618522}, {-114.23912485834349, 42.67784524816636}, {-114.23952718950476, 42.67769791345572}, {-114.23999116575574, 42.677386626685646}, {-114.24048944148089, 42.67724527831817}, {-114.241314164082, 42.67699656963459}, {-114.24195248087176, 42.676729402854455}, {-114.24240805338327, 42.67645818447628}, {-114.24311814376759, 42.67608562786248}, {-114.24355505557568, 42.67596026910592}, {-114.24477528843009, 42.67578037408335}, {-114.24521195320149, 42.675790315723084}, {-114.24576310286596, 42.67606342521258}, {-114.2467516503271, 42.676300425443266}, {-114.2474970507903, 42.676777404382534}, {-114.24910805618318, 42.67760249691951}, {-114.24971203666782, 42.67767705336001}, {-114.25014930420876, 42.67756278302376}, {-114.25107740672941, 42.677654319638556}, {-114.25187256038463, 42.677646259180754}, {-114.25216885710465, 42.677753657678224}, {-114.25223329954821, 42.678306700105715}, {-114.25279040055142, 42.678712300300425}, {-114.25345425195313, 42.678693062516}, {-114.25372209992645, 42.67868529937817}, {-114.25422830058905, 42.67839869989619}, {-114.25469089972272, 42.67851959990614}, {-114.25525630026085, 42.67839799985663}, {-114.2563918004244, 42.678740799683624}, {-114.25714179936351, 42.67950249986307}, {-114.25712530000669, 42.6819502000424}, {-114.25711160069862, 42.68397369991884}, {-114.25465699999884, 42.68442620019711}, {-114.25229229999773, 42.684861999674204}, {-114.24974329893801, 42.68533019969429}, {-114.2486267002264, 42.685511500004914}, {-114.24862660051338, 42.68554050010786}, {-114.24483440027073, 42.68552580030558}, {-114.24131170000318, 42.68551210025312}, {-114.24115469964434, 42.685511400293755}, {-114.2399323000535, 42.68459820015348}, {-114.2399485999843, 42.681876499955926}}, nil, DefaultIndexOptions), + NewPoly([]Point{{-114.24970880003785, 42.69640819992281}, {-114.24970389972798, 42.692787600018605}, {-114.25460269953487, 42.69281529997132}, {-114.25950169966605, 42.69284299991165}, {-114.25951680034598, 42.69646220021525}, {-114.2546128001919, 42.69643530009867}, {-114.24970880003785, 42.69640819992281}}, nil, DefaultIndexOptions), + NewPoly([]Point{{-122.50865178071805, 47.61633533468668}, {-122.50746427348945, 47.6148250023897}, {-122.50762759349631, 47.61480254865959}, {-122.50778991457659, 47.61477700108817}, {-122.50795111006781, 47.61474837844346}, {-122.50811105151087, 47.61471670312629}, {-122.51010371333871, 47.61430140449804}, {-122.51016786562644, 47.6142883120613}, {-122.51041138093365, 47.61424362213619}, {-122.51040948099681, 47.61458176413451}, {-122.51040824760994, 47.614801121949036}, {-122.5104030903819, 47.61571858749849}, {-122.51039374700463, 47.61572085227092}, {-122.51038431649077, 47.61572294324917}, {-122.51037480423024, 47.61572485861667}, {-122.51036521830783, 47.61572659716236}, {-122.51026191115182, 47.615750784801655}, {-122.51015949332798, 47.615776646785115}, {-122.51007599582063, 47.61579915156894}, {-122.50999317294806, 47.6158227693494}, {-122.5099449262308, 47.615836900530496}, {-122.50989743499666, 47.61585215743006}, {-122.50985075673788, 47.6158685200638}, {-122.50980494714995, 47.61588596844757}, {-122.50976006103016, 47.61590448380809}, {-122.50971615497232, 47.61592404192218}, {-122.50967327838381, 47.61594461977769}, {-122.50963148606186, 47.61596619133478}, {-122.50959082651548, 47.61598873297563}, {-122.50955135094863, 47.6160122150271}, {-122.50951310517539, 47.61603661144916}, {-122.50947613500989, 47.61606189135753}, {-122.50944048716445, 47.61608802386794}, {-122.50940620296163, 47.616114978095965}, {-122.50939632239182, 47.61612695102005}, {-122.50938583635751, 47.616138685960564}, {-122.50937475743511, 47.61615016959558}, {-122.50936310089598, 47.6161613886031}, {-122.50935087841822, 47.61617232905581}, {-122.50933810527319, 47.61618297763166}, {-122.50932479673226, 47.61619332161441}, {-122.50931096896512, 47.616203350104364}, {-122.50929663724307, 47.61621305038511}, {-122.50928181953245, 47.61622241034595}, {-122.50926653379958, 47.6162314184816}, {-122.50925079801074, 47.61624006570906}, {-122.50923462923394, 47.6162483411286}, {-122.50921804992707, 47.61625623444614}, {-122.50920107715808, 47.61626373657857}, {-122.50918373158828, 47.61627083844286}, {-122.50916603387886, 47.61627753156154}, {-122.50914800648772, 47.616283808668186}, {-122.50912966917784, 47.61628966128524}, {-122.50911104350872, 47.61629508275189}, {-122.50909215373491, 47.616300066407184}, {-122.50907301961938, 47.61630460740689}, {-122.50905366631491, 47.61630869909014}, {-122.50903411627938, 47.61631233782372}, {-122.50901439107238, 47.61631551815777}, {-122.50899451584671, 47.61631823645919}, {-122.5089745139586, 47.61632049030575}, {-122.50895440966254, 47.61632227606429}, {-122.50893422541641, 47.61632359312931}, {-122.50891398637307, 47.61632443726198}, {-122.50889371678699, 47.616324809673436}, {-122.50887343911609, 47.61632470915263}, {-122.50885317941147, 47.61632413630507}, {-122.50883296102938, 47.616323091130724}, {-122.508812807326, 47.6163215748407}, {-122.50879274345411, 47.61631958985712}, {-122.50877279276996, 47.61631713860209}, {-122.50875901261351, 47.61631791309698}, {-122.50874528006777, 47.616319003081905}, {-122.50873160950579, 47.616320408556895}, {-122.5087180179955, 47.61632212588859}, {-122.50870451991005, 47.616324155682584}, {-122.50869113231737, 47.61632649430547}, {-122.50867786959051, 47.616329139335114}, {-122.50866474700086, 47.61633208713811}, {-122.50865178071805, 47.61633533468668}}, nil, DefaultIndexOptions), } intersects := false for _, bounds := range bounds { @@ -128,7 +128,7 @@ func TestIssue241(t *testing.T) { {2.2509634494781494, 48.841891534086436}, {2.2513389587402344, 48.84261881872204}, {2.2546112537384033, 48.8428518300122}, - }}, DefaultIndex) + }}, DefaultIndexOptions) p1 := P(2.253119945526123, 48.841404318083505) expect(t, !g.IntersectsPoint(p1)) expect(t, !g.ContainsPoint(p1)) diff --git a/vendor/github.com/tidwall/geojson/geometry/line.go b/vendor/github.com/tidwall/geojson/geometry/line.go index 2ea1a36b..ec6fe24b 100644 --- a/vendor/github.com/tidwall/geojson/geometry/line.go +++ b/vendor/github.com/tidwall/geojson/geometry/line.go @@ -10,9 +10,9 @@ type Line struct { } // NewLine creates a new Line -func NewLine(points []Point, index int) *Line { +func NewLine(points []Point, opts *IndexOptions) *Line { line := new(Line) - line.baseSeries = makeSeries(points, true, false, index) + line.baseSeries = makeSeries(points, true, false, opts) return line } diff --git a/vendor/github.com/tidwall/geojson/geometry/line_test.go b/vendor/github.com/tidwall/geojson/geometry/line_test.go index a20d365f..a50799e2 100644 --- a/vendor/github.com/tidwall/geojson/geometry/line_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/line_test.go @@ -7,7 +7,7 @@ package geometry import "testing" func TestLineNewLine(t *testing.T) { - line := NewLine(u1, DefaultIndex) + line := NewLine(u1, DefaultIndexOptions) expect(t, !line.Empty()) } @@ -43,12 +43,12 @@ func TestLineMove(t *testing.T) { } func TestLineContainsPoint(t *testing.T) { - line := NewLine(u1, DefaultIndex) + line := NewLine(u1, DefaultIndexOptions) expect(t, line.ContainsPoint(P(0, 0))) expect(t, line.ContainsPoint(P(10, 10))) expect(t, line.ContainsPoint(P(0, 5))) expect(t, !line.ContainsPoint(P(5, 5))) - line = NewLine(v1, DefaultIndex) + line = NewLine(v1, DefaultIndexOptions) expect(t, line.ContainsPoint(P(0, 10))) expect(t, !line.ContainsPoint(P(0, 0))) expect(t, line.ContainsPoint(P(5, 0))) @@ -59,7 +59,7 @@ func TestLineContainsPoint(t *testing.T) { } func TestLineIntersectsPoint(t *testing.T) { - line := NewLine(v1, DefaultIndex) + line := NewLine(v1, DefaultIndexOptions) expect(t, line.IntersectsPoint(P(0, 10))) expect(t, !line.IntersectsPoint(P(0, 0))) expect(t, line.IntersectsPoint(P(5, 0))) @@ -70,10 +70,10 @@ func TestLineIntersectsPoint(t *testing.T) { } func TestLineContainsRect(t *testing.T) { - line := NewLine(v1, DefaultIndex) + line := NewLine(v1, DefaultIndexOptions) expect(t, !line.ContainsRect(R(0, 0, 10, 10))) expect(t, line.ContainsRect(R(0, 10, 0, 10))) - line = NewLine(u1, DefaultIndex) + line = NewLine(u1, DefaultIndexOptions) expect(t, line.ContainsRect(R(0, 0, 0, 10))) line = nil expect(t, !line.ContainsRect(Rect{})) @@ -81,7 +81,7 @@ func TestLineContainsRect(t *testing.T) { } func TestLineIntersectsRect(t *testing.T) { - line := NewLine(v1, DefaultIndex) + line := NewLine(v1, DefaultIndexOptions) expect(t, line.IntersectsRect(R(0, 0, 10, 10))) expect(t, line.IntersectsRect(R(0, 0, 2.5, 5))) expect(t, !line.IntersectsRect(R(0, 0, 2.4, 5))) @@ -130,15 +130,15 @@ func TestLineIntersectsLine(t *testing.T) { lns := [][]Point{u1, u2, u3, u4, v1, v2, v3, v4} for i := 0; i < len(lns); i++ { for j := 0; j < len(lns); j++ { - expect(t, NewLine(lns[i], DefaultIndex).IntersectsLine( - NewLine(lns[j], DefaultIndex), + expect(t, NewLine(lns[i], DefaultIndexOptions).IntersectsLine( + NewLine(lns[j], DefaultIndexOptions), )) } } - line := NewLine(u1, DefaultIndex) - expect(t, !line.IntersectsLine(NewLine(nil, DefaultIndex))) - expect(t, !NewLine(nil, DefaultIndex).IntersectsLine(NewLine(nil, DefaultIndex))) - expect(t, !NewLine(nil, DefaultIndex).IntersectsLine(line)) + line := NewLine(u1, DefaultIndexOptions) + expect(t, !line.IntersectsLine(NewLine(nil, DefaultIndexOptions))) + expect(t, !NewLine(nil, DefaultIndexOptions).IntersectsLine(NewLine(nil, DefaultIndexOptions))) + expect(t, !NewLine(nil, DefaultIndexOptions).IntersectsLine(line)) expect(t, line.IntersectsLine(line.Move(5, 0))) expect(t, line.IntersectsLine(line.Move(10, 0))) expect(t, !line.IntersectsLine(line.Move(11, 0))) @@ -147,27 +147,27 @@ func TestLineIntersectsLine(t *testing.T) { } func TestLineContainsPoly(t *testing.T) { - line := NewLine(u1, DefaultIndex) - poly := NewPoly(octagon, nil, DefaultIndex) + line := NewLine(u1, DefaultIndexOptions) + poly := NewPoly(octagon, nil, DefaultIndexOptions) expect(t, !line.ContainsPoly(poly)) expect(t, line.ContainsPoly(NewPoly( []Point{P(0, 10), P(0, 0), P(0, 10)}, - nil, DefaultIndex, + nil, DefaultIndexOptions, ))) expect(t, line.ContainsPoly(NewPoly( []Point{P(0, 0), P(10, 0), P(0, 0)}, - nil, DefaultIndex, + nil, DefaultIndexOptions, ))) expect(t, !L().ContainsPoly(NewPoly( []Point{P(0, 0), P(10, 0), P(0, 0)}, - nil, DefaultIndex, + nil, DefaultIndexOptions, ))) - expect(t, !line.ContainsPoly(NewPoly(nil, nil, DefaultIndex))) + expect(t, !line.ContainsPoly(NewPoly(nil, nil, DefaultIndexOptions))) } func TestLineIntersectsPoly(t *testing.T) { - line := NewLine(u1, DefaultIndex) - poly := NewPoly(octagon, nil, DefaultIndex) + line := NewLine(u1, DefaultIndexOptions) + poly := NewPoly(octagon, nil, DefaultIndexOptions) expect(t, line.IntersectsPoly(poly)) expect(t, line.IntersectsPoly(poly.Move(5, 0))) expect(t, line.IntersectsPoly(poly.Move(10, 0))) diff --git a/vendor/github.com/tidwall/geojson/geometry/pip_bench_test.go b/vendor/github.com/tidwall/geojson/geometry/pip_bench_test.go index 88b18843..92e39af6 100644 --- a/vendor/github.com/tidwall/geojson/geometry/pip_bench_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/pip_bench_test.go @@ -17,10 +17,10 @@ func testBig( ) { N, T := 100000, 4 - simple := newRing(points, DefaultIndex) - simple.(*baseSeries).tree = nil - tree := newRing(points, DefaultIndex) - tree.(*baseSeries).buildTree() + simple := newRing(points, DefaultIndexOptions) + simple.(*baseSeries).clearIndex() + tree := newRing(points, DefaultIndexOptions) + tree.(*baseSeries).buildIndex() pointOn := points[len(points)/2] // ioutil.WriteFile(label+".svg", []byte(tools.SVG(tree.(*baseSeries).tree)), 0666) diff --git a/vendor/github.com/tidwall/geojson/geometry/point_test.go b/vendor/github.com/tidwall/geojson/geometry/point_test.go index 29f19eb6..46062283 100644 --- a/vendor/github.com/tidwall/geojson/geometry/point_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/point_test.go @@ -74,17 +74,17 @@ func TestPointIntersectsLine(t *testing.T) { } func TestPointContainsPoly(t *testing.T) { - expect(t, !P(5, 5).ContainsPoly(NewPoly(nil, nil, DefaultIndex))) - expect(t, !P(5, 5).ContainsPoly(NewPoly([]Point{P(0, 0), P(10, 0)}, nil, DefaultIndex))) + expect(t, !P(5, 5).ContainsPoly(NewPoly(nil, nil, DefaultIndexOptions))) + expect(t, !P(5, 5).ContainsPoly(NewPoly([]Point{P(0, 0), P(10, 0)}, nil, DefaultIndexOptions))) expect(t, !P(5, 5).ContainsPoly(&Poly{Exterior: R(0, 0, 10, 10)})) expect(t, P(5, 5).ContainsPoly(&Poly{Exterior: R(5, 5, 5, 5)})) } func TestPointIntersectsPoly(t *testing.T) { - octa := NewPoly(octagon, nil, DefaultIndex) - concave1 := NewPoly(concave1, nil, DefaultIndex) - expect(t, !P(5, 5).IntersectsPoly(NewPoly(nil, nil, DefaultIndex))) - expect(t, !P(5, 5).IntersectsPoly(NewPoly([]Point{P(0, 0), P(10, 0)}, nil, DefaultIndex))) + octa := NewPoly(octagon, nil, DefaultIndexOptions) + concave1 := NewPoly(concave1, nil, DefaultIndexOptions) + expect(t, !P(5, 5).IntersectsPoly(NewPoly(nil, nil, DefaultIndexOptions))) + expect(t, !P(5, 5).IntersectsPoly(NewPoly([]Point{P(0, 0), P(10, 0)}, nil, DefaultIndexOptions))) expect(t, P(5, 5).IntersectsPoly(octa)) expect(t, P(0, 5).IntersectsPoly(octa)) expect(t, !P(1, 1).IntersectsPoly(octa)) diff --git a/vendor/github.com/tidwall/geojson/geometry/poly.go b/vendor/github.com/tidwall/geojson/geometry/poly.go index 027403d1..a408e011 100644 --- a/vendor/github.com/tidwall/geojson/geometry/poly.go +++ b/vendor/github.com/tidwall/geojson/geometry/poly.go @@ -11,13 +11,13 @@ type Poly struct { } // NewPoly ... -func NewPoly(exterior []Point, holes [][]Point, index int) *Poly { +func NewPoly(exterior []Point, holes [][]Point, opts *IndexOptions) *Poly { poly := new(Poly) - poly.Exterior = newRing(exterior, index) + poly.Exterior = newRing(exterior, opts) if len(holes) > 0 { poly.Holes = make([]Ring, len(holes)) for i := range holes { - poly.Holes[i] = newRing(holes[i], index) + poly.Holes[i] = newRing(holes[i], opts) } } return poly @@ -60,7 +60,7 @@ func (poly *Poly) Move(deltaX, deltaY float64) *Poly { npoly.Exterior = Ring(series.Move(deltaX, deltaY)) } else { nseries := makeSeries( - seriesCopyPoints(poly.Exterior), false, true, DefaultIndex) + seriesCopyPoints(poly.Exterior), false, true, DefaultIndexOptions) npoly.Exterior = Ring(nseries.Move(deltaX, deltaY)) } if len(poly.Holes) > 0 { @@ -70,7 +70,7 @@ func (poly *Poly) Move(deltaX, deltaY float64) *Poly { npoly.Holes[i] = Ring(series.Move(deltaX, deltaY)) } else { nseries := makeSeries( - seriesCopyPoints(hole), false, true, DefaultIndex) + seriesCopyPoints(hole), false, true, DefaultIndexOptions) npoly.Holes[i] = Ring(nseries.Move(deltaX, deltaY)) } } diff --git a/vendor/github.com/tidwall/geojson/geometry/poly_test.go b/vendor/github.com/tidwall/geojson/geometry/poly_test.go index a610b873..2e565df9 100644 --- a/vendor/github.com/tidwall/geojson/geometry/poly_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/poly_test.go @@ -9,19 +9,19 @@ import ( ) func newPolyIndexed(exterior []Point, holes [][]Point) *Poly { - poly := NewPoly(exterior, holes, DefaultIndex) - poly.Exterior.(*baseSeries).buildTree() + poly := NewPoly(exterior, holes, DefaultIndexOptions) + poly.Exterior.(*baseSeries).buildIndex() for _, hole := range poly.Holes { - hole.(*baseSeries).buildTree() + hole.(*baseSeries).buildIndex() } return poly } func newPolySimple(exterior []Point, holes [][]Point) *Poly { - poly := NewPoly(exterior, holes, DefaultIndex) - poly.Exterior.(*baseSeries).tree = nil + poly := NewPoly(exterior, holes, DefaultIndexOptions) + poly.Exterior.(*baseSeries).clearIndex() for _, hole := range poly.Holes { - hole.(*baseSeries).tree = nil + hole.(*baseSeries).clearIndex() } return poly } @@ -169,22 +169,22 @@ func TestPolyIntersectsLine(t *testing.T) { func TestPolyContainsPoly(t *testing.T) { holes1 := [][]Point{[]Point{{4, 4}, {6, 4}, {6, 6}, {4, 6}, {4, 4}}} holes2 := [][]Point{[]Point{{5, 4}, {7, 4}, {7, 6}, {5, 6}, {5, 4}}} - poly1 := NewPoly(octagon, holes1, DefaultIndex) - poly2 := NewPoly(octagon, holes2, DefaultIndex) + poly1 := NewPoly(octagon, holes1, DefaultIndexOptions) + poly2 := NewPoly(octagon, holes2, DefaultIndexOptions) - expect(t, !poly1.ContainsPoly(NewPoly(holes2[0], nil, DefaultIndex))) + expect(t, !poly1.ContainsPoly(NewPoly(holes2[0], nil, DefaultIndexOptions))) expect(t, !poly1.ContainsPoly(poly2)) dualPolyTest(t, octagon, holes1, func(t *testing.T, poly *Poly) { expect(t, poly.ContainsPoly(poly1)) expect(t, !poly.ContainsPoly(poly1.Move(1, 0))) - expect(t, poly.ContainsPoly(NewPoly(holes1[0], nil, DefaultIndex))) - expect(t, !poly.ContainsPoly(NewPoly(holes2[0], nil, DefaultIndex))) + expect(t, poly.ContainsPoly(NewPoly(holes1[0], nil, DefaultIndexOptions))) + expect(t, !poly.ContainsPoly(NewPoly(holes2[0], nil, DefaultIndexOptions))) }) } func TestPolyClockwise(t *testing.T) { - expect(t, !NewPoly(bowtie, nil, DefaultIndex).Clockwise()) + expect(t, !NewPoly(bowtie, nil, DefaultIndexOptions).Clockwise()) var poly *Poly expect(t, !poly.Clockwise()) } @@ -212,28 +212,28 @@ func Test369(t *testing.T) { {-122.44109272956847, 37.7326855231885}, {-122.44109272956847, 37.731870943026074}, }, - }, DefaultIndex) + }, DefaultIndexOptions) a := NewPoly([]Point{ {-122.4408378, 37.7341129}, {-122.4408378, 37.733}, {-122.44, 37.733}, {-122.44, 37.7343129}, {-122.4408378, 37.7341129}, - }, nil, DefaultIndex) + }, nil, DefaultIndexOptions) b := NewPoly([]Point{ {-122.44091033935547, 37.731981251280985}, {-122.43994474411011, 37.731981251280985}, {-122.43994474411011, 37.73254976045042}, {-122.44091033935547, 37.73254976045042}, {-122.44091033935547, 37.731981251280985}, - }, nil, DefaultIndex) + }, nil, DefaultIndexOptions) c := NewPoly([]Point{ {-122.4408378, 37.7341129}, {-122.4408378, 37.733}, {-122.44, 37.733}, {-122.44, 37.7341129}, {-122.4408378, 37.7341129}, - }, nil, DefaultIndex) + }, nil, DefaultIndexOptions) expect(t, polyHoles.IntersectsPoly(a)) expect(t, !polyHoles.IntersectsPoly(b)) expect(t, !polyHoles.IntersectsPoly(c)) diff --git a/vendor/github.com/tidwall/geojson/geometry/quadtree.go b/vendor/github.com/tidwall/geojson/geometry/quadtree.go new file mode 100644 index 00000000..e4279fb9 --- /dev/null +++ b/vendor/github.com/tidwall/geojson/geometry/quadtree.go @@ -0,0 +1,255 @@ +package geometry + +import "encoding/binary" + +const qMaxItems = 16 +const qMaxDepth = 16 + +type qNode struct { + split bool + items []uint32 + quads [4]*qNode +} + +func (n *qNode) insert(series *baseSeries, bounds, rect Rect, item, depth int) { + if depth == qMaxDepth { + // limit depth and insert now + n.items = append(n.items, uint32(item)) + } else if n.split { + // qnode is split so try to insert into a quad + q := n.chooseQuad(bounds, rect) + if q == -1 { + // insert into overflow + n.items = append(n.items, uint32(item)) + } else { + // insert into quad + qbounds := quadBounds(bounds, q) + if n.quads[q] == nil { + n.quads[q] = new(qNode) + } + n.quads[q].insert(series, qbounds, rect, item, depth+1) + } + } else if len(n.items) == qMaxItems { + // split qnode, keep current items in place + var nitems []uint32 + for i := 0; i < len(n.items); i++ { + iitem := n.items[i] + irect := series.SegmentAt(int(iitem)).Rect() + q := n.chooseQuad(bounds, irect) + if q == -1 { + nitems = append(nitems, iitem) + } else { + qbounds := quadBounds(bounds, q) + if n.quads[q] == nil { + n.quads[q] = new(qNode) + } + n.quads[q].insert(series, qbounds, irect, int(iitem), depth+1) + } + } + n.items = nitems + n.split = true + n.insert(series, bounds, rect, item, depth) + } else { + n.items = append(n.items, uint32(item)) + } +} + +func (n *qNode) chooseQuad(bounds, rect Rect) int { + mid := Point{ + X: (bounds.Min.X + bounds.Max.X) / 2, + Y: (bounds.Min.Y + bounds.Max.Y) / 2, + } + if rect.Max.X < mid.X { + if rect.Max.Y < mid.Y { + return 2 + } + if rect.Min.Y < mid.Y { + return -1 + } + return 0 + } + if rect.Min.X < mid.X { + return -1 + } + if rect.Max.Y < mid.Y { + return 3 + } + if rect.Min.Y < mid.Y { + return -1 + } + return 1 +} + +func quadBounds(bounds Rect, q int) (qbounds Rect) { + switch q { + case 0: + qbounds.Min.X = bounds.Min.X + qbounds.Min.Y = (bounds.Min.Y + bounds.Max.Y) / 2 + qbounds.Max.X = (bounds.Min.X + bounds.Max.X) / 2 + qbounds.Max.Y = bounds.Max.Y + case 1: + qbounds.Min.X = (bounds.Min.X + bounds.Max.X) / 2 + qbounds.Min.Y = (bounds.Min.Y + bounds.Max.Y) / 2 + qbounds.Max.X = bounds.Max.X + qbounds.Max.Y = bounds.Max.Y + case 2: + qbounds.Min.X = bounds.Min.X + qbounds.Min.Y = bounds.Min.Y + qbounds.Max.X = (bounds.Min.X + bounds.Max.X) / 2 + qbounds.Max.Y = (bounds.Min.Y + bounds.Max.Y) / 2 + case 3: + qbounds.Min.X = (bounds.Min.X + bounds.Max.X) / 2 + qbounds.Min.Y = bounds.Min.Y + qbounds.Max.X = bounds.Max.X + qbounds.Max.Y = (bounds.Min.Y + bounds.Max.Y) / 2 + } + return +} + +func (n *qNode) search( + series *baseSeries, + bounds, rect Rect, + iter func(seg Segment, item int) bool, +) bool { + for _, item := range n.items { + seg := series.SegmentAt(int(item)) + irect := seg.Rect() + if irect.IntersectsRect(rect) { + if !iter(seg, int(item)) { + return false + } + } + } + if n.split { + for q := 0; q < 4; q++ { + if n.quads[q] != nil { + qbounds := quadBounds(bounds, q) + if qbounds.IntersectsRect(rect) { + if !n.quads[q].search(series, qbounds, rect, iter) { + return false + } + } + } + } + } + return true +} +func numBytes(n uint32) byte { + if n <= 0xFF { + return 1 + } + if n <= 0xFFFF { + return 2 + } + return 4 +} + +func appendNum(dst []byte, num uint32, ibytes byte) []byte { + switch ibytes { + case 1: + dst = append(dst, byte(num)) + case 2: + dst = append(dst, 0, 0) + binary.LittleEndian.PutUint16(dst[len(dst)-2:], uint16(num)) + default: + dst = append(dst, 0, 0, 0, 0) + binary.LittleEndian.PutUint32(dst[len(dst)-4:], uint32(num)) + } + return dst +} + +func readNum(data []byte, ibytes byte) uint32 { + switch ibytes { + case 1: + return uint32(data[0]) + case 2: + return uint32(binary.LittleEndian.Uint16(data)) + default: + return binary.LittleEndian.Uint32(data) + } +} +func (n *qNode) compress(dst []byte, bounds Rect) []byte { + ibytes := numBytes(uint32(len(n.items))) + for i := 0; i < len(n.items); i++ { + ibytes2 := numBytes(n.items[i]) + if ibytes2 > ibytes { + ibytes = ibytes2 + } + } + dst = append(dst, ibytes) + dst = appendNum(dst, uint32(len(n.items)), ibytes) + for i := 0; i < len(n.items); i++ { + dst = appendNum(dst, n.items[i], ibytes) + } + if !n.split { + dst = append(dst, 0) + return dst + } + // store the quads + dst = append(dst, 1) + // first make the address space + var mark [4]int + for q := 0; q < 4; q++ { + if n.quads[q] == nil { + // no quad, no address + dst = append(dst, 0) + } else { + // yes quad, plus addres + dst = append(dst, 1) + mark[q] = len(dst) + dst = append(dst, 0, 0, 0, 0) + } + } + // next add each quad + for q := 0; q < 4; q++ { + if n.quads[q] != nil { + binary.LittleEndian.PutUint32(dst[mark[q]:], uint32(len(dst))) + dst = n.quads[q].compress(dst, quadBounds(bounds, q)) + } + } + return dst +} + +func qCompressSearch( + data []byte, + addr int, + series *baseSeries, + bounds, rect Rect, + iter func(seg Segment, item int) bool, +) bool { + ibytes := data[addr] + addr++ + nItems := int(readNum(data[addr:], ibytes)) + addr += int(ibytes) + for i := 0; i < nItems; i++ { + item := int(readNum(data[addr:], ibytes)) + addr += int(ibytes) + seg := series.SegmentAt(int(item)) + irect := seg.Rect() + if irect.IntersectsRect(rect) { + if !iter(seg, int(item)) { + return false + } + } + } + split := data[addr] == 1 + addr++ + if split { + for q := 0; q < 4; q++ { + use := data[addr] == 1 + addr++ + if !use { + continue + } + naddr := int(binary.LittleEndian.Uint32(data[addr:])) + addr += 4 + qbounds := quadBounds(bounds, q) + if qbounds.IntersectsRect(rect) { + if !qCompressSearch(data, naddr, series, qbounds, rect, iter) { + return false + } + } + } + } + return true +} diff --git a/vendor/github.com/tidwall/geojson/geometry/rect_test.go b/vendor/github.com/tidwall/geojson/geometry/rect_test.go index 7e674c01..5f0933fb 100644 --- a/vendor/github.com/tidwall/geojson/geometry/rect_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/rect_test.go @@ -150,22 +150,22 @@ func TestRectIntersectsLine(t *testing.T) { } func TestRectContainsPoly(t *testing.T) { - oct := NewPoly(octagon, nil, DefaultIndex) + oct := NewPoly(octagon, nil, DefaultIndexOptions) expect(t, R(0, 0, 10, 10).ContainsPoly(oct)) expect(t, !R(0, 0, 10, 10).ContainsPoly(oct.Move(1, 0))) expect(t, !R(0, 0, 10, 10).ContainsPoly(oct.Move(1, 1))) - expect(t, !R(0, 0, 10, 10).ContainsPoly(NewPoly(nil, nil, DefaultIndex))) + expect(t, !R(0, 0, 10, 10).ContainsPoly(NewPoly(nil, nil, DefaultIndexOptions))) } func TestRectIntersectsPoly(t *testing.T) { - oct := NewPoly(octagon, nil, DefaultIndex) + oct := NewPoly(octagon, nil, DefaultIndexOptions) expect(t, R(0, 0, 10, 10).IntersectsPoly(oct)) expect(t, R(0, 0, 10, 10).IntersectsPoly(oct.Move(1, 0))) expect(t, R(0, 0, 10, 10).IntersectsPoly(oct.Move(0, 1))) expect(t, !R(0, 0, 10, 10).IntersectsPoly(oct.Move(10, 10))) expect(t, !R(0, 0, 10, 10).IntersectsPoly(oct.Move(11, 10))) expect(t, !R(0, 0, 10, 10).IntersectsPoly(oct.Move(-11, 0))) - expect(t, !R(0, 0, 10, 10).IntersectsPoly(NewPoly(nil, nil, DefaultIndex))) + expect(t, !R(0, 0, 10, 10).IntersectsPoly(NewPoly(nil, nil, DefaultIndexOptions))) } func TestRectClockwise(t *testing.T) { diff --git a/vendor/github.com/tidwall/geojson/geometry/ring.go b/vendor/github.com/tidwall/geojson/geometry/ring.go index cd032ad1..dae70149 100644 --- a/vendor/github.com/tidwall/geojson/geometry/ring.go +++ b/vendor/github.com/tidwall/geojson/geometry/ring.go @@ -13,8 +13,8 @@ const complexRingMinPoints = 16 // Ring ... type Ring = Series -func newRing(points []Point, index int) Ring { - series := makeSeries(points, true, true, index) +func newRing(points []Point, opts *IndexOptions) Ring { + series := makeSeries(points, true, true, opts) return &series } diff --git a/vendor/github.com/tidwall/geojson/geometry/ring_test.go b/vendor/github.com/tidwall/geojson/geometry/ring_test.go index 7501b1b9..f4eee1e7 100644 --- a/vendor/github.com/tidwall/geojson/geometry/ring_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/ring_test.go @@ -10,16 +10,16 @@ import ( ) func newRingXSimple(points []Point) Ring { - ring := newRing(points, DefaultIndex) - if ring.(*baseSeries).tree != nil { - ring.(*baseSeries).tree = nil + ring := newRing(points, DefaultIndexOptions) + if ring.(*baseSeries).Index() != nil { + ring.(*baseSeries).clearIndex() } return ring } func newRingXIndexed(points []Point) Ring { - ring := newRing(points, DefaultIndex) - if ring.(*baseSeries).tree == nil { - ring.(*baseSeries).buildTree() + ring := newRing(points, DefaultIndexOptions) + if ring.(*baseSeries).Index() == nil { + ring.(*baseSeries).buildIndex() } return ring } @@ -66,7 +66,7 @@ func TestRingXContainsPoint(t *testing.T) { P(3, 4), P(1, 4), P(0, 3), P(0, 0), } - ring := newRing(shape, DefaultIndex) + ring := newRing(shape, DefaultIndexOptions) expect(t, !ringContainsPoint(ring, P(0, 3.5), true).hit) expect(t, !ringContainsPoint(ring, P(0.4, 3.5), true).hit) expect(t, ringContainsPoint(ring, P(0.5, 3.5), true).hit) @@ -97,7 +97,7 @@ func TestRingXIntersectsSegment(t *testing.T) { t.Run("Cases", func(t *testing.T) { ring := newRing([]Point{ P(0, 0), P(4, 0), P(4, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("1", func(t *testing.T) { expect(t, ringIntersectsSegment(ring, S(2, 2, 4, 4), true)) expect(t, ringIntersectsSegment(ring, S(2, 2, 4, 4), false)) @@ -145,42 +145,42 @@ func TestRingXIntersectsSegment(t *testing.T) { t.Run("12", func(t *testing.T) { ring := newRing([]Point{ {0, 0}, {2, 0}, {4, 0}, {4, 4}, {0, 4}, {0, 0}, - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringIntersectsSegment(ring, S(1, 0, 3, 0), true)) expect(t, !ringIntersectsSegment(ring, S(1, 0, 3, 0), false)) }) t.Run("13", func(t *testing.T) { ring := newRing([]Point{ {0, 0}, {4, 0}, {4, 4}, {2, 4}, {0, 4}, {0, 0}, - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringIntersectsSegment(ring, S(0, 4, 4, 4), true)) expect(t, !ringIntersectsSegment(ring, S(0, 4, 4, 4), false)) }) t.Run("14", func(t *testing.T) { ring := newRing([]Point{ {0, 0}, {4, 0}, {4, 4}, {2, 4}, {0, 4}, {0, 0}, - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringIntersectsSegment(ring, S(-1, -2, 0, 0), true)) expect(t, !ringIntersectsSegment(ring, S(-1, -2, 0, 0), false)) }) t.Run("15", func(t *testing.T) { ring := newRing([]Point{ {0, 0}, {4, 0}, {4, 4}, {2, 4}, {0, 4}, {0, 0}, - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringIntersectsSegment(ring, S(0, 4, 5, 4), true)) expect(t, !ringIntersectsSegment(ring, S(0, 4, 5, 4), false)) }) t.Run("16", func(t *testing.T) { ring := newRing([]Point{ {0, 0}, {4, 0}, {4, 4}, {2, 4}, {0, 4}, {0, 0}, - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringIntersectsSegment(ring, S(1, 4, 5, 4), true)) expect(t, !ringIntersectsSegment(ring, S(1, 4, 5, 4), false)) }) t.Run("17", func(t *testing.T) { ring := newRing([]Point{ {0, 0}, {4, 0}, {4, 4}, {2, 4}, {0, 4}, {0, 0}, - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringIntersectsSegment(ring, S(1, 4, 4, 4), true)) expect(t, !ringIntersectsSegment(ring, S(1, 4, 4, 4), false)) }) @@ -815,7 +815,7 @@ func TestRingXContainsSegment(t *testing.T) { ring := newRing([]Point{ P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 3), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("1", func(t *testing.T) { expect(t, !ringContainsSegment(ring, S(1.5, 3.5, 2.5, 3.5), true)) expect(t, !ringContainsSegment(ring, S(1.5, 3.5, 2.5, 3.5), false)) @@ -840,7 +840,7 @@ func TestRingXContainsSegment(t *testing.T) { ring := newRing([]Point{ P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 5), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringContainsSegment(ring, S(1.5, 4.5, 2.5, 4.5), true)) expect(t, !ringContainsSegment(ring, S(1.5, 4.5, 2.5, 4.5), false)) }) @@ -849,7 +849,7 @@ func TestRingXContainsSegment(t *testing.T) { P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2.5, 3), P(2, 4), P(1.5, 3), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, !ringContainsSegment(ring, S(1.25, 3.5, 2.75, 3.5), true)) expect(t, !ringContainsSegment(ring, S(1.25, 3.5, 2.75, 3.5), false)) }) @@ -858,7 +858,7 @@ func TestRingXContainsSegment(t *testing.T) { P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2.5, 5), P(2, 4), P(1.5, 5), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, !ringContainsSegment(ring, S(1.25, 4.5, 2.75, 4.5), true)) expect(t, !ringContainsSegment(ring, S(1.25, 4.5, 2.75, 4.5), false)) }) @@ -882,14 +882,14 @@ func TestRingXContainsSegment(t *testing.T) { ring := newRing([]Point{ P(0, 0), P(2, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 3), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringContainsSegment(ring, S(1, 0, 3, 0), true)) expect(t, !ringContainsSegment(ring, S(1, 0, 3, 0), false)) }) t.Run("14", func(t *testing.T) { ring := newRing([]Point{ P(0, 0), P(4, 0), P(2, 2), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringContainsSegment(ring, S(1, 3, 3, 1), true)) expect(t, ringContainsSegment(ring, S(3, 1, 1, 3), true)) expect(t, !ringContainsSegment(ring, S(1, 3, 3, 1), false)) @@ -908,24 +908,24 @@ func TestRingXContainsSegment(t *testing.T) { func TestRingXContainsRing(t *testing.T) { t.Run("Empty", func(t *testing.T) { - expect(t, !ringContainsRing(newRing(nil, DefaultIndex), R(0, 0, 1, 1), true)) - expect(t, !ringContainsRing(R(0, 0, 1, 1), newRing(nil, DefaultIndex), true)) + expect(t, !ringContainsRing(newRing(nil, DefaultIndexOptions), R(0, 0, 1, 1), true)) + expect(t, !ringContainsRing(R(0, 0, 1, 1), newRing(nil, DefaultIndexOptions), true)) }) t.Run("Exact", func(t *testing.T) { expect(t, ringContainsRing(R(0, 0, 1, 1), R(0, 0, 1, 1), true)) expect(t, !ringContainsRing(R(0, 0, 1, 1), R(0, 0, 1, 1), false)) - expect(t, ringContainsRing(newRing(concave1, DefaultIndex), newRing(concave1, DefaultIndex), true)) - expect(t, !ringContainsRing(newRing(concave1, DefaultIndex), newRing(concave1, DefaultIndex), false)) - expect(t, ringContainsRing(newRing(octagon, DefaultIndex), newRing(octagon, DefaultIndex), true)) - expect(t, !ringContainsRing(newRing(octagon, DefaultIndex), newRing(octagon, DefaultIndex), false)) + expect(t, ringContainsRing(newRing(concave1, DefaultIndexOptions), newRing(concave1, DefaultIndexOptions), true)) + expect(t, !ringContainsRing(newRing(concave1, DefaultIndexOptions), newRing(concave1, DefaultIndexOptions), false)) + expect(t, ringContainsRing(newRing(octagon, DefaultIndexOptions), newRing(octagon, DefaultIndexOptions), true)) + expect(t, !ringContainsRing(newRing(octagon, DefaultIndexOptions), newRing(octagon, DefaultIndexOptions), false)) }) t.Run("Cases", func(t *testing.T) { // concave ring := newRing([]Point{ P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 3), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("1", func(t *testing.T) { expect(t, ringContainsRing(ring, R(1, 1, 3, 2), true)) expect(t, ringContainsRing(ring, R(1, 1, 3, 2), false)) @@ -951,7 +951,7 @@ func TestRingXContainsRing(t *testing.T) { P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 5), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("6", func(t *testing.T) { expect(t, ringContainsRing(ring, R(1, 2, 3, 3), true)) expect(t, ringContainsRing(ring, R(1, 2, 3, 3), false)) @@ -968,7 +968,7 @@ func TestRingXContainsRing(t *testing.T) { ring = newRing([]Point{ P(0, 0), P(2, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 5), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringContainsRing(ring, R(1, 0, 3, 1), true)) expect(t, !ringContainsRing(ring, R(1, 0, 3, 1), false)) }) @@ -976,13 +976,13 @@ func TestRingXContainsRing(t *testing.T) { ring = newRing([]Point{ P(0, 0), P(4, 0), P(4, 3), P(2, 4), P(0, 3), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, ringContainsRing(ring, R(1, 1, 3, 2), true)) expect(t, ringContainsRing(ring, R(1, 1, 3, 2), false)) }) ring = newRing([]Point{ P(0, 0), P(4, 0), P(4, 3), P(3, 4), P(1, 4), P(0, 3), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("11", func(t *testing.T) { expect(t, ringContainsRing(ring, R(1, 1, 3, 2), true)) expect(t, ringContainsRing(ring, R(1, 1, 3, 2), false)) @@ -1024,10 +1024,10 @@ func TestRingXContainsRing(t *testing.T) { t.Run("Identical", func(t *testing.T) { shapes := []Ring{ R(0, 0, 10, 10), - newRing(octagon, DefaultIndex), - newRing(concave1, DefaultIndex), newRing(concave2, DefaultIndex), - newRing(concave3, DefaultIndex), newRing(concave4, DefaultIndex), - newRing(ri, DefaultIndex), + newRing(octagon, DefaultIndexOptions), + newRing(concave1, DefaultIndexOptions), newRing(concave2, DefaultIndexOptions), + newRing(concave3, DefaultIndexOptions), newRing(concave4, DefaultIndexOptions), + newRing(ri, DefaultIndexOptions), } for i, shape := range shapes { t.Run(fmt.Sprintf("Shape%d", i), func(t *testing.T) { @@ -1038,7 +1038,7 @@ func TestRingXContainsRing(t *testing.T) { t.Run("Big", func(t *testing.T) { // use rhode island - ring := newRing(ri, DefaultIndex) + ring := newRing(ri, DefaultIndexOptions) expect(t, ringContainsRing(ring.Rect(), ring, true)) expect(t, ringContainsRing(ring, ring, true)) @@ -1055,15 +1055,15 @@ func TestRingXIntersectsRing(t *testing.T) { return t1 } t.Run("Empty", func(t *testing.T) { - expect(t, !intersectsBothWays(newRing(nil, DefaultIndex), R(0, 0, 1, 1), true)) - expect(t, !intersectsBothWays(R(0, 0, 1, 1), newRing(nil, DefaultIndex), true)) + expect(t, !intersectsBothWays(newRing(nil, DefaultIndexOptions), R(0, 0, 1, 1), true)) + expect(t, !intersectsBothWays(R(0, 0, 1, 1), newRing(nil, DefaultIndexOptions), true)) }) t.Run("Cases", func(t *testing.T) { // concave ring := newRing([]Point{ P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 3), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("1", func(t *testing.T) { expect(t, intersectsBothWays(ring, R(1, 1, 3, 2), true)) expect(t, intersectsBothWays(ring, R(1, 1, 3, 2), false)) @@ -1089,7 +1089,7 @@ func TestRingXIntersectsRing(t *testing.T) { P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 5), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("6", func(t *testing.T) { expect(t, intersectsBothWays(ring, R(1, 2, 3, 3), true)) expect(t, intersectsBothWays(ring, R(1, 2, 3, 3), false)) @@ -1106,7 +1106,7 @@ func TestRingXIntersectsRing(t *testing.T) { ring = newRing([]Point{ P(0, 0), P(2, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 5), P(1, 4), P(0, 4), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, intersectsBothWays(ring, R(1, 0, 3, 1), true)) expect(t, intersectsBothWays(ring, R(1, 0, 3, 1), false)) }) @@ -1114,13 +1114,13 @@ func TestRingXIntersectsRing(t *testing.T) { ring = newRing([]Point{ P(0, 0), P(4, 0), P(4, 3), P(2, 4), P(0, 3), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) expect(t, intersectsBothWays(ring, R(1, 1, 3, 2), true)) expect(t, intersectsBothWays(ring, R(1, 1, 3, 2), false)) }) ring = newRing([]Point{ P(0, 0), P(4, 0), P(4, 3), P(3, 4), P(1, 4), P(0, 3), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) t.Run("11", func(t *testing.T) { expect(t, intersectsBothWays(ring, R(1, 1, 3, 2), true)) expect(t, intersectsBothWays(ring, R(1, 1, 3, 2), false)) @@ -1167,12 +1167,12 @@ func TestRingXContainsLine(t *testing.T) { P(0, 0), P(4, 0), P(4, 3), P(3, 4), P(1, 4), P(0, 3), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) makeLine := func(start Point) *Line { return NewLine([]Point{ start, start.Move(0, 1), start.Move(1, 1), start.Move(1, 2), start.Move(2, 2), - }, DefaultIndex) + }, DefaultIndexOptions) } t.Run("1", func(t *testing.T) { expect(t, ringContainsLine(ring, makeLine(P(1, 1)), true)) @@ -1285,12 +1285,12 @@ func TestRingXIntersectsLine(t *testing.T) { P(0, 0), P(4, 0), P(4, 3), P(3, 4), P(1, 4), P(0, 3), P(0, 0), - }, DefaultIndex) + }, DefaultIndexOptions) makeLine := func(start Point) *Line { return NewLine([]Point{ start, start.Move(0, 1), start.Move(1, 1), start.Move(1, 2), start.Move(2, 2), - }, DefaultIndex) + }, DefaultIndexOptions) } t.Run("1", func(t *testing.T) { expect(t, ringIntersectsLine(ring, makeLine(P(1, 1)), true)) diff --git a/vendor/github.com/tidwall/geojson/geometry/rtree.go b/vendor/github.com/tidwall/geojson/geometry/rtree.go new file mode 100644 index 00000000..42869a01 --- /dev/null +++ b/vendor/github.com/tidwall/geojson/geometry/rtree.go @@ -0,0 +1,384 @@ +package geometry + +import ( + "encoding/binary" + "math" +) + +const rDims = 2 +const rMaxEntries = 16 + +type rRect struct { + data interface{} + min, max [rDims]float64 +} + +type rNode struct { + count int + rects [rMaxEntries + 1]rRect +} + +// rTree ... +type rTree struct { + height int + root rRect + count int + reinsert []rRect +} + +func (r *rRect) expand(b *rRect) { + for i := 0; i < rDims; i++ { + if b.min[i] < r.min[i] { + r.min[i] = b.min[i] + } + if b.max[i] > r.max[i] { + r.max[i] = b.max[i] + } + } +} + +// Insert inserts an item into the RTree +func (tr *rTree) Insert(min, max []float64, value interface{}) { + var item rRect + fit(min, max, value, &item) + tr.insert(&item) +} + +func (tr *rTree) insert(item *rRect) { + if tr.root.data == nil { + fit(item.min[:], item.max[:], new(rNode), &tr.root) + } + grown := tr.root.insert(item, tr.height) + if grown { + tr.root.expand(item) + } + if tr.root.data.(*rNode).count == rMaxEntries+1 { + newRoot := new(rNode) + tr.root.splitLargestAxisEdgeSnap(&newRoot.rects[1]) + newRoot.rects[0] = tr.root + newRoot.count = 2 + tr.root.data = newRoot + tr.root.recalc() + tr.height++ + } + tr.count++ +} + +func (r *rRect) chooseLeastEnlargement(b *rRect) int { + j, jenlargement, jarea := -1, 0.0, 0.0 + n := r.data.(*rNode) + for i := 0; i < n.count; i++ { + // force inline + area := n.rects[i].max[0] - n.rects[i].min[0] + for j := 1; j < rDims; j++ { + area *= n.rects[i].max[j] - n.rects[i].min[j] + } + var enlargement float64 + // force inline + enlargedArea := 1.0 + for j := 0; j < len(n.rects[i].min); j++ { + if b.max[j] > n.rects[i].max[j] { + if b.min[j] < n.rects[i].min[j] { + enlargedArea *= b.max[j] - b.min[j] + } else { + enlargedArea *= b.max[j] - n.rects[i].min[j] + } + } else { + if b.min[j] < n.rects[i].min[j] { + enlargedArea *= n.rects[i].max[j] - b.min[j] + } else { + enlargedArea *= n.rects[i].max[j] - n.rects[i].min[j] + } + } + } + enlargement = enlargedArea - area + + if j == -1 || enlargement < jenlargement { + j, jenlargement, jarea = i, enlargement, area + } else if enlargement == jenlargement { + if area < jarea { + j, jenlargement, jarea = i, enlargement, area + } + } + } + return j +} + +func (r *rRect) recalc() { + n := r.data.(*rNode) + r.min = n.rects[0].min + r.max = n.rects[0].max + for i := 1; i < n.count; i++ { + r.expand(&n.rects[i]) + } +} + +// contains return struct when b is fully contained inside of n +func (r *rRect) contains(b *rRect) bool { + for i := 0; i < rDims; i++ { + if b.min[i] < r.min[i] || b.max[i] > r.max[i] { + return false + } + } + return true +} + +func (r *rRect) largestAxis() (axis int, size float64) { + j, jsz := 0, 0.0 + for i := 0; i < rDims; i++ { + sz := r.max[i] - r.min[i] + if i == 0 || sz > jsz { + j, jsz = i, sz + } + } + return j, jsz +} + +func (r *rRect) splitLargestAxisEdgeSnap(right *rRect) { + axis, _ := r.largestAxis() + left := r + leftNode := left.data.(*rNode) + rightNode := new(rNode) + right.data = rightNode + + var equals []rRect + for i := 0; i < leftNode.count; i++ { + minDist := leftNode.rects[i].min[axis] - left.min[axis] + maxDist := left.max[axis] - leftNode.rects[i].max[axis] + if minDist < maxDist { + // stay left + } else { + if minDist > maxDist { + // move to right + rightNode.rects[rightNode.count] = leftNode.rects[i] + rightNode.count++ + } else { + // move to equals, at the end of the left array + equals = append(equals, leftNode.rects[i]) + } + leftNode.rects[i] = leftNode.rects[leftNode.count-1] + leftNode.rects[leftNode.count-1].data = nil + leftNode.count-- + i-- + } + } + for _, b := range equals { + if leftNode.count < rightNode.count { + leftNode.rects[leftNode.count] = b + leftNode.count++ + } else { + rightNode.rects[rightNode.count] = b + rightNode.count++ + } + } + left.recalc() + right.recalc() +} + +func (r *rRect) insert(item *rRect, height int) (grown bool) { + n := r.data.(*rNode) + if height == 0 { + n.rects[n.count] = *item + n.count++ + grown = !r.contains(item) + return grown + } + // choose subtree + index := r.chooseLeastEnlargement(item) + child := &n.rects[index] + grown = child.insert(item, height-1) + if grown { + child.expand(item) + grown = !r.contains(item) + } + if child.data.(*rNode).count == rMaxEntries+1 { + child.splitLargestAxisEdgeSnap(&n.rects[n.count]) + n.count++ + } + return grown +} + +// fit an external item into a rect type +func fit(min, max []float64, value interface{}, target *rRect) { + if max == nil { + max = min + } + if len(min) != len(max) { + panic("min/max dimension mismatch") + } + if len(min) != rDims { + panic("invalid number of dimensions") + } + for i := 0; i < rDims; i++ { + target.min[i] = min[i] + target.max[i] = max[i] + } + target.data = value +} + +func (r *rRect) intersects(b *rRect) bool { + for i := 0; i < rDims; i++ { + if b.min[i] > r.max[i] || b.max[i] < r.min[i] { + return false + } + } + return true +} + +func (r *rRect) search( + target *rRect, height int, + iter func(min, max []float64, value interface{}) bool, +) bool { + n := r.data.(*rNode) + if height == 0 { + for i := 0; i < n.count; i++ { + if target.intersects(&n.rects[i]) { + if !iter(n.rects[i].min[:], n.rects[i].max[:], + n.rects[i].data) { + return false + } + } + } + } else { + for i := 0; i < n.count; i++ { + if target.intersects(&n.rects[i]) { + if !n.rects[i].search(target, height-1, iter) { + return false + } + } + } + } + return true +} + +func (tr *rTree) search( + target *rRect, + iter func(min, max []float64, value interface{}) bool, +) { + if tr.root.data == nil { + return + } + if target.intersects(&tr.root) { + tr.root.search(target, tr.height, iter) + } +} + +// Search ... +func (tr *rTree) Search( + min, max []float64, + iter func(min, max []float64, value interface{}) bool, +) { + var target rRect + fit(min, max, nil, &target) + tr.search(&target, iter) +} + +func appendFloat(dst []byte, num float64) []byte { + var buf [8]byte + binary.LittleEndian.PutUint64(buf[:], math.Float64bits(num)) + return append(dst, buf[:]...) +} + +func (r *rRect) compress(dst []byte, height int) []byte { + n := r.data.(*rNode) + dst = appendFloat(dst, r.min[0]) + dst = appendFloat(dst, r.min[1]) + dst = appendFloat(dst, r.max[0]) + dst = appendFloat(dst, r.max[1]) + dst = append(dst, byte(n.count)) + if height == 0 { + var ibytes byte = 1 + for i := 0; i < n.count; i++ { + ibytes2 := numBytes(uint32(n.rects[i].data.(int))) + if ibytes2 > ibytes { + ibytes = ibytes2 + } + } + dst = append(dst, ibytes) + for i := 0; i < n.count; i++ { + dst = appendNum(dst, uint32(n.rects[i].data.(int)), ibytes) + } + return dst + } + mark := make([]int, n.count) + for i := 0; i < n.count; i++ { + mark[i] = len(dst) + dst = append(dst, 0, 0, 0, 0) + } + for i := 0; i < n.count; i++ { + binary.LittleEndian.PutUint32(dst[mark[i]:], uint32(len(dst))) + dst = n.rects[i].compress(dst, height-1) + } + return dst +} + +func (tr *rTree) compress(dst []byte) []byte { + if tr.root.data == nil { + return dst + } + dst = append(dst, byte(tr.height)) + return tr.root.compress(dst, tr.height) +} + +func rCompressSearch( + data []byte, + addr int, + series *baseSeries, + rect Rect, + iter func(seg Segment, item int) bool, +) bool { + if int(addr) == len(data) { + return true + } + height := int(data[addr]) + addr++ + return rnCompressSearch(data, addr, series, rect, height, iter) +} + +func rnCompressSearch( + data []byte, + addr int, + series *baseSeries, + rect Rect, + height int, + iter func(seg Segment, item int) bool, +) bool { + var nrect Rect + nrect.Min.X = math.Float64frombits(binary.LittleEndian.Uint64(data[addr:])) + addr += 8 + nrect.Min.Y = math.Float64frombits(binary.LittleEndian.Uint64(data[addr:])) + addr += 8 + nrect.Max.X = math.Float64frombits(binary.LittleEndian.Uint64(data[addr:])) + addr += 8 + nrect.Max.Y = math.Float64frombits(binary.LittleEndian.Uint64(data[addr:])) + addr += 8 + if !rect.IntersectsRect(nrect) { + return true + } + count := int(data[addr]) + addr++ + if height == 0 { + ibytes := data[addr] + addr++ + for i := 0; i < count; i++ { + item := int(readNum(data[addr:], ibytes)) + addr += int(ibytes) + seg := series.SegmentAt(int(item)) + irect := seg.Rect() + if irect.IntersectsRect(rect) { + if !iter(seg, int(item)) { + return false + } + } + } + return true + } + for i := 0; i < count; i++ { + naddr := int(binary.LittleEndian.Uint32(data[addr:])) + addr += 4 + if !rnCompressSearch(data, naddr, series, rect, height-1, iter) { + return false + } + } + return true +} diff --git a/vendor/github.com/tidwall/geojson/geometry/series.go b/vendor/github.com/tidwall/geojson/geometry/series.go index 413962e5..8fb099ad 100644 --- a/vendor/github.com/tidwall/geojson/geometry/series.go +++ b/vendor/github.com/tidwall/geojson/geometry/series.go @@ -4,12 +4,53 @@ package geometry -import "github.com/tidwall/boxtree/d2" +import ( + "encoding/binary" + "reflect" + "unsafe" +) -// DefaultIndex are the minumum number of points required before it makes -// sense to index the segments. -// 64 seems to be the sweet spot -const DefaultIndex = 64 +// IndexKind is the kind of index to use in the options. +type IndexKind byte + +// IndexKind types +const ( + None IndexKind = iota + RTree + RTreeCompressed + QuadTree + QuadTreeCompressed +) + +func (kind IndexKind) String() string { + switch kind { + default: + return "Unknown" + case None: + return "None" + case RTree: + return "RTree" + case RTreeCompressed: + return "RTreeCompressed" + case QuadTree: + return "QuadTree" + case QuadTreeCompressed: + return "QuadTreeCompressed" + } + +} + +// IndexOptions are segment indexing options +type IndexOptions struct { + Kind IndexKind + MinPoints int +} + +// DefaultIndexOptions ... +var DefaultIndexOptions = &IndexOptions{ + Kind: QuadTree, + MinPoints: 64, +} // Series is just a series of points with utilities for efficiently accessing // segments from rectangle queries, making stuff like point-in-polygon lookups @@ -40,13 +81,19 @@ type baseSeries struct { closed bool // points create a closed shape clockwise bool // points move clockwise convex bool // points create a convex shape + indexKind IndexKind // index kind + index interface{} // actual index rect Rect // minumum bounding rectangle points []Point // original points - tree *d2.BoxTree // segment tree. } // makeSeries returns a processed baseSeries. -func makeSeries(points []Point, copyPoints, closed bool, index int) baseSeries { +func makeSeries( + points []Point, copyPoints, closed bool, opts *IndexOptions, +) baseSeries { + if opts == nil { + opts = DefaultIndexOptions + } var series baseSeries series.closed = closed if copyPoints { @@ -55,20 +102,17 @@ func makeSeries(points []Point, copyPoints, closed bool, index int) baseSeries { } else { series.points = points } - if index != 0 && len(points) >= int(index) { - series.tree = new(d2.BoxTree) + series.convex, series.rect, series.clockwise = processPoints(points, closed) + if opts.MinPoints != 0 && len(points) >= opts.MinPoints { + series.indexKind = opts.Kind + series.buildIndex() } - series.convex, series.rect, series.clockwise = - processPoints(points, closed, series.tree) return series } // Index ... func (series *baseSeries) Index() interface{} { - if series.tree == nil { - return nil - } - return series.tree + return series.index } // Clockwise ... @@ -82,9 +126,10 @@ func (series *baseSeries) Move(deltaX, deltaY float64) Series { points[i].X = series.points[i].X + deltaX points[i].Y = series.points[i].Y + deltaY } - nseries := makeSeries(points, false, series.closed, 0) - if series.tree != nil { - nseries.buildTree() + nseries := makeSeries(points, false, series.closed, nil) + nseries.indexKind = series.indexKind + if series.Index() != nil { + nseries.buildIndex() } return &nseries } @@ -123,8 +168,11 @@ func (series *baseSeries) PointAt(index int) Point { } // Search finds a searches for segments that intersect the provided rectangle -func (series *baseSeries) Search(rect Rect, iter func(seg Segment, idx int) bool) { - if series.tree == nil { +func (series *baseSeries) Search( + rect Rect, iter func(seg Segment, idx int) bool, +) { + switch v := series.index.(type) { + default: n := series.NumSegments() for i := 0; i < n; i++ { seg := series.SegmentAt(i) @@ -134,8 +182,8 @@ func (series *baseSeries) Search(rect Rect, iter func(seg Segment, idx int) bool } } } - } else { - series.tree.Search( + case *rTree: + v.Search( []float64{rect.Min.X, rect.Min.Y}, []float64{rect.Max.X, rect.Max.Y}, func(_, _ []float64, value interface{}) bool { @@ -153,6 +201,24 @@ func (series *baseSeries) Search(rect Rect, iter func(seg Segment, idx int) bool return true }, ) + case *qNode: + v.search(series, series.rect, rect, iter) + case *byte: + // convert the byte pointer back to a valid slice + data := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ + Data: uintptr(unsafe.Pointer(v)), + Len: 0xFFFFFFFF, + Cap: 0xFFFFFFFF, + })) + n := binary.LittleEndian.Uint32(data[1:]) + data = data[:n:n] + switch data[0] { + case 1: + rCompressSearch(data, 5, series, rect, iter) + case 2: + qCompressSearch(data, 5, series, series.rect, rect, iter) + } + } } @@ -185,16 +251,9 @@ func (series *baseSeries) SegmentAt(index int) Segment { return seg } -func (series *baseSeries) buildTree() { - if series.tree == nil { - series.tree = new(d2.BoxTree) - processPoints(series.points, series.closed, series.tree) - } -} - // processPoints tests if the ring is convex, calculates the outer // rectangle, and inserts segments into a boxtree in one pass. -func processPoints(points []Point, closed bool, tree *d2.BoxTree) ( +func processPoints(points []Point, closed bool) ( convex bool, rect Rect, clockwise bool, ) { if (closed && len(points) < 3) || len(points) < 2 { @@ -203,33 +262,9 @@ func processPoints(points []Point, closed bool, tree *d2.BoxTree) ( var concave bool var dir int var a, b, c Point - var segCount int var cwc float64 - if closed { - segCount = len(points) - } else { - segCount = len(points) - 1 - } for i := 0; i < len(points); i++ { - // process the segments for tree insertion - if tree != nil && i < segCount { - var seg Segment - seg.A = points[i] - if closed && i == len(points)-1 { - if seg.A == points[0] { - break - } - seg.B = points[0] - } else { - seg.B = points[i+1] - } - rect := seg.Rect() - tree.Insert( - []float64{rect.Min.X, rect.Min.Y}, - []float64{rect.Max.X, rect.Max.Y}, i) - } - // process the rectangle inflation if i == 0 { rect = Rect{points[i], points[i]} @@ -286,3 +321,54 @@ func processPoints(points []Point, closed bool, tree *d2.BoxTree) ( } return !concave, rect, cwc > 0 } + +func (series *baseSeries) clearIndex() { + series.index = nil +} + +func (series *baseSeries) setCompressed(data []byte) { + binary.LittleEndian.PutUint32(data[1:], uint32(len(data))) + smaller := make([]byte, len(data)) + copy(smaller, data) + // use the byte point instead of a double reference to the byte slice + series.index = &smaller[0] +} + +func (series *baseSeries) buildIndex() { + if series.index != nil { + // already built + return + } + switch series.indexKind { + case RTree, RTreeCompressed: + tr := new(rTree) + n := series.NumSegments() + for i := 0; i < n; i++ { + rect := series.SegmentAt(i).Rect() + tr.Insert( + []float64{rect.Min.X, rect.Min.Y}, + []float64{rect.Max.X, rect.Max.Y}, i) + } + if series.indexKind == RTreeCompressed { + series.setCompressed( + tr.compress([]byte{1, 0, 0, 0, 0}), + ) + } else { + series.index = tr + } + case QuadTree, QuadTreeCompressed: + root := new(qNode) + n := series.NumSegments() + for i := 0; i < n; i++ { + seg := series.SegmentAt(i) + root.insert(series, series.rect, seg.Rect(), i, 0) + } + if series.indexKind == QuadTreeCompressed { + series.setCompressed( + root.compress([]byte{2, 0, 0, 0, 0}, series.rect), + ) + } else { + series.index = root + } + } +} diff --git a/vendor/github.com/tidwall/geojson/geometry/series_test.go b/vendor/github.com/tidwall/geojson/geometry/series_test.go index f4344770..85839cb1 100644 --- a/vendor/github.com/tidwall/geojson/geometry/series_test.go +++ b/vendor/github.com/tidwall/geojson/geometry/series_test.go @@ -30,16 +30,16 @@ func seriesForEachPoint(ring Ring, iter func(point Point) bool) { func TestSeriesEmpty(t *testing.T) { var series *baseSeries expect(t, series.Empty()) - series2 := makeSeries(nil, false, false, 0) + series2 := makeSeries(nil, false, false, &IndexOptions{Kind: None}) expect(t, series2.Empty()) } func TestSeriesIndex(t *testing.T) { - series := makeSeries(nil, false, false, 0) + series := makeSeries(nil, false, false, &IndexOptions{Kind: None}) expect(t, series.Index() == nil) series = makeSeries([]Point{ P(0, 0), P(10, 0), P(10, 10), P(0, 10), P(0, 0), - }, true, true, 1) + }, true, true, &IndexOptions{Kind: RTree, MinPoints: 1}) expect(t, series.Index() != nil) } @@ -48,27 +48,27 @@ func TestSeriesClockwise(t *testing.T) { var series baseSeries series = makeSeries([]Point{ P(0, 0), P(10, 0), P(10, 10), P(0, 10), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Clockwise()) series = makeSeries([]Point{ P(0, 0), P(10, 0), P(10, 10), P(0, 10), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Clockwise()) series = makeSeries([]Point{ P(0, 0), P(10, 0), P(10, 10), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Clockwise()) series = makeSeries([]Point{ P(0, 0), P(0, 10), P(10, 10), P(10, 0), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, series.Clockwise()) series = makeSeries([]Point{ P(0, 0), P(0, 10), P(10, 10), P(10, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, series.Clockwise()) series = makeSeries([]Point{ P(0, 0), P(0, 10), P(10, 10), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, series.Clockwise()) } @@ -76,19 +76,19 @@ func TestSeriesConvex(t *testing.T) { t.Run("1", func(t *testing.T) { series := makeSeries([]Point{ P(0, 0), P(4, 0), P(4, 4), P(0, 4), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, series.Convex()) }) t.Run("2", func(t *testing.T) { series := makeSeries([]Point{ P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(1, 4), P(0, 4), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, series.Convex()) }) t.Run("3", func(t *testing.T) { series := makeSeries([]Point{ P(0, 0), P(4, 0), P(4, 4), P(2, 5), P(0, 4), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, series.Convex()) }) t.Run("4", func(t *testing.T) { @@ -96,7 +96,7 @@ func TestSeriesConvex(t *testing.T) { P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 5), P(1, 4), P(0, 4), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Convex()) }) t.Run("5", func(t *testing.T) { @@ -104,28 +104,28 @@ func TestSeriesConvex(t *testing.T) { P(0, 0), P(4, 0), P(4, 4), P(3, 4), P(2, 3), P(1, 4), P(0, 4), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Convex()) }) t.Run("5", func(t *testing.T) { series := makeSeries([]Point{ P(0, 0), P(4, 0), P(4, 4), P(0, 4), P(-1, 2), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, series.Convex()) }) t.Run("6", func(t *testing.T) { series := makeSeries([]Point{ P(0, 0), P(4, 0), P(4, 4), P(0, 4), P(0, 3), P(-1, 2), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Convex()) }) t.Run("6", func(t *testing.T) { series := makeSeries([]Point{ P(0, 0), P(4, 0), P(4, 4), P(0, 4), P(-1, 2), P(0, 1), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Convex()) }) t.Run("7", func(t *testing.T) { @@ -133,14 +133,14 @@ func TestSeriesConvex(t *testing.T) { P(0, 0), P(4, 0), P(4, 4), P(3, 3), P(2, 5), P(1, 3), P(0, 4), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Convex()) }) t.Run("8", func(t *testing.T) { series := makeSeries([]Point{ P(0, 0), P(0, 4), P(1, 3), P(4, 4), P(2, 5), P(3, 3), P(4, 0), P(0, 0), - }, true, true, DefaultIndex) + }, true, true, DefaultIndexOptions) expect(t, !series.Convex()) }) } @@ -151,9 +151,9 @@ func testScanSeries( ) []Segment { t.Helper() if index { - series.buildTree() + series.buildIndex() } else { - series.tree = nil + series.clearIndex() } var segs1 []Segment seriesForEachSegment(series, func(seg Segment) bool { @@ -178,51 +178,51 @@ func testScanSeries( } func TestSeriesBasic(t *testing.T) { - series := makeSeries(octagon, true, true, DefaultIndex) + series := makeSeries(octagon, true, true, DefaultIndexOptions) expect(t, reflect.DeepEqual(seriesCopyPoints(&series), octagon)) expect(t, series.Convex()) expect(t, series.Rect() == R(0, 0, 10, 10)) expect(t, series.Closed()) - series = makeSeries(octagon, false, true, DefaultIndex) + series = makeSeries(octagon, false, true, DefaultIndexOptions) expect(t, reflect.DeepEqual(seriesCopyPoints(&series), octagon)) - series = makeSeries(ri, true, true, DefaultIndex) + series = makeSeries(ri, true, true, DefaultIndexOptions) testScanSeries(t, &series, true, len(ri)-1, false) testScanSeries(t, &series, false, len(ri)-1, false) // small lines - series = makeSeries([]Point{}, true, false, DefaultIndex) + series = makeSeries([]Point{}, true, false, DefaultIndexOptions) testScanSeries(t, &series, true, 0, true) testScanSeries(t, &series, false, 0, true) - series = makeSeries([]Point{P(5, 5)}, true, false, DefaultIndex) + series = makeSeries([]Point{P(5, 5)}, true, false, DefaultIndexOptions) testScanSeries(t, &series, true, 0, true) testScanSeries(t, &series, false, 0, true) - series = makeSeries([]Point{P(5, 5), P(10, 10)}, true, false, DefaultIndex) + series = makeSeries([]Point{P(5, 5), P(10, 10)}, true, false, DefaultIndexOptions) testScanSeries(t, &series, true, 1, false) testScanSeries(t, &series, false, 1, false) // small rings - series = makeSeries([]Point{}, true, true, DefaultIndex) + series = makeSeries([]Point{}, true, true, DefaultIndexOptions) testScanSeries(t, &series, true, 0, true) testScanSeries(t, &series, false, 0, true) - series = makeSeries([]Point{P(5, 5)}, true, true, DefaultIndex) + series = makeSeries([]Point{P(5, 5)}, true, true, DefaultIndexOptions) testScanSeries(t, &series, true, 0, true) testScanSeries(t, &series, false, 0, true) - series = makeSeries([]Point{P(5, 5), P(10, 10)}, true, true, DefaultIndex) + series = makeSeries([]Point{P(5, 5), P(10, 10)}, true, true, DefaultIndexOptions) testScanSeries(t, &series, true, 0, true) testScanSeries(t, &series, false, 0, true) - series = makeSeries([]Point{P(5, 5), P(10, 10), P(10, 5)}, true, true, DefaultIndex) + series = makeSeries([]Point{P(5, 5), P(10, 10), P(10, 5)}, true, true, DefaultIndexOptions) testScanSeries(t, &series, true, 3, false) testScanSeries(t, &series, false, 3, false) } func TestSeriesSearch(t *testing.T) { - series := makeSeries(octagon, true, true, DefaultIndex) + series := makeSeries(octagon, true, true, DefaultIndexOptions) var segs []Segment series.Search(R(0, 0, 0, 0), func(seg Segment, _ int) bool { segs = append(segs, seg) @@ -284,7 +284,7 @@ func TestSeriesSearch(t *testing.T) { func TestSeriesBig(t *testing.T) { t.Run("Closed", func(t *testing.T) { // clip off the last point to force an auto closure - series := makeSeries(ri[:len(ri)-1], true, true, DefaultIndex) + series := makeSeries(ri[:len(ri)-1], true, true, DefaultIndexOptions) var seg2sA []Segment series.Search(series.Rect(), func(seg Segment, idx int) bool { seg2sA = append(seg2sA, seg) @@ -299,7 +299,7 @@ func TestSeriesBig(t *testing.T) { expect(t, checkSegsDups(seg2sA, seg2sB)) // use all points - series2 := makeSeries(ri, true, true, DefaultIndex) + series2 := makeSeries(ri, true, true, DefaultIndexOptions) var seg2sC []Segment seriesForEachSegment(&series2, func(seg Segment) bool { seg2sC = append(seg2sC, seg) @@ -318,7 +318,7 @@ func TestSeriesBig(t *testing.T) { expect(t, first == seg2sA[0]) }) t.Run("Opened", func(t *testing.T) { - series := makeSeries(az, true, false, DefaultIndex) + series := makeSeries(az, true, false, DefaultIndexOptions) var seg2sA []Segment series.Search(series.Rect(), func(seg Segment, idx int) bool { seg2sA = append(seg2sA, seg) @@ -339,7 +339,7 @@ func TestSeriesReverse(t *testing.T) { for i := len(shape) - 1; i >= 0; i-- { rev = append(rev, shape[i]) } - series := makeSeries(rev, true, true, DefaultIndex) + series := makeSeries(rev, true, true, DefaultIndexOptions) var seg2sA []Segment series.Search(series.Rect(), func(seg Segment, idx int) bool { seg2sA = append(seg2sA, seg) @@ -375,14 +375,14 @@ func checkSegsDups(a, b []Segment) bool { func TestSeriesMove(t *testing.T) { shapes := [][]Point{ri, octagon} for _, shape := range shapes { - series := makeSeries(shape, true, true, DefaultIndex) - series.tree = nil + series := makeSeries(shape, true, true, DefaultIndexOptions) + series.clearIndex() series2 := series.Move(60, 70) expect(t, series2.NumPoints() == len(shape)) for i := 0; i < len(shape); i++ { expect(t, series2.PointAt(i) == shape[i].Move(60, 70)) } - series.buildTree() + series.buildIndex() series2 = series.Move(60, 70) expect(t, series2.NumPoints() == len(shape)) for i := 0; i < len(shape); i++ { diff --git a/vendor/github.com/tidwall/geojson/linestring.go b/vendor/github.com/tidwall/geojson/linestring.go index a849a91c..5896c549 100644 --- a/vendor/github.com/tidwall/geojson/linestring.go +++ b/vendor/github.com/tidwall/geojson/linestring.go @@ -138,7 +138,8 @@ func parseJSONLineString(keys *parseKeys, opts *ParseOptions) (Object, error) { // https://tools.ietf.org/html/rfc7946#section-3.1.4 return nil, errCoordinatesInvalid } - line := geometry.NewLine(points, opts.IndexGeometry) + gopts := toGeometryOpts(opts) + line := geometry.NewLine(points, &gopts) g.base = *line g.extra = ex if err := parseBBoxAndExtras(&g.extra, keys, opts); err != nil { diff --git a/vendor/github.com/tidwall/geojson/multilinestring.go b/vendor/github.com/tidwall/geojson/multilinestring.go index 01365d9e..b751abf3 100644 --- a/vendor/github.com/tidwall/geojson/multilinestring.go +++ b/vendor/github.com/tidwall/geojson/multilinestring.go @@ -69,7 +69,8 @@ func parseJSONMultiLineString( err = errCoordinatesInvalid return false } - line := geometry.NewLine(coords, opts.IndexGeometry) + gopts := toGeometryOpts(opts) + line := geometry.NewLine(coords, &gopts) g.children = append(g.children, &LineString{base: *line, extra: ex}) return true }) diff --git a/vendor/github.com/tidwall/geojson/multipolygon.go b/vendor/github.com/tidwall/geojson/multipolygon.go index 7c22cddc..dbf1d0ad 100644 --- a/vendor/github.com/tidwall/geojson/multipolygon.go +++ b/vendor/github.com/tidwall/geojson/multipolygon.go @@ -79,7 +79,8 @@ func parseJSONMultiPolygon( if len(coords) > 1 { holes = coords[1:] } - poly := geometry.NewPoly(exterior, holes, opts.IndexGeometry) + gopts := toGeometryOpts(opts) + poly := geometry.NewPoly(exterior, holes, &gopts) g.children = append(g.children, &Polygon{base: *poly, extra: ex}) return true }) diff --git a/vendor/github.com/tidwall/geojson/object.go b/vendor/github.com/tidwall/geojson/object.go index c643b3f2..eb041ae7 100644 --- a/vendor/github.com/tidwall/geojson/object.go +++ b/vendor/github.com/tidwall/geojson/object.go @@ -84,12 +84,16 @@ type ParseOptions struct { // disable indexing. // The default is 64. IndexGeometry int + // IndexGeometryKind is the kind of index implementation. + // Default is QuadTreeCompressed + IndexGeometryKind geometry.IndexKind } // DefaultParseOptions ... var DefaultParseOptions = &ParseOptions{ - IndexChildren: geometry.DefaultIndex, - IndexGeometry: geometry.DefaultIndex, + IndexChildren: 64, + IndexGeometry: 64, + IndexGeometryKind: geometry.QuadTreeCompressed, } // Parse a GeoJSON object @@ -124,6 +128,17 @@ func Parse(data string, opts *ParseOptions) (Object, error) { } } +func toGeometryOpts(opts *ParseOptions) geometry.IndexOptions { + var gopts geometry.IndexOptions + if opts == nil { + gopts = *geometry.DefaultIndexOptions + } else { + gopts.Kind = opts.IndexGeometryKind + gopts.MinPoints = opts.IndexGeometry + } + return gopts +} + type parseKeys struct { rCoordinates gjson.Result rGeometries gjson.Result diff --git a/vendor/github.com/tidwall/geojson/object_test.go b/vendor/github.com/tidwall/geojson/object_test.go index 9713184a..330ccbbc 100644 --- a/vendor/github.com/tidwall/geojson/object_test.go +++ b/vendor/github.com/tidwall/geojson/object_test.go @@ -36,11 +36,11 @@ func RO(minX, minY, maxX, maxY float64) *Rect { } func LO(points []geometry.Point) *LineString { - return NewLineString(geometry.NewLine(points, geometry.DefaultIndex)) + return NewLineString(geometry.NewLine(points, nil)) } func PPO(exterior []geometry.Point, holes [][]geometry.Point) *Polygon { - return NewPolygon(geometry.NewPoly(exterior, holes, geometry.DefaultIndex)) + return NewPolygon(geometry.NewPoly(exterior, holes, nil)) } func expectJSON(t testing.TB, data string, expect interface{}) Object { diff --git a/vendor/github.com/tidwall/geojson/polygon.go b/vendor/github.com/tidwall/geojson/polygon.go index 50fd73ad..32cca45e 100644 --- a/vendor/github.com/tidwall/geojson/polygon.go +++ b/vendor/github.com/tidwall/geojson/polygon.go @@ -156,7 +156,8 @@ func parseJSONPolygon(keys *parseKeys, opts *ParseOptions) (Object, error) { if len(coords) > 1 { holes = coords[1:] } - poly := geometry.NewPoly(exterior, holes, opts.IndexGeometry) + gopts := toGeometryOpts(opts) + poly := geometry.NewPoly(exterior, holes, &gopts) g.base = *poly g.extra = ex if err := parseBBoxAndExtras(&g.extra, keys, opts); err != nil {