rtred/dims/d10/rtree.go

686 lines
21 KiB
Go
Raw Normal View History

2016-07-22 01:30:24 +03:00
// generated; DO NOT EDIT!
2016-06-11 03:23:19 +03:00
/*
TITLE
R-TREES: A DYNAMIC INDEX STRUCTURE FOR SPATIAL SEARCHING
DESCRIPTION
A Go version of the RTree algorithm.
AUTHORS
* 1983 Original algorithm and test code by Antonin Guttman and Michael Stonebraker, UC Berkely
* 1994 ANCI C ported from original test code by Melinda Green - melinda@superliminal.com
* 1995 Sphere volume fix for degeneracy problem submitted by Paul Brook
* 2004 Templated C++ port by Greg Douglas
* 2016 Go port by Josh Baker
LICENSE:
Entirely free for all uses. Enjoy!
*/
// Implementation of RTree, a multidimensional bounding rectangle tree.
package rtree
import "math"
2016-09-03 23:57:44 +03:00
func fmin(a, b float64) float64 {
2016-06-11 03:23:19 +03:00
if a < b {
return a
}
return b
}
2016-09-03 23:57:44 +03:00
func fmax(a, b float64) float64 {
2016-06-11 03:23:19 +03:00
if a > b {
return a
}
return b
}
const (
2016-09-03 23:57:44 +03:00
numDims = 10
maxNodes = 8
minNodes = maxNodes / 2
useSphericalVolume = true // Better split classification, may be slower on some systems
2016-06-11 03:23:19 +03:00
)
2016-06-26 01:13:51 +03:00
var unitSphereVolume = []float64{
0.000000, 2.000000, 3.141593, // Dimension 0,1,2
4.188790, 4.934802, 5.263789, // Dimension 3,4,5
5.167713, 4.724766, 4.058712, // Dimension 6,7,8
3.298509, 2.550164, 1.884104, // Dimension 9,10,11
1.335263, 0.910629, 0.599265, // Dimension 12,13,14
0.381443, 0.235331, 0.140981, // Dimension 15,16,17
0.082146, 0.046622, 0.025807, // Dimension 18,19,20
2016-09-03 23:57:44 +03:00
}[numDims]
2016-06-11 03:23:19 +03:00
type RTree struct {
2016-09-03 23:57:44 +03:00
root *nodeT ///< Root of tree
2016-06-11 03:23:19 +03:00
}
/// Minimal bounding rectangle (n-dimensional)
2016-09-03 23:57:44 +03:00
type rectT struct {
min [numDims]float64 ///< Min dimensions of bounding box
max [numDims]float64 ///< Max dimensions of bounding box
2016-06-11 03:23:19 +03:00
}
/// May be data or may be another subtree
/// The parents level determines this.
/// If the parents level is 0, then this is data
2016-09-03 23:57:44 +03:00
type branchT struct {
rect rectT ///< Bounds
child *nodeT ///< Child node
2016-06-11 03:23:19 +03:00
data interface{} ///< Data Id or Ptr
}
2016-09-03 23:57:44 +03:00
/// nodeT for each branch level
type nodeT struct {
count int ///< Count
level int ///< Leaf is zero, others positive
branch [maxNodes]branchT ///< Branch
2016-06-11 03:23:19 +03:00
}
2016-09-03 23:57:44 +03:00
func (node *nodeT) isInternalNode() bool {
2016-06-11 03:23:19 +03:00
return (node.level > 0) // Not a leaf, but a internal node
}
2016-09-03 23:57:44 +03:00
func (node *nodeT) isLeaf() bool {
2016-06-11 03:23:19 +03:00
return (node.level == 0) // A leaf, contains data
}
/// A link list of nodes for reinsertion after a delete operation
2016-09-03 23:57:44 +03:00
type listNodeT struct {
next *listNodeT ///< Next in list
node *nodeT ///< Node
2016-06-11 03:23:19 +03:00
}
2016-09-03 23:57:44 +03:00
const notTaken = -1 // indicates that position
2016-06-11 03:23:19 +03:00
/// Variables for finding a split partition
2016-09-03 23:57:44 +03:00
type partitionVarsT struct {
partition [maxNodes + 1]int
2016-06-11 03:23:19 +03:00
total int
minFill int
count [2]int
2016-09-03 23:57:44 +03:00
cover [2]rectT
2016-06-11 03:23:19 +03:00
area [2]float64
2016-09-03 23:57:44 +03:00
branchBuf [maxNodes + 1]branchT
2016-06-11 03:23:19 +03:00
branchCount int
2016-09-03 23:57:44 +03:00
coverSplit rectT
2016-06-11 03:23:19 +03:00
coverSplitArea float64
}
2016-09-03 23:57:44 +03:00
func New() *RTree {
2016-06-11 03:23:19 +03:00
// We only support machine word size simple data type eg. integer index or object pointer.
// Since we are storing as union with non data branch
return &RTree{
2016-09-03 23:57:44 +03:00
root: &nodeT{},
2016-06-11 03:23:19 +03:00
}
}
/// Insert entry
/// \param a_min Min of bounding rect
/// \param a_max Max of bounding rect
/// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed.
2016-09-03 23:57:44 +03:00
func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) {
var branch branchT
2016-06-11 03:23:19 +03:00
branch.data = dataId
2016-09-03 23:57:44 +03:00
for axis := 0; axis < numDims; axis++ {
2016-06-11 03:23:19 +03:00
branch.rect.min[axis] = min[axis]
branch.rect.max[axis] = max[axis]
}
2016-09-03 23:57:44 +03:00
insertRect(&branch, &tr.root, 0)
2016-06-11 03:23:19 +03:00
}
/// Remove entry
/// \param a_min Min of bounding rect
/// \param a_max Max of bounding rect
/// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed.
2016-09-03 23:57:44 +03:00
func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) {
var rect rectT
for axis := 0; axis < numDims; axis++ {
2016-06-11 03:23:19 +03:00
rect.min[axis] = min[axis]
rect.max[axis] = max[axis]
}
2016-09-03 23:57:44 +03:00
removeRect(&rect, dataId, &tr.root)
2016-06-11 03:23:19 +03:00
}
/// Find all within search rectangle
/// \param a_min Min of search bounding rect
/// \param a_max Max of search bounding rect
2016-09-03 23:57:44 +03:00
/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array.
2016-06-11 03:23:19 +03:00
/// \param a_resultCallback Callback function to return result. Callback should return 'true' to continue searching
/// \param a_context User context to pass as parameter to a_resultCallback
/// \return Returns the number of entries found
2016-09-03 23:57:44 +03:00
func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int {
var rect rectT
for axis := 0; axis < numDims; axis++ {
2016-06-11 03:23:19 +03:00
rect.min[axis] = min[axis]
rect.max[axis] = max[axis]
}
2016-09-03 23:57:44 +03:00
foundCount, _ := search(tr.root, rect, 0, resultCallback)
2016-06-11 03:23:19 +03:00
return foundCount
}
/// Count the data elements in this container. This is slow as no internal counter is maintained.
func (tr *RTree) Count() int {
var count int
2016-09-03 23:57:44 +03:00
countRec(tr.root, &count)
2016-06-11 03:23:19 +03:00
return count
}
/// Remove all entries from tree
func (tr *RTree) RemoveAll() {
// Delete all existing nodes
2016-09-03 23:57:44 +03:00
tr.root = &nodeT{}
2016-06-11 03:23:19 +03:00
}
2016-09-03 23:57:44 +03:00
func countRec(node *nodeT, count *int) {
if node.isInternalNode() { // not a leaf node
for index := 0; index < node.count; index++ {
countRec(node.branch[index].child, count)
}
} else { // A leaf node
*count += node.count
2016-06-11 03:23:19 +03:00
}
}
// Inserts a new data rectangle into the index structure.
// Recursively descends tree, propagates splits back up.
// Returns 0 if node was not split. Old node updated.
// If node was split, returns 1 and sets the pointer pointed to by
// new_node to point to the new node. Old node updated to become one of two.
// The level argument specifies the number of steps up from the leaf
// level to insert; e.g. a data rectangle goes in at level = 0.
2016-09-03 23:57:44 +03:00
func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool {
2016-06-11 03:23:19 +03:00
// recurse until we reach the correct level for the new record. data records
// will always be called with a_level == 0 (leaf)
if node.level > level {
// Still above level for insertion, go down tree recursively
2016-09-03 23:57:44 +03:00
var otherNode *nodeT
//var newBranch branchT
2016-06-11 03:23:19 +03:00
// find the optimal branch for this record
2016-09-03 23:57:44 +03:00
index := pickBranch(&branch.rect, node)
2016-06-11 03:23:19 +03:00
// recursively insert this record into the picked branch
2016-09-03 23:57:44 +03:00
childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level)
2016-06-11 03:23:19 +03:00
if !childWasSplit {
// Child was not split. Merge the bounding box of the new record with the
// existing bounding box
2016-09-03 23:57:44 +03:00
node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect))
2016-06-11 03:23:19 +03:00
return false
} else {
// Child was split. The old branches are now re-partitioned to two nodes
// so we have to re-calculate the bounding boxes of each node
2016-09-03 23:57:44 +03:00
node.branch[index].rect = nodeCover(node.branch[index].child)
var newBranch branchT
2016-06-11 03:23:19 +03:00
newBranch.child = otherNode
2016-09-03 23:57:44 +03:00
newBranch.rect = nodeCover(otherNode)
2016-06-11 03:23:19 +03:00
// The old node is already a child of a_node. Now add the newly-created
// node to a_node as well. a_node might be split because of that.
2016-09-03 23:57:44 +03:00
return addBranch(&newBranch, node, newNode)
2016-06-11 03:23:19 +03:00
}
} else if node.level == level {
// We have reached level for insertion. Add rect, split if necessary
2016-09-03 23:57:44 +03:00
return addBranch(branch, node, newNode)
2016-06-11 03:23:19 +03:00
} else {
// Should never occur
return false
}
}
// Insert a data rectangle into an index structure.
2016-09-03 23:57:44 +03:00
// insertRect provides for splitting the root;
2016-06-11 03:23:19 +03:00
// returns 1 if root was split, 0 if it was not.
// The level argument specifies the number of steps up from the leaf
// level to insert; e.g. a data rectangle goes in at level = 0.
// InsertRect2 does the recursion.
//
2016-09-03 23:57:44 +03:00
func insertRect(branch *branchT, root **nodeT, level int) bool {
var newNode *nodeT
2016-06-11 03:23:19 +03:00
2016-09-03 23:57:44 +03:00
if insertRectRec(branch, *root, &newNode, level) { // Root split
2016-06-11 03:23:19 +03:00
// Grow tree taller and new root
2016-09-03 23:57:44 +03:00
newRoot := &nodeT{}
2016-06-11 03:23:19 +03:00
newRoot.level = (*root).level + 1
2016-09-03 23:57:44 +03:00
var newBranch branchT
2016-06-11 03:23:19 +03:00
// add old root node as a child of the new root
2016-09-03 23:57:44 +03:00
newBranch.rect = nodeCover(*root)
2016-06-11 03:23:19 +03:00
newBranch.child = *root
2016-09-03 23:57:44 +03:00
addBranch(&newBranch, newRoot, nil)
2016-06-11 03:23:19 +03:00
// add the split node as a child of the new root
2016-09-03 23:57:44 +03:00
newBranch.rect = nodeCover(newNode)
2016-06-11 03:23:19 +03:00
newBranch.child = newNode
2016-09-03 23:57:44 +03:00
addBranch(&newBranch, newRoot, nil)
2016-06-11 03:23:19 +03:00
// set the new root as the root node
*root = newRoot
return true
}
return false
}
// Find the smallest rectangle that includes all rectangles in branches of a node.
2016-09-03 23:57:44 +03:00
func nodeCover(node *nodeT) rectT {
2016-06-11 03:23:19 +03:00
rect := node.branch[0].rect
for index := 1; index < node.count; index++ {
2016-09-03 23:57:44 +03:00
rect = combineRect(&rect, &(node.branch[index].rect))
2016-06-11 03:23:19 +03:00
}
return rect
}
// Add a branch to a node. Split the node if necessary.
// Returns 0 if node not split. Old node updated.
// Returns 1 if node split, sets *new_node to address of new node.
// Old node updated, becomes one of two.
2016-09-03 23:57:44 +03:00
func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool {
if node.count < maxNodes { // Split won't be necessary
2016-06-11 03:23:19 +03:00
node.branch[node.count] = *branch
node.count++
return false
} else {
2016-09-03 23:57:44 +03:00
splitNode(node, branch, newNode)
2016-06-11 03:23:19 +03:00
return true
}
}
// Disconnect a dependent node.
// Caller must return (or stop using iteration index) after this as count has changed
2016-09-03 23:57:44 +03:00
func disconnectBranch(node *nodeT, index int) {
2016-06-11 03:23:19 +03:00
// Remove element by swapping with the last element to prevent gaps in array
node.branch[index] = node.branch[node.count-1]
2016-06-12 03:28:47 +03:00
node.branch[node.count-1].data = nil
2016-06-12 15:55:35 +03:00
node.branch[node.count-1].child = nil
2016-06-11 03:23:19 +03:00
node.count--
}
// Pick a branch. Pick the one that will need the smallest increase
// in area to accomodate the new rectangle. This will result in the
// least total area for the covering rectangles in the current node.
// In case of a tie, pick the one which was smaller before, to get
// the best resolution when searching.
2016-09-03 23:57:44 +03:00
func pickBranch(rect *rectT, node *nodeT) int {
2016-06-11 03:23:19 +03:00
var firstTime bool = true
var increase float64
var bestIncr float64 = -1
var area float64
var bestArea float64
var best int
2016-09-03 23:57:44 +03:00
var tempRect rectT
2016-06-11 03:23:19 +03:00
for index := 0; index < node.count; index++ {
curRect := &node.branch[index].rect
2016-09-03 23:57:44 +03:00
area = calcRectVolume(curRect)
tempRect = combineRect(rect, curRect)
increase = calcRectVolume(&tempRect) - area
2016-06-11 03:23:19 +03:00
if (increase < bestIncr) || firstTime {
best = index
bestArea = area
bestIncr = increase
firstTime = false
} else if (increase == bestIncr) && (area < bestArea) {
best = index
bestArea = area
bestIncr = increase
}
}
return best
}
// Combine two rectangles into larger one containing both
2016-09-03 23:57:44 +03:00
func combineRect(rectA, rectB *rectT) rectT {
var newRect rectT
2016-06-11 03:23:19 +03:00
2016-09-03 23:57:44 +03:00
for index := 0; index < numDims; index++ {
newRect.min[index] = fmin(rectA.min[index], rectB.min[index])
newRect.max[index] = fmax(rectA.max[index], rectB.max[index])
2016-06-11 03:23:19 +03:00
}
return newRect
}
// Split a node.
// Divides the nodes branches and the extra one between two nodes.
// Old node is one of the new ones, and one really new one is created.
// Tries more than one method for choosing a partition, uses best result.
2016-09-03 23:57:44 +03:00
func splitNode(node *nodeT, branch *branchT, newNode **nodeT) {
2016-06-11 03:23:19 +03:00
// Could just use local here, but member or external is faster since it is reused
2016-09-03 23:57:44 +03:00
var localVars partitionVarsT
2016-06-11 03:23:19 +03:00
parVars := &localVars
// Load all the branches into a buffer, initialize old node
2016-09-03 23:57:44 +03:00
getBranches(node, branch, parVars)
2016-06-11 03:23:19 +03:00
// Find partition
2016-09-03 23:57:44 +03:00
choosePartition(parVars, minNodes)
2016-06-11 03:23:19 +03:00
// Create a new node to hold (about) half of the branches
2016-09-03 23:57:44 +03:00
*newNode = &nodeT{}
2016-06-11 03:23:19 +03:00
(*newNode).level = node.level
// Put branches from buffer into 2 nodes according to the chosen partition
node.count = 0
2016-09-03 23:57:44 +03:00
loadNodes(node, *newNode, parVars)
2016-06-11 03:23:19 +03:00
}
// Calculate the n-dimensional volume of a rectangle
2016-09-03 23:57:44 +03:00
func rectVolume(rect *rectT) float64 {
2016-06-11 03:23:19 +03:00
var volume float64 = 1
2016-09-03 23:57:44 +03:00
for index := 0; index < numDims; index++ {
2016-06-11 03:23:19 +03:00
volume *= rect.max[index] - rect.min[index]
}
return volume
}
2016-09-03 23:57:44 +03:00
// The exact volume of the bounding sphere for the given rectT
func rectSphericalVolume(rect *rectT) float64 {
2016-06-11 03:23:19 +03:00
var sumOfSquares float64 = 0
var radius float64
2016-09-03 23:57:44 +03:00
for index := 0; index < numDims; index++ {
2016-06-11 03:23:19 +03:00
halfExtent := (rect.max[index] - rect.min[index]) * 0.5
sumOfSquares += halfExtent * halfExtent
}
radius = math.Sqrt(sumOfSquares)
2016-07-22 01:30:24 +03:00
// Pow maybe slow, so test for common dims just use x*x, x*x*x.
2016-09-03 23:57:44 +03:00
if numDims == 5 {
2016-07-22 01:30:24 +03:00
return (radius * radius * radius * radius * radius * unitSphereVolume)
2016-09-03 23:57:44 +03:00
} else if numDims == 4 {
2016-06-11 03:23:19 +03:00
return (radius * radius * radius * radius * unitSphereVolume)
2016-09-03 23:57:44 +03:00
} else if numDims == 3 {
2016-06-11 03:23:19 +03:00
return (radius * radius * radius * unitSphereVolume)
2016-09-03 23:57:44 +03:00
} else if numDims == 2 {
2016-06-11 03:23:19 +03:00
return (radius * radius * unitSphereVolume)
} else {
2016-09-03 23:57:44 +03:00
return (math.Pow(radius, numDims) * unitSphereVolume)
2016-06-11 03:23:19 +03:00
}
}
// Use one of the methods to calculate retangle volume
2016-09-03 23:57:44 +03:00
func calcRectVolume(rect *rectT) float64 {
if useSphericalVolume {
return rectSphericalVolume(rect) // Slower but helps certain merge cases
2016-06-11 03:23:19 +03:00
} else { // RTREE_USE_SPHERICAL_VOLUME
2016-09-03 23:57:44 +03:00
return rectVolume(rect) // Faster but can cause poor merges
2016-06-11 03:23:19 +03:00
} // RTREE_USE_SPHERICAL_VOLUME
}
// Load branch buffer with branches from full node plus the extra branch.
2016-09-03 23:57:44 +03:00
func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) {
2016-06-11 03:23:19 +03:00
// Load the branch buffer
2016-09-03 23:57:44 +03:00
for index := 0; index < maxNodes; index++ {
2016-06-11 03:23:19 +03:00
parVars.branchBuf[index] = node.branch[index]
}
2016-09-03 23:57:44 +03:00
parVars.branchBuf[maxNodes] = *branch
parVars.branchCount = maxNodes + 1
2016-06-11 03:23:19 +03:00
// Calculate rect containing all in the set
parVars.coverSplit = parVars.branchBuf[0].rect
2016-09-03 23:57:44 +03:00
for index := 1; index < maxNodes+1; index++ {
parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect)
2016-06-11 03:23:19 +03:00
}
2016-09-03 23:57:44 +03:00
parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit)
2016-06-11 03:23:19 +03:00
}
// Method #0 for choosing a partition:
// As the seeds for the two groups, pick the two rects that would waste the
// most area if covered by a single rectangle, i.e. evidently the worst pair
// to have in the same group.
// Of the remaining, one at a time is chosen to be put in one of the two groups.
// The one chosen is the one with the greatest difference in area expansion
// depending on which group - the rect most strongly attracted to one group
// and repelled from the other.
// If one group gets too full (more would force other group to violate min
// fill requirement) then other group gets the rest.
// These last are the ones that can go in either group most easily.
2016-09-03 23:57:44 +03:00
func choosePartition(parVars *partitionVarsT, minFill int) {
2016-06-11 03:23:19 +03:00
var biggestDiff float64
var group, chosen, betterGroup int
2016-09-03 23:57:44 +03:00
initParVars(parVars, parVars.branchCount, minFill)
pickSeeds(parVars)
2016-06-11 03:23:19 +03:00
for ((parVars.count[0] + parVars.count[1]) < parVars.total) &&
(parVars.count[0] < (parVars.total - parVars.minFill)) &&
(parVars.count[1] < (parVars.total - parVars.minFill)) {
biggestDiff = -1
for index := 0; index < parVars.total; index++ {
2016-09-03 23:57:44 +03:00
if notTaken == parVars.partition[index] {
2016-06-11 03:23:19 +03:00
curRect := &parVars.branchBuf[index].rect
2016-09-03 23:57:44 +03:00
rect0 := combineRect(curRect, &parVars.cover[0])
rect1 := combineRect(curRect, &parVars.cover[1])
growth0 := calcRectVolume(&rect0) - parVars.area[0]
growth1 := calcRectVolume(&rect1) - parVars.area[1]
2016-06-11 03:23:19 +03:00
diff := growth1 - growth0
if diff >= 0 {
group = 0
} else {
group = 1
diff = -diff
}
if diff > biggestDiff {
biggestDiff = diff
chosen = index
betterGroup = group
} else if (diff == biggestDiff) && (parVars.count[group] < parVars.count[betterGroup]) {
chosen = index
betterGroup = group
}
}
}
2016-09-03 23:57:44 +03:00
classify(chosen, betterGroup, parVars)
2016-06-11 03:23:19 +03:00
}
// If one group too full, put remaining rects in the other
if (parVars.count[0] + parVars.count[1]) < parVars.total {
if parVars.count[0] >= parVars.total-parVars.minFill {
group = 1
} else {
group = 0
}
for index := 0; index < parVars.total; index++ {
2016-09-03 23:57:44 +03:00
if notTaken == parVars.partition[index] {
classify(index, group, parVars)
2016-06-11 03:23:19 +03:00
}
}
}
}
// Copy branches from the buffer into two nodes according to the partition.
2016-09-03 23:57:44 +03:00
func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) {
2016-06-11 03:23:19 +03:00
for index := 0; index < parVars.total; index++ {
targetNodeIndex := parVars.partition[index]
2016-09-03 23:57:44 +03:00
targetNodes := []*nodeT{nodeA, nodeB}
2016-06-11 03:23:19 +03:00
2016-09-03 23:57:44 +03:00
// It is assured that addBranch here will not cause a node split.
addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil)
2016-06-11 03:23:19 +03:00
}
}
2016-09-03 23:57:44 +03:00
// Initialize a partitionVarsT structure.
func initParVars(parVars *partitionVarsT, maxRects, minFill int) {
2016-06-11 03:23:19 +03:00
parVars.count[0] = 0
parVars.count[1] = 0
parVars.area[0] = 0
parVars.area[1] = 0
parVars.total = maxRects
parVars.minFill = minFill
for index := 0; index < maxRects; index++ {
2016-09-03 23:57:44 +03:00
parVars.partition[index] = notTaken
2016-06-11 03:23:19 +03:00
}
}
2016-09-03 23:57:44 +03:00
func pickSeeds(parVars *partitionVarsT) {
2016-06-11 03:23:19 +03:00
var seed0, seed1 int
var worst, waste float64
2016-09-03 23:57:44 +03:00
var area [maxNodes + 1]float64
2016-06-11 03:23:19 +03:00
for index := 0; index < parVars.total; index++ {
2016-09-03 23:57:44 +03:00
area[index] = calcRectVolume(&parVars.branchBuf[index].rect)
2016-06-11 03:23:19 +03:00
}
worst = -parVars.coverSplitArea - 1
for indexA := 0; indexA < parVars.total-1; indexA++ {
for indexB := indexA + 1; indexB < parVars.total; indexB++ {
2016-09-03 23:57:44 +03:00
oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect)
waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB]
2016-06-11 03:23:19 +03:00
if waste > worst {
worst = waste
seed0 = indexA
seed1 = indexB
}
}
}
2016-09-03 23:57:44 +03:00
classify(seed0, 0, parVars)
classify(seed1, 1, parVars)
2016-06-11 03:23:19 +03:00
}
// Put a branch in one of the groups.
2016-09-03 23:57:44 +03:00
func classify(index, group int, parVars *partitionVarsT) {
2016-06-11 03:23:19 +03:00
parVars.partition[index] = group
// Calculate combined rect
if parVars.count[group] == 0 {
parVars.cover[group] = parVars.branchBuf[index].rect
} else {
2016-09-03 23:57:44 +03:00
parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group])
2016-06-11 03:23:19 +03:00
}
// Calculate volume of combined rect
2016-09-03 23:57:44 +03:00
parVars.area[group] = calcRectVolume(&parVars.cover[group])
2016-06-11 03:23:19 +03:00
parVars.count[group]++
}
// Delete a data rectangle from an index structure.
2016-09-03 23:57:44 +03:00
// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node.
2016-06-11 03:23:19 +03:00
// Returns 1 if record not found, 0 if success.
2016-09-03 23:57:44 +03:00
// removeRect provides for eliminating the root.
func removeRect(rect *rectT, id interface{}, root **nodeT) bool {
var reInsertList *listNodeT
2016-06-11 03:23:19 +03:00
2016-09-03 23:57:44 +03:00
if !removeRectRec(rect, id, *root, &reInsertList) {
2016-06-11 03:23:19 +03:00
// Found and deleted a data item
// Reinsert any branches from eliminated nodes
for reInsertList != nil {
tempNode := reInsertList.node
for index := 0; index < tempNode.count; index++ {
// TODO go over this code. should I use (tempNode->m_level - 1)?
2016-09-03 23:57:44 +03:00
insertRect(&tempNode.branch[index], root, tempNode.level)
2016-06-11 03:23:19 +03:00
}
reInsertList = reInsertList.next
}
// Check for redundant root (not leaf, 1 child) and eliminate TODO replace
// if with while? In case there is a whole branch of redundant roots...
2016-09-03 23:57:44 +03:00
if (*root).count == 1 && (*root).isInternalNode() {
2016-06-11 03:23:19 +03:00
tempNode := (*root).branch[0].child
*root = tempNode
}
return false
} else {
return true
}
}
// Delete a rectangle from non-root part of an index structure.
2016-09-03 23:57:44 +03:00
// Called by removeRect. Descends tree recursively,
2016-06-11 03:23:19 +03:00
// merges branches on the way back up.
// Returns 1 if record not found, 0 if success.
2016-09-03 23:57:44 +03:00
func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool {
if node.isInternalNode() { // not a leaf node
2016-06-11 03:23:19 +03:00
for index := 0; index < node.count; index++ {
2016-09-03 23:57:44 +03:00
if overlap(*rect, node.branch[index].rect) {
if !removeRectRec(rect, id, node.branch[index].child, listNode) {
if node.branch[index].child.count >= minNodes {
2016-06-11 03:23:19 +03:00
// child removed, just resize parent rect
2016-09-03 23:57:44 +03:00
node.branch[index].rect = nodeCover(node.branch[index].child)
2016-06-11 03:23:19 +03:00
} else {
// child removed, not enough entries in node, eliminate node
2016-09-03 23:57:44 +03:00
reInsert(node.branch[index].child, listNode)
disconnectBranch(node, index) // Must return after this call as count has changed
2016-06-11 03:23:19 +03:00
}
return false
}
}
}
return true
} else { // A leaf node
for index := 0; index < node.count; index++ {
if node.branch[index].data == id {
2016-09-03 23:57:44 +03:00
disconnectBranch(node, index) // Must return after this call as count has changed
2016-06-11 03:23:19 +03:00
return false
}
}
return true
}
}
// Decide whether two rectangles overlap.
2016-09-03 23:57:44 +03:00
func overlap(rectA, rectB rectT) bool {
for index := 0; index < numDims; index++ {
2016-06-11 03:23:19 +03:00
if rectA.min[index] > rectB.max[index] ||
rectB.min[index] > rectA.max[index] {
return false
}
}
return true
}
// Add a node to the reinsertion list. All its branches will later
// be reinserted into the index structure.
2016-09-03 23:57:44 +03:00
func reInsert(node *nodeT, listNode **listNodeT) {
newListNode := &listNodeT{}
2016-06-11 03:23:19 +03:00
newListNode.node = node
newListNode.next = *listNode
*listNode = newListNode
}
2016-09-03 23:57:44 +03:00
// search in an index tree or subtree for all data retangles that overlap the argument rectangle.
func search(node *nodeT, rect rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) {
if node.isInternalNode() {
2016-06-11 03:23:19 +03:00
// This is an internal node in the tree
for index := 0; index < node.count; index++ {
2016-09-03 23:57:44 +03:00
if overlap(rect, node.branch[index].rect) {
2016-06-25 22:51:38 +03:00
var ok bool
2016-09-03 23:57:44 +03:00
foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback)
2016-06-25 22:51:38 +03:00
if !ok {
2016-06-11 03:23:19 +03:00
// The callback indicated to stop searching
2016-06-25 22:51:38 +03:00
return foundCount, false
2016-06-11 03:23:19 +03:00
}
}
}
} else {
// This is a leaf node
for index := 0; index < node.count; index++ {
2016-09-03 23:57:44 +03:00
if overlap(rect, node.branch[index].rect) {
2016-06-11 03:23:19 +03:00
id := node.branch[index].data
2016-06-25 22:51:38 +03:00
foundCount++
if !resultCallback(id) {
return foundCount, false // Don't continue searching
2016-06-11 03:23:19 +03:00
}
}
}
}
2016-06-25 22:51:38 +03:00
return foundCount, true // Continue searching
2016-06-11 03:23:19 +03:00
}