diff --git a/vendor/github.com/tidwall/geojson/circle.go b/vendor/github.com/tidwall/geojson/circle.go index 3cdd8492..50bac786 100644 --- a/vendor/github.com/tidwall/geojson/circle.go +++ b/vendor/github.com/tidwall/geojson/circle.go @@ -1,7 +1,9 @@ package geojson import ( + "math" "strconv" + "sync" "github.com/tidwall/geojson/geo" "github.com/tidwall/geojson/geometry" @@ -210,12 +212,46 @@ func (g *Circle) getObject() Object { return makeCircleObject(g.center, g.meters, g.steps) } -func makeCircleObject(center geometry.Point, meters float64, steps int) Object { +var llmu sync.RWMutex +var llobj Object + +func makeCircleObjectA(center geometry.Point, meters float64, steps int) Object { if meters <= 0 { return NewPoint(center) } meters = geo.NormalizeDistance(meters) - var points []geometry.Point + points := make([]geometry.Point, 0, steps+1) + + // calc the four corners + maxY, _ := geo.DestinationPoint(center.Y, center.X, meters, 0) + _, maxX := geo.DestinationPoint(center.Y, center.X, meters, 90) + minY, _ := geo.DestinationPoint(center.Y, center.X, meters, 180) + _, minX := geo.DestinationPoint(center.Y, center.X, meters, 270) + lons := (maxX - minX) / 2 + lats := (maxY - minY) / 2 + + for th := 0.0; th <= 360.0; th += 360.0 / float64(steps) { + radians := (math.Pi / 180) * th + x := center.X + lats*math.Cos(radians) + y := center.Y + lons*math.Sin(radians) + points = append(points, geometry.Point{X: x, Y: y}) + } + // add last connecting point, make a total of steps+1 + points = append(points, points[0]) + + return NewPolygon( + geometry.NewPoly(points, nil, &geometry.IndexOptions{ + Kind: geometry.None, + }), + ) +} +func makeCircleObjectB(center geometry.Point, meters float64, steps int) Object { + if meters <= 0 { + return NewPoint(center) + } + meters = geo.NormalizeDistance(meters) + points := make([]geometry.Point, 0, steps+1) + step := 360.0 / float64(steps) i := 0 for deg := 360.0; deg > 0; deg -= step { @@ -223,11 +259,59 @@ func makeCircleObject(center geometry.Point, meters float64, steps int) Object { points = append(points, geometry.Point{X: lon, Y: lat}) i++ } + // add last connecting point, make a total of steps+1 + points = append(points, points[0]) + + return NewPolygon( + geometry.NewPoly(points, nil, &geometry.IndexOptions{ + Kind: geometry.None, + }), + ) +} + +func makeCircleObject(center geometry.Point, meters float64, steps int) Object { + if meters <= 0 { + return NewPoint(center) + } + + meters = geo.NormalizeDistance(meters) + points := make([]geometry.Point, 0, steps+1) + return makeCircleObjectA(center, meters, steps) + + llmu.RLock() + if llobj != nil { + llmu.RUnlock() + return llobj + } + llmu.RUnlock() + llmu.Lock() + if llobj != nil { + llmu.Unlock() + return llobj + } + defer llmu.Unlock() + + 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++ + } + // add last connecting point, make a total of steps+1 + points = append(points, points[0]) + + // for i := 0; i < steps; i++ { + // fmt.Printf("%d: %v\n", i, points[i].X) + // } + // 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( + + llobj = NewPolygon( geometry.NewPoly(points, nil, geometry.DefaultIndexOptions), ) + // println(llobj.String()) + return llobj }