Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions geojson/geojson_s2_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,6 @@ import (

// ------------------------------------------------------------------------

// creates a shape index with all of the given polygons
// and queries it with vertex model closed which considers
// polygon edges and vertices to be part of the polygon.
func polygonsContainsPoint(s2pgns []*s2.Polygon,
point *s2.Point) bool {
idx := s2.NewShapeIndex()
for _, s2pgn := range s2pgns {
idx.Add(s2pgn)
}

return s2.NewContainsPointQuery(idx, s2.VertexModelClosed).Contains(*point)
}

// project the point to all of the linestrings and check if
// any of the projections are equal to the point.
func polylineIntersectsPoint(pls []*s2.Polyline,
Expand Down Expand Up @@ -66,6 +53,21 @@ func polylineIntersectsPolygons(pls []*s2.Polyline,
containsQuery := s2.NewContainsPointQuery(idx, s2.VertexModelClosed)
for _, pl := range pls {
for _, point := range *pl {

// Precheck points within the bounds of the polygon
// and for small polygons, check if the point is contained
for _, s2pgn := range s2pgns {
Comment thread
Likith101 marked this conversation as resolved.
if !s2pgn.PointWithinBound(point) {
continue
}

if small, inside := s2pgn.SmallPolygonContainsPoint(point); small {
if inside {
return true
}
}
}

if containsQuery.Contains(point) {
return true
}
Expand Down Expand Up @@ -95,12 +97,29 @@ func polylineIntersectsPolygons(pls []*s2.Polyline,
// so we create a shape index and query it instead
// s2.VertexModelClosed will not consider points on the edges, so
// behaviour there is arbitrary
func polygonIntersectsPoint(s2pgns []*s2.Polygon,
func polygonsIntersectsPoint(s2pgns []*s2.Polygon,
point *s2.Point) bool {
idx := s2.NewShapeIndex()
for _, pgn := range s2pgns {
if !pgn.PointWithinBound(*point) {
continue
}

// We don't early exit here because the point may be contained
// on the vertices of the polygon, which is not considered
if small, inside := pgn.SmallPolygonContainsPoint(*point); small {
if inside {
return true
}
}

idx.Add(pgn)
}

if idx.Len() == 0 {
return false
}

return s2.NewContainsPointQuery(idx, s2.VertexModelClosed).Contains(*point)
}

Expand Down
14 changes: 6 additions & 8 deletions geojson/geojson_shapes_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,7 @@ func checkPointIntersectsShape(point *s2.Point, shapeIn, other index.GeoJSON) (b
// check if the other shape is a polygon.
if p2, ok := other.(*Polygon); ok {
// check if the point is contained within the polygon.
if polygonsContainsPoint([]*s2.Polygon{p2.s2pgn}, point) {
if polygonsIntersectsPoint([]*s2.Polygon{p2.s2pgn}, point) {
return true, nil
}

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

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

Expand All @@ -1205,7 +1205,7 @@ func checkPolygonIntersectsShape(s2pgn *s2.Polygon, shapeIn,
// check if the other shape is a multipoint.
if p2, ok := other.(*MultiPoint); ok {
for _, s2point := range p2.s2points {
if polygonIntersectsPoint([]*s2.Polygon{s2pgn}, s2point) {
if polygonsIntersectsPoint([]*s2.Polygon{s2pgn}, s2point) {
return true, nil
}
}
Expand Down Expand Up @@ -1293,10 +1293,8 @@ func checkMultiPolygonContainsShape(s2pgns []*s2.Polygon,
shapeIn, other index.GeoJSON) (bool, error) {
// check if the other shape is a point.
if p2, ok := other.(*Point); ok {
for _, s2pgn := range s2pgns {
if polygonIntersectsPoint([]*s2.Polygon{s2pgn}, p2.s2point) {
return true, nil
}
if polygonsIntersectsPoint(s2pgns, p2.s2point) {
return true, nil
}

return false, nil
Expand Down
21 changes: 21 additions & 0 deletions s2/polygon.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,27 @@ func (p *Polygon) ContainsPoint(point Point) bool {
return NewContainsPointQuery(p.index, VertexModelSemiOpen).Contains(point)
}

// Check whether the point is within the bounds of the polygon.
func (p *Polygon) PointWithinBound(point Point) bool {
return p.bound.ContainsPoint(point)
}

// SmallPolygonContainsPoint checks if the polygon is small enough to use brute force
// returns whether the check is possible and whether the point is contained
// Does not consider vertices of the polygon
func (p *Polygon) SmallPolygonContainsPoint(point Point) (bool, bool) {
const maxBruteForceVertices = 32
if p.numVertices < maxBruteForceVertices || p.index == nil {
inside := false
for _, l := range p.loops {
inside = inside != l.bruteForceContainsPoint(point)
}
return true, inside
}

return false, false
}

// ContainsCell reports whether the polygon contains the given cell.
func (p *Polygon) ContainsCell(cell Cell) bool {
it := p.index.Iterator()
Expand Down
Loading