mirror of
https://github.com/ergochat/ergo.git
synced 2024-12-24 19:52:35 +01:00
98 lines
2.5 KiB
Go
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
|
||
|
}
|