mirror of https://github.com/tidwall/tile38.git
fix perf regression
This commit is contained in:
parent
9428b84484
commit
0ce2dab945
|
@ -1,294 +0,0 @@
|
||||||
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)
|
|
||||||
}
|
|
|
@ -192,12 +192,20 @@ func (g Feature) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g Feature) Within(o Object) bool {
|
func (g Feature) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return g.Geometry.Within(o)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g Feature) Intersects(o Object) bool {
|
func (g Feature) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return g.Geometry.Intersects(o)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -178,12 +178,36 @@ func (g FeatureCollection) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g FeatureCollection) Within(o Object) bool {
|
func (g FeatureCollection) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Features) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, f := range g.Features {
|
||||||
|
if !f.Within(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g FeatureCollection) Intersects(o Object) bool {
|
func (g FeatureCollection) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Features) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, f := range g.Features {
|
||||||
|
if f.Intersects(o) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -177,12 +177,36 @@ func (g GeometryCollection) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g GeometryCollection) Within(o Object) bool {
|
func (g GeometryCollection) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Geometries) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, g := range g.Geometries {
|
||||||
|
if !g.Within(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g GeometryCollection) Intersects(o Object) bool {
|
func (g GeometryCollection) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Geometries) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, g := range g.Geometries {
|
||||||
|
if g.Intersects(o) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -98,12 +98,20 @@ func (g LineString) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g LineString) Within(o Object) bool {
|
func (g LineString) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return polyPositions(g.Coordinates).Inside(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g LineString) Intersects(o Object) bool {
|
func (g LineString) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return polyPositions(g.Coordinates).LineStringIntersects(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -2,6 +2,7 @@ package geojson
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tidwall/tile38/geojson/geohash"
|
"github.com/tidwall/tile38/geojson/geohash"
|
||||||
|
"github.com/tidwall/tile38/geojson/poly"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MultiLineString is a geojson object with the type "MultiLineString"
|
// MultiLineString is a geojson object with the type "MultiLineString"
|
||||||
|
@ -9,50 +10,36 @@ type MultiLineString struct {
|
||||||
Coordinates [][]Position
|
Coordinates [][]Position
|
||||||
BBox *BBox
|
BBox *BBox
|
||||||
bboxDefined bool
|
bboxDefined bool
|
||||||
linestrings []LineString
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillMultiLineString(coordinates [][]Position, bbox *BBox, err error) (MultiLineString, error) {
|
func fillMultiLineString(coordinates [][]Position, bbox *BBox, err error) (MultiLineString, error) {
|
||||||
linestrings := make([]LineString, len(coordinates))
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for i, ps := range coordinates {
|
for _, coordinates := range coordinates {
|
||||||
linestrings[i], err = fillLineString(ps, nil, nil)
|
if len(coordinates) < 2 {
|
||||||
if err != nil {
|
err = errLineStringInvalidCoordinates
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bboxDefined := bbox != nil
|
bboxDefined := bbox != nil
|
||||||
if !bboxDefined {
|
if !bboxDefined {
|
||||||
cbbox := mlCalculatedBBox(linestrings, nil)
|
cbbox := level3CalculatedBBox(coordinates, nil, false)
|
||||||
bbox = &cbbox
|
bbox = &cbbox
|
||||||
}
|
}
|
||||||
return MultiLineString{
|
return MultiLineString{
|
||||||
Coordinates: coordinates,
|
Coordinates: coordinates,
|
||||||
BBox: bbox,
|
BBox: bbox,
|
||||||
bboxDefined: bboxDefined,
|
bboxDefined: bboxDefined,
|
||||||
linestrings: linestrings,
|
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func mlCalculatedBBox(linestrings []LineString, bbox *BBox) BBox {
|
func (g MultiLineString) getLineString(index int) LineString {
|
||||||
if bbox != nil {
|
return LineString{Coordinates: g.Coordinates[index]}
|
||||||
return *bbox
|
|
||||||
}
|
|
||||||
var cbbox BBox
|
|
||||||
for i, g := range linestrings {
|
|
||||||
if i == 0 {
|
|
||||||
cbbox = g.CalculatedBBox()
|
|
||||||
} else {
|
|
||||||
cbbox = cbbox.union(g.CalculatedBBox())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cbbox
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculatedBBox is exterior bbox containing the object.
|
// CalculatedBBox is exterior bbox containing the object.
|
||||||
func (g MultiLineString) CalculatedBBox() BBox {
|
func (g MultiLineString) CalculatedBBox() BBox {
|
||||||
return mlCalculatedBBox(g.linestrings, g.BBox)
|
return level3CalculatedBBox(g.Coordinates, g.BBox, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculatedPoint is a point representation of the object.
|
// CalculatedPoint is a point representation of the object.
|
||||||
|
@ -110,13 +97,6 @@ func (g MultiLineString) hasPositions() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g MultiLineString) getLineString(index int) LineString {
|
|
||||||
if index < len(g.linestrings) {
|
|
||||||
return g.linestrings[index]
|
|
||||||
}
|
|
||||||
return LineString{Coordinates: g.Coordinates[index]}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithinBBox detects if the object is fully contained inside a bbox.
|
// WithinBBox detects if the object is fully contained inside a bbox.
|
||||||
func (g MultiLineString) WithinBBox(bbox BBox) bool {
|
func (g MultiLineString) WithinBBox(bbox BBox) bool {
|
||||||
if g.bboxDefined {
|
if g.bboxDefined {
|
||||||
|
@ -125,10 +105,15 @@ func (g MultiLineString) WithinBBox(bbox BBox) bool {
|
||||||
if len(g.Coordinates) == 0 {
|
if len(g.Coordinates) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := range g.Coordinates {
|
for _, ls := range g.Coordinates {
|
||||||
if !g.getLineString(i).WithinBBox(bbox) {
|
if len(ls) == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
for _, p := range ls {
|
||||||
|
if !poly.Point(p).InsideRect(rectBBox(bbox)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -138,8 +123,8 @@ func (g MultiLineString) IntersectsBBox(bbox BBox) bool {
|
||||||
if g.bboxDefined {
|
if g.bboxDefined {
|
||||||
return rectBBox(g.CalculatedBBox()).IntersectsRect(rectBBox(bbox))
|
return rectBBox(g.CalculatedBBox()).IntersectsRect(rectBBox(bbox))
|
||||||
}
|
}
|
||||||
for i := range g.Coordinates {
|
for _, ls := range g.Coordinates {
|
||||||
if g.getLineString(i).IntersectsBBox(bbox) {
|
if polyPositions(ls).IntersectsRect(rectBBox(bbox)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,12 +133,36 @@ func (g MultiLineString) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g MultiLineString) Within(o Object) bool {
|
func (g MultiLineString) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, ls := range g.Coordinates {
|
||||||
|
if !polyPositions(ls).Inside(polyExteriorHoles(v.Coordinates)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g MultiLineString) Intersects(o Object) bool {
|
func (g MultiLineString) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, ls := range g.Coordinates {
|
||||||
|
if polyPositions(ls).Intersects(polyExteriorHoles(v.Coordinates)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -25,10 +25,6 @@ func fillMultiPoint(coordinates []Position, bbox *BBox, err error) (MultiPoint,
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g MultiPoint) getPoint(index int) Point {
|
|
||||||
return Point{Coordinates: g.Coordinates[index]}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CalculatedBBox is exterior bbox containing the object.
|
// CalculatedBBox is exterior bbox containing the object.
|
||||||
func (g MultiPoint) CalculatedBBox() BBox {
|
func (g MultiPoint) CalculatedBBox() BBox {
|
||||||
return level2CalculatedBBox(g.Coordinates, g.BBox)
|
return level2CalculatedBBox(g.Coordinates, g.BBox)
|
||||||
|
@ -112,12 +108,36 @@ func (g MultiPoint) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g MultiPoint) Within(o Object) bool {
|
func (g MultiPoint) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, p := range g.Coordinates {
|
||||||
|
if !poly.Point(p).Inside(polyExteriorHoles(v.Coordinates)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g MultiPoint) Intersects(o Object) bool {
|
func (g MultiPoint) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, p := range g.Coordinates {
|
||||||
|
if poly.Point(p).Intersects(polyExteriorHoles(v.Coordinates)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -22,7 +22,7 @@ func fillMultiPolygon(coordinates [][][]Position, bbox *BBox, err error) (MultiP
|
||||||
}
|
}
|
||||||
bboxDefined := bbox != nil
|
bboxDefined := bbox != nil
|
||||||
if !bboxDefined {
|
if !bboxDefined {
|
||||||
cbbox := mpCalculatedBBox(polygons, nil)
|
cbbox := calculatedBBox(polygons, nil)
|
||||||
bbox = &cbbox
|
bbox = &cbbox
|
||||||
}
|
}
|
||||||
return MultiPolygon{
|
return MultiPolygon{
|
||||||
|
@ -33,16 +33,16 @@ func fillMultiPolygon(coordinates [][][]Position, bbox *BBox, err error) (MultiP
|
||||||
}, err
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func mpCalculatedBBox(polygons []Polygon, bbox *BBox) BBox {
|
func calculatedBBox(polygons []Polygon, bbox *BBox) BBox {
|
||||||
if bbox != nil {
|
if bbox != nil {
|
||||||
return *bbox
|
return *bbox
|
||||||
}
|
}
|
||||||
var cbbox BBox
|
var cbbox BBox
|
||||||
for i, g := range polygons {
|
for i, p := range polygons {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
cbbox = g.CalculatedBBox()
|
cbbox = p.CalculatedBBox()
|
||||||
} else {
|
} else {
|
||||||
cbbox = cbbox.union(g.CalculatedBBox())
|
cbbox = cbbox.union(p.CalculatedBBox())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cbbox
|
return cbbox
|
||||||
|
@ -50,7 +50,7 @@ func mpCalculatedBBox(polygons []Polygon, bbox *BBox) BBox {
|
||||||
|
|
||||||
// CalculatedBBox is exterior bbox containing the object.
|
// CalculatedBBox is exterior bbox containing the object.
|
||||||
func (g MultiPolygon) CalculatedBBox() BBox {
|
func (g MultiPolygon) CalculatedBBox() BBox {
|
||||||
return mpCalculatedBBox(g.polygons, g.BBox)
|
return calculatedBBox(g.polygons, g.BBox)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculatedPoint is a point representation of the object.
|
// CalculatedPoint is a point representation of the object.
|
||||||
|
@ -148,12 +148,32 @@ func (g MultiPolygon) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g MultiPolygon) Within(o Object) bool {
|
func (g MultiPolygon) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !v.Within(o) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g MultiPolygon) Intersects(o Object) bool {
|
func (g MultiPolygon) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if v.Intersects(o) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -182,6 +182,171 @@ func objectMap(json string, from int) (Object, error) {
|
||||||
return o, err
|
return o, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func withinObjectShared(g Object, o Object, pin func(v Polygon) bool) bool {
|
||||||
|
bbp := o.bboxPtr()
|
||||||
|
if bbp != nil {
|
||||||
|
if !g.WithinBBox(*bbp) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if o.IsBBoxDefined() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch v := o.(type) {
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
case Point:
|
||||||
|
return g.WithinBBox(v.CalculatedBBox())
|
||||||
|
case SimplePoint:
|
||||||
|
return g.WithinBBox(v.CalculatedBBox())
|
||||||
|
case MultiPoint:
|
||||||
|
for i := range v.Coordinates {
|
||||||
|
if g.Within(Point{Coordinates: v.Coordinates[i]}) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case LineString:
|
||||||
|
if len(v.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(v.Coordinates))
|
||||||
|
case Point:
|
||||||
|
return poly.Point(g.Coordinates).IntersectsLineString(polyPositions(v.Coordinates))
|
||||||
|
case MultiPoint:
|
||||||
|
if len(v.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, p := range v.Coordinates {
|
||||||
|
if !poly.Point(p).IntersectsLineString(polyPositions(v.Coordinates)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case MultiLineString:
|
||||||
|
for i := range v.Coordinates {
|
||||||
|
if g.Within(v.getLineString(i)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case Polygon:
|
||||||
|
if len(v.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return pin(v)
|
||||||
|
case MultiPolygon:
|
||||||
|
for i := range v.Coordinates {
|
||||||
|
if pin(v.getPolygon(i)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case Feature:
|
||||||
|
return g.Within(v.Geometry)
|
||||||
|
case FeatureCollection:
|
||||||
|
if len(v.Features) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, f := range v.Features {
|
||||||
|
if !g.Within(f) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case GeometryCollection:
|
||||||
|
if len(v.Geometries) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, f := range v.Geometries {
|
||||||
|
if !g.Within(f) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func intersectsObjectShared(g Object, o Object, pin func(v Polygon) bool) bool {
|
||||||
|
bbp := o.bboxPtr()
|
||||||
|
if bbp != nil {
|
||||||
|
if !g.IntersectsBBox(*bbp) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if o.IsBBoxDefined() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch v := o.(type) {
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
case Point:
|
||||||
|
return g.IntersectsBBox(v.CalculatedBBox())
|
||||||
|
case SimplePoint:
|
||||||
|
return g.IntersectsBBox(v.CalculatedBBox())
|
||||||
|
case MultiPoint:
|
||||||
|
for i := range v.Coordinates {
|
||||||
|
if (Point{Coordinates: v.Coordinates[i]}).Intersects(g) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case LineString:
|
||||||
|
if g, ok := g.(LineString); ok {
|
||||||
|
a := polyPositions(g.Coordinates)
|
||||||
|
b := polyPositions(v.Coordinates)
|
||||||
|
return a.LineStringIntersectsLineString(b)
|
||||||
|
}
|
||||||
|
return o.Intersects(g)
|
||||||
|
case MultiLineString:
|
||||||
|
for i := range v.Coordinates {
|
||||||
|
if g.Intersects(v.getLineString(i)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case Polygon:
|
||||||
|
if len(v.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return pin(v)
|
||||||
|
case MultiPolygon:
|
||||||
|
for _, coords := range v.Coordinates {
|
||||||
|
if pin(Polygon{Coordinates: coords}) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case Feature:
|
||||||
|
return g.Intersects(v.Geometry)
|
||||||
|
case FeatureCollection:
|
||||||
|
if len(v.Features) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, f := range v.Features {
|
||||||
|
if g.Intersects(f) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case GeometryCollection:
|
||||||
|
if len(v.Geometries) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, f := range v.Geometries {
|
||||||
|
if g.Intersects(f) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CirclePolygon returns a Polygon around the radius.
|
// CirclePolygon returns a Polygon around the radius.
|
||||||
func CirclePolygon(x, y, meters float64, steps int) Polygon {
|
func CirclePolygon(x, y, meters float64, steps int) Polygon {
|
||||||
if steps < 3 {
|
if steps < 3 {
|
||||||
|
@ -202,6 +367,21 @@ func CirclePolygon(x, y, meters float64, steps int) Polygon {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
||||||
func jsonMarshalString(s string) []byte {
|
func jsonMarshalString(s string) []byte {
|
||||||
for i := 0; i < len(s); i++ {
|
for i := 0; i < len(s); i++ {
|
||||||
if s[i] < ' ' || s[i] == '\\' || s[i] == '"' || s[i] > 126 {
|
if s[i] < ' ' || s[i] == '\\' || s[i] == '"' || s[i] > 126 {
|
||||||
|
|
|
@ -42,72 +42,3 @@ func TestCirclePolygon(t *testing.T) {
|
||||||
t.Fatal("should intersect")
|
t.Fatal("should intersect")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue281(t *testing.T) {
|
|
||||||
p := testJSON(t, `{"type":"Polygon","coordinates":[[
|
|
||||||
[-74.008283,40.718249],
|
|
||||||
[-74.007339,40.713305],
|
|
||||||
[-73.999013,40.714866],
|
|
||||||
[-74.001760,40.720851],
|
|
||||||
[-74.008283,40.718249]
|
|
||||||
]]}`)
|
|
||||||
|
|
||||||
// intersects polygon
|
|
||||||
ls1 := testJSON(t, `{"type":"LineString","coordinates":[
|
|
||||||
[-74.003648,40.717533],
|
|
||||||
[-73.99575233459473,40.72046126415031],
|
|
||||||
[-73.99721145629883,40.72338850378556]
|
|
||||||
]}`)
|
|
||||||
|
|
||||||
// outside polygon
|
|
||||||
ls2 := testJSON(t, `{"type":"LineString","coordinates":[
|
|
||||||
[-74.007682,40.722998],
|
|
||||||
[-74.001932,40.728462],
|
|
||||||
[-74.001846,40.723583]
|
|
||||||
]}`)
|
|
||||||
|
|
||||||
// inside polygon
|
|
||||||
ls3 := testJSON(t, `{"type":"LineString","coordinates":[
|
|
||||||
[-74.006910,40.717598],
|
|
||||||
[-74.006137,40.715387],
|
|
||||||
[-74.001331,40.715907]
|
|
||||||
]}`)
|
|
||||||
|
|
||||||
if !ls1.Intersects(p) {
|
|
||||||
t.Fatalf("expected true")
|
|
||||||
}
|
|
||||||
if !p.Intersects(ls1) {
|
|
||||||
t.Fatalf("expected true")
|
|
||||||
}
|
|
||||||
if ls1.Within(p) {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
if p.Within(ls1) {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
if ls2.Intersects(p) {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
if p.Intersects(ls2) {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
if ls2.Within(p) {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
if p.Within(ls2) {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
if !ls3.Intersects(p) {
|
|
||||||
t.Fatalf("expected true")
|
|
||||||
}
|
|
||||||
if !p.Intersects(ls3) {
|
|
||||||
t.Fatalf("expected true")
|
|
||||||
}
|
|
||||||
if !ls3.Within(p) {
|
|
||||||
t.Fatalf("expected true")
|
|
||||||
}
|
|
||||||
if p.Within(ls3) {
|
|
||||||
t.Fatalf("expected false")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -105,12 +105,20 @@ func (g Point) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g Point) Within(o Object) bool {
|
func (g Point) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return poly.Point(g.Coordinates).Inside(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g Point) Intersects(o Object) bool {
|
func (g Point) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return poly.Point(g.Coordinates).Intersects(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -145,12 +145,26 @@ func (g Polygon) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g Polygon) Within(o Object) bool {
|
func (g Polygon) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return polyPositions(g.Coordinates[0]).Inside(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g Polygon) Intersects(o Object) bool {
|
func (g Polygon) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
if len(g.Coordinates) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return polyPositions(g.Coordinates[0]).Intersects(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
|
@ -87,12 +87,20 @@ func (g SimplePoint) IntersectsBBox(bbox BBox) bool {
|
||||||
|
|
||||||
// Within detects if the object is fully contained inside another object.
|
// Within detects if the object is fully contained inside another object.
|
||||||
func (g SimplePoint) Within(o Object) bool {
|
func (g SimplePoint) Within(o Object) bool {
|
||||||
return withinObjectShared(g, o)
|
return withinObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return poly.Point(Position{X: g.X, Y: g.Y, Z: 0}).Inside(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersects detects if the object intersects another object.
|
// Intersects detects if the object intersects another object.
|
||||||
func (g SimplePoint) Intersects(o Object) bool {
|
func (g SimplePoint) Intersects(o Object) bool {
|
||||||
return intersectsObjectShared(g, o)
|
return intersectsObjectShared(g, o,
|
||||||
|
func(v Polygon) bool {
|
||||||
|
return poly.Point(Position{X: g.X, Y: g.Y, Z: 0}).Intersects(polyExteriorHoles(v.Coordinates))
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nearby detects if the object is nearby a position.
|
// Nearby detects if the object is nearby a position.
|
||||||
|
|
Loading…
Reference in New Issue