mirror of https://github.com/tidwall/tile38.git
Add subcommand to the INTERSECTS and WITHIN
This commit is contained in:
parent
e60191caed
commit
c4d9ba26d9
|
@ -417,9 +417,11 @@ func (c *Collection) Nearby(sparse uint8, lat, lon, meters, minZ, maxZ float64,
|
|||
}
|
||||
|
||||
// Within returns all object that are fully contained within an object or bounding box. Set obj to nil in order to use the bounding box.
|
||||
func (c *Collection) Within(sparse uint8, obj geojson.Object, minLat, minLon, maxLat, maxLon, minZ, maxZ float64, iterator func(id string, obj geojson.Object, fields []float64) bool) bool {
|
||||
func (c *Collection) Within(sparse uint8, obj geojson.Object, minLat, minLon, maxLat, maxLon, lat, lon, meters, minZ, maxZ float64, iterator func(id string, obj geojson.Object, fields []float64) bool) bool {
|
||||
var keepon = true
|
||||
var bbox geojson.BBox
|
||||
center := geojson.Position{X: lon, Y: lat, Z: 0}
|
||||
|
||||
if obj != nil {
|
||||
bbox = obj.CalculatedBBox()
|
||||
if minZ == math.Inf(-1) && maxZ == math.Inf(+1) {
|
||||
|
@ -428,6 +430,8 @@ func (c *Collection) Within(sparse uint8, obj geojson.Object, minLat, minLon, ma
|
|||
bbox.Max.Z = maxZ
|
||||
}
|
||||
}
|
||||
} else if meters != -1 {
|
||||
bbox = geojson.BBoxesFromCenter(lat, lon, meters)
|
||||
} else {
|
||||
bbox = geojson.BBox{Min: geojson.Position{X: minLon, Y: minLat, Z: minZ}, Max: geojson.Position{X: maxLon, Y: maxLat, Z: maxZ}}
|
||||
}
|
||||
|
@ -443,6 +447,15 @@ func (c *Collection) Within(sparse uint8, obj geojson.Object, minLat, minLon, ma
|
|||
}
|
||||
return true
|
||||
})
|
||||
} else if meters != -1 {
|
||||
keepon = c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
if o.WithinCircle(center, meters) {
|
||||
if iterator(id, o, fields) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
if keepon {
|
||||
keepon = c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
|
@ -467,6 +480,13 @@ func (c *Collection) Within(sparse uint8, obj geojson.Object, minLat, minLon, ma
|
|||
}
|
||||
return true
|
||||
})
|
||||
} else if meters != -1 {
|
||||
return c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
if o.WithinCircle(center, meters) {
|
||||
return iterator(id, o, fields)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
return c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
if o.WithinBBox(bbox) {
|
||||
|
@ -477,9 +497,10 @@ func (c *Collection) Within(sparse uint8, obj geojson.Object, minLat, minLon, ma
|
|||
}
|
||||
|
||||
// Intersects returns all object that are intersect an object or bounding box. Set obj to nil in order to use the bounding box.
|
||||
func (c *Collection) Intersects(sparse uint8, obj geojson.Object, minLat, minLon, maxLat, maxLon, minZ, maxZ float64, iterator func(id string, obj geojson.Object, fields []float64) bool) bool {
|
||||
func (c *Collection) Intersects(sparse uint8, obj geojson.Object, minLat, minLon, maxLat, maxLon, lat, lon, meters, minZ, maxZ float64, iterator func(id string, obj geojson.Object, fields []float64) bool) bool {
|
||||
var keepon = true
|
||||
var bbox geojson.BBox
|
||||
center := geojson.Position{X: lon, Y: lat, Z: 0}
|
||||
if obj != nil {
|
||||
bbox = obj.CalculatedBBox()
|
||||
if minZ == math.Inf(-1) && maxZ == math.Inf(+1) {
|
||||
|
@ -488,6 +509,8 @@ func (c *Collection) Intersects(sparse uint8, obj geojson.Object, minLat, minLon
|
|||
bbox.Max.Z = maxZ
|
||||
}
|
||||
}
|
||||
} else if meters != -1 {
|
||||
bbox = geojson.BBoxesFromCenter(lat, lon, meters)
|
||||
} else {
|
||||
bbox = geojson.BBox{Min: geojson.Position{X: minLon, Y: minLat, Z: minZ}, Max: geojson.Position{X: maxLon, Y: maxLat, Z: maxZ}}
|
||||
}
|
||||
|
@ -514,6 +537,15 @@ func (c *Collection) Intersects(sparse uint8, obj geojson.Object, minLat, minLon
|
|||
}
|
||||
return true
|
||||
})
|
||||
} else if meters != -1 {
|
||||
keepon = c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
if o.IntersectsCircle(center, meters) {
|
||||
if iterator(id, o, fields) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
if keepon {
|
||||
keepon = c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
|
@ -538,6 +570,13 @@ func (c *Collection) Intersects(sparse uint8, obj geojson.Object, minLat, minLon
|
|||
}
|
||||
return true
|
||||
})
|
||||
} else if meters != -1 {
|
||||
return c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
if o.IntersectsCircle(center, meters) {
|
||||
return iterator(id, o, fields)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
return c.geoSearch(bbox, func(id string, o geojson.Object, fields []float64) bool {
|
||||
if o.IntersectsBBox(bbox) {
|
||||
|
|
|
@ -87,6 +87,7 @@ func (c *Controller) cmdSearchArgs(cmd string, vs []resp.Value, types []string)
|
|||
err = errInvalidArgument(typ)
|
||||
return
|
||||
}
|
||||
s.meters = -1 // this will become non-negative if search is within a circle
|
||||
switch ltyp {
|
||||
case "point":
|
||||
var slat, slon, smeters string
|
||||
|
@ -127,6 +128,41 @@ func (c *Controller) cmdSearchArgs(cmd string, vs []resp.Value, types []string)
|
|||
err = errInvalidArgument(smeters)
|
||||
return
|
||||
}
|
||||
if s.meters < 0 {
|
||||
err = errInvalidArgument(smeters)
|
||||
return
|
||||
}
|
||||
}
|
||||
case "circle":
|
||||
var slat, slon, smeters string
|
||||
if vs, slat, ok = tokenval(vs); !ok || slat == "" {
|
||||
err = errInvalidNumberOfArguments
|
||||
return
|
||||
}
|
||||
if vs, slon, ok = tokenval(vs); !ok || slon == "" {
|
||||
err = errInvalidNumberOfArguments
|
||||
return
|
||||
}
|
||||
if vs, smeters, ok = tokenval(vs); !ok || smeters == "" {
|
||||
err = errInvalidArgument(slat)
|
||||
return
|
||||
}
|
||||
|
||||
if s.lat, err = strconv.ParseFloat(slat, 64); err != nil {
|
||||
err = errInvalidArgument(slat)
|
||||
return
|
||||
}
|
||||
if s.lon, err = strconv.ParseFloat(slon, 64); err != nil {
|
||||
err = errInvalidArgument(slon)
|
||||
return
|
||||
}
|
||||
if s.meters, err = strconv.ParseFloat(smeters, 64); err != nil {
|
||||
err = errInvalidArgument(smeters)
|
||||
return
|
||||
}
|
||||
if s.meters < 0 {
|
||||
err = errInvalidArgument(smeters)
|
||||
return
|
||||
}
|
||||
case "object":
|
||||
var obj string
|
||||
|
@ -292,7 +328,8 @@ func (c *Controller) cmdSearchArgs(cmd string, vs []resp.Value, types []string)
|
|||
}
|
||||
|
||||
var nearbyTypes = []string{"point"}
|
||||
var withinOrIntersectsTypes = []string{"geo", "bounds", "hash", "tile", "quadkey", "get", "object"}
|
||||
var withinOrIntersectsTypes = []string{
|
||||
"geo", "bounds", "hash", "tile", "quadkey", "get", "object", "circle"}
|
||||
|
||||
func (c *Controller) cmdNearby(msg *server.Message) (res resp.Value, err error) {
|
||||
start := time.Now()
|
||||
|
@ -449,7 +486,11 @@ func (c *Controller) cmdWithinOrIntersects(cmd string, msg *server.Message) (res
|
|||
if sw.col != nil {
|
||||
minZ, maxZ := zMinMaxFromWheres(s.wheres)
|
||||
if cmd == "within" {
|
||||
sw.col.Within(s.sparse, s.o, s.minLat, s.minLon, s.maxLat, s.maxLon, minZ, maxZ,
|
||||
sw.col.Within(s.sparse,
|
||||
s.o,
|
||||
s.minLat, s.minLon, s.maxLat, s.maxLon,
|
||||
s.lat, s.lon, s.meters,
|
||||
minZ, maxZ,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
if c.hasExpired(s.key, id) {
|
||||
return true
|
||||
|
@ -463,7 +504,11 @@ func (c *Controller) cmdWithinOrIntersects(cmd string, msg *server.Message) (res
|
|||
},
|
||||
)
|
||||
} else if cmd == "intersects" {
|
||||
sw.col.Intersects(s.sparse, s.o, s.minLat, s.minLon, s.maxLat, s.maxLon, minZ, maxZ,
|
||||
sw.col.Intersects(s.sparse,
|
||||
s.o,
|
||||
s.minLat, s.minLon, s.maxLat, s.maxLon,
|
||||
s.lat, s.lon, s.meters,
|
||||
minZ, maxZ,
|
||||
func(id string, o geojson.Object, fields []float64) bool {
|
||||
if c.hasExpired(s.key, id) {
|
||||
return true
|
||||
|
|
|
@ -674,7 +674,7 @@
|
|||
"group": "search"
|
||||
},
|
||||
"WITHIN": {
|
||||
"summary": "Searches for ids that are nearby a point",
|
||||
"summary": "Searches for ids that completely within the area",
|
||||
"complexity": "O(log(N)) where N is the number of ids in the area",
|
||||
"arguments":[
|
||||
{
|
||||
|
@ -836,6 +836,23 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CIRCLE",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "lat",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "lon",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "meters",
|
||||
"type": "double"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TILE",
|
||||
"arguments":[
|
||||
|
@ -878,7 +895,7 @@
|
|||
"group": "search"
|
||||
},
|
||||
"INTERSECTS": {
|
||||
"summary": "Searches for ids that are nearby a point",
|
||||
"summary": "Searches for ids that intersect an area",
|
||||
"complexity": "O(log(N)) where N is the number of ids in the area",
|
||||
"arguments":[
|
||||
{
|
||||
|
@ -1040,6 +1057,23 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CIRCLE",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "lat",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "lon",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "meters",
|
||||
"type": "double"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TILE",
|
||||
"arguments":[
|
||||
|
|
|
@ -840,7 +840,7 @@ var commandsJSON = `{
|
|||
"group": "search"
|
||||
},
|
||||
"WITHIN": {
|
||||
"summary": "Searches for ids that are nearby a point",
|
||||
"summary": "Searches for ids that completely within the area",
|
||||
"complexity": "O(log(N)) where N is the number of ids in the area",
|
||||
"arguments":[
|
||||
{
|
||||
|
@ -1002,6 +1002,23 @@ var commandsJSON = `{
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CIRCLE",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "lat",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "lon",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "meters",
|
||||
"type": "double"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TILE",
|
||||
"arguments":[
|
||||
|
@ -1044,7 +1061,7 @@ var commandsJSON = `{
|
|||
"group": "search"
|
||||
},
|
||||
"INTERSECTS": {
|
||||
"summary": "Searches for ids that are nearby a point",
|
||||
"summary": "Searches for ids that intersect an area",
|
||||
"complexity": "O(log(N)) where N is the number of ids in the area",
|
||||
"arguments":[
|
||||
{
|
||||
|
@ -1206,6 +1223,23 @@ var commandsJSON = `{
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CIRCLE",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "lat",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "lon",
|
||||
"type": "double"
|
||||
},
|
||||
{
|
||||
"name": "meters",
|
||||
"type": "double"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "TILE",
|
||||
"arguments":[
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package geojson
|
||||
|
||||
import (
|
||||
"github.com/tidwall/tile38/pkg/geojson/geo"
|
||||
)
|
||||
|
||||
func SegmentIntersectsCircle(start, end, center Position, meters float64) bool {
|
||||
// These are faster checks. If they succeed there's no need do complicate things.
|
||||
if center.DistanceTo(start) <= meters {
|
||||
return true
|
||||
}
|
||||
if center.DistanceTo(end) <= meters {
|
||||
return true
|
||||
}
|
||||
|
||||
// Distance between start and end
|
||||
l := geo.DistanceTo(start.Y, start.X, end.Y, end.X)
|
||||
|
||||
// Unit direction vector
|
||||
dx := (end.X - start.X) / l
|
||||
dy := (end.Y - start.Y) / l
|
||||
|
||||
// Point of the line closest to the center
|
||||
t := dx * (center.X - start.X) + dy * (center.Y - start.Y)
|
||||
px := t * dx + start.X
|
||||
py := t * dy + start.Y
|
||||
if px < start.X || px > end.X || py < start.Y || py > end.Y {
|
||||
// closest point is outside the segment
|
||||
return false
|
||||
}
|
||||
|
||||
// Distance from the closest point to the center
|
||||
return geo.DistanceTo(center.Y, center.X, py, px) <= meters
|
||||
}
|
|
@ -199,6 +199,11 @@ func (g Feature) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g Feature) WithinCircle(center Position, meters float64) bool {
|
||||
return g.Geometry.WithinCircle(center, meters)
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g Feature) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -208,6 +213,11 @@ func (g Feature) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g Feature) IntersectsCircle(center Position, meters float64) bool {
|
||||
return g.Geometry.IntersectsCircle(center, meters)
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g Feature) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -193,6 +193,19 @@ func (g FeatureCollection) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g FeatureCollection) WithinCircle(center Position, meters float64) bool {
|
||||
if len(g.Features) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, feature := range g.Features {
|
||||
if !feature.WithinCircle(center, meters) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g FeatureCollection) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -211,6 +224,16 @@ func (g FeatureCollection) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g FeatureCollection) IntersectsCircle(center Position, meters float64) bool {
|
||||
for _, feature := range g.Features {
|
||||
if feature.IntersectsCircle(center, meters) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g FeatureCollection) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -192,6 +192,19 @@ func (g GeometryCollection) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g GeometryCollection) WithinCircle(center Position, meters float64) bool {
|
||||
if len(g.Geometries) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, geometry := range g.Geometries {
|
||||
if !geometry.WithinCircle(center, meters) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g GeometryCollection) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -209,6 +222,16 @@ func (g GeometryCollection) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g GeometryCollection) IntersectsCircle(center Position, meters float64) bool {
|
||||
for _, geometry := range g.Geometries {
|
||||
if geometry.IntersectsCircle(center, meters) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g GeometryCollection) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -105,6 +105,19 @@ func (g LineString) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g LineString) WithinCircle(center Position, meters float64) bool {
|
||||
if len(g.Coordinates) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, position := range g.Coordinates {
|
||||
if center.DistanceTo(position) >= meters {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g LineString) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -114,6 +127,16 @@ func (g LineString) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g LineString) IntersectsCircle(center Position, meters float64) bool {
|
||||
for i := 0; i < len(g.Coordinates) - 1 ; i++ {
|
||||
if SegmentIntersectsCircle(g.Coordinates[i], g.Coordinates[i + 1], center, meters) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g LineString) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -148,6 +148,24 @@ func (g MultiLineString) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g MultiLineString) WithinCircle(center Position, meters float64) bool {
|
||||
if len(g.Coordinates) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, ls := range g.Coordinates {
|
||||
if len(ls) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, position := range ls {
|
||||
if center.DistanceTo(position) >= meters {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g MultiLineString) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -165,6 +183,18 @@ func (g MultiLineString) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g MultiLineString) IntersectsCircle(center Position, meters float64) bool {
|
||||
for _, ls := range g.Coordinates {
|
||||
for i := 0; i < len(ls) - 1 ; i++ {
|
||||
if SegmentIntersectsCircle(ls[i], ls[i + 1], center, meters) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g MultiLineString) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -123,6 +123,19 @@ func (g MultiPoint) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g MultiPoint) WithinCircle(center Position, meters float64) bool {
|
||||
if len(g.Coordinates) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, position := range g.Coordinates {
|
||||
if center.DistanceTo(position) >= meters {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g MultiPoint) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -140,6 +153,16 @@ func (g MultiPoint) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g MultiPoint) IntersectsCircle(center Position, meters float64) bool {
|
||||
for _, position := range g.Coordinates {
|
||||
if center.DistanceTo(position) <= meters {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g MultiPoint) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -161,6 +161,19 @@ func (g MultiPolygon) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g MultiPolygon) WithinCircle(center Position, meters float64) bool {
|
||||
if len(g.polygons) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, polygon := range g.polygons {
|
||||
if !polygon.WithinCircle(center, meters) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g MultiPolygon) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -176,6 +189,16 @@ func (g MultiPolygon) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g MultiPolygon) IntersectsCircle(center Position, meters float64) bool {
|
||||
for _, polygon := range g.polygons {
|
||||
if polygon.IntersectsCircle(center, meters) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g MultiPolygon) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -68,6 +68,10 @@ type Object interface {
|
|||
Within(o Object) bool
|
||||
// Intersects detects if the object intersects another object.
|
||||
Intersects(o Object) bool
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
WithinCircle(center Position, meters float64) bool
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
IntersectsCircle(center Position, meters float64) bool
|
||||
// Nearby detects if the object is nearby a position.
|
||||
Nearby(center Position, meters float64) bool
|
||||
// CalculatedBBox is exterior bbox containing the object.
|
||||
|
|
|
@ -112,6 +112,11 @@ func (g Point) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g Point) WithinCircle(center Position, meters float64) bool {
|
||||
return geo.DistanceTo(g.Coordinates.Y, g.Coordinates.X, center.Y, center.X) < meters
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g Point) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -121,6 +126,11 @@ func (g Point) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g Point) IntersectsCircle(center Position, meters float64) bool {
|
||||
return geo.DistanceTo(g.Coordinates.Y, g.Coordinates.X, center.Y, center.X) <= meters
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g Point) Nearby(center Position, meters float64) bool {
|
||||
return geo.DistanceTo(g.Coordinates.Y, g.Coordinates.X, center.Y, center.X) <= meters
|
||||
|
|
|
@ -155,6 +155,19 @@ func (g Polygon) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g Polygon) WithinCircle(center Position, meters float64) bool {
|
||||
if len(g.Coordinates) == 0 {
|
||||
return false
|
||||
}
|
||||
for _, position := range g.Coordinates[0] {
|
||||
if center.DistanceTo(position) >= meters {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g Polygon) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -167,6 +180,21 @@ func (g Polygon) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g Polygon) IntersectsCircle(center Position, meters float64) bool {
|
||||
if g.Intersects(New2DPoint(center.X, center.Y)) {
|
||||
return true
|
||||
}
|
||||
for _, polygon := range g.Coordinates {
|
||||
for i := 0; i < len(polygon) - 1 ; i++ {
|
||||
if SegmentIntersectsCircle(polygon[i], polygon[i + 1], center, meters) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g Polygon) Nearby(center Position, meters float64) bool {
|
||||
return nearbyObjectShared(g, center.X, center.Y, meters)
|
||||
|
|
|
@ -94,6 +94,11 @@ func (g SimplePoint) Within(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (g SimplePoint) WithinCircle(center Position, meters float64) bool {
|
||||
return geo.DistanceTo(center.Y, center.X, g.Y, g.X) < meters
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (g SimplePoint) Intersects(o Object) bool {
|
||||
return intersectsObjectShared(g, o,
|
||||
|
@ -103,6 +108,11 @@ func (g SimplePoint) Intersects(o Object) bool {
|
|||
)
|
||||
}
|
||||
|
||||
// IntersectsCircle detects if the object intersects a circle.
|
||||
func (g SimplePoint) IntersectsCircle(center Position, meters float64) bool {
|
||||
return geo.DistanceTo(center.Y, center.X, g.Y, g.X) <= meters
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (g SimplePoint) Nearby(center Position, meters float64) bool {
|
||||
return geo.DistanceTo(center.Y, center.X, g.Y, g.X) <= meters
|
||||
|
|
|
@ -25,10 +25,18 @@ func (s String) Within(o Object) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// WithinCircle detects if the object is fully contained inside a circle.
|
||||
func (s String) WithinCircle(center Position, meters float64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Intersects detects if the object intersects another object.
|
||||
func (s String) Intersects(o Object) bool {
|
||||
return false
|
||||
}
|
||||
func (s String) IntersectsCircle(center Position, meters float64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Nearby detects if the object is nearby a position.
|
||||
func (s String) Nearby(center Position, meters float64) bool {
|
||||
|
|
Loading…
Reference in New Issue