Skip to content

Commit b34bfe4

Browse files
authored
MB-66210: Added back pre checks for small polygons intersects point (#28)
- Removed Duplicate function for polygon intersecting/containing point - Renamed functions to better reflect its purpose - Added prechecks for all areas which check polygon intersecting points - Added 2 new functions for polygons to enable these prechecks
1 parent ed70de5 commit b34bfe4

3 files changed

Lines changed: 60 additions & 22 deletions

File tree

geojson/geojson_s2_util.go

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,6 @@ import (
2525

2626
// ------------------------------------------------------------------------
2727

28-
// creates a shape index with all of the given polygons
29-
// and queries it with vertex model closed which considers
30-
// polygon edges and vertices to be part of the polygon.
31-
func polygonsContainsPoint(s2pgns []*s2.Polygon,
32-
point *s2.Point) bool {
33-
idx := s2.NewShapeIndex()
34-
for _, s2pgn := range s2pgns {
35-
idx.Add(s2pgn)
36-
}
37-
38-
return s2.NewContainsPointQuery(idx, s2.VertexModelClosed).Contains(*point)
39-
}
40-
4128
// project the point to all of the linestrings and check if
4229
// any of the projections are equal to the point.
4330
func polylineIntersectsPoint(pls []*s2.Polyline,
@@ -66,6 +53,21 @@ func polylineIntersectsPolygons(pls []*s2.Polyline,
6653
containsQuery := s2.NewContainsPointQuery(idx, s2.VertexModelClosed)
6754
for _, pl := range pls {
6855
for _, point := range *pl {
56+
57+
// Precheck points within the bounds of the polygon
58+
// and for small polygons, check if the point is contained
59+
for _, s2pgn := range s2pgns {
60+
if !s2pgn.PointWithinBound(point) {
61+
continue
62+
}
63+
64+
if small, inside := s2pgn.SmallPolygonContainsPoint(point); small {
65+
if inside {
66+
return true
67+
}
68+
}
69+
}
70+
6971
if containsQuery.Contains(point) {
7072
return true
7173
}
@@ -95,12 +97,29 @@ func polylineIntersectsPolygons(pls []*s2.Polyline,
9597
// so we create a shape index and query it instead
9698
// s2.VertexModelClosed will not consider points on the edges, so
9799
// behaviour there is arbitrary
98-
func polygonIntersectsPoint(s2pgns []*s2.Polygon,
100+
func polygonsIntersectsPoint(s2pgns []*s2.Polygon,
99101
point *s2.Point) bool {
100102
idx := s2.NewShapeIndex()
101103
for _, pgn := range s2pgns {
104+
if !pgn.PointWithinBound(*point) {
105+
continue
106+
}
107+
108+
// We don't early exit here because the point may be contained
109+
// on the vertices of the polygon, which is not considered
110+
if small, inside := pgn.SmallPolygonContainsPoint(*point); small {
111+
if inside {
112+
return true
113+
}
114+
}
115+
102116
idx.Add(pgn)
103117
}
118+
119+
if idx.Len() == 0 {
120+
return false
121+
}
122+
104123
return s2.NewContainsPointQuery(idx, s2.VertexModelClosed).Contains(*point)
105124
}
106125

geojson/geojson_shapes_impl.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ func checkPointIntersectsShape(point *s2.Point, shapeIn, other index.GeoJSON) (b
933933
// check if the other shape is a polygon.
934934
if p2, ok := other.(*Polygon); ok {
935935
// check if the point is contained within the polygon.
936-
if polygonsContainsPoint([]*s2.Polygon{p2.s2pgn}, point) {
936+
if polygonsIntersectsPoint([]*s2.Polygon{p2.s2pgn}, point) {
937937
return true, nil
938938
}
939939

@@ -943,7 +943,7 @@ func checkPointIntersectsShape(point *s2.Point, shapeIn, other index.GeoJSON) (b
943943
// check if the other shape is a multipolygon.
944944
if p2, ok := other.(*MultiPolygon); ok {
945945
// check if the point is contained within any of the polygons
946-
if polygonsContainsPoint(p2.s2pgns, point) {
946+
if polygonsIntersectsPoint(p2.s2pgns, point) {
947947
return true, nil
948948
}
949949

@@ -1195,7 +1195,7 @@ func checkPolygonIntersectsShape(s2pgn *s2.Polygon, shapeIn,
11951195
other index.GeoJSON) (bool, error) {
11961196
// check if the other shape is a point.
11971197
if p2, ok := other.(*Point); ok {
1198-
if polygonIntersectsPoint([]*s2.Polygon{s2pgn}, p2.s2point) {
1198+
if polygonsIntersectsPoint([]*s2.Polygon{s2pgn}, p2.s2point) {
11991199
return true, nil
12001200
}
12011201

@@ -1205,7 +1205,7 @@ func checkPolygonIntersectsShape(s2pgn *s2.Polygon, shapeIn,
12051205
// check if the other shape is a multipoint.
12061206
if p2, ok := other.(*MultiPoint); ok {
12071207
for _, s2point := range p2.s2points {
1208-
if polygonIntersectsPoint([]*s2.Polygon{s2pgn}, s2point) {
1208+
if polygonsIntersectsPoint([]*s2.Polygon{s2pgn}, s2point) {
12091209
return true, nil
12101210
}
12111211
}
@@ -1293,10 +1293,8 @@ func checkMultiPolygonContainsShape(s2pgns []*s2.Polygon,
12931293
shapeIn, other index.GeoJSON) (bool, error) {
12941294
// check if the other shape is a point.
12951295
if p2, ok := other.(*Point); ok {
1296-
for _, s2pgn := range s2pgns {
1297-
if polygonIntersectsPoint([]*s2.Polygon{s2pgn}, p2.s2point) {
1298-
return true, nil
1299-
}
1296+
if polygonsIntersectsPoint(s2pgns, p2.s2point) {
1297+
return true, nil
13001298
}
13011299

13021300
return false, nil

s2/polygon.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,27 @@ func (p *Polygon) ContainsPoint(point Point) bool {
613613
return NewContainsPointQuery(p.index, VertexModelSemiOpen).Contains(point)
614614
}
615615

616+
// Check whether the point is within the bounds of the polygon.
617+
func (p *Polygon) PointWithinBound(point Point) bool {
618+
return p.bound.ContainsPoint(point)
619+
}
620+
621+
// SmallPolygonContainsPoint checks if the polygon is small enough to use brute force
622+
// returns whether the check is possible and whether the point is contained
623+
// Does not consider vertices of the polygon
624+
func (p *Polygon) SmallPolygonContainsPoint(point Point) (bool, bool) {
625+
const maxBruteForceVertices = 32
626+
if p.numVertices < maxBruteForceVertices || p.index == nil {
627+
inside := false
628+
for _, l := range p.loops {
629+
inside = inside != l.bruteForceContainsPoint(point)
630+
}
631+
return true, inside
632+
}
633+
634+
return false, false
635+
}
636+
616637
// ContainsCell reports whether the polygon contains the given cell.
617638
func (p *Polygon) ContainsCell(cell Cell) bool {
618639
it := p.index.Iterator()

0 commit comments

Comments
 (0)