tidwall cfc65a13f6 Refactor repository and build scripts
This commit includes updates that affects the build, testing, and
deployment of Tile38.

- The root level build.sh has been broken up into multiple scripts
  and placed in the "scripts" directory.

- The vendor directory has been updated to follow the Go modules
  rules, thus `make` should work on isolated environments. Also
  some vendored packages may have been updated to a later
  version, if needed.

- The Makefile has been updated to allow for making single
  binaries such as `make tile38-server`. There is some scaffolding
  during the build process, so from now on all binaries should be
  made using make. For example, to run a development version of
  the tile38-cli binary, do this:
     make tile38-cli && ./tile38-cli
  not this:
     go run cmd/tile38-cli/main.go

- Travis.CI docker push script has been updated to address a
  change to Docker's JSON repo meta output, which in turn fixes
  a bug where new Tile38 versions were not being properly pushed
  to Docker
2019-11-18 10:33:15 -07:00

337 lines
6.7 KiB
Go

package geojson
import (
"github.com/tidwall/geojson/geometry"
"github.com/tidwall/rbang"
)
type collection struct {
children []Object
extra *extra
tree *rbang.RTree
prect geometry.Rect
pempty bool
}
func (g *collection) Indexed() bool {
return g.tree != nil
}
func (g *collection) Children() []Object {
return g.children
}
// ForEach ...
func (g *collection) ForEach(iter func(geom Object) bool) bool {
for _, child := range g.children {
if !child.ForEach(iter) {
return false
}
}
return true
}
// Base ...
func (g *collection) Base() []Object {
return g.children
}
func (g *collection) Search(rect geometry.Rect, iter func(child Object) bool) {
if g.tree != nil {
g.tree.Search(
[2]float64{rect.Min.X, rect.Min.Y},
[2]float64{rect.Max.X, rect.Max.Y},
func(_, _ [2]float64, value interface{}) bool {
return iter(value.(Object))
},
)
} else {
for _, child := range g.children {
if child.Empty() {
continue
}
if child.Rect().IntersectsRect(rect) {
if !iter(child) {
break
}
}
}
}
}
// Empty ...
func (g *collection) Empty() bool {
return g.pempty
}
// Valid ...
func (g *collection) Valid() bool {
return g.Rect().Valid()
}
// Rect ...
func (g *collection) Rect() geometry.Rect {
return g.prect
}
// Center ...
func (g *collection) Center() geometry.Point {
return g.Rect().Center()
}
// AppendJSON ...
func (g *collection) AppendJSON(dst []byte) []byte {
// this should never be called
return append(dst, "null"...)
}
// JSON ...
func (g *collection) JSON() string {
return string(g.AppendJSON(nil))
}
// MarshalJSON ...
func (g *collection) MarshalJSON() ([]byte, error) {
return g.AppendJSON(nil), nil
}
// String ...
func (g *collection) String() string {
return string(g.AppendJSON(nil))
}
// Within ...
func (g *collection) Within(obj Object) bool {
return obj.Contains(g)
}
// Contains ...
func (g *collection) Contains(obj Object) bool {
if g.Empty() {
return false
}
// all of obj must be contained by any number of the collection children
var objContained bool
obj.ForEach(func(geom Object) bool {
if geom.Empty() {
// ignore empties
return true
}
var geomContained bool
g.Search(geom.Rect(), func(child Object) bool {
if child.Contains(geom) {
// found a child object that contains geom, end inner loop
geomContained = true
return false
}
return true
})
if !geomContained {
// unmark and quit the loop
objContained = false
return false
}
// mark that at least one geom is contained
objContained = true
return true
})
return objContained
}
func (g *collection) Spatial() Spatial { return g }
func (g *collection) WithinRect(rect geometry.Rect) bool {
if g.Empty() {
return false
}
var withinCount int
g.Search(rect, func(child Object) bool {
if child.Spatial().WithinRect(rect) {
withinCount++
return true
}
return false
})
return withinCount == len(g.children)
}
func (g *collection) WithinPoint(point geometry.Point) bool {
if g.Empty() {
return false
}
var withinCount int
g.Search(point.Rect(), func(child Object) bool {
if child.Spatial().WithinPoint(point) {
withinCount++
return true
}
return false
})
return withinCount == len(g.children)
}
func (g *collection) WithinLine(line *geometry.Line) bool {
if g.Empty() {
return false
}
var withinCount int
g.Search(line.Rect(), func(child Object) bool {
if child.Spatial().WithinLine(line) {
withinCount++
return true
}
return false
})
return withinCount == len(g.children)
}
func (g *collection) WithinPoly(poly *geometry.Poly) bool {
if g.Empty() {
return false
}
var withinCount int
g.Search(poly.Rect(), func(child Object) bool {
if child.Spatial().WithinPoly(poly) {
withinCount++
return true
}
return false
})
return withinCount == len(g.children)
}
// Intersects ...
func (g *collection) Intersects(obj Object) bool {
// check if any of obj intersects with any of collection
var intersects bool
obj.ForEach(func(geom Object) bool {
if geom.Empty() {
// ignore the empties
return true
}
g.Search(geom.Rect(), func(child Object) bool {
if child.Intersects(geom) {
intersects = true
return false
}
return true
})
if intersects {
return false
}
return true
})
return intersects
}
func (g *collection) IntersectsPoint(point geometry.Point) bool {
var intersects bool
g.Search(point.Rect(), func(child Object) bool {
if child.Spatial().IntersectsPoint(point) {
intersects = true
return false
}
return true
})
return intersects
}
func (g *collection) IntersectsRect(rect geometry.Rect) bool {
var intersects bool
g.Search(rect, func(child Object) bool {
if child.Spatial().IntersectsRect(rect) {
intersects = true
return false
}
return true
})
return intersects
}
func (g *collection) IntersectsLine(line *geometry.Line) bool {
var intersects bool
g.Search(line.Rect(), func(child Object) bool {
if child.Spatial().IntersectsLine(line) {
intersects = true
return false
}
return true
})
return intersects
}
func (g *collection) IntersectsPoly(poly *geometry.Poly) bool {
var intersects bool
g.Search(poly.Rect(), func(child Object) bool {
if child.Spatial().IntersectsPoly(poly) {
intersects = true
return false
}
return true
})
return intersects
}
// NumPoints ...
func (g *collection) NumPoints() int {
var n int
for _, child := range g.children {
n += child.NumPoints()
}
return n
}
func (g *collection) parseInitRectIndex(opts *ParseOptions) {
g.pempty = true
var count int
for _, child := range g.children {
if child.Empty() {
continue
}
if g.pempty && !child.Empty() {
g.pempty = false
}
if count == 0 {
g.prect = child.Rect()
} else {
if len(g.children) == 1 {
g.prect = child.Rect()
} else {
g.prect = unionRects(g.prect, child.Rect())
}
}
count++
}
if count > 0 && opts.IndexChildren != 0 && count >= opts.IndexChildren {
g.tree = new(rbang.RTree)
for _, child := range g.children {
if child.Empty() {
continue
}
rect := child.Rect()
g.tree.Insert(
[2]float64{rect.Min.X, rect.Min.Y},
[2]float64{rect.Max.X, rect.Max.Y},
child,
)
}
}
}
// Distance ...
func (g *collection) Distance(obj Object) float64 {
return obj.Spatial().DistancePoint(g.Center())
}
func (g *collection) DistancePoint(point geometry.Point) float64 {
return geoDistancePoints(g.Center(), point)
}
func (g *collection) DistanceRect(rect geometry.Rect) float64 {
return geoDistancePoints(g.Center(), rect.Center())
}
func (g *collection) DistanceLine(line *geometry.Line) float64 {
return geoDistancePoints(g.Center(), line.Rect().Center())
}
func (g *collection) DistancePoly(poly *geometry.Poly) float64 {
return geoDistancePoints(g.Center(), poly.Rect().Center())
}