From b3dc025545f8545636fb5dce988faa57dbed3a42 Mon Sep 17 00:00:00 2001 From: tidwall Date: Wed, 25 Mar 2020 15:07:14 -0700 Subject: [PATCH] Optimize point in ring --- go.mod | 2 +- go.sum | 2 + .../tidwall/geojson/geometry/ring.go | 67 +++++++++++++------ vendor/modules.txt | 2 +- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index ae9f3aaa..ec4839e1 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/tidwall/buntdb v1.1.0 github.com/tidwall/cities v0.0.0-20190730194520-dbe1ae0b862c // indirect github.com/tidwall/geoindex v1.1.0 - github.com/tidwall/geojson v1.1.12 + github.com/tidwall/geojson v1.1.13 github.com/tidwall/gjson v1.3.2 github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb // indirect github.com/tidwall/lotsa v0.0.0-20180225195211-a03631ac7f1c // indirect diff --git a/go.sum b/go.sum index 44f58978..370ca2d7 100644 --- a/go.sum +++ b/go.sum @@ -67,6 +67,8 @@ github.com/tidwall/geojson v1.1.10 h1:ALzsrTn62pq65DudSQpYDjjCUaq6dP1XQm51GVYgJy github.com/tidwall/geojson v1.1.10/go.mod h1:tBjfxeALRFLc25LLpjtWzy2nIrNmW1ze1EAhLtd8+QQ= github.com/tidwall/geojson v1.1.12 h1:Ol83kqH2zeYJHP16xteZtr8VRukIXeF/TqVvJodM41M= github.com/tidwall/geojson v1.1.12/go.mod h1:tBjfxeALRFLc25LLpjtWzy2nIrNmW1ze1EAhLtd8+QQ= +github.com/tidwall/geojson v1.1.13 h1:P7f58SrQgyb9k3HjKStRLug4i/0U+1MJ00f/4Z92wcM= +github.com/tidwall/geojson v1.1.13/go.mod h1:tBjfxeALRFLc25LLpjtWzy2nIrNmW1ze1EAhLtd8+QQ= github.com/tidwall/gjson v1.3.2 h1:+7p3qQFaH3fOMXAJSrdZwGKcOO/lYdGS0HqGhPqDdTI= github.com/tidwall/gjson v1.3.2/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb h1:5NSYaAdrnblKByzd7XByQEJVT8+9v0W/tIY0Oo4OwrE= diff --git a/vendor/github.com/tidwall/geojson/geometry/ring.go b/vendor/github.com/tidwall/geojson/geometry/ring.go index 4affa962..07351026 100644 --- a/vendor/github.com/tidwall/geojson/geometry/ring.go +++ b/vendor/github.com/tidwall/geojson/geometry/ring.go @@ -24,30 +24,59 @@ type ringResult struct { } func ringContainsPoint(ring Ring, point Point, allowOnEdge bool) ringResult { - // println("A") - var idx = -1 - // find all intersecting segments on the y-axis var in bool + var idx int + rect := Rect{Point{math.Inf(-1), point.Y}, Point{math.Inf(+1), point.Y}} + if bs, ok := ring.(*baseSeries); ok { + in, idx = ringContainsPointBaseSeries(rect, bs, point, allowOnEdge) + } else { + in, idx = ringContainsPointGeneric(rect, ring, point, allowOnEdge) + } + return ringResult{hit: in, idx: idx} +} + +func containsPointSearcher(point Point, allowOnEdge bool, idx *int, in *bool, seg Segment, index int) bool { + // perform a raycast operation on the segments + res := seg.Raycast(point) + if res.On { + *in = allowOnEdge + *idx = index + return false + } + if res.In { + *in = !*in + } + return true +} + +// NOTE: Although it may seem that ringContainsPointBaseSeries and ringContainsPointGeneric +// are the same, they are not. Because the type of the `ring` argument is known in +// ringContainsPointBaseSeries, the compiler can prove that the closure passed to +// ring.Search does not escape, and hence save us 3 heap allocations and ~6% runtime. + +func ringContainsPointBaseSeries(rect Rect, ring *baseSeries, point Point, allowOnEdge bool) (bool, int) { + var idx = -1 + var in bool + ring.Search( - Rect{Point{math.Inf(-1), point.Y}, Point{math.Inf(+1), point.Y}}, + rect, func(seg Segment, index int) bool { - // fmt.Printf("%v %v\n", point, seg) - // perform a raycast operation on the segments - res := seg.Raycast(point) - if res.On { - // println(1) - in = allowOnEdge - idx = index - return false - } - if res.In { - // println(2) - in = !in - } - return true + return containsPointSearcher(point, allowOnEdge, &idx, &in, seg, index) }, ) - return ringResult{hit: in, idx: idx} + return in, idx +} + +func ringContainsPointGeneric(rect Rect, ring Ring, point Point, allowOnEdge bool) (bool, int) { + var idx = -1 + var in bool + ring.Search( + rect, + func(seg Segment, index int) bool { + return containsPointSearcher(point, allowOnEdge, &idx, &in, seg, index) + }, + ) + return in, idx } func ringIntersectsPoint(ring Ring, point Point, allowOnEdge bool) ringResult { diff --git a/vendor/modules.txt b/vendor/modules.txt index 34c3c6f9..1a0562e3 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -81,7 +81,7 @@ github.com/tidwall/buntdb # github.com/tidwall/geoindex v1.1.0 github.com/tidwall/geoindex github.com/tidwall/geoindex/child -# github.com/tidwall/geojson v1.1.12 +# github.com/tidwall/geojson v1.1.13 github.com/tidwall/geojson github.com/tidwall/geojson/geo github.com/tidwall/geojson/geometry