diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index 277766f0..7d4876bb 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -2,6 +2,8 @@ package geojson import ( "strconv" + "sync/atomic" + "unsafe" "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" @@ -9,7 +11,7 @@ import ( // Circle ... type Circle struct { - Object + object *Object center geometry.Point meters float64 haversine float64 @@ -27,27 +29,6 @@ func NewCircle(center geometry.Point, meters float64, steps int) *Circle { g.center = center g.meters = meters g.steps = steps - if meters <= 0 { - g.Object = NewPoint(center) - } else { - meters = geo.NormalizeDistance(meters) - var points []geometry.Point - step := 360.0 / float64(steps) - i := 0 - for deg := 360.0; deg > 0; deg -= step { - lat, lon := geo.DestinationPoint(center.Y, center.X, meters, deg) - points = append(points, geometry.Point{X: lon, Y: lat}) - i++ - } - // TODO: account for the pole and antimerdian. In most cases only a - // polygon is needed, but when the circle bounds passes the 90/180 - // lines, we need to create a multipolygon - points = append(points, points[0]) - g.Object = NewPolygon( - geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), - ) - g.haversine = geo.DistanceToHaversine(meters) - } return g } @@ -128,7 +109,7 @@ func (g *Circle) Contains(obj Object) bool { return true default: // No simple cases, so using polygon approximation. - return g.Object.Contains(other) + return g.getObject().Contains(other) } } @@ -185,6 +166,76 @@ func (g *Circle) Intersects(obj Object) bool { return false default: // No simple cases, so using polygon approximation. - return g.Object.Intersects(obj) + return g.getObject().Intersects(obj) } } + +// Empty ... +func (g *Circle) Empty() bool { + return false +} + +// ForEach ... +func (g *Circle) ForEach(iter func(geom Object) bool) bool { + return iter(g) +} + +// NumPoints ... +func (g *Circle) NumPoints() int { + return 1 +} + +// Distance ... +func (g *Circle) Distance(other Object) float64 { + return g.getObject().Distance(other) +} + +// Rect ... +func (g *Circle) Rect() geometry.Rect { + return g.getObject().Rect() +} + +// Spatial ... +func (g *Circle) Spatial() Spatial { + return g.getObject().Spatial() +} + +func (g *Circle) getObject() Object { + for { + object := (*Object)(atomic.LoadPointer( + (*unsafe.Pointer)(unsafe.Pointer(&g.object))), + ) + if object != nil { + return *object + } + newObject := makeCircleObject(g.center, g.meters, g.steps) + if atomic.CompareAndSwapPointer( + (*unsafe.Pointer)(unsafe.Pointer(&g.object)), + nil, unsafe.Pointer(&newObject), + ) { + return *object + } + } +} + +func makeCircleObject(center geometry.Point, meters float64, steps int) Object { + if meters <= 0 { + return NewPoint(center) + } + meters = geo.NormalizeDistance(meters) + var points []geometry.Point + step := 360.0 / float64(steps) + i := 0 + for deg := 360.0; deg > 0; deg -= step { + lat, lon := geo.DestinationPoint(center.Y, center.X, meters, deg) + points = append(points, geometry.Point{X: lon, Y: lat}) + i++ + } + // TODO: account for the pole and antimerdian. In most cases only a + // polygon is needed, but when the circle bounds passes the 90/180 + // lines, we need to create a multipolygon + points = append(points, points[0]) + return NewPolygon( + geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), + ) +}