package geojson import ( "github.com/tidwall/tile38/geojson/poly" ) // withinObjectShared returns true if g is within o func withinObjectShared(g, o Object) bool { bbp := o.bboxPtr() if bbp != nil { if !g.WithinBBox(*bbp) { return false } if o.IsBBoxDefined() { return true } } switch o := o.(type) { default: return false case SimplePoint: return g.WithinBBox(o.CalculatedBBox()) case Point: return g.WithinBBox(o.CalculatedBBox()) case MultiPoint: for i := range o.Coordinates { if g.Within(o.getPoint(i)) { return true } } return false case LineString: if len(o.Coordinates) == 0 { return false } switch g := g.(type) { default: return false case SimplePoint: return poly.Point(Position{X: g.X, Y: g.Y, Z: 0}).IntersectsLineString(polyPositions(o.Coordinates)) case Point: return poly.Point(g.Coordinates).IntersectsLineString(polyPositions(o.Coordinates)) case MultiPoint: if len(o.Coordinates) == 0 { return false } for _, p := range o.Coordinates { if !poly.Point(p).IntersectsLineString(polyPositions(o.Coordinates)) { return false } } return true } case MultiLineString: for i := range o.Coordinates { if g.Within(o.getLineString(i)) { return true } } return false case MultiPolygon: for i := range o.Coordinates { if g.Within(o.getPolygon(i)) { return true } } return false case Feature: return g.Within(o.Geometry) case FeatureCollection: for _, o := range o.Features { if g.Within(o) { return true } } return false case GeometryCollection: for _, o := range o.Geometries { if g.Within(o) { return true } } return false case Polygon: if len(o.Coordinates) == 0 { return false } exterior, holes := polyExteriorHoles(o.Coordinates) switch g := g.(type) { default: return false case SimplePoint: return poly.Point(Position{X: g.X, Y: g.Y, Z: 0}).Inside(exterior, holes) case Point: return poly.Point(g.Coordinates).Inside(exterior, holes) case MultiPoint: if len(g.Coordinates) == 0 { return false } for i := range g.Coordinates { if !g.getPoint(i).Within(o) { return false } } return true case LineString: return polyPositions(g.Coordinates).Inside(exterior, holes) case MultiLineString: if len(g.Coordinates) == 0 { return false } for i := range g.Coordinates { if !g.getLineString(i).Within(o) { return false } } return true case Polygon: if len(g.Coordinates) == 0 { return false } return polyPositions(g.Coordinates[0]).Inside(exterior, holes) case MultiPolygon: if len(g.Coordinates) == 0 { return false } for i := range g.Coordinates { if !g.getPolygon(i).Within(o) { return false } } return true case GeometryCollection: if len(g.Geometries) == 0 { return false } for _, g := range g.Geometries { if !g.Within(o) { return false } } return true case Feature: return g.Geometry.Within(o) case FeatureCollection: if len(g.Features) == 0 { return false } for _, g := range g.Features { if !g.Within(o) { return false } } return true } } } // intersectsObjectShared detects if g intersects with o func intersectsObjectShared(g, o Object) bool { bbp := o.bboxPtr() if bbp != nil { if !g.IntersectsBBox(*bbp) { return false } if o.IsBBoxDefined() { return true } } switch o := o.(type) { default: return false case SimplePoint: return g.IntersectsBBox(o.CalculatedBBox()) case Point: return g.IntersectsBBox(o.CalculatedBBox()) case MultiPoint: for i := range o.Coordinates { if o.getPoint(i).Intersects(g) { return true } } return false case LineString: if g, ok := g.(LineString); ok { a := polyPositions(g.Coordinates) b := polyPositions(o.Coordinates) return a.LineStringIntersectsLineString(b) } return o.Intersects(g) case MultiLineString: for i := range o.Coordinates { if g.Intersects(o.getLineString(i)) { return true } } return false case MultiPolygon: for i := range o.Coordinates { if g.Intersects(o.getPolygon(i)) { return true } } return false case Feature: return g.Intersects(o.Geometry) case FeatureCollection: for _, f := range o.Features { if g.Intersects(f) { return true } } return false case GeometryCollection: for _, f := range o.Geometries { if g.Intersects(f) { return true } } return false case Polygon: if len(o.Coordinates) == 0 { return false } exterior, holes := polyExteriorHoles(o.Coordinates) switch g := g.(type) { default: return false case SimplePoint: return poly.Point(Position{X: g.X, Y: g.Y, Z: 0}).Intersects(exterior, holes) case Point: return poly.Point(g.Coordinates).Intersects(exterior, holes) case MultiPoint: for i := range g.Coordinates { if g.getPoint(i).Intersects(o) { return true } } return false case LineString: return polyPositions(g.Coordinates).LineStringIntersects(exterior, holes) case MultiLineString: for i := range g.Coordinates { if g.getLineString(i).Intersects(o) { return true } } return false case Polygon: if len(g.Coordinates) == 0 { return false } return polyPositions(g.Coordinates[0]).Intersects(exterior, holes) case MultiPolygon: for i := range g.Coordinates { if g.getPolygon(i).Intersects(o) { return true } } return false case GeometryCollection: for _, g := range g.Geometries { if g.Intersects(o) { return true } } return false case Feature: return g.Geometry.Intersects(o) case FeatureCollection: for _, g := range g.Features { if g.Intersects(o) { return true } } return false } } } // The object's calculated bounding box must intersect the radius of the circle to pass. func nearbyObjectShared(g Object, x, y float64, meters float64) bool { if !g.hasPositions() { return false } center := Position{X: x, Y: y, Z: 0} bbox := g.CalculatedBBox() if bbox.Min.X == bbox.Max.X && bbox.Min.Y == bbox.Max.Y { // just a point, return is point is inside of the circle return center.DistanceTo(bbox.Min) <= meters } circlePoly := CirclePolygon(x, y, meters, 12) return g.Intersects(circlePoly) }