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

98 lines
2.5 KiB
Go

package base
import "math"
// Load bulk load items into the R-tree.
func (tr *RTree) Load(mins, maxs [][]float64, items []interface{}) {
if len(items) < tr.minEntries {
for i := 0; i < len(items); i++ {
tr.Insert(mins[i], maxs[i], items[i])
}
return
}
// prefill the items
fitems := make([]*treeNode, len(items))
for i := 0; i < len(items); i++ {
item := &treeItem{min: mins[i], max: maxs[i], item: items[i]}
fitems[i] = item.unsafeNode()
}
// following equations are defined in the paper describing OMT
N := len(fitems)
M := tr.maxEntries
h := int(math.Ceil(math.Log(float64(N)) / math.Log(float64(M))))
Nsubtree := int(math.Pow(float64(M), float64(h-1)))
S := int(math.Ceil(math.Sqrt(float64(N) / float64(Nsubtree))))
// sort by the initial axis
axis := 0
sortByAxis(fitems, axis)
// build the root node. it's split differently from the subtrees.
children := make([]*treeNode, 0, S)
for i := 0; i < S; i++ {
var part []*treeNode
if i == S-1 {
// last split
part = fitems[len(fitems)/S*i:]
} else {
part = fitems[len(fitems)/S*i : len(fitems)/S*(i+1)]
}
children = append(children, tr.omt(part, h-1, axis+1))
}
node := tr.createNode(children)
node.leaf = false
node.height = h
tr.calcBBox(node)
if tr.data.count == 0 {
// save as is if tree is empty
tr.data = node
} else if tr.data.height == node.height {
// split root if trees have the same height
tr.splitRoot(tr.data, node)
} else {
if tr.data.height < node.height {
// swap trees if inserted one is bigger
tr.data, node = node, tr.data
}
// insert the small tree into the large tree at appropriate level
tr.insert(node, nil, tr.data.height-node.height-1, true)
}
}
func (tr *RTree) omt(fitems []*treeNode, h, axis int) *treeNode {
if len(fitems) <= tr.maxEntries {
// reached leaf level; return leaf
children := make([]*treeNode, len(fitems))
copy(children, fitems)
node := tr.createNode(children)
node.height = h
tr.calcBBox(node)
return node
}
// sort the items on a different axis than the previous level.
sortByAxis(fitems, axis%tr.dims)
children := make([]*treeNode, 0, tr.maxEntries)
partsz := len(fitems) / tr.maxEntries
for i := 0; i < tr.maxEntries; i++ {
var part []*treeNode
if i == tr.maxEntries-1 {
// last part
part = fitems[partsz*i:]
} else {
part = fitems[partsz*i : partsz*(i+1)]
}
children = append(children, tr.omt(part, h-1, axis+1))
}
node := tr.createNode(children)
node.height = h
node.leaf = false
tr.calcBBox(node)
return node
}