Optimize point in ring

This commit is contained in:
tidwall 2020-03-25 15:07:14 -07:00
parent 5162ac5fd7
commit b3dc025545
4 changed files with 52 additions and 21 deletions

2
go.mod
View File

@ -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

2
go.sum
View File

@ -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=

View File

@ -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 {

2
vendor/modules.txt vendored
View File

@ -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