From d4a8a3d30d5729f85edfba1745241f3a621d0359 Mon Sep 17 00:00:00 2001 From: Josh Baker Date: Sat, 3 Sep 2016 14:37:29 -0700 Subject: [PATCH] combined --- .gitignore | 3 - dims/d1/rtree.go | 685 --- dims/d10/rtree.go | 685 --- dims/d11/rtree.go | 685 --- dims/d12/rtree.go | 685 --- dims/d13/rtree.go | 685 --- dims/d14/rtree.go | 685 --- dims/d15/rtree.go | 685 --- dims/d16/rtree.go | 685 --- dims/d17/rtree.go | 685 --- dims/d18/rtree.go | 685 --- dims/d19/rtree.go | 685 --- dims/d2/rtree.go | 685 --- dims/d20/rtree.go | 685 --- dims/d3/rtree.go | 685 --- dims/d4/rtree.go | 685 --- dims/d5/rtree.go | 685 --- dims/d6/rtree.go | 685 --- dims/d7/rtree.go | 685 --- dims/d8/rtree.go | 685 --- dims/d9/rtree.go | 685 --- gen/gen.go | 14 +- gen/gen.sh | 2 + gen/src/rtree.go | 15 +- gen/src/rtree_base.go | 358 +- rtree.go | 13248 +++++++++++++++++++++++++++++++++++++++- 26 files changed, 13355 insertions(+), 13985 deletions(-) delete mode 100644 .gitignore delete mode 100644 dims/d1/rtree.go delete mode 100644 dims/d10/rtree.go delete mode 100644 dims/d11/rtree.go delete mode 100644 dims/d12/rtree.go delete mode 100644 dims/d13/rtree.go delete mode 100644 dims/d14/rtree.go delete mode 100644 dims/d15/rtree.go delete mode 100644 dims/d16/rtree.go delete mode 100644 dims/d17/rtree.go delete mode 100644 dims/d18/rtree.go delete mode 100644 dims/d19/rtree.go delete mode 100644 dims/d2/rtree.go delete mode 100644 dims/d20/rtree.go delete mode 100644 dims/d3/rtree.go delete mode 100644 dims/d4/rtree.go delete mode 100644 dims/d5/rtree.go delete mode 100644 dims/d6/rtree.go delete mode 100644 dims/d7/rtree.go delete mode 100644 dims/d8/rtree.go delete mode 100644 dims/d9/rtree.go diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 2aad0e1..0000000 --- a/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.DS_Store -*.swp - diff --git a/dims/d1/rtree.go b/dims/d1/rtree.go deleted file mode 100644 index 20ac8b2..0000000 --- a/dims/d1/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 1 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d10/rtree.go b/dims/d10/rtree.go deleted file mode 100644 index 81504d8..0000000 --- a/dims/d10/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 10 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d11/rtree.go b/dims/d11/rtree.go deleted file mode 100644 index a3553e1..0000000 --- a/dims/d11/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 11 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d12/rtree.go b/dims/d12/rtree.go deleted file mode 100644 index 91e6992..0000000 --- a/dims/d12/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 12 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d13/rtree.go b/dims/d13/rtree.go deleted file mode 100644 index af9c67a..0000000 --- a/dims/d13/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 13 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d14/rtree.go b/dims/d14/rtree.go deleted file mode 100644 index 79dc36b..0000000 --- a/dims/d14/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 14 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d15/rtree.go b/dims/d15/rtree.go deleted file mode 100644 index 5ea5f24..0000000 --- a/dims/d15/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 15 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d16/rtree.go b/dims/d16/rtree.go deleted file mode 100644 index 6d2bc68..0000000 --- a/dims/d16/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 16 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d17/rtree.go b/dims/d17/rtree.go deleted file mode 100644 index 2a069fc..0000000 --- a/dims/d17/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 17 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d18/rtree.go b/dims/d18/rtree.go deleted file mode 100644 index e6c56b7..0000000 --- a/dims/d18/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 18 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d19/rtree.go b/dims/d19/rtree.go deleted file mode 100644 index 230f3a7..0000000 --- a/dims/d19/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 19 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d2/rtree.go b/dims/d2/rtree.go deleted file mode 100644 index 750460f..0000000 --- a/dims/d2/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 2 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d20/rtree.go b/dims/d20/rtree.go deleted file mode 100644 index 74246c3..0000000 --- a/dims/d20/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 20 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d3/rtree.go b/dims/d3/rtree.go deleted file mode 100644 index a8b840a..0000000 --- a/dims/d3/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 3 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d4/rtree.go b/dims/d4/rtree.go deleted file mode 100644 index 3c8688c..0000000 --- a/dims/d4/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 4 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d5/rtree.go b/dims/d5/rtree.go deleted file mode 100644 index 4094f9b..0000000 --- a/dims/d5/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 5 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d6/rtree.go b/dims/d6/rtree.go deleted file mode 100644 index 197df96..0000000 --- a/dims/d6/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 6 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d7/rtree.go b/dims/d7/rtree.go deleted file mode 100644 index 79444cf..0000000 --- a/dims/d7/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 7 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d8/rtree.go b/dims/d8/rtree.go deleted file mode 100644 index 51f2fef..0000000 --- a/dims/d8/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 8 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/dims/d9/rtree.go b/dims/d9/rtree.go deleted file mode 100644 index 402cec8..0000000 --- a/dims/d9/rtree.go +++ /dev/null @@ -1,685 +0,0 @@ -// generated; DO NOT EDIT! - -/* - -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" - -func fmin(a, b float64) float64 { - if a < b { - return a - } - return b -} -func fmax(a, b float64) float64 { - if a > b { - return a - } - return b -} - -const ( - numDims = 9 - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems -) - -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 -}[numDims] - -type RTree struct { - root *nodeT ///< Root of tree -} - -/// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box -} - -/// May be data or may be another subtree -/// The parents level determines this. -/// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node - data interface{} ///< Data Id or Ptr -} - -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch -} - -func (node *nodeT) isInternalNode() bool { - return (node.level > 0) // Not a leaf, but a internal node -} -func (node *nodeT) isLeaf() bool { - return (node.level == 0) // A leaf, contains data -} - -/// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node -} - -const notTaken = -1 // indicates that position - -/// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int - total int - minFill int - count [2]int - cover [2]rectT - area [2]float64 - - branchBuf [maxNodes + 1]branchT - branchCount int - coverSplit rectT - coverSplitArea float64 -} - -func New() *RTree { - // 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{ - root: &nodeT{}, - } -} - -/// 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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT - branch.data = dataId - for axis := 0; axis < numDims; axis++ { - branch.rect.min[axis] = min[axis] - branch.rect.max[axis] = max[axis] - } - insertRect(&branch, &tr.root, 0) -} - -/// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - removeRect(&rect, dataId, &tr.root) -} - -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. -/// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { - rect.min[axis] = min[axis] - rect.max[axis] = max[axis] - } - foundCount, _ := search(tr.root, rect, 0, resultCallback) - 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 - countRec(tr.root, &count) - return count -} - -/// Remove all entries from tree -func (tr *RTree) RemoveAll() { - // Delete all existing nodes - tr.root = &nodeT{} -} - -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 - } -} - -// 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { - // 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 - var otherNode *nodeT - //var newBranch branchT - - // find the optimal branch for this record - index := pickBranch(&branch.rect, node) - - // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) - - if !childWasSplit { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) - 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT - newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) - - // 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. - return addBranch(&newBranch, node, newNode) - } - } else if node.level == level { - // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) - } else { - // Should never occur - return false - } -} - -// Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; -// 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. -// -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT - - if insertRectRec(branch, *root, &newNode, level) { // Root split - - // Grow tree taller and new root - newRoot := &nodeT{} - newRoot.level = (*root).level + 1 - - var newBranch branchT - - // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) - newBranch.child = *root - addBranch(&newBranch, newRoot, nil) - - // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) - newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) - - // 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. -func nodeCover(node *nodeT) rectT { - rect := node.branch[0].rect - for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) - } - 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary - node.branch[node.count] = *branch - node.count++ - return false - } else { - splitNode(node, branch, newNode) - return true - } -} - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { - // Remove element by swapping with the last element to prevent gaps in array - node.branch[index] = node.branch[node.count-1] - node.branch[node.count-1].data = nil - node.branch[node.count-1].child = nil - 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. -func pickBranch(rect *rectT, node *nodeT) int { - var firstTime bool = true - var increase float64 - var bestIncr float64 = -1 - var area float64 - var bestArea float64 - var best int - var tempRect rectT - - for index := 0; index < node.count; index++ { - curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area - 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 -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT - - 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]) - } - - 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { - // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT - parVars := &localVars - - // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) - - // Find partition - choosePartition(parVars, minNodes) - - // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} - (*newNode).level = node.level - - // Put branches from buffer into 2 nodes according to the chosen partition - node.count = 0 - loadNodes(node, *newNode, parVars) -} - -// Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { - var volume float64 = 1 - for index := 0; index < numDims; index++ { - volume *= rect.max[index] - rect.min[index] - } - return volume -} - -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { - var sumOfSquares float64 = 0 - var radius float64 - - for index := 0; index < numDims; index++ { - halfExtent := (rect.max[index] - rect.min[index]) * 0.5 - sumOfSquares += halfExtent * halfExtent - } - - radius = math.Sqrt(sumOfSquares) - - // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) - } else { - return (math.Pow(radius, numDims) * unitSphereVolume) - } -} - -// Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases - } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges - } // RTREE_USE_SPHERICAL_VOLUME -} - -// Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { - // Load the branch buffer - for index := 0; index < maxNodes; index++ { - parVars.branchBuf[index] = node.branch[index] - } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 - - // Calculate rect containing all in the set - parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) - } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) -} - -// 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. -func choosePartition(parVars *partitionVarsT, minFill int) { - var biggestDiff float64 - var group, chosen, betterGroup int - - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) - - 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++ { - if notTaken == parVars.partition[index] { - curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] - 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 - } - } - } - classify(chosen, betterGroup, parVars) - } - - // 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++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) - } - } - } -} - -// Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { - for index := 0; index < parVars.total; index++ { - targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} - - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) - } -} - -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { - 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++ { - parVars.partition[index] = notTaken - } -} - -func pickSeeds(parVars *partitionVarsT) { - var seed0, seed1 int - var worst, waste float64 - var area [maxNodes + 1]float64 - - for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) - } - - worst = -parVars.coverSplitArea - 1 - for indexA := 0; indexA < parVars.total-1; indexA++ { - for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] - if waste > worst { - worst = waste - seed0 = indexA - seed1 = indexB - } - } - } - - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) -} - -// Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { - parVars.partition[index] = group - - // Calculate combined rect - if parVars.count[group] == 0 { - parVars.cover[group] = parVars.branchBuf[index].rect - } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) - } - - // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) - - parVars.count[group]++ -} - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT - - if !removeRectRec(rect, id, *root, &reInsertList) { - // 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)? - insertRect(&tempNode.branch[index], root, tempNode.level) - } - 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... - if (*root).count == 1 && (*root).isInternalNode() { - tempNode := (*root).branch[0].child - *root = tempNode - } - return false - } else { - return true - } -} - -// Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { - if node.isInternalNode() { // not a leaf node - for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { - // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) - } else { - // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed - } - return false - } - } - } - return true - } else { // A leaf node - for index := 0; index < node.count; index++ { - if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed - return false - } - } - return true - } -} - -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { - 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. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} - newListNode.node = node - newListNode.next = *listNode - *listNode = newListNode -} - -// 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() { - // This is an internal node in the tree - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) - if !ok { - // The callback indicated to stop searching - return foundCount, false - } - } - } - } else { - // This is a leaf node - for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { - id := node.branch[index].data - foundCount++ - if !resultCallback(id) { - return foundCount, false // Don't continue searching - } - - } - } - } - return foundCount, true // Continue searching -} diff --git a/gen/gen.go b/gen/gen.go index d5cea17..2a70992 100644 --- a/gen/gen.go +++ b/gen/gen.go @@ -58,9 +58,6 @@ func main() { output += line + "\n" } } - if err := ioutil.WriteFile("../rtree.go", []byte(output), 0666); err != nil { - log.Fatal(err) - } // process rtree_base.go if err := os.RemoveAll("../dims"); err != nil { log.Fatal(err) @@ -71,19 +68,20 @@ func main() { if err != nil { log.Fatal(err) } - data = []byte(strings.Replace(string(data), "// +build ignore", "// generated; DO NOT EDIT!", -1)) + data = []byte(strings.Split(string(data), "// FILE_START")[1]) if debug { data = []byte(strings.Replace(string(data), "TDEBUG", "true", -1)) } else { data = []byte(strings.Replace(string(data), "TDEBUG", "false", -1)) } data = []byte(strings.Replace(string(data), "TNUMDIMS", strconv.FormatInt(int64(i+1), 10), -1)) + data = []byte(strings.Replace(string(data), "DD_", "d"+strconv.FormatInt(int64(i+1), 10), -1)) if err := os.MkdirAll("../dims/d"+sdim, 0777); err != nil { log.Fatal(err) } - if err := ioutil.WriteFile("../dims/d"+sdim+"/rtree.go", data, 0666); err != nil { - log.Fatal(err) - } + output = string(append([]byte(output), data...)) + } + if err := ioutil.WriteFile("../rtree.go", []byte(output), 0666); err != nil { + log.Fatal(err) } - } diff --git a/gen/gen.sh b/gen/gen.sh index 1410380..edf3189 100755 --- a/gen/gen.sh +++ b/gen/gen.sh @@ -5,3 +5,5 @@ set -e cd $(dirname "${BASH_SOURCE[0]}") go run gen.go --dims=20 --debug=false +cd .. +go fmt diff --git a/gen/src/rtree.go b/gen/src/rtree.go index 4e9a4ff..5c1a438 100644 --- a/gen/src/rtree.go +++ b/gen/src/rtree.go @@ -1,13 +1,8 @@ // +build ignore + package rtree -import ( - "math" - - // BEGIN - dTNUMDIMS "github.com/tidwall/rtree/dims/dTNUMDIMS" - // END -) +import "math" type Iterator func(item Item) bool type Item interface { @@ -17,7 +12,7 @@ type Item interface { type RTree struct { ctx interface{} // BEGIN - trTNUMDIMS *dTNUMDIMS.RTree + trTNUMDIMS *dTNUMDIMSRTree // END } @@ -25,7 +20,7 @@ func New(ctx interface{}) *RTree { return &RTree{ ctx: ctx, // BEGIN - trTNUMDIMS: dTNUMDIMS.New(), + trTNUMDIMS: dTNUMDIMSNew(), // END } } @@ -79,7 +74,7 @@ func (tr *RTree) Remove(item Item) { } func (tr *RTree) Reset() { // BEGIN - tr.trTNUMDIMS = dTNUMDIMS.New() + tr.trTNUMDIMS = dTNUMDIMSNew() // END } func (tr *RTree) Count() int { diff --git a/gen/src/rtree_base.go b/gen/src/rtree_base.go index 4a361e4..81d2163 100644 --- a/gen/src/rtree_base.go +++ b/gen/src/rtree_base.go @@ -29,13 +29,15 @@ package rtree import "math" -func fmin(a, b float64) float64 { +// FILE_START + +func DD_fmin(a, b float64) float64 { if a < b { return a } return b } -func fmax(a, b float64) float64 { +func DD_fmax(a, b float64) float64 { if a > b { return a } @@ -43,13 +45,13 @@ func fmax(a, b float64) float64 { } const ( - numDims = TNUMDIMS - maxNodes = 8 - minNodes = maxNodes / 2 - useSphericalVolume = true // Better split classification, may be slower on some systems + DD_numDims = TNUMDIMS + DD_maxNodes = 8 + DD_minNodes = DD_maxNodes / 2 + DD_useSphericalVolume = true // Better split classification, may be slower on some systems ) -var unitSphereVolume = []float64{ +var DD_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 @@ -57,69 +59,69 @@ var unitSphereVolume = []float64{ 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 -}[numDims] +}[DD_numDims] -type RTree struct { - root *nodeT ///< Root of tree +type DD_RTree struct { + root *DD_nodeT ///< Root of tree } /// Minimal bounding rectangle (n-dimensional) -type rectT struct { - min [numDims]float64 ///< Min dimensions of bounding box - max [numDims]float64 ///< Max dimensions of bounding box +type DD_rectT struct { + min [DD_numDims]float64 ///< Min dimensions of bounding box + max [DD_numDims]float64 ///< Max dimensions of bounding box } /// May be data or may be another subtree /// The parents level determines this. /// If the parents level is 0, then this is data -type branchT struct { - rect rectT ///< Bounds - child *nodeT ///< Child node +type DD_branchT struct { + rect DD_rectT ///< Bounds + child *DD_nodeT ///< Child node data interface{} ///< Data Id or Ptr } -/// nodeT for each branch level -type nodeT struct { - count int ///< Count - level int ///< Leaf is zero, others positive - branch [maxNodes]branchT ///< Branch +/// DD_nodeT for each branch level +type DD_nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [DD_maxNodes]DD_branchT ///< Branch } -func (node *nodeT) isInternalNode() bool { +func (node *DD_nodeT) isInternalNode() bool { return (node.level > 0) // Not a leaf, but a internal node } -func (node *nodeT) isLeaf() bool { +func (node *DD_nodeT) isLeaf() bool { return (node.level == 0) // A leaf, contains data } /// A link list of nodes for reinsertion after a delete operation -type listNodeT struct { - next *listNodeT ///< Next in list - node *nodeT ///< Node +type DD_listNodeT struct { + next *DD_listNodeT ///< Next in list + node *DD_nodeT ///< Node } -const notTaken = -1 // indicates that position +const DD_notTaken = -1 // indicates that position /// Variables for finding a split partition -type partitionVarsT struct { - partition [maxNodes + 1]int +type DD_partitionVarsT struct { + partition [DD_maxNodes + 1]int total int minFill int count [2]int - cover [2]rectT + cover [2]DD_rectT area [2]float64 - branchBuf [maxNodes + 1]branchT + branchBuf [DD_maxNodes + 1]DD_branchT branchCount int - coverSplit rectT + coverSplit DD_rectT coverSplitArea float64 } -func New() *RTree { +func DD_New() *DD_RTree { // 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{ - root: &nodeT{}, + return &DD_RTree{ + root: &DD_nodeT{}, } } @@ -127,63 +129,63 @@ func New() *RTree { /// \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. -func (tr *RTree) Insert(min, max [numDims]float64, dataId interface{}) { - var branch branchT +func (tr *DD_RTree) Insert(min, max [DD_numDims]float64, dataId interface{}) { + var branch DD_branchT branch.data = dataId - for axis := 0; axis < numDims; axis++ { + for axis := 0; axis < DD_numDims; axis++ { branch.rect.min[axis] = min[axis] branch.rect.max[axis] = max[axis] } - insertRect(&branch, &tr.root, 0) + DD_insertRect(&branch, &tr.root, 0) } /// 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. -func (tr *RTree) Remove(min, max [numDims]float64, dataId interface{}) { - var rect rectT - for axis := 0; axis < numDims; axis++ { +func (tr *DD_RTree) Remove(min, max [DD_numDims]float64, dataId interface{}) { + var rect DD_rectT + for axis := 0; axis < DD_numDims; axis++ { rect.min[axis] = min[axis] rect.max[axis] = max[axis] } - removeRect(&rect, dataId, &tr.root) + DD_removeRect(&rect, dataId, &tr.root) } -/// Find all within search rectangle -/// \param a_min Min of search bounding rect -/// \param a_max Max of search bounding rect -/// \param a_searchResult search result array. Caller should set grow size. Function will reset, not append to array. +/// Find all within DD_search rectangle +/// \param a_min Min of DD_search bounding rect +/// \param a_max Max of DD_search bounding rect +/// \param a_searchResult DD_search result array. Caller should set grow size. Function will reset, not append to array. /// \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 -func (tr *RTree) Search(min, max [numDims]float64, resultCallback func(data interface{}) bool) int { - var rect rectT - for axis := 0; axis < numDims; axis++ { +func (tr *DD_RTree) Search(min, max [DD_numDims]float64, resultCallback func(data interface{}) bool) int { + var rect DD_rectT + for axis := 0; axis < DD_numDims; axis++ { rect.min[axis] = min[axis] rect.max[axis] = max[axis] } - foundCount, _ := search(tr.root, rect, 0, resultCallback) + foundCount, _ := DD_search(tr.root, rect, 0, resultCallback) return foundCount } /// Count the data elements in this container. This is slow as no internal counter is maintained. -func (tr *RTree) Count() int { +func (tr *DD_RTree) Count() int { var count int - countRec(tr.root, &count) + DD_countRec(tr.root, &count) return count } /// Remove all entries from tree -func (tr *RTree) RemoveAll() { +func (tr *DD_RTree) RemoveAll() { // Delete all existing nodes - tr.root = &nodeT{} + tr.root = &DD_nodeT{} } -func countRec(node *nodeT, count *int) { +func DD_countRec(node *DD_nodeT, count *int) { if node.isInternalNode() { // not a leaf node for index := 0; index < node.count; index++ { - countRec(node.branch[index].child, count) + DD_countRec(node.branch[index].child, count) } } else { // A leaf node *count += node.count @@ -197,40 +199,40 @@ func countRec(node *nodeT, count *int) { // 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. -func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) bool { +func DD_insertRectRec(branch *DD_branchT, node *DD_nodeT, newNode **DD_nodeT, level int) bool { // 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 - var otherNode *nodeT - //var newBranch branchT + var otherNode *DD_nodeT + //var newBranch DD_branchT // find the optimal branch for this record - index := pickBranch(&branch.rect, node) + index := DD_pickBranch(&branch.rect, node) // recursively insert this record into the picked branch - childWasSplit := insertRectRec(branch, node.branch[index].child, &otherNode, level) + childWasSplit := DD_insertRectRec(branch, node.branch[index].child, &otherNode, level) if !childWasSplit { // Child was not split. Merge the bounding box of the new record with the // existing bounding box - node.branch[index].rect = combineRect(&branch.rect, &(node.branch[index].rect)) + node.branch[index].rect = DD_combineRect(&branch.rect, &(node.branch[index].rect)) 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 - node.branch[index].rect = nodeCover(node.branch[index].child) - var newBranch branchT + node.branch[index].rect = DD_nodeCover(node.branch[index].child) + var newBranch DD_branchT newBranch.child = otherNode - newBranch.rect = nodeCover(otherNode) + newBranch.rect = DD_nodeCover(otherNode) // 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. - return addBranch(&newBranch, node, newNode) + return DD_addBranch(&newBranch, node, newNode) } } else if node.level == level { // We have reached level for insertion. Add rect, split if necessary - return addBranch(branch, node, newNode) + return DD_addBranch(branch, node, newNode) } else { // Should never occur return false @@ -238,32 +240,32 @@ func insertRectRec(branch *branchT, node *nodeT, newNode **nodeT, level int) boo } // Insert a data rectangle into an index structure. -// insertRect provides for splitting the root; +// DD_insertRect provides for splitting the root; // 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. // -func insertRect(branch *branchT, root **nodeT, level int) bool { - var newNode *nodeT +func DD_insertRect(branch *DD_branchT, root **DD_nodeT, level int) bool { + var newNode *DD_nodeT - if insertRectRec(branch, *root, &newNode, level) { // Root split + if DD_insertRectRec(branch, *root, &newNode, level) { // Root split // Grow tree taller and new root - newRoot := &nodeT{} + newRoot := &DD_nodeT{} newRoot.level = (*root).level + 1 - var newBranch branchT + var newBranch DD_branchT // add old root node as a child of the new root - newBranch.rect = nodeCover(*root) + newBranch.rect = DD_nodeCover(*root) newBranch.child = *root - addBranch(&newBranch, newRoot, nil) + DD_addBranch(&newBranch, newRoot, nil) // add the split node as a child of the new root - newBranch.rect = nodeCover(newNode) + newBranch.rect = DD_nodeCover(newNode) newBranch.child = newNode - addBranch(&newBranch, newRoot, nil) + DD_addBranch(&newBranch, newRoot, nil) // set the new root as the root node *root = newRoot @@ -274,10 +276,10 @@ func insertRect(branch *branchT, root **nodeT, level int) bool { } // Find the smallest rectangle that includes all rectangles in branches of a node. -func nodeCover(node *nodeT) rectT { +func DD_nodeCover(node *DD_nodeT) DD_rectT { rect := node.branch[0].rect for index := 1; index < node.count; index++ { - rect = combineRect(&rect, &(node.branch[index].rect)) + rect = DD_combineRect(&rect, &(node.branch[index].rect)) } return rect } @@ -286,20 +288,20 @@ func nodeCover(node *nodeT) rectT { // 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. -func addBranch(branch *branchT, node *nodeT, newNode **nodeT) bool { - if node.count < maxNodes { // Split won't be necessary +func DD_addBranch(branch *DD_branchT, node *DD_nodeT, newNode **DD_nodeT) bool { + if node.count < DD_maxNodes { // Split won't be necessary node.branch[node.count] = *branch node.count++ return false } else { - splitNode(node, branch, newNode) + DD_splitNode(node, branch, newNode) return true } } // Disconnect a dependent node. // Caller must return (or stop using iteration index) after this as count has changed -func disconnectBranch(node *nodeT, index int) { +func DD_disconnectBranch(node *DD_nodeT, index int) { // Remove element by swapping with the last element to prevent gaps in array node.branch[index] = node.branch[node.count-1] node.branch[node.count-1].data = nil @@ -312,20 +314,20 @@ func disconnectBranch(node *nodeT, index int) { // 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. -func pickBranch(rect *rectT, node *nodeT) int { +func DD_pickBranch(rect *DD_rectT, node *DD_nodeT) int { var firstTime bool = true var increase float64 var bestIncr float64 = -1 var area float64 var bestArea float64 var best int - var tempRect rectT + var tempRect DD_rectT for index := 0; index < node.count; index++ { curRect := &node.branch[index].rect - area = calcRectVolume(curRect) - tempRect = combineRect(rect, curRect) - increase = calcRectVolume(&tempRect) - area + area = DD_calcRectVolume(curRect) + tempRect = DD_combineRect(rect, curRect) + increase = DD_calcRectVolume(&tempRect) - area if (increase < bestIncr) || firstTime { best = index bestArea = area @@ -341,12 +343,12 @@ func pickBranch(rect *rectT, node *nodeT) int { } // Combine two rectangles into larger one containing both -func combineRect(rectA, rectB *rectT) rectT { - var newRect rectT +func DD_combineRect(rectA, rectB *DD_rectT) DD_rectT { + var newRect DD_rectT - 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]) + for index := 0; index < DD_numDims; index++ { + newRect.min[index] = DD_fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = DD_fmax(rectA.max[index], rectB.max[index]) } return newRect @@ -356,41 +358,41 @@ func combineRect(rectA, rectB *rectT) rectT { // 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. -func splitNode(node *nodeT, branch *branchT, newNode **nodeT) { +func DD_splitNode(node *DD_nodeT, branch *DD_branchT, newNode **DD_nodeT) { // Could just use local here, but member or external is faster since it is reused - var localVars partitionVarsT + var localVars DD_partitionVarsT parVars := &localVars // Load all the branches into a buffer, initialize old node - getBranches(node, branch, parVars) + DD_getBranches(node, branch, parVars) // Find partition - choosePartition(parVars, minNodes) + DD_choosePartition(parVars, DD_minNodes) // Create a new node to hold (about) half of the branches - *newNode = &nodeT{} + *newNode = &DD_nodeT{} (*newNode).level = node.level // Put branches from buffer into 2 nodes according to the chosen partition node.count = 0 - loadNodes(node, *newNode, parVars) + DD_loadNodes(node, *newNode, parVars) } // Calculate the n-dimensional volume of a rectangle -func rectVolume(rect *rectT) float64 { +func DD_rectVolume(rect *DD_rectT) float64 { var volume float64 = 1 - for index := 0; index < numDims; index++ { + for index := 0; index < DD_numDims; index++ { volume *= rect.max[index] - rect.min[index] } return volume } -// The exact volume of the bounding sphere for the given rectT -func rectSphericalVolume(rect *rectT) float64 { +// The exact volume of the bounding sphere for the given DD_rectT +func DD_rectSphericalVolume(rect *DD_rectT) float64 { var sumOfSquares float64 = 0 var radius float64 - for index := 0; index < numDims; index++ { + for index := 0; index < DD_numDims; index++ { halfExtent := (rect.max[index] - rect.min[index]) * 0.5 sumOfSquares += halfExtent * halfExtent } @@ -398,43 +400,43 @@ func rectSphericalVolume(rect *rectT) float64 { radius = math.Sqrt(sumOfSquares) // Pow maybe slow, so test for common dims just use x*x, x*x*x. - if numDims == 5 { - return (radius * radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 4 { - return (radius * radius * radius * radius * unitSphereVolume) - } else if numDims == 3 { - return (radius * radius * radius * unitSphereVolume) - } else if numDims == 2 { - return (radius * radius * unitSphereVolume) + if DD_numDims == 5 { + return (radius * radius * radius * radius * radius * DD_unitSphereVolume) + } else if DD_numDims == 4 { + return (radius * radius * radius * radius * DD_unitSphereVolume) + } else if DD_numDims == 3 { + return (radius * radius * radius * DD_unitSphereVolume) + } else if DD_numDims == 2 { + return (radius * radius * DD_unitSphereVolume) } else { - return (math.Pow(radius, numDims) * unitSphereVolume) + return (math.Pow(radius, DD_numDims) * DD_unitSphereVolume) } } // Use one of the methods to calculate retangle volume -func calcRectVolume(rect *rectT) float64 { - if useSphericalVolume { - return rectSphericalVolume(rect) // Slower but helps certain merge cases +func DD_calcRectVolume(rect *DD_rectT) float64 { + if DD_useSphericalVolume { + return DD_rectSphericalVolume(rect) // Slower but helps certain merge cases } else { // RTREE_USE_SPHERICAL_VOLUME - return rectVolume(rect) // Faster but can cause poor merges + return DD_rectVolume(rect) // Faster but can cause poor merges } // RTREE_USE_SPHERICAL_VOLUME } // Load branch buffer with branches from full node plus the extra branch. -func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { +func DD_getBranches(node *DD_nodeT, branch *DD_branchT, parVars *DD_partitionVarsT) { // Load the branch buffer - for index := 0; index < maxNodes; index++ { + for index := 0; index < DD_maxNodes; index++ { parVars.branchBuf[index] = node.branch[index] } - parVars.branchBuf[maxNodes] = *branch - parVars.branchCount = maxNodes + 1 + parVars.branchBuf[DD_maxNodes] = *branch + parVars.branchCount = DD_maxNodes + 1 // Calculate rect containing all in the set parVars.coverSplit = parVars.branchBuf[0].rect - for index := 1; index < maxNodes+1; index++ { - parVars.coverSplit = combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + for index := 1; index < DD_maxNodes+1; index++ { + parVars.coverSplit = DD_combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) } - parVars.coverSplitArea = calcRectVolume(&parVars.coverSplit) + parVars.coverSplitArea = DD_calcRectVolume(&parVars.coverSplit) } // Method #0 for choosing a partition: @@ -448,24 +450,24 @@ func getBranches(node *nodeT, branch *branchT, parVars *partitionVarsT) { // 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. -func choosePartition(parVars *partitionVarsT, minFill int) { +func DD_choosePartition(parVars *DD_partitionVarsT, minFill int) { var biggestDiff float64 var group, chosen, betterGroup int - initParVars(parVars, parVars.branchCount, minFill) - pickSeeds(parVars) + DD_initParVars(parVars, parVars.branchCount, minFill) + DD_pickSeeds(parVars) 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++ { - if notTaken == parVars.partition[index] { + if DD_notTaken == parVars.partition[index] { curRect := &parVars.branchBuf[index].rect - rect0 := combineRect(curRect, &parVars.cover[0]) - rect1 := combineRect(curRect, &parVars.cover[1]) - growth0 := calcRectVolume(&rect0) - parVars.area[0] - growth1 := calcRectVolume(&rect1) - parVars.area[1] + rect0 := DD_combineRect(curRect, &parVars.cover[0]) + rect1 := DD_combineRect(curRect, &parVars.cover[1]) + growth0 := DD_calcRectVolume(&rect0) - parVars.area[0] + growth1 := DD_calcRectVolume(&rect1) - parVars.area[1] diff := growth1 - growth0 if diff >= 0 { group = 0 @@ -484,7 +486,7 @@ func choosePartition(parVars *partitionVarsT, minFill int) { } } } - classify(chosen, betterGroup, parVars) + DD_classify(chosen, betterGroup, parVars) } // If one group too full, put remaining rects in the other @@ -495,26 +497,26 @@ func choosePartition(parVars *partitionVarsT, minFill int) { group = 0 } for index := 0; index < parVars.total; index++ { - if notTaken == parVars.partition[index] { - classify(index, group, parVars) + if DD_notTaken == parVars.partition[index] { + DD_classify(index, group, parVars) } } } } // Copy branches from the buffer into two nodes according to the partition. -func loadNodes(nodeA, nodeB *nodeT, parVars *partitionVarsT) { +func DD_loadNodes(nodeA, nodeB *DD_nodeT, parVars *DD_partitionVarsT) { for index := 0; index < parVars.total; index++ { targetNodeIndex := parVars.partition[index] - targetNodes := []*nodeT{nodeA, nodeB} + targetNodes := []*DD_nodeT{nodeA, nodeB} - // It is assured that addBranch here will not cause a node split. - addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + // It is assured that DD_addBranch here will not cause a node split. + DD_addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) } } -// Initialize a partitionVarsT structure. -func initParVars(parVars *partitionVarsT, maxRects, minFill int) { +// Initialize a DD_partitionVarsT structure. +func DD_initParVars(parVars *DD_partitionVarsT, maxRects, minFill int) { parVars.count[0] = 0 parVars.count[1] = 0 parVars.area[0] = 0 @@ -522,24 +524,24 @@ func initParVars(parVars *partitionVarsT, maxRects, minFill int) { parVars.total = maxRects parVars.minFill = minFill for index := 0; index < maxRects; index++ { - parVars.partition[index] = notTaken + parVars.partition[index] = DD_notTaken } } -func pickSeeds(parVars *partitionVarsT) { +func DD_pickSeeds(parVars *DD_partitionVarsT) { var seed0, seed1 int var worst, waste float64 - var area [maxNodes + 1]float64 + var area [DD_maxNodes + 1]float64 for index := 0; index < parVars.total; index++ { - area[index] = calcRectVolume(&parVars.branchBuf[index].rect) + area[index] = DD_calcRectVolume(&parVars.branchBuf[index].rect) } worst = -parVars.coverSplitArea - 1 for indexA := 0; indexA < parVars.total-1; indexA++ { for indexB := indexA + 1; indexB < parVars.total; indexB++ { - oneRect := combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) - waste = calcRectVolume(&oneRect) - area[indexA] - area[indexB] + oneRect := DD_combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = DD_calcRectVolume(&oneRect) - area[indexA] - area[indexB] if waste > worst { worst = waste seed0 = indexA @@ -548,35 +550,35 @@ func pickSeeds(parVars *partitionVarsT) { } } - classify(seed0, 0, parVars) - classify(seed1, 1, parVars) + DD_classify(seed0, 0, parVars) + DD_classify(seed1, 1, parVars) } // Put a branch in one of the groups. -func classify(index, group int, parVars *partitionVarsT) { +func DD_classify(index, group int, parVars *DD_partitionVarsT) { parVars.partition[index] = group // Calculate combined rect if parVars.count[group] == 0 { parVars.cover[group] = parVars.branchBuf[index].rect } else { - parVars.cover[group] = combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + parVars.cover[group] = DD_combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) } // Calculate volume of combined rect - parVars.area[group] = calcRectVolume(&parVars.cover[group]) + parVars.area[group] = DD_calcRectVolume(&parVars.cover[group]) parVars.count[group]++ } // Delete a data rectangle from an index structure. -// Pass in a pointer to a rectT, the tid of the record, ptr to ptr to root node. +// Pass in a pointer to a DD_rectT, the tid of the record, ptr to ptr to root node. // Returns 1 if record not found, 0 if success. -// removeRect provides for eliminating the root. -func removeRect(rect *rectT, id interface{}, root **nodeT) bool { - var reInsertList *listNodeT +// DD_removeRect provides for eliminating the root. +func DD_removeRect(rect *DD_rectT, id interface{}, root **DD_nodeT) bool { + var reInsertList *DD_listNodeT - if !removeRectRec(rect, id, *root, &reInsertList) { + if !DD_removeRectRec(rect, id, *root, &reInsertList) { // Found and deleted a data item // Reinsert any branches from eliminated nodes for reInsertList != nil { @@ -584,7 +586,7 @@ func removeRect(rect *rectT, id interface{}, root **nodeT) bool { for index := 0; index < tempNode.count; index++ { // TODO go over this code. should I use (tempNode->m_level - 1)? - insertRect(&tempNode.branch[index], root, tempNode.level) + DD_insertRect(&tempNode.branch[index], root, tempNode.level) } reInsertList = reInsertList.next } @@ -602,21 +604,21 @@ func removeRect(rect *rectT, id interface{}, root **nodeT) bool { } // Delete a rectangle from non-root part of an index structure. -// Called by removeRect. Descends tree recursively, +// Called by DD_removeRect. Descends tree recursively, // merges branches on the way back up. // Returns 1 if record not found, 0 if success. -func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNodeT) bool { +func DD_removeRectRec(rect *DD_rectT, id interface{}, node *DD_nodeT, listNode **DD_listNodeT) bool { if node.isInternalNode() { // not a leaf node for index := 0; index < node.count; index++ { - if overlap(*rect, node.branch[index].rect) { - if !removeRectRec(rect, id, node.branch[index].child, listNode) { - if node.branch[index].child.count >= minNodes { + if DD_overlap(*rect, node.branch[index].rect) { + if !DD_removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= DD_minNodes { // child removed, just resize parent rect - node.branch[index].rect = nodeCover(node.branch[index].child) + node.branch[index].rect = DD_nodeCover(node.branch[index].child) } else { // child removed, not enough entries in node, eliminate node - reInsert(node.branch[index].child, listNode) - disconnectBranch(node, index) // Must return after this call as count has changed + DD_reInsert(node.branch[index].child, listNode) + DD_disconnectBranch(node, index) // Must return after this call as count has changed } return false } @@ -626,7 +628,7 @@ func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNode } else { // A leaf node for index := 0; index < node.count; index++ { if node.branch[index].data == id { - disconnectBranch(node, index) // Must return after this call as count has changed + DD_disconnectBranch(node, index) // Must return after this call as count has changed return false } } @@ -634,9 +636,9 @@ func removeRectRec(rect *rectT, id interface{}, node *nodeT, listNode **listNode } } -// Decide whether two rectangles overlap. -func overlap(rectA, rectB rectT) bool { - for index := 0; index < numDims; index++ { +// Decide whether two rectangles DD_overlap. +func DD_overlap(rectA, rectB DD_rectT) bool { + for index := 0; index < DD_numDims; index++ { if rectA.min[index] > rectB.max[index] || rectB.min[index] > rectA.max[index] { return false @@ -647,21 +649,21 @@ func overlap(rectA, rectB rectT) bool { // Add a node to the reinsertion list. All its branches will later // be reinserted into the index structure. -func reInsert(node *nodeT, listNode **listNodeT) { - newListNode := &listNodeT{} +func DD_reInsert(node *DD_nodeT, listNode **DD_listNodeT) { + newListNode := &DD_listNodeT{} newListNode.node = node newListNode.next = *listNode *listNode = newListNode } -// 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) { +// DD_search in an index tree or subtree for all data retangles that DD_overlap the argument rectangle. +func DD_search(node *DD_nodeT, rect DD_rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { if node.isInternalNode() { // This is an internal node in the tree for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { + if DD_overlap(rect, node.branch[index].rect) { var ok bool - foundCount, ok = search(node.branch[index].child, rect, foundCount, resultCallback) + foundCount, ok = DD_search(node.branch[index].child, rect, foundCount, resultCallback) if !ok { // The callback indicated to stop searching return foundCount, false @@ -671,7 +673,7 @@ func search(node *nodeT, rect rectT, foundCount int, resultCallback func(data in } else { // This is a leaf node for index := 0; index < node.count; index++ { - if overlap(rect, node.branch[index].rect) { + if DD_overlap(rect, node.branch[index].rect) { id := node.branch[index].data foundCount++ if !resultCallback(id) { diff --git a/rtree.go b/rtree.go index 947c3de..330a1f5 100644 --- a/rtree.go +++ b/rtree.go @@ -1,30 +1,8 @@ // generated; DO NOT EDIT! + package rtree -import ( - "math" - - d1 "github.com/tidwall/rtree/dims/d1" - d2 "github.com/tidwall/rtree/dims/d2" - d3 "github.com/tidwall/rtree/dims/d3" - d4 "github.com/tidwall/rtree/dims/d4" - d5 "github.com/tidwall/rtree/dims/d5" - d6 "github.com/tidwall/rtree/dims/d6" - d7 "github.com/tidwall/rtree/dims/d7" - d8 "github.com/tidwall/rtree/dims/d8" - d9 "github.com/tidwall/rtree/dims/d9" - d10 "github.com/tidwall/rtree/dims/d10" - d11 "github.com/tidwall/rtree/dims/d11" - d12 "github.com/tidwall/rtree/dims/d12" - d13 "github.com/tidwall/rtree/dims/d13" - d14 "github.com/tidwall/rtree/dims/d14" - d15 "github.com/tidwall/rtree/dims/d15" - d16 "github.com/tidwall/rtree/dims/d16" - d17 "github.com/tidwall/rtree/dims/d17" - d18 "github.com/tidwall/rtree/dims/d18" - d19 "github.com/tidwall/rtree/dims/d19" - d20 "github.com/tidwall/rtree/dims/d20" -) +import "math" type Iterator func(item Item) bool type Item interface { @@ -32,52 +10,52 @@ type Item interface { } type RTree struct { - ctx interface{} - tr1 *d1.RTree - tr2 *d2.RTree - tr3 *d3.RTree - tr4 *d4.RTree - tr5 *d5.RTree - tr6 *d6.RTree - tr7 *d7.RTree - tr8 *d8.RTree - tr9 *d9.RTree - tr10 *d10.RTree - tr11 *d11.RTree - tr12 *d12.RTree - tr13 *d13.RTree - tr14 *d14.RTree - tr15 *d15.RTree - tr16 *d16.RTree - tr17 *d17.RTree - tr18 *d18.RTree - tr19 *d19.RTree - tr20 *d20.RTree + ctx interface{} + tr1 *d1RTree + tr2 *d2RTree + tr3 *d3RTree + tr4 *d4RTree + tr5 *d5RTree + tr6 *d6RTree + tr7 *d7RTree + tr8 *d8RTree + tr9 *d9RTree + tr10 *d10RTree + tr11 *d11RTree + tr12 *d12RTree + tr13 *d13RTree + tr14 *d14RTree + tr15 *d15RTree + tr16 *d16RTree + tr17 *d17RTree + tr18 *d18RTree + tr19 *d19RTree + tr20 *d20RTree } func New(ctx interface{}) *RTree { return &RTree{ - ctx: ctx, - tr1: d1.New(), - tr2: d2.New(), - tr3: d3.New(), - tr4: d4.New(), - tr5: d5.New(), - tr6: d6.New(), - tr7: d7.New(), - tr8: d8.New(), - tr9: d9.New(), - tr10: d10.New(), - tr11: d11.New(), - tr12: d12.New(), - tr13: d13.New(), - tr14: d14.New(), - tr15: d15.New(), - tr16: d16.New(), - tr17: d17.New(), - tr18: d18.New(), - tr19: d19.New(), - tr20: d20.New(), + ctx: ctx, + tr1: d1New(), + tr2: d2New(), + tr3: d3New(), + tr4: d4New(), + tr5: d5New(), + tr6: d6New(), + tr7: d7New(), + tr8: d8New(), + tr9: d9New(), + tr10: d10New(), + tr11: d11New(), + tr12: d12New(), + tr13: d13New(), + tr14: d14New(), + tr15: d15New(), + tr16: d16New(), + tr17: d17New(), + tr18: d18New(), + tr19: d19New(), + tr20: d20New(), } } @@ -353,26 +331,26 @@ func (tr *RTree) Remove(item Item) { } } func (tr *RTree) Reset() { - tr.tr1 = d1.New() - tr.tr2 = d2.New() - tr.tr3 = d3.New() - tr.tr4 = d4.New() - tr.tr5 = d5.New() - tr.tr6 = d6.New() - tr.tr7 = d7.New() - tr.tr8 = d8.New() - tr.tr9 = d9.New() - tr.tr10 = d10.New() - tr.tr11 = d11.New() - tr.tr12 = d12.New() - tr.tr13 = d13.New() - tr.tr14 = d14.New() - tr.tr15 = d15.New() - tr.tr16 = d16.New() - tr.tr17 = d17.New() - tr.tr18 = d18.New() - tr.tr19 = d19.New() - tr.tr20 = d20.New() + tr.tr1 = d1New() + tr.tr2 = d2New() + tr.tr3 = d3New() + tr.tr4 = d4New() + tr.tr5 = d5New() + tr.tr6 = d6New() + tr.tr7 = d7New() + tr.tr8 = d8New() + tr.tr9 = d9New() + tr.tr10 = d10New() + tr.tr11 = d11New() + tr.tr12 = d12New() + tr.tr13 = d13New() + tr.tr14 = d14New() + tr.tr15 = d15New() + tr.tr16 = d16New() + tr.tr17 = d17New() + tr.tr18 = d18New() + tr.tr19 = d19New() + tr.tr20 = d20New() } func (tr *RTree) Count() int { count := 0 @@ -934,4 +912,13102 @@ func (tr *RTree) search20(min, max []float64, iter Iterator) bool { return !ended } +func d1fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d1fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} +const ( + d1numDims = 1 + d1maxNodes = 8 + d1minNodes = d1maxNodes / 2 + d1useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d1unitSphereVolume = []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 +}[d1numDims] + +type d1RTree struct { + root *d1nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d1rectT struct { + min [d1numDims]float64 ///< Min dimensions of bounding box + max [d1numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d1branchT struct { + rect d1rectT ///< Bounds + child *d1nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d1nodeT for each branch level +type d1nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d1maxNodes]d1branchT ///< Branch +} + +func (node *d1nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d1nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d1listNodeT struct { + next *d1listNodeT ///< Next in list + node *d1nodeT ///< Node +} + +const d1notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d1partitionVarsT struct { + partition [d1maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d1rectT + area [2]float64 + + branchBuf [d1maxNodes + 1]d1branchT + branchCount int + coverSplit d1rectT + coverSplitArea float64 +} + +func d1New() *d1RTree { + // 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 &d1RTree{ + root: &d1nodeT{}, + } +} + +/// 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. +func (tr *d1RTree) Insert(min, max [d1numDims]float64, dataId interface{}) { + var branch d1branchT + branch.data = dataId + for axis := 0; axis < d1numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d1insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d1RTree) Remove(min, max [d1numDims]float64, dataId interface{}) { + var rect d1rectT + for axis := 0; axis < d1numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d1removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d1search rectangle +/// \param a_min Min of d1search bounding rect +/// \param a_max Max of d1search bounding rect +/// \param a_searchResult d1search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d1RTree) Search(min, max [d1numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d1rectT + for axis := 0; axis < d1numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d1search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d1RTree) Count() int { + var count int + d1countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d1RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d1nodeT{} +} + +func d1countRec(node *d1nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d1countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d1insertRectRec(branch *d1branchT, node *d1nodeT, newNode **d1nodeT, level int) bool { + // 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 + var otherNode *d1nodeT + //var newBranch d1branchT + + // find the optimal branch for this record + index := d1pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d1insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d1combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d1nodeCover(node.branch[index].child) + var newBranch d1branchT + newBranch.child = otherNode + newBranch.rect = d1nodeCover(otherNode) + + // 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. + return d1addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d1addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d1insertRect provides for splitting the root; +// 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. +// +func d1insertRect(branch *d1branchT, root **d1nodeT, level int) bool { + var newNode *d1nodeT + + if d1insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d1nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d1branchT + + // add old root node as a child of the new root + newBranch.rect = d1nodeCover(*root) + newBranch.child = *root + d1addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d1nodeCover(newNode) + newBranch.child = newNode + d1addBranch(&newBranch, newRoot, nil) + + // 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. +func d1nodeCover(node *d1nodeT) d1rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d1combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d1addBranch(branch *d1branchT, node *d1nodeT, newNode **d1nodeT) bool { + if node.count < d1maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d1splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d1disconnectBranch(node *d1nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d1pickBranch(rect *d1rectT, node *d1nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d1rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d1calcRectVolume(curRect) + tempRect = d1combineRect(rect, curRect) + increase = d1calcRectVolume(&tempRect) - area + 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 +func d1combineRect(rectA, rectB *d1rectT) d1rectT { + var newRect d1rectT + + for index := 0; index < d1numDims; index++ { + newRect.min[index] = d1fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d1fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d1splitNode(node *d1nodeT, branch *d1branchT, newNode **d1nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d1partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d1getBranches(node, branch, parVars) + + // Find partition + d1choosePartition(parVars, d1minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d1nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d1loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d1rectVolume(rect *d1rectT) float64 { + var volume float64 = 1 + for index := 0; index < d1numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d1rectT +func d1rectSphericalVolume(rect *d1rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d1numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d1numDims == 5 { + return (radius * radius * radius * radius * radius * d1unitSphereVolume) + } else if d1numDims == 4 { + return (radius * radius * radius * radius * d1unitSphereVolume) + } else if d1numDims == 3 { + return (radius * radius * radius * d1unitSphereVolume) + } else if d1numDims == 2 { + return (radius * radius * d1unitSphereVolume) + } else { + return (math.Pow(radius, d1numDims) * d1unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d1calcRectVolume(rect *d1rectT) float64 { + if d1useSphericalVolume { + return d1rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d1rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d1getBranches(node *d1nodeT, branch *d1branchT, parVars *d1partitionVarsT) { + // Load the branch buffer + for index := 0; index < d1maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d1maxNodes] = *branch + parVars.branchCount = d1maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d1maxNodes+1; index++ { + parVars.coverSplit = d1combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d1calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d1choosePartition(parVars *d1partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d1initParVars(parVars, parVars.branchCount, minFill) + d1pickSeeds(parVars) + + 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++ { + if d1notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d1combineRect(curRect, &parVars.cover[0]) + rect1 := d1combineRect(curRect, &parVars.cover[1]) + growth0 := d1calcRectVolume(&rect0) - parVars.area[0] + growth1 := d1calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d1classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d1notTaken == parVars.partition[index] { + d1classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d1loadNodes(nodeA, nodeB *d1nodeT, parVars *d1partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d1nodeT{nodeA, nodeB} + + // It is assured that d1addBranch here will not cause a node split. + d1addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d1partitionVarsT structure. +func d1initParVars(parVars *d1partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d1notTaken + } +} + +func d1pickSeeds(parVars *d1partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d1maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d1calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d1combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d1calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d1classify(seed0, 0, parVars) + d1classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d1classify(index, group int, parVars *d1partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d1combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d1calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d1rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d1removeRect provides for eliminating the root. +func d1removeRect(rect *d1rectT, id interface{}, root **d1nodeT) bool { + var reInsertList *d1listNodeT + + if !d1removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d1insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d1removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d1removeRectRec(rect *d1rectT, id interface{}, node *d1nodeT, listNode **d1listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d1overlap(*rect, node.branch[index].rect) { + if !d1removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d1minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d1nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d1reInsert(node.branch[index].child, listNode) + d1disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d1disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d1overlap. +func d1overlap(rectA, rectB d1rectT) bool { + for index := 0; index < d1numDims; index++ { + 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. +func d1reInsert(node *d1nodeT, listNode **d1listNodeT) { + newListNode := &d1listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d1search in an index tree or subtree for all data retangles that d1overlap the argument rectangle. +func d1search(node *d1nodeT, rect d1rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d1overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d1search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d1overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d2fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d2fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d2numDims = 2 + d2maxNodes = 8 + d2minNodes = d2maxNodes / 2 + d2useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d2unitSphereVolume = []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 +}[d2numDims] + +type d2RTree struct { + root *d2nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d2rectT struct { + min [d2numDims]float64 ///< Min dimensions of bounding box + max [d2numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d2branchT struct { + rect d2rectT ///< Bounds + child *d2nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d2nodeT for each branch level +type d2nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d2maxNodes]d2branchT ///< Branch +} + +func (node *d2nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d2nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d2listNodeT struct { + next *d2listNodeT ///< Next in list + node *d2nodeT ///< Node +} + +const d2notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d2partitionVarsT struct { + partition [d2maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d2rectT + area [2]float64 + + branchBuf [d2maxNodes + 1]d2branchT + branchCount int + coverSplit d2rectT + coverSplitArea float64 +} + +func d2New() *d2RTree { + // 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 &d2RTree{ + root: &d2nodeT{}, + } +} + +/// 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. +func (tr *d2RTree) Insert(min, max [d2numDims]float64, dataId interface{}) { + var branch d2branchT + branch.data = dataId + for axis := 0; axis < d2numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d2insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d2RTree) Remove(min, max [d2numDims]float64, dataId interface{}) { + var rect d2rectT + for axis := 0; axis < d2numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d2removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d2search rectangle +/// \param a_min Min of d2search bounding rect +/// \param a_max Max of d2search bounding rect +/// \param a_searchResult d2search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d2RTree) Search(min, max [d2numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d2rectT + for axis := 0; axis < d2numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d2search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d2RTree) Count() int { + var count int + d2countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d2RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d2nodeT{} +} + +func d2countRec(node *d2nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d2countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d2insertRectRec(branch *d2branchT, node *d2nodeT, newNode **d2nodeT, level int) bool { + // 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 + var otherNode *d2nodeT + //var newBranch d2branchT + + // find the optimal branch for this record + index := d2pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d2insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d2combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d2nodeCover(node.branch[index].child) + var newBranch d2branchT + newBranch.child = otherNode + newBranch.rect = d2nodeCover(otherNode) + + // 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. + return d2addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d2addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d2insertRect provides for splitting the root; +// 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. +// +func d2insertRect(branch *d2branchT, root **d2nodeT, level int) bool { + var newNode *d2nodeT + + if d2insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d2nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d2branchT + + // add old root node as a child of the new root + newBranch.rect = d2nodeCover(*root) + newBranch.child = *root + d2addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d2nodeCover(newNode) + newBranch.child = newNode + d2addBranch(&newBranch, newRoot, nil) + + // 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. +func d2nodeCover(node *d2nodeT) d2rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d2combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d2addBranch(branch *d2branchT, node *d2nodeT, newNode **d2nodeT) bool { + if node.count < d2maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d2splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d2disconnectBranch(node *d2nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d2pickBranch(rect *d2rectT, node *d2nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d2rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d2calcRectVolume(curRect) + tempRect = d2combineRect(rect, curRect) + increase = d2calcRectVolume(&tempRect) - area + 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 +func d2combineRect(rectA, rectB *d2rectT) d2rectT { + var newRect d2rectT + + for index := 0; index < d2numDims; index++ { + newRect.min[index] = d2fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d2fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d2splitNode(node *d2nodeT, branch *d2branchT, newNode **d2nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d2partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d2getBranches(node, branch, parVars) + + // Find partition + d2choosePartition(parVars, d2minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d2nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d2loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d2rectVolume(rect *d2rectT) float64 { + var volume float64 = 1 + for index := 0; index < d2numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d2rectT +func d2rectSphericalVolume(rect *d2rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d2numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d2numDims == 5 { + return (radius * radius * radius * radius * radius * d2unitSphereVolume) + } else if d2numDims == 4 { + return (radius * radius * radius * radius * d2unitSphereVolume) + } else if d2numDims == 3 { + return (radius * radius * radius * d2unitSphereVolume) + } else if d2numDims == 2 { + return (radius * radius * d2unitSphereVolume) + } else { + return (math.Pow(radius, d2numDims) * d2unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d2calcRectVolume(rect *d2rectT) float64 { + if d2useSphericalVolume { + return d2rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d2rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d2getBranches(node *d2nodeT, branch *d2branchT, parVars *d2partitionVarsT) { + // Load the branch buffer + for index := 0; index < d2maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d2maxNodes] = *branch + parVars.branchCount = d2maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d2maxNodes+1; index++ { + parVars.coverSplit = d2combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d2calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d2choosePartition(parVars *d2partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d2initParVars(parVars, parVars.branchCount, minFill) + d2pickSeeds(parVars) + + 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++ { + if d2notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d2combineRect(curRect, &parVars.cover[0]) + rect1 := d2combineRect(curRect, &parVars.cover[1]) + growth0 := d2calcRectVolume(&rect0) - parVars.area[0] + growth1 := d2calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d2classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d2notTaken == parVars.partition[index] { + d2classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d2loadNodes(nodeA, nodeB *d2nodeT, parVars *d2partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d2nodeT{nodeA, nodeB} + + // It is assured that d2addBranch here will not cause a node split. + d2addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d2partitionVarsT structure. +func d2initParVars(parVars *d2partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d2notTaken + } +} + +func d2pickSeeds(parVars *d2partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d2maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d2calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d2combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d2calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d2classify(seed0, 0, parVars) + d2classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d2classify(index, group int, parVars *d2partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d2combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d2calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d2rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d2removeRect provides for eliminating the root. +func d2removeRect(rect *d2rectT, id interface{}, root **d2nodeT) bool { + var reInsertList *d2listNodeT + + if !d2removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d2insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d2removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d2removeRectRec(rect *d2rectT, id interface{}, node *d2nodeT, listNode **d2listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d2overlap(*rect, node.branch[index].rect) { + if !d2removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d2minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d2nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d2reInsert(node.branch[index].child, listNode) + d2disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d2disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d2overlap. +func d2overlap(rectA, rectB d2rectT) bool { + for index := 0; index < d2numDims; index++ { + 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. +func d2reInsert(node *d2nodeT, listNode **d2listNodeT) { + newListNode := &d2listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d2search in an index tree or subtree for all data retangles that d2overlap the argument rectangle. +func d2search(node *d2nodeT, rect d2rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d2overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d2search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d2overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d3fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d3fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d3numDims = 3 + d3maxNodes = 8 + d3minNodes = d3maxNodes / 2 + d3useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d3unitSphereVolume = []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 +}[d3numDims] + +type d3RTree struct { + root *d3nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d3rectT struct { + min [d3numDims]float64 ///< Min dimensions of bounding box + max [d3numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d3branchT struct { + rect d3rectT ///< Bounds + child *d3nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d3nodeT for each branch level +type d3nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d3maxNodes]d3branchT ///< Branch +} + +func (node *d3nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d3nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d3listNodeT struct { + next *d3listNodeT ///< Next in list + node *d3nodeT ///< Node +} + +const d3notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d3partitionVarsT struct { + partition [d3maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d3rectT + area [2]float64 + + branchBuf [d3maxNodes + 1]d3branchT + branchCount int + coverSplit d3rectT + coverSplitArea float64 +} + +func d3New() *d3RTree { + // 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 &d3RTree{ + root: &d3nodeT{}, + } +} + +/// 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. +func (tr *d3RTree) Insert(min, max [d3numDims]float64, dataId interface{}) { + var branch d3branchT + branch.data = dataId + for axis := 0; axis < d3numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d3insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d3RTree) Remove(min, max [d3numDims]float64, dataId interface{}) { + var rect d3rectT + for axis := 0; axis < d3numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d3removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d3search rectangle +/// \param a_min Min of d3search bounding rect +/// \param a_max Max of d3search bounding rect +/// \param a_searchResult d3search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d3RTree) Search(min, max [d3numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d3rectT + for axis := 0; axis < d3numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d3search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d3RTree) Count() int { + var count int + d3countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d3RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d3nodeT{} +} + +func d3countRec(node *d3nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d3countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d3insertRectRec(branch *d3branchT, node *d3nodeT, newNode **d3nodeT, level int) bool { + // 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 + var otherNode *d3nodeT + //var newBranch d3branchT + + // find the optimal branch for this record + index := d3pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d3insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d3combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d3nodeCover(node.branch[index].child) + var newBranch d3branchT + newBranch.child = otherNode + newBranch.rect = d3nodeCover(otherNode) + + // 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. + return d3addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d3addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d3insertRect provides for splitting the root; +// 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. +// +func d3insertRect(branch *d3branchT, root **d3nodeT, level int) bool { + var newNode *d3nodeT + + if d3insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d3nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d3branchT + + // add old root node as a child of the new root + newBranch.rect = d3nodeCover(*root) + newBranch.child = *root + d3addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d3nodeCover(newNode) + newBranch.child = newNode + d3addBranch(&newBranch, newRoot, nil) + + // 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. +func d3nodeCover(node *d3nodeT) d3rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d3combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d3addBranch(branch *d3branchT, node *d3nodeT, newNode **d3nodeT) bool { + if node.count < d3maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d3splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d3disconnectBranch(node *d3nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d3pickBranch(rect *d3rectT, node *d3nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d3rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d3calcRectVolume(curRect) + tempRect = d3combineRect(rect, curRect) + increase = d3calcRectVolume(&tempRect) - area + 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 +func d3combineRect(rectA, rectB *d3rectT) d3rectT { + var newRect d3rectT + + for index := 0; index < d3numDims; index++ { + newRect.min[index] = d3fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d3fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d3splitNode(node *d3nodeT, branch *d3branchT, newNode **d3nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d3partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d3getBranches(node, branch, parVars) + + // Find partition + d3choosePartition(parVars, d3minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d3nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d3loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d3rectVolume(rect *d3rectT) float64 { + var volume float64 = 1 + for index := 0; index < d3numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d3rectT +func d3rectSphericalVolume(rect *d3rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d3numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d3numDims == 5 { + return (radius * radius * radius * radius * radius * d3unitSphereVolume) + } else if d3numDims == 4 { + return (radius * radius * radius * radius * d3unitSphereVolume) + } else if d3numDims == 3 { + return (radius * radius * radius * d3unitSphereVolume) + } else if d3numDims == 2 { + return (radius * radius * d3unitSphereVolume) + } else { + return (math.Pow(radius, d3numDims) * d3unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d3calcRectVolume(rect *d3rectT) float64 { + if d3useSphericalVolume { + return d3rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d3rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d3getBranches(node *d3nodeT, branch *d3branchT, parVars *d3partitionVarsT) { + // Load the branch buffer + for index := 0; index < d3maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d3maxNodes] = *branch + parVars.branchCount = d3maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d3maxNodes+1; index++ { + parVars.coverSplit = d3combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d3calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d3choosePartition(parVars *d3partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d3initParVars(parVars, parVars.branchCount, minFill) + d3pickSeeds(parVars) + + 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++ { + if d3notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d3combineRect(curRect, &parVars.cover[0]) + rect1 := d3combineRect(curRect, &parVars.cover[1]) + growth0 := d3calcRectVolume(&rect0) - parVars.area[0] + growth1 := d3calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d3classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d3notTaken == parVars.partition[index] { + d3classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d3loadNodes(nodeA, nodeB *d3nodeT, parVars *d3partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d3nodeT{nodeA, nodeB} + + // It is assured that d3addBranch here will not cause a node split. + d3addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d3partitionVarsT structure. +func d3initParVars(parVars *d3partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d3notTaken + } +} + +func d3pickSeeds(parVars *d3partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d3maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d3calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d3combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d3calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d3classify(seed0, 0, parVars) + d3classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d3classify(index, group int, parVars *d3partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d3combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d3calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d3rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d3removeRect provides for eliminating the root. +func d3removeRect(rect *d3rectT, id interface{}, root **d3nodeT) bool { + var reInsertList *d3listNodeT + + if !d3removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d3insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d3removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d3removeRectRec(rect *d3rectT, id interface{}, node *d3nodeT, listNode **d3listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d3overlap(*rect, node.branch[index].rect) { + if !d3removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d3minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d3nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d3reInsert(node.branch[index].child, listNode) + d3disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d3disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d3overlap. +func d3overlap(rectA, rectB d3rectT) bool { + for index := 0; index < d3numDims; index++ { + 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. +func d3reInsert(node *d3nodeT, listNode **d3listNodeT) { + newListNode := &d3listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d3search in an index tree or subtree for all data retangles that d3overlap the argument rectangle. +func d3search(node *d3nodeT, rect d3rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d3overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d3search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d3overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d4fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d4fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d4numDims = 4 + d4maxNodes = 8 + d4minNodes = d4maxNodes / 2 + d4useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d4unitSphereVolume = []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 +}[d4numDims] + +type d4RTree struct { + root *d4nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d4rectT struct { + min [d4numDims]float64 ///< Min dimensions of bounding box + max [d4numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d4branchT struct { + rect d4rectT ///< Bounds + child *d4nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d4nodeT for each branch level +type d4nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d4maxNodes]d4branchT ///< Branch +} + +func (node *d4nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d4nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d4listNodeT struct { + next *d4listNodeT ///< Next in list + node *d4nodeT ///< Node +} + +const d4notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d4partitionVarsT struct { + partition [d4maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d4rectT + area [2]float64 + + branchBuf [d4maxNodes + 1]d4branchT + branchCount int + coverSplit d4rectT + coverSplitArea float64 +} + +func d4New() *d4RTree { + // 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 &d4RTree{ + root: &d4nodeT{}, + } +} + +/// 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. +func (tr *d4RTree) Insert(min, max [d4numDims]float64, dataId interface{}) { + var branch d4branchT + branch.data = dataId + for axis := 0; axis < d4numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d4insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d4RTree) Remove(min, max [d4numDims]float64, dataId interface{}) { + var rect d4rectT + for axis := 0; axis < d4numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d4removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d4search rectangle +/// \param a_min Min of d4search bounding rect +/// \param a_max Max of d4search bounding rect +/// \param a_searchResult d4search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d4RTree) Search(min, max [d4numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d4rectT + for axis := 0; axis < d4numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d4search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d4RTree) Count() int { + var count int + d4countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d4RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d4nodeT{} +} + +func d4countRec(node *d4nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d4countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d4insertRectRec(branch *d4branchT, node *d4nodeT, newNode **d4nodeT, level int) bool { + // 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 + var otherNode *d4nodeT + //var newBranch d4branchT + + // find the optimal branch for this record + index := d4pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d4insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d4combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d4nodeCover(node.branch[index].child) + var newBranch d4branchT + newBranch.child = otherNode + newBranch.rect = d4nodeCover(otherNode) + + // 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. + return d4addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d4addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d4insertRect provides for splitting the root; +// 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. +// +func d4insertRect(branch *d4branchT, root **d4nodeT, level int) bool { + var newNode *d4nodeT + + if d4insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d4nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d4branchT + + // add old root node as a child of the new root + newBranch.rect = d4nodeCover(*root) + newBranch.child = *root + d4addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d4nodeCover(newNode) + newBranch.child = newNode + d4addBranch(&newBranch, newRoot, nil) + + // 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. +func d4nodeCover(node *d4nodeT) d4rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d4combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d4addBranch(branch *d4branchT, node *d4nodeT, newNode **d4nodeT) bool { + if node.count < d4maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d4splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d4disconnectBranch(node *d4nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d4pickBranch(rect *d4rectT, node *d4nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d4rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d4calcRectVolume(curRect) + tempRect = d4combineRect(rect, curRect) + increase = d4calcRectVolume(&tempRect) - area + 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 +func d4combineRect(rectA, rectB *d4rectT) d4rectT { + var newRect d4rectT + + for index := 0; index < d4numDims; index++ { + newRect.min[index] = d4fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d4fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d4splitNode(node *d4nodeT, branch *d4branchT, newNode **d4nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d4partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d4getBranches(node, branch, parVars) + + // Find partition + d4choosePartition(parVars, d4minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d4nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d4loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d4rectVolume(rect *d4rectT) float64 { + var volume float64 = 1 + for index := 0; index < d4numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d4rectT +func d4rectSphericalVolume(rect *d4rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d4numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d4numDims == 5 { + return (radius * radius * radius * radius * radius * d4unitSphereVolume) + } else if d4numDims == 4 { + return (radius * radius * radius * radius * d4unitSphereVolume) + } else if d4numDims == 3 { + return (radius * radius * radius * d4unitSphereVolume) + } else if d4numDims == 2 { + return (radius * radius * d4unitSphereVolume) + } else { + return (math.Pow(radius, d4numDims) * d4unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d4calcRectVolume(rect *d4rectT) float64 { + if d4useSphericalVolume { + return d4rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d4rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d4getBranches(node *d4nodeT, branch *d4branchT, parVars *d4partitionVarsT) { + // Load the branch buffer + for index := 0; index < d4maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d4maxNodes] = *branch + parVars.branchCount = d4maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d4maxNodes+1; index++ { + parVars.coverSplit = d4combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d4calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d4choosePartition(parVars *d4partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d4initParVars(parVars, parVars.branchCount, minFill) + d4pickSeeds(parVars) + + 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++ { + if d4notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d4combineRect(curRect, &parVars.cover[0]) + rect1 := d4combineRect(curRect, &parVars.cover[1]) + growth0 := d4calcRectVolume(&rect0) - parVars.area[0] + growth1 := d4calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d4classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d4notTaken == parVars.partition[index] { + d4classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d4loadNodes(nodeA, nodeB *d4nodeT, parVars *d4partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d4nodeT{nodeA, nodeB} + + // It is assured that d4addBranch here will not cause a node split. + d4addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d4partitionVarsT structure. +func d4initParVars(parVars *d4partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d4notTaken + } +} + +func d4pickSeeds(parVars *d4partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d4maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d4calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d4combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d4calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d4classify(seed0, 0, parVars) + d4classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d4classify(index, group int, parVars *d4partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d4combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d4calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d4rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d4removeRect provides for eliminating the root. +func d4removeRect(rect *d4rectT, id interface{}, root **d4nodeT) bool { + var reInsertList *d4listNodeT + + if !d4removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d4insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d4removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d4removeRectRec(rect *d4rectT, id interface{}, node *d4nodeT, listNode **d4listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d4overlap(*rect, node.branch[index].rect) { + if !d4removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d4minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d4nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d4reInsert(node.branch[index].child, listNode) + d4disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d4disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d4overlap. +func d4overlap(rectA, rectB d4rectT) bool { + for index := 0; index < d4numDims; index++ { + 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. +func d4reInsert(node *d4nodeT, listNode **d4listNodeT) { + newListNode := &d4listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d4search in an index tree or subtree for all data retangles that d4overlap the argument rectangle. +func d4search(node *d4nodeT, rect d4rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d4overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d4search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d4overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d5fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d5fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d5numDims = 5 + d5maxNodes = 8 + d5minNodes = d5maxNodes / 2 + d5useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d5unitSphereVolume = []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 +}[d5numDims] + +type d5RTree struct { + root *d5nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d5rectT struct { + min [d5numDims]float64 ///< Min dimensions of bounding box + max [d5numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d5branchT struct { + rect d5rectT ///< Bounds + child *d5nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d5nodeT for each branch level +type d5nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d5maxNodes]d5branchT ///< Branch +} + +func (node *d5nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d5nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d5listNodeT struct { + next *d5listNodeT ///< Next in list + node *d5nodeT ///< Node +} + +const d5notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d5partitionVarsT struct { + partition [d5maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d5rectT + area [2]float64 + + branchBuf [d5maxNodes + 1]d5branchT + branchCount int + coverSplit d5rectT + coverSplitArea float64 +} + +func d5New() *d5RTree { + // 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 &d5RTree{ + root: &d5nodeT{}, + } +} + +/// 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. +func (tr *d5RTree) Insert(min, max [d5numDims]float64, dataId interface{}) { + var branch d5branchT + branch.data = dataId + for axis := 0; axis < d5numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d5insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d5RTree) Remove(min, max [d5numDims]float64, dataId interface{}) { + var rect d5rectT + for axis := 0; axis < d5numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d5removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d5search rectangle +/// \param a_min Min of d5search bounding rect +/// \param a_max Max of d5search bounding rect +/// \param a_searchResult d5search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d5RTree) Search(min, max [d5numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d5rectT + for axis := 0; axis < d5numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d5search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d5RTree) Count() int { + var count int + d5countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d5RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d5nodeT{} +} + +func d5countRec(node *d5nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d5countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d5insertRectRec(branch *d5branchT, node *d5nodeT, newNode **d5nodeT, level int) bool { + // 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 + var otherNode *d5nodeT + //var newBranch d5branchT + + // find the optimal branch for this record + index := d5pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d5insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d5combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d5nodeCover(node.branch[index].child) + var newBranch d5branchT + newBranch.child = otherNode + newBranch.rect = d5nodeCover(otherNode) + + // 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. + return d5addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d5addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d5insertRect provides for splitting the root; +// 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. +// +func d5insertRect(branch *d5branchT, root **d5nodeT, level int) bool { + var newNode *d5nodeT + + if d5insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d5nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d5branchT + + // add old root node as a child of the new root + newBranch.rect = d5nodeCover(*root) + newBranch.child = *root + d5addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d5nodeCover(newNode) + newBranch.child = newNode + d5addBranch(&newBranch, newRoot, nil) + + // 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. +func d5nodeCover(node *d5nodeT) d5rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d5combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d5addBranch(branch *d5branchT, node *d5nodeT, newNode **d5nodeT) bool { + if node.count < d5maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d5splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d5disconnectBranch(node *d5nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d5pickBranch(rect *d5rectT, node *d5nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d5rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d5calcRectVolume(curRect) + tempRect = d5combineRect(rect, curRect) + increase = d5calcRectVolume(&tempRect) - area + 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 +func d5combineRect(rectA, rectB *d5rectT) d5rectT { + var newRect d5rectT + + for index := 0; index < d5numDims; index++ { + newRect.min[index] = d5fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d5fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d5splitNode(node *d5nodeT, branch *d5branchT, newNode **d5nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d5partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d5getBranches(node, branch, parVars) + + // Find partition + d5choosePartition(parVars, d5minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d5nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d5loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d5rectVolume(rect *d5rectT) float64 { + var volume float64 = 1 + for index := 0; index < d5numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d5rectT +func d5rectSphericalVolume(rect *d5rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d5numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d5numDims == 5 { + return (radius * radius * radius * radius * radius * d5unitSphereVolume) + } else if d5numDims == 4 { + return (radius * radius * radius * radius * d5unitSphereVolume) + } else if d5numDims == 3 { + return (radius * radius * radius * d5unitSphereVolume) + } else if d5numDims == 2 { + return (radius * radius * d5unitSphereVolume) + } else { + return (math.Pow(radius, d5numDims) * d5unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d5calcRectVolume(rect *d5rectT) float64 { + if d5useSphericalVolume { + return d5rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d5rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d5getBranches(node *d5nodeT, branch *d5branchT, parVars *d5partitionVarsT) { + // Load the branch buffer + for index := 0; index < d5maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d5maxNodes] = *branch + parVars.branchCount = d5maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d5maxNodes+1; index++ { + parVars.coverSplit = d5combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d5calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d5choosePartition(parVars *d5partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d5initParVars(parVars, parVars.branchCount, minFill) + d5pickSeeds(parVars) + + 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++ { + if d5notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d5combineRect(curRect, &parVars.cover[0]) + rect1 := d5combineRect(curRect, &parVars.cover[1]) + growth0 := d5calcRectVolume(&rect0) - parVars.area[0] + growth1 := d5calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d5classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d5notTaken == parVars.partition[index] { + d5classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d5loadNodes(nodeA, nodeB *d5nodeT, parVars *d5partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d5nodeT{nodeA, nodeB} + + // It is assured that d5addBranch here will not cause a node split. + d5addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d5partitionVarsT structure. +func d5initParVars(parVars *d5partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d5notTaken + } +} + +func d5pickSeeds(parVars *d5partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d5maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d5calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d5combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d5calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d5classify(seed0, 0, parVars) + d5classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d5classify(index, group int, parVars *d5partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d5combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d5calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d5rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d5removeRect provides for eliminating the root. +func d5removeRect(rect *d5rectT, id interface{}, root **d5nodeT) bool { + var reInsertList *d5listNodeT + + if !d5removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d5insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d5removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d5removeRectRec(rect *d5rectT, id interface{}, node *d5nodeT, listNode **d5listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d5overlap(*rect, node.branch[index].rect) { + if !d5removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d5minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d5nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d5reInsert(node.branch[index].child, listNode) + d5disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d5disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d5overlap. +func d5overlap(rectA, rectB d5rectT) bool { + for index := 0; index < d5numDims; index++ { + 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. +func d5reInsert(node *d5nodeT, listNode **d5listNodeT) { + newListNode := &d5listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d5search in an index tree or subtree for all data retangles that d5overlap the argument rectangle. +func d5search(node *d5nodeT, rect d5rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d5overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d5search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d5overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d6fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d6fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d6numDims = 6 + d6maxNodes = 8 + d6minNodes = d6maxNodes / 2 + d6useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d6unitSphereVolume = []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 +}[d6numDims] + +type d6RTree struct { + root *d6nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d6rectT struct { + min [d6numDims]float64 ///< Min dimensions of bounding box + max [d6numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d6branchT struct { + rect d6rectT ///< Bounds + child *d6nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d6nodeT for each branch level +type d6nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d6maxNodes]d6branchT ///< Branch +} + +func (node *d6nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d6nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d6listNodeT struct { + next *d6listNodeT ///< Next in list + node *d6nodeT ///< Node +} + +const d6notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d6partitionVarsT struct { + partition [d6maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d6rectT + area [2]float64 + + branchBuf [d6maxNodes + 1]d6branchT + branchCount int + coverSplit d6rectT + coverSplitArea float64 +} + +func d6New() *d6RTree { + // 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 &d6RTree{ + root: &d6nodeT{}, + } +} + +/// 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. +func (tr *d6RTree) Insert(min, max [d6numDims]float64, dataId interface{}) { + var branch d6branchT + branch.data = dataId + for axis := 0; axis < d6numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d6insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d6RTree) Remove(min, max [d6numDims]float64, dataId interface{}) { + var rect d6rectT + for axis := 0; axis < d6numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d6removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d6search rectangle +/// \param a_min Min of d6search bounding rect +/// \param a_max Max of d6search bounding rect +/// \param a_searchResult d6search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d6RTree) Search(min, max [d6numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d6rectT + for axis := 0; axis < d6numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d6search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d6RTree) Count() int { + var count int + d6countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d6RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d6nodeT{} +} + +func d6countRec(node *d6nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d6countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d6insertRectRec(branch *d6branchT, node *d6nodeT, newNode **d6nodeT, level int) bool { + // 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 + var otherNode *d6nodeT + //var newBranch d6branchT + + // find the optimal branch for this record + index := d6pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d6insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d6combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d6nodeCover(node.branch[index].child) + var newBranch d6branchT + newBranch.child = otherNode + newBranch.rect = d6nodeCover(otherNode) + + // 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. + return d6addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d6addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d6insertRect provides for splitting the root; +// 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. +// +func d6insertRect(branch *d6branchT, root **d6nodeT, level int) bool { + var newNode *d6nodeT + + if d6insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d6nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d6branchT + + // add old root node as a child of the new root + newBranch.rect = d6nodeCover(*root) + newBranch.child = *root + d6addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d6nodeCover(newNode) + newBranch.child = newNode + d6addBranch(&newBranch, newRoot, nil) + + // 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. +func d6nodeCover(node *d6nodeT) d6rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d6combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d6addBranch(branch *d6branchT, node *d6nodeT, newNode **d6nodeT) bool { + if node.count < d6maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d6splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d6disconnectBranch(node *d6nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d6pickBranch(rect *d6rectT, node *d6nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d6rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d6calcRectVolume(curRect) + tempRect = d6combineRect(rect, curRect) + increase = d6calcRectVolume(&tempRect) - area + 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 +func d6combineRect(rectA, rectB *d6rectT) d6rectT { + var newRect d6rectT + + for index := 0; index < d6numDims; index++ { + newRect.min[index] = d6fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d6fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d6splitNode(node *d6nodeT, branch *d6branchT, newNode **d6nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d6partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d6getBranches(node, branch, parVars) + + // Find partition + d6choosePartition(parVars, d6minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d6nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d6loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d6rectVolume(rect *d6rectT) float64 { + var volume float64 = 1 + for index := 0; index < d6numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d6rectT +func d6rectSphericalVolume(rect *d6rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d6numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d6numDims == 5 { + return (radius * radius * radius * radius * radius * d6unitSphereVolume) + } else if d6numDims == 4 { + return (radius * radius * radius * radius * d6unitSphereVolume) + } else if d6numDims == 3 { + return (radius * radius * radius * d6unitSphereVolume) + } else if d6numDims == 2 { + return (radius * radius * d6unitSphereVolume) + } else { + return (math.Pow(radius, d6numDims) * d6unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d6calcRectVolume(rect *d6rectT) float64 { + if d6useSphericalVolume { + return d6rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d6rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d6getBranches(node *d6nodeT, branch *d6branchT, parVars *d6partitionVarsT) { + // Load the branch buffer + for index := 0; index < d6maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d6maxNodes] = *branch + parVars.branchCount = d6maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d6maxNodes+1; index++ { + parVars.coverSplit = d6combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d6calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d6choosePartition(parVars *d6partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d6initParVars(parVars, parVars.branchCount, minFill) + d6pickSeeds(parVars) + + 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++ { + if d6notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d6combineRect(curRect, &parVars.cover[0]) + rect1 := d6combineRect(curRect, &parVars.cover[1]) + growth0 := d6calcRectVolume(&rect0) - parVars.area[0] + growth1 := d6calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d6classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d6notTaken == parVars.partition[index] { + d6classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d6loadNodes(nodeA, nodeB *d6nodeT, parVars *d6partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d6nodeT{nodeA, nodeB} + + // It is assured that d6addBranch here will not cause a node split. + d6addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d6partitionVarsT structure. +func d6initParVars(parVars *d6partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d6notTaken + } +} + +func d6pickSeeds(parVars *d6partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d6maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d6calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d6combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d6calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d6classify(seed0, 0, parVars) + d6classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d6classify(index, group int, parVars *d6partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d6combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d6calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d6rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d6removeRect provides for eliminating the root. +func d6removeRect(rect *d6rectT, id interface{}, root **d6nodeT) bool { + var reInsertList *d6listNodeT + + if !d6removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d6insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d6removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d6removeRectRec(rect *d6rectT, id interface{}, node *d6nodeT, listNode **d6listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d6overlap(*rect, node.branch[index].rect) { + if !d6removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d6minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d6nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d6reInsert(node.branch[index].child, listNode) + d6disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d6disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d6overlap. +func d6overlap(rectA, rectB d6rectT) bool { + for index := 0; index < d6numDims; index++ { + 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. +func d6reInsert(node *d6nodeT, listNode **d6listNodeT) { + newListNode := &d6listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d6search in an index tree or subtree for all data retangles that d6overlap the argument rectangle. +func d6search(node *d6nodeT, rect d6rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d6overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d6search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d6overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d7fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d7fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d7numDims = 7 + d7maxNodes = 8 + d7minNodes = d7maxNodes / 2 + d7useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d7unitSphereVolume = []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 +}[d7numDims] + +type d7RTree struct { + root *d7nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d7rectT struct { + min [d7numDims]float64 ///< Min dimensions of bounding box + max [d7numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d7branchT struct { + rect d7rectT ///< Bounds + child *d7nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d7nodeT for each branch level +type d7nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d7maxNodes]d7branchT ///< Branch +} + +func (node *d7nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d7nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d7listNodeT struct { + next *d7listNodeT ///< Next in list + node *d7nodeT ///< Node +} + +const d7notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d7partitionVarsT struct { + partition [d7maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d7rectT + area [2]float64 + + branchBuf [d7maxNodes + 1]d7branchT + branchCount int + coverSplit d7rectT + coverSplitArea float64 +} + +func d7New() *d7RTree { + // 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 &d7RTree{ + root: &d7nodeT{}, + } +} + +/// 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. +func (tr *d7RTree) Insert(min, max [d7numDims]float64, dataId interface{}) { + var branch d7branchT + branch.data = dataId + for axis := 0; axis < d7numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d7insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d7RTree) Remove(min, max [d7numDims]float64, dataId interface{}) { + var rect d7rectT + for axis := 0; axis < d7numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d7removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d7search rectangle +/// \param a_min Min of d7search bounding rect +/// \param a_max Max of d7search bounding rect +/// \param a_searchResult d7search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d7RTree) Search(min, max [d7numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d7rectT + for axis := 0; axis < d7numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d7search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d7RTree) Count() int { + var count int + d7countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d7RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d7nodeT{} +} + +func d7countRec(node *d7nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d7countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d7insertRectRec(branch *d7branchT, node *d7nodeT, newNode **d7nodeT, level int) bool { + // 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 + var otherNode *d7nodeT + //var newBranch d7branchT + + // find the optimal branch for this record + index := d7pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d7insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d7combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d7nodeCover(node.branch[index].child) + var newBranch d7branchT + newBranch.child = otherNode + newBranch.rect = d7nodeCover(otherNode) + + // 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. + return d7addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d7addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d7insertRect provides for splitting the root; +// 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. +// +func d7insertRect(branch *d7branchT, root **d7nodeT, level int) bool { + var newNode *d7nodeT + + if d7insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d7nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d7branchT + + // add old root node as a child of the new root + newBranch.rect = d7nodeCover(*root) + newBranch.child = *root + d7addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d7nodeCover(newNode) + newBranch.child = newNode + d7addBranch(&newBranch, newRoot, nil) + + // 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. +func d7nodeCover(node *d7nodeT) d7rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d7combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d7addBranch(branch *d7branchT, node *d7nodeT, newNode **d7nodeT) bool { + if node.count < d7maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d7splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d7disconnectBranch(node *d7nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d7pickBranch(rect *d7rectT, node *d7nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d7rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d7calcRectVolume(curRect) + tempRect = d7combineRect(rect, curRect) + increase = d7calcRectVolume(&tempRect) - area + 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 +func d7combineRect(rectA, rectB *d7rectT) d7rectT { + var newRect d7rectT + + for index := 0; index < d7numDims; index++ { + newRect.min[index] = d7fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d7fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d7splitNode(node *d7nodeT, branch *d7branchT, newNode **d7nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d7partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d7getBranches(node, branch, parVars) + + // Find partition + d7choosePartition(parVars, d7minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d7nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d7loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d7rectVolume(rect *d7rectT) float64 { + var volume float64 = 1 + for index := 0; index < d7numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d7rectT +func d7rectSphericalVolume(rect *d7rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d7numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d7numDims == 5 { + return (radius * radius * radius * radius * radius * d7unitSphereVolume) + } else if d7numDims == 4 { + return (radius * radius * radius * radius * d7unitSphereVolume) + } else if d7numDims == 3 { + return (radius * radius * radius * d7unitSphereVolume) + } else if d7numDims == 2 { + return (radius * radius * d7unitSphereVolume) + } else { + return (math.Pow(radius, d7numDims) * d7unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d7calcRectVolume(rect *d7rectT) float64 { + if d7useSphericalVolume { + return d7rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d7rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d7getBranches(node *d7nodeT, branch *d7branchT, parVars *d7partitionVarsT) { + // Load the branch buffer + for index := 0; index < d7maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d7maxNodes] = *branch + parVars.branchCount = d7maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d7maxNodes+1; index++ { + parVars.coverSplit = d7combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d7calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d7choosePartition(parVars *d7partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d7initParVars(parVars, parVars.branchCount, minFill) + d7pickSeeds(parVars) + + 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++ { + if d7notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d7combineRect(curRect, &parVars.cover[0]) + rect1 := d7combineRect(curRect, &parVars.cover[1]) + growth0 := d7calcRectVolume(&rect0) - parVars.area[0] + growth1 := d7calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d7classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d7notTaken == parVars.partition[index] { + d7classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d7loadNodes(nodeA, nodeB *d7nodeT, parVars *d7partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d7nodeT{nodeA, nodeB} + + // It is assured that d7addBranch here will not cause a node split. + d7addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d7partitionVarsT structure. +func d7initParVars(parVars *d7partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d7notTaken + } +} + +func d7pickSeeds(parVars *d7partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d7maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d7calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d7combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d7calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d7classify(seed0, 0, parVars) + d7classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d7classify(index, group int, parVars *d7partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d7combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d7calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d7rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d7removeRect provides for eliminating the root. +func d7removeRect(rect *d7rectT, id interface{}, root **d7nodeT) bool { + var reInsertList *d7listNodeT + + if !d7removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d7insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d7removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d7removeRectRec(rect *d7rectT, id interface{}, node *d7nodeT, listNode **d7listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d7overlap(*rect, node.branch[index].rect) { + if !d7removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d7minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d7nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d7reInsert(node.branch[index].child, listNode) + d7disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d7disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d7overlap. +func d7overlap(rectA, rectB d7rectT) bool { + for index := 0; index < d7numDims; index++ { + 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. +func d7reInsert(node *d7nodeT, listNode **d7listNodeT) { + newListNode := &d7listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d7search in an index tree or subtree for all data retangles that d7overlap the argument rectangle. +func d7search(node *d7nodeT, rect d7rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d7overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d7search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d7overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d8fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d8fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d8numDims = 8 + d8maxNodes = 8 + d8minNodes = d8maxNodes / 2 + d8useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d8unitSphereVolume = []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 +}[d8numDims] + +type d8RTree struct { + root *d8nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d8rectT struct { + min [d8numDims]float64 ///< Min dimensions of bounding box + max [d8numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d8branchT struct { + rect d8rectT ///< Bounds + child *d8nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d8nodeT for each branch level +type d8nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d8maxNodes]d8branchT ///< Branch +} + +func (node *d8nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d8nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d8listNodeT struct { + next *d8listNodeT ///< Next in list + node *d8nodeT ///< Node +} + +const d8notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d8partitionVarsT struct { + partition [d8maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d8rectT + area [2]float64 + + branchBuf [d8maxNodes + 1]d8branchT + branchCount int + coverSplit d8rectT + coverSplitArea float64 +} + +func d8New() *d8RTree { + // 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 &d8RTree{ + root: &d8nodeT{}, + } +} + +/// 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. +func (tr *d8RTree) Insert(min, max [d8numDims]float64, dataId interface{}) { + var branch d8branchT + branch.data = dataId + for axis := 0; axis < d8numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d8insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d8RTree) Remove(min, max [d8numDims]float64, dataId interface{}) { + var rect d8rectT + for axis := 0; axis < d8numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d8removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d8search rectangle +/// \param a_min Min of d8search bounding rect +/// \param a_max Max of d8search bounding rect +/// \param a_searchResult d8search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d8RTree) Search(min, max [d8numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d8rectT + for axis := 0; axis < d8numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d8search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d8RTree) Count() int { + var count int + d8countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d8RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d8nodeT{} +} + +func d8countRec(node *d8nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d8countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d8insertRectRec(branch *d8branchT, node *d8nodeT, newNode **d8nodeT, level int) bool { + // 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 + var otherNode *d8nodeT + //var newBranch d8branchT + + // find the optimal branch for this record + index := d8pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d8insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d8combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d8nodeCover(node.branch[index].child) + var newBranch d8branchT + newBranch.child = otherNode + newBranch.rect = d8nodeCover(otherNode) + + // 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. + return d8addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d8addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d8insertRect provides for splitting the root; +// 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. +// +func d8insertRect(branch *d8branchT, root **d8nodeT, level int) bool { + var newNode *d8nodeT + + if d8insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d8nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d8branchT + + // add old root node as a child of the new root + newBranch.rect = d8nodeCover(*root) + newBranch.child = *root + d8addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d8nodeCover(newNode) + newBranch.child = newNode + d8addBranch(&newBranch, newRoot, nil) + + // 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. +func d8nodeCover(node *d8nodeT) d8rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d8combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d8addBranch(branch *d8branchT, node *d8nodeT, newNode **d8nodeT) bool { + if node.count < d8maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d8splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d8disconnectBranch(node *d8nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d8pickBranch(rect *d8rectT, node *d8nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d8rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d8calcRectVolume(curRect) + tempRect = d8combineRect(rect, curRect) + increase = d8calcRectVolume(&tempRect) - area + 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 +func d8combineRect(rectA, rectB *d8rectT) d8rectT { + var newRect d8rectT + + for index := 0; index < d8numDims; index++ { + newRect.min[index] = d8fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d8fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d8splitNode(node *d8nodeT, branch *d8branchT, newNode **d8nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d8partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d8getBranches(node, branch, parVars) + + // Find partition + d8choosePartition(parVars, d8minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d8nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d8loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d8rectVolume(rect *d8rectT) float64 { + var volume float64 = 1 + for index := 0; index < d8numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d8rectT +func d8rectSphericalVolume(rect *d8rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d8numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d8numDims == 5 { + return (radius * radius * radius * radius * radius * d8unitSphereVolume) + } else if d8numDims == 4 { + return (radius * radius * radius * radius * d8unitSphereVolume) + } else if d8numDims == 3 { + return (radius * radius * radius * d8unitSphereVolume) + } else if d8numDims == 2 { + return (radius * radius * d8unitSphereVolume) + } else { + return (math.Pow(radius, d8numDims) * d8unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d8calcRectVolume(rect *d8rectT) float64 { + if d8useSphericalVolume { + return d8rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d8rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d8getBranches(node *d8nodeT, branch *d8branchT, parVars *d8partitionVarsT) { + // Load the branch buffer + for index := 0; index < d8maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d8maxNodes] = *branch + parVars.branchCount = d8maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d8maxNodes+1; index++ { + parVars.coverSplit = d8combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d8calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d8choosePartition(parVars *d8partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d8initParVars(parVars, parVars.branchCount, minFill) + d8pickSeeds(parVars) + + 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++ { + if d8notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d8combineRect(curRect, &parVars.cover[0]) + rect1 := d8combineRect(curRect, &parVars.cover[1]) + growth0 := d8calcRectVolume(&rect0) - parVars.area[0] + growth1 := d8calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d8classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d8notTaken == parVars.partition[index] { + d8classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d8loadNodes(nodeA, nodeB *d8nodeT, parVars *d8partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d8nodeT{nodeA, nodeB} + + // It is assured that d8addBranch here will not cause a node split. + d8addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d8partitionVarsT structure. +func d8initParVars(parVars *d8partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d8notTaken + } +} + +func d8pickSeeds(parVars *d8partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d8maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d8calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d8combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d8calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d8classify(seed0, 0, parVars) + d8classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d8classify(index, group int, parVars *d8partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d8combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d8calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d8rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d8removeRect provides for eliminating the root. +func d8removeRect(rect *d8rectT, id interface{}, root **d8nodeT) bool { + var reInsertList *d8listNodeT + + if !d8removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d8insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d8removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d8removeRectRec(rect *d8rectT, id interface{}, node *d8nodeT, listNode **d8listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d8overlap(*rect, node.branch[index].rect) { + if !d8removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d8minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d8nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d8reInsert(node.branch[index].child, listNode) + d8disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d8disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d8overlap. +func d8overlap(rectA, rectB d8rectT) bool { + for index := 0; index < d8numDims; index++ { + 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. +func d8reInsert(node *d8nodeT, listNode **d8listNodeT) { + newListNode := &d8listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d8search in an index tree or subtree for all data retangles that d8overlap the argument rectangle. +func d8search(node *d8nodeT, rect d8rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d8overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d8search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d8overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d9fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d9fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d9numDims = 9 + d9maxNodes = 8 + d9minNodes = d9maxNodes / 2 + d9useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d9unitSphereVolume = []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 +}[d9numDims] + +type d9RTree struct { + root *d9nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d9rectT struct { + min [d9numDims]float64 ///< Min dimensions of bounding box + max [d9numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d9branchT struct { + rect d9rectT ///< Bounds + child *d9nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d9nodeT for each branch level +type d9nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d9maxNodes]d9branchT ///< Branch +} + +func (node *d9nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d9nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d9listNodeT struct { + next *d9listNodeT ///< Next in list + node *d9nodeT ///< Node +} + +const d9notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d9partitionVarsT struct { + partition [d9maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d9rectT + area [2]float64 + + branchBuf [d9maxNodes + 1]d9branchT + branchCount int + coverSplit d9rectT + coverSplitArea float64 +} + +func d9New() *d9RTree { + // 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 &d9RTree{ + root: &d9nodeT{}, + } +} + +/// 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. +func (tr *d9RTree) Insert(min, max [d9numDims]float64, dataId interface{}) { + var branch d9branchT + branch.data = dataId + for axis := 0; axis < d9numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d9insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d9RTree) Remove(min, max [d9numDims]float64, dataId interface{}) { + var rect d9rectT + for axis := 0; axis < d9numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d9removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d9search rectangle +/// \param a_min Min of d9search bounding rect +/// \param a_max Max of d9search bounding rect +/// \param a_searchResult d9search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d9RTree) Search(min, max [d9numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d9rectT + for axis := 0; axis < d9numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d9search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d9RTree) Count() int { + var count int + d9countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d9RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d9nodeT{} +} + +func d9countRec(node *d9nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d9countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d9insertRectRec(branch *d9branchT, node *d9nodeT, newNode **d9nodeT, level int) bool { + // 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 + var otherNode *d9nodeT + //var newBranch d9branchT + + // find the optimal branch for this record + index := d9pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d9insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d9combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d9nodeCover(node.branch[index].child) + var newBranch d9branchT + newBranch.child = otherNode + newBranch.rect = d9nodeCover(otherNode) + + // 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. + return d9addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d9addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d9insertRect provides for splitting the root; +// 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. +// +func d9insertRect(branch *d9branchT, root **d9nodeT, level int) bool { + var newNode *d9nodeT + + if d9insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d9nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d9branchT + + // add old root node as a child of the new root + newBranch.rect = d9nodeCover(*root) + newBranch.child = *root + d9addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d9nodeCover(newNode) + newBranch.child = newNode + d9addBranch(&newBranch, newRoot, nil) + + // 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. +func d9nodeCover(node *d9nodeT) d9rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d9combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d9addBranch(branch *d9branchT, node *d9nodeT, newNode **d9nodeT) bool { + if node.count < d9maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d9splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d9disconnectBranch(node *d9nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d9pickBranch(rect *d9rectT, node *d9nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d9rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d9calcRectVolume(curRect) + tempRect = d9combineRect(rect, curRect) + increase = d9calcRectVolume(&tempRect) - area + 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 +func d9combineRect(rectA, rectB *d9rectT) d9rectT { + var newRect d9rectT + + for index := 0; index < d9numDims; index++ { + newRect.min[index] = d9fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d9fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d9splitNode(node *d9nodeT, branch *d9branchT, newNode **d9nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d9partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d9getBranches(node, branch, parVars) + + // Find partition + d9choosePartition(parVars, d9minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d9nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d9loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d9rectVolume(rect *d9rectT) float64 { + var volume float64 = 1 + for index := 0; index < d9numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d9rectT +func d9rectSphericalVolume(rect *d9rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d9numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d9numDims == 5 { + return (radius * radius * radius * radius * radius * d9unitSphereVolume) + } else if d9numDims == 4 { + return (radius * radius * radius * radius * d9unitSphereVolume) + } else if d9numDims == 3 { + return (radius * radius * radius * d9unitSphereVolume) + } else if d9numDims == 2 { + return (radius * radius * d9unitSphereVolume) + } else { + return (math.Pow(radius, d9numDims) * d9unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d9calcRectVolume(rect *d9rectT) float64 { + if d9useSphericalVolume { + return d9rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d9rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d9getBranches(node *d9nodeT, branch *d9branchT, parVars *d9partitionVarsT) { + // Load the branch buffer + for index := 0; index < d9maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d9maxNodes] = *branch + parVars.branchCount = d9maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d9maxNodes+1; index++ { + parVars.coverSplit = d9combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d9calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d9choosePartition(parVars *d9partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d9initParVars(parVars, parVars.branchCount, minFill) + d9pickSeeds(parVars) + + 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++ { + if d9notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d9combineRect(curRect, &parVars.cover[0]) + rect1 := d9combineRect(curRect, &parVars.cover[1]) + growth0 := d9calcRectVolume(&rect0) - parVars.area[0] + growth1 := d9calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d9classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d9notTaken == parVars.partition[index] { + d9classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d9loadNodes(nodeA, nodeB *d9nodeT, parVars *d9partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d9nodeT{nodeA, nodeB} + + // It is assured that d9addBranch here will not cause a node split. + d9addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d9partitionVarsT structure. +func d9initParVars(parVars *d9partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d9notTaken + } +} + +func d9pickSeeds(parVars *d9partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d9maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d9calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d9combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d9calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d9classify(seed0, 0, parVars) + d9classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d9classify(index, group int, parVars *d9partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d9combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d9calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d9rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d9removeRect provides for eliminating the root. +func d9removeRect(rect *d9rectT, id interface{}, root **d9nodeT) bool { + var reInsertList *d9listNodeT + + if !d9removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d9insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d9removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d9removeRectRec(rect *d9rectT, id interface{}, node *d9nodeT, listNode **d9listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d9overlap(*rect, node.branch[index].rect) { + if !d9removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d9minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d9nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d9reInsert(node.branch[index].child, listNode) + d9disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d9disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d9overlap. +func d9overlap(rectA, rectB d9rectT) bool { + for index := 0; index < d9numDims; index++ { + 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. +func d9reInsert(node *d9nodeT, listNode **d9listNodeT) { + newListNode := &d9listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d9search in an index tree or subtree for all data retangles that d9overlap the argument rectangle. +func d9search(node *d9nodeT, rect d9rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d9overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d9search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d9overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d10fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d10fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d10numDims = 10 + d10maxNodes = 8 + d10minNodes = d10maxNodes / 2 + d10useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d10unitSphereVolume = []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 +}[d10numDims] + +type d10RTree struct { + root *d10nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d10rectT struct { + min [d10numDims]float64 ///< Min dimensions of bounding box + max [d10numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d10branchT struct { + rect d10rectT ///< Bounds + child *d10nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d10nodeT for each branch level +type d10nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d10maxNodes]d10branchT ///< Branch +} + +func (node *d10nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d10nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d10listNodeT struct { + next *d10listNodeT ///< Next in list + node *d10nodeT ///< Node +} + +const d10notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d10partitionVarsT struct { + partition [d10maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d10rectT + area [2]float64 + + branchBuf [d10maxNodes + 1]d10branchT + branchCount int + coverSplit d10rectT + coverSplitArea float64 +} + +func d10New() *d10RTree { + // 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 &d10RTree{ + root: &d10nodeT{}, + } +} + +/// 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. +func (tr *d10RTree) Insert(min, max [d10numDims]float64, dataId interface{}) { + var branch d10branchT + branch.data = dataId + for axis := 0; axis < d10numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d10insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d10RTree) Remove(min, max [d10numDims]float64, dataId interface{}) { + var rect d10rectT + for axis := 0; axis < d10numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d10removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d10search rectangle +/// \param a_min Min of d10search bounding rect +/// \param a_max Max of d10search bounding rect +/// \param a_searchResult d10search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d10RTree) Search(min, max [d10numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d10rectT + for axis := 0; axis < d10numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d10search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d10RTree) Count() int { + var count int + d10countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d10RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d10nodeT{} +} + +func d10countRec(node *d10nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d10countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d10insertRectRec(branch *d10branchT, node *d10nodeT, newNode **d10nodeT, level int) bool { + // 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 + var otherNode *d10nodeT + //var newBranch d10branchT + + // find the optimal branch for this record + index := d10pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d10insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d10combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d10nodeCover(node.branch[index].child) + var newBranch d10branchT + newBranch.child = otherNode + newBranch.rect = d10nodeCover(otherNode) + + // 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. + return d10addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d10addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d10insertRect provides for splitting the root; +// 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. +// +func d10insertRect(branch *d10branchT, root **d10nodeT, level int) bool { + var newNode *d10nodeT + + if d10insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d10nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d10branchT + + // add old root node as a child of the new root + newBranch.rect = d10nodeCover(*root) + newBranch.child = *root + d10addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d10nodeCover(newNode) + newBranch.child = newNode + d10addBranch(&newBranch, newRoot, nil) + + // 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. +func d10nodeCover(node *d10nodeT) d10rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d10combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d10addBranch(branch *d10branchT, node *d10nodeT, newNode **d10nodeT) bool { + if node.count < d10maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d10splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d10disconnectBranch(node *d10nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d10pickBranch(rect *d10rectT, node *d10nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d10rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d10calcRectVolume(curRect) + tempRect = d10combineRect(rect, curRect) + increase = d10calcRectVolume(&tempRect) - area + 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 +func d10combineRect(rectA, rectB *d10rectT) d10rectT { + var newRect d10rectT + + for index := 0; index < d10numDims; index++ { + newRect.min[index] = d10fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d10fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d10splitNode(node *d10nodeT, branch *d10branchT, newNode **d10nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d10partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d10getBranches(node, branch, parVars) + + // Find partition + d10choosePartition(parVars, d10minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d10nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d10loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d10rectVolume(rect *d10rectT) float64 { + var volume float64 = 1 + for index := 0; index < d10numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d10rectT +func d10rectSphericalVolume(rect *d10rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d10numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d10numDims == 5 { + return (radius * radius * radius * radius * radius * d10unitSphereVolume) + } else if d10numDims == 4 { + return (radius * radius * radius * radius * d10unitSphereVolume) + } else if d10numDims == 3 { + return (radius * radius * radius * d10unitSphereVolume) + } else if d10numDims == 2 { + return (radius * radius * d10unitSphereVolume) + } else { + return (math.Pow(radius, d10numDims) * d10unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d10calcRectVolume(rect *d10rectT) float64 { + if d10useSphericalVolume { + return d10rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d10rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d10getBranches(node *d10nodeT, branch *d10branchT, parVars *d10partitionVarsT) { + // Load the branch buffer + for index := 0; index < d10maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d10maxNodes] = *branch + parVars.branchCount = d10maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d10maxNodes+1; index++ { + parVars.coverSplit = d10combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d10calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d10choosePartition(parVars *d10partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d10initParVars(parVars, parVars.branchCount, minFill) + d10pickSeeds(parVars) + + 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++ { + if d10notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d10combineRect(curRect, &parVars.cover[0]) + rect1 := d10combineRect(curRect, &parVars.cover[1]) + growth0 := d10calcRectVolume(&rect0) - parVars.area[0] + growth1 := d10calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d10classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d10notTaken == parVars.partition[index] { + d10classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d10loadNodes(nodeA, nodeB *d10nodeT, parVars *d10partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d10nodeT{nodeA, nodeB} + + // It is assured that d10addBranch here will not cause a node split. + d10addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d10partitionVarsT structure. +func d10initParVars(parVars *d10partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d10notTaken + } +} + +func d10pickSeeds(parVars *d10partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d10maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d10calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d10combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d10calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d10classify(seed0, 0, parVars) + d10classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d10classify(index, group int, parVars *d10partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d10combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d10calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d10rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d10removeRect provides for eliminating the root. +func d10removeRect(rect *d10rectT, id interface{}, root **d10nodeT) bool { + var reInsertList *d10listNodeT + + if !d10removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d10insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d10removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d10removeRectRec(rect *d10rectT, id interface{}, node *d10nodeT, listNode **d10listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d10overlap(*rect, node.branch[index].rect) { + if !d10removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d10minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d10nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d10reInsert(node.branch[index].child, listNode) + d10disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d10disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d10overlap. +func d10overlap(rectA, rectB d10rectT) bool { + for index := 0; index < d10numDims; index++ { + 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. +func d10reInsert(node *d10nodeT, listNode **d10listNodeT) { + newListNode := &d10listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d10search in an index tree or subtree for all data retangles that d10overlap the argument rectangle. +func d10search(node *d10nodeT, rect d10rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d10overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d10search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d10overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d11fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d11fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d11numDims = 11 + d11maxNodes = 8 + d11minNodes = d11maxNodes / 2 + d11useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d11unitSphereVolume = []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 +}[d11numDims] + +type d11RTree struct { + root *d11nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d11rectT struct { + min [d11numDims]float64 ///< Min dimensions of bounding box + max [d11numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d11branchT struct { + rect d11rectT ///< Bounds + child *d11nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d11nodeT for each branch level +type d11nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d11maxNodes]d11branchT ///< Branch +} + +func (node *d11nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d11nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d11listNodeT struct { + next *d11listNodeT ///< Next in list + node *d11nodeT ///< Node +} + +const d11notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d11partitionVarsT struct { + partition [d11maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d11rectT + area [2]float64 + + branchBuf [d11maxNodes + 1]d11branchT + branchCount int + coverSplit d11rectT + coverSplitArea float64 +} + +func d11New() *d11RTree { + // 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 &d11RTree{ + root: &d11nodeT{}, + } +} + +/// 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. +func (tr *d11RTree) Insert(min, max [d11numDims]float64, dataId interface{}) { + var branch d11branchT + branch.data = dataId + for axis := 0; axis < d11numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d11insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d11RTree) Remove(min, max [d11numDims]float64, dataId interface{}) { + var rect d11rectT + for axis := 0; axis < d11numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d11removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d11search rectangle +/// \param a_min Min of d11search bounding rect +/// \param a_max Max of d11search bounding rect +/// \param a_searchResult d11search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d11RTree) Search(min, max [d11numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d11rectT + for axis := 0; axis < d11numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d11search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d11RTree) Count() int { + var count int + d11countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d11RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d11nodeT{} +} + +func d11countRec(node *d11nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d11countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d11insertRectRec(branch *d11branchT, node *d11nodeT, newNode **d11nodeT, level int) bool { + // 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 + var otherNode *d11nodeT + //var newBranch d11branchT + + // find the optimal branch for this record + index := d11pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d11insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d11combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d11nodeCover(node.branch[index].child) + var newBranch d11branchT + newBranch.child = otherNode + newBranch.rect = d11nodeCover(otherNode) + + // 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. + return d11addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d11addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d11insertRect provides for splitting the root; +// 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. +// +func d11insertRect(branch *d11branchT, root **d11nodeT, level int) bool { + var newNode *d11nodeT + + if d11insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d11nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d11branchT + + // add old root node as a child of the new root + newBranch.rect = d11nodeCover(*root) + newBranch.child = *root + d11addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d11nodeCover(newNode) + newBranch.child = newNode + d11addBranch(&newBranch, newRoot, nil) + + // 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. +func d11nodeCover(node *d11nodeT) d11rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d11combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d11addBranch(branch *d11branchT, node *d11nodeT, newNode **d11nodeT) bool { + if node.count < d11maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d11splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d11disconnectBranch(node *d11nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d11pickBranch(rect *d11rectT, node *d11nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d11rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d11calcRectVolume(curRect) + tempRect = d11combineRect(rect, curRect) + increase = d11calcRectVolume(&tempRect) - area + 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 +func d11combineRect(rectA, rectB *d11rectT) d11rectT { + var newRect d11rectT + + for index := 0; index < d11numDims; index++ { + newRect.min[index] = d11fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d11fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d11splitNode(node *d11nodeT, branch *d11branchT, newNode **d11nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d11partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d11getBranches(node, branch, parVars) + + // Find partition + d11choosePartition(parVars, d11minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d11nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d11loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d11rectVolume(rect *d11rectT) float64 { + var volume float64 = 1 + for index := 0; index < d11numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d11rectT +func d11rectSphericalVolume(rect *d11rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d11numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d11numDims == 5 { + return (radius * radius * radius * radius * radius * d11unitSphereVolume) + } else if d11numDims == 4 { + return (radius * radius * radius * radius * d11unitSphereVolume) + } else if d11numDims == 3 { + return (radius * radius * radius * d11unitSphereVolume) + } else if d11numDims == 2 { + return (radius * radius * d11unitSphereVolume) + } else { + return (math.Pow(radius, d11numDims) * d11unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d11calcRectVolume(rect *d11rectT) float64 { + if d11useSphericalVolume { + return d11rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d11rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d11getBranches(node *d11nodeT, branch *d11branchT, parVars *d11partitionVarsT) { + // Load the branch buffer + for index := 0; index < d11maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d11maxNodes] = *branch + parVars.branchCount = d11maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d11maxNodes+1; index++ { + parVars.coverSplit = d11combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d11calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d11choosePartition(parVars *d11partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d11initParVars(parVars, parVars.branchCount, minFill) + d11pickSeeds(parVars) + + 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++ { + if d11notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d11combineRect(curRect, &parVars.cover[0]) + rect1 := d11combineRect(curRect, &parVars.cover[1]) + growth0 := d11calcRectVolume(&rect0) - parVars.area[0] + growth1 := d11calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d11classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d11notTaken == parVars.partition[index] { + d11classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d11loadNodes(nodeA, nodeB *d11nodeT, parVars *d11partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d11nodeT{nodeA, nodeB} + + // It is assured that d11addBranch here will not cause a node split. + d11addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d11partitionVarsT structure. +func d11initParVars(parVars *d11partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d11notTaken + } +} + +func d11pickSeeds(parVars *d11partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d11maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d11calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d11combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d11calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d11classify(seed0, 0, parVars) + d11classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d11classify(index, group int, parVars *d11partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d11combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d11calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d11rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d11removeRect provides for eliminating the root. +func d11removeRect(rect *d11rectT, id interface{}, root **d11nodeT) bool { + var reInsertList *d11listNodeT + + if !d11removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d11insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d11removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d11removeRectRec(rect *d11rectT, id interface{}, node *d11nodeT, listNode **d11listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d11overlap(*rect, node.branch[index].rect) { + if !d11removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d11minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d11nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d11reInsert(node.branch[index].child, listNode) + d11disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d11disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d11overlap. +func d11overlap(rectA, rectB d11rectT) bool { + for index := 0; index < d11numDims; index++ { + 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. +func d11reInsert(node *d11nodeT, listNode **d11listNodeT) { + newListNode := &d11listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d11search in an index tree or subtree for all data retangles that d11overlap the argument rectangle. +func d11search(node *d11nodeT, rect d11rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d11overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d11search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d11overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d12fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d12fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d12numDims = 12 + d12maxNodes = 8 + d12minNodes = d12maxNodes / 2 + d12useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d12unitSphereVolume = []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 +}[d12numDims] + +type d12RTree struct { + root *d12nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d12rectT struct { + min [d12numDims]float64 ///< Min dimensions of bounding box + max [d12numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d12branchT struct { + rect d12rectT ///< Bounds + child *d12nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d12nodeT for each branch level +type d12nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d12maxNodes]d12branchT ///< Branch +} + +func (node *d12nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d12nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d12listNodeT struct { + next *d12listNodeT ///< Next in list + node *d12nodeT ///< Node +} + +const d12notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d12partitionVarsT struct { + partition [d12maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d12rectT + area [2]float64 + + branchBuf [d12maxNodes + 1]d12branchT + branchCount int + coverSplit d12rectT + coverSplitArea float64 +} + +func d12New() *d12RTree { + // 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 &d12RTree{ + root: &d12nodeT{}, + } +} + +/// 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. +func (tr *d12RTree) Insert(min, max [d12numDims]float64, dataId interface{}) { + var branch d12branchT + branch.data = dataId + for axis := 0; axis < d12numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d12insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d12RTree) Remove(min, max [d12numDims]float64, dataId interface{}) { + var rect d12rectT + for axis := 0; axis < d12numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d12removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d12search rectangle +/// \param a_min Min of d12search bounding rect +/// \param a_max Max of d12search bounding rect +/// \param a_searchResult d12search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d12RTree) Search(min, max [d12numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d12rectT + for axis := 0; axis < d12numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d12search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d12RTree) Count() int { + var count int + d12countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d12RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d12nodeT{} +} + +func d12countRec(node *d12nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d12countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d12insertRectRec(branch *d12branchT, node *d12nodeT, newNode **d12nodeT, level int) bool { + // 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 + var otherNode *d12nodeT + //var newBranch d12branchT + + // find the optimal branch for this record + index := d12pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d12insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d12combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d12nodeCover(node.branch[index].child) + var newBranch d12branchT + newBranch.child = otherNode + newBranch.rect = d12nodeCover(otherNode) + + // 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. + return d12addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d12addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d12insertRect provides for splitting the root; +// 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. +// +func d12insertRect(branch *d12branchT, root **d12nodeT, level int) bool { + var newNode *d12nodeT + + if d12insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d12nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d12branchT + + // add old root node as a child of the new root + newBranch.rect = d12nodeCover(*root) + newBranch.child = *root + d12addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d12nodeCover(newNode) + newBranch.child = newNode + d12addBranch(&newBranch, newRoot, nil) + + // 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. +func d12nodeCover(node *d12nodeT) d12rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d12combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d12addBranch(branch *d12branchT, node *d12nodeT, newNode **d12nodeT) bool { + if node.count < d12maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d12splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d12disconnectBranch(node *d12nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d12pickBranch(rect *d12rectT, node *d12nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d12rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d12calcRectVolume(curRect) + tempRect = d12combineRect(rect, curRect) + increase = d12calcRectVolume(&tempRect) - area + 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 +func d12combineRect(rectA, rectB *d12rectT) d12rectT { + var newRect d12rectT + + for index := 0; index < d12numDims; index++ { + newRect.min[index] = d12fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d12fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d12splitNode(node *d12nodeT, branch *d12branchT, newNode **d12nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d12partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d12getBranches(node, branch, parVars) + + // Find partition + d12choosePartition(parVars, d12minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d12nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d12loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d12rectVolume(rect *d12rectT) float64 { + var volume float64 = 1 + for index := 0; index < d12numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d12rectT +func d12rectSphericalVolume(rect *d12rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d12numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d12numDims == 5 { + return (radius * radius * radius * radius * radius * d12unitSphereVolume) + } else if d12numDims == 4 { + return (radius * radius * radius * radius * d12unitSphereVolume) + } else if d12numDims == 3 { + return (radius * radius * radius * d12unitSphereVolume) + } else if d12numDims == 2 { + return (radius * radius * d12unitSphereVolume) + } else { + return (math.Pow(radius, d12numDims) * d12unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d12calcRectVolume(rect *d12rectT) float64 { + if d12useSphericalVolume { + return d12rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d12rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d12getBranches(node *d12nodeT, branch *d12branchT, parVars *d12partitionVarsT) { + // Load the branch buffer + for index := 0; index < d12maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d12maxNodes] = *branch + parVars.branchCount = d12maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d12maxNodes+1; index++ { + parVars.coverSplit = d12combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d12calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d12choosePartition(parVars *d12partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d12initParVars(parVars, parVars.branchCount, minFill) + d12pickSeeds(parVars) + + 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++ { + if d12notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d12combineRect(curRect, &parVars.cover[0]) + rect1 := d12combineRect(curRect, &parVars.cover[1]) + growth0 := d12calcRectVolume(&rect0) - parVars.area[0] + growth1 := d12calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d12classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d12notTaken == parVars.partition[index] { + d12classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d12loadNodes(nodeA, nodeB *d12nodeT, parVars *d12partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d12nodeT{nodeA, nodeB} + + // It is assured that d12addBranch here will not cause a node split. + d12addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d12partitionVarsT structure. +func d12initParVars(parVars *d12partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d12notTaken + } +} + +func d12pickSeeds(parVars *d12partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d12maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d12calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d12combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d12calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d12classify(seed0, 0, parVars) + d12classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d12classify(index, group int, parVars *d12partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d12combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d12calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d12rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d12removeRect provides for eliminating the root. +func d12removeRect(rect *d12rectT, id interface{}, root **d12nodeT) bool { + var reInsertList *d12listNodeT + + if !d12removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d12insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d12removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d12removeRectRec(rect *d12rectT, id interface{}, node *d12nodeT, listNode **d12listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d12overlap(*rect, node.branch[index].rect) { + if !d12removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d12minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d12nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d12reInsert(node.branch[index].child, listNode) + d12disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d12disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d12overlap. +func d12overlap(rectA, rectB d12rectT) bool { + for index := 0; index < d12numDims; index++ { + 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. +func d12reInsert(node *d12nodeT, listNode **d12listNodeT) { + newListNode := &d12listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d12search in an index tree or subtree for all data retangles that d12overlap the argument rectangle. +func d12search(node *d12nodeT, rect d12rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d12overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d12search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d12overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d13fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d13fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d13numDims = 13 + d13maxNodes = 8 + d13minNodes = d13maxNodes / 2 + d13useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d13unitSphereVolume = []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 +}[d13numDims] + +type d13RTree struct { + root *d13nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d13rectT struct { + min [d13numDims]float64 ///< Min dimensions of bounding box + max [d13numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d13branchT struct { + rect d13rectT ///< Bounds + child *d13nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d13nodeT for each branch level +type d13nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d13maxNodes]d13branchT ///< Branch +} + +func (node *d13nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d13nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d13listNodeT struct { + next *d13listNodeT ///< Next in list + node *d13nodeT ///< Node +} + +const d13notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d13partitionVarsT struct { + partition [d13maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d13rectT + area [2]float64 + + branchBuf [d13maxNodes + 1]d13branchT + branchCount int + coverSplit d13rectT + coverSplitArea float64 +} + +func d13New() *d13RTree { + // 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 &d13RTree{ + root: &d13nodeT{}, + } +} + +/// 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. +func (tr *d13RTree) Insert(min, max [d13numDims]float64, dataId interface{}) { + var branch d13branchT + branch.data = dataId + for axis := 0; axis < d13numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d13insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d13RTree) Remove(min, max [d13numDims]float64, dataId interface{}) { + var rect d13rectT + for axis := 0; axis < d13numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d13removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d13search rectangle +/// \param a_min Min of d13search bounding rect +/// \param a_max Max of d13search bounding rect +/// \param a_searchResult d13search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d13RTree) Search(min, max [d13numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d13rectT + for axis := 0; axis < d13numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d13search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d13RTree) Count() int { + var count int + d13countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d13RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d13nodeT{} +} + +func d13countRec(node *d13nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d13countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d13insertRectRec(branch *d13branchT, node *d13nodeT, newNode **d13nodeT, level int) bool { + // 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 + var otherNode *d13nodeT + //var newBranch d13branchT + + // find the optimal branch for this record + index := d13pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d13insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d13combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d13nodeCover(node.branch[index].child) + var newBranch d13branchT + newBranch.child = otherNode + newBranch.rect = d13nodeCover(otherNode) + + // 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. + return d13addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d13addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d13insertRect provides for splitting the root; +// 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. +// +func d13insertRect(branch *d13branchT, root **d13nodeT, level int) bool { + var newNode *d13nodeT + + if d13insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d13nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d13branchT + + // add old root node as a child of the new root + newBranch.rect = d13nodeCover(*root) + newBranch.child = *root + d13addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d13nodeCover(newNode) + newBranch.child = newNode + d13addBranch(&newBranch, newRoot, nil) + + // 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. +func d13nodeCover(node *d13nodeT) d13rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d13combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d13addBranch(branch *d13branchT, node *d13nodeT, newNode **d13nodeT) bool { + if node.count < d13maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d13splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d13disconnectBranch(node *d13nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d13pickBranch(rect *d13rectT, node *d13nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d13rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d13calcRectVolume(curRect) + tempRect = d13combineRect(rect, curRect) + increase = d13calcRectVolume(&tempRect) - area + 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 +func d13combineRect(rectA, rectB *d13rectT) d13rectT { + var newRect d13rectT + + for index := 0; index < d13numDims; index++ { + newRect.min[index] = d13fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d13fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d13splitNode(node *d13nodeT, branch *d13branchT, newNode **d13nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d13partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d13getBranches(node, branch, parVars) + + // Find partition + d13choosePartition(parVars, d13minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d13nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d13loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d13rectVolume(rect *d13rectT) float64 { + var volume float64 = 1 + for index := 0; index < d13numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d13rectT +func d13rectSphericalVolume(rect *d13rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d13numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d13numDims == 5 { + return (radius * radius * radius * radius * radius * d13unitSphereVolume) + } else if d13numDims == 4 { + return (radius * radius * radius * radius * d13unitSphereVolume) + } else if d13numDims == 3 { + return (radius * radius * radius * d13unitSphereVolume) + } else if d13numDims == 2 { + return (radius * radius * d13unitSphereVolume) + } else { + return (math.Pow(radius, d13numDims) * d13unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d13calcRectVolume(rect *d13rectT) float64 { + if d13useSphericalVolume { + return d13rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d13rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d13getBranches(node *d13nodeT, branch *d13branchT, parVars *d13partitionVarsT) { + // Load the branch buffer + for index := 0; index < d13maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d13maxNodes] = *branch + parVars.branchCount = d13maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d13maxNodes+1; index++ { + parVars.coverSplit = d13combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d13calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d13choosePartition(parVars *d13partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d13initParVars(parVars, parVars.branchCount, minFill) + d13pickSeeds(parVars) + + 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++ { + if d13notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d13combineRect(curRect, &parVars.cover[0]) + rect1 := d13combineRect(curRect, &parVars.cover[1]) + growth0 := d13calcRectVolume(&rect0) - parVars.area[0] + growth1 := d13calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d13classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d13notTaken == parVars.partition[index] { + d13classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d13loadNodes(nodeA, nodeB *d13nodeT, parVars *d13partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d13nodeT{nodeA, nodeB} + + // It is assured that d13addBranch here will not cause a node split. + d13addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d13partitionVarsT structure. +func d13initParVars(parVars *d13partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d13notTaken + } +} + +func d13pickSeeds(parVars *d13partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d13maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d13calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d13combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d13calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d13classify(seed0, 0, parVars) + d13classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d13classify(index, group int, parVars *d13partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d13combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d13calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d13rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d13removeRect provides for eliminating the root. +func d13removeRect(rect *d13rectT, id interface{}, root **d13nodeT) bool { + var reInsertList *d13listNodeT + + if !d13removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d13insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d13removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d13removeRectRec(rect *d13rectT, id interface{}, node *d13nodeT, listNode **d13listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d13overlap(*rect, node.branch[index].rect) { + if !d13removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d13minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d13nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d13reInsert(node.branch[index].child, listNode) + d13disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d13disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d13overlap. +func d13overlap(rectA, rectB d13rectT) bool { + for index := 0; index < d13numDims; index++ { + 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. +func d13reInsert(node *d13nodeT, listNode **d13listNodeT) { + newListNode := &d13listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d13search in an index tree or subtree for all data retangles that d13overlap the argument rectangle. +func d13search(node *d13nodeT, rect d13rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d13overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d13search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d13overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d14fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d14fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d14numDims = 14 + d14maxNodes = 8 + d14minNodes = d14maxNodes / 2 + d14useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d14unitSphereVolume = []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 +}[d14numDims] + +type d14RTree struct { + root *d14nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d14rectT struct { + min [d14numDims]float64 ///< Min dimensions of bounding box + max [d14numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d14branchT struct { + rect d14rectT ///< Bounds + child *d14nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d14nodeT for each branch level +type d14nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d14maxNodes]d14branchT ///< Branch +} + +func (node *d14nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d14nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d14listNodeT struct { + next *d14listNodeT ///< Next in list + node *d14nodeT ///< Node +} + +const d14notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d14partitionVarsT struct { + partition [d14maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d14rectT + area [2]float64 + + branchBuf [d14maxNodes + 1]d14branchT + branchCount int + coverSplit d14rectT + coverSplitArea float64 +} + +func d14New() *d14RTree { + // 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 &d14RTree{ + root: &d14nodeT{}, + } +} + +/// 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. +func (tr *d14RTree) Insert(min, max [d14numDims]float64, dataId interface{}) { + var branch d14branchT + branch.data = dataId + for axis := 0; axis < d14numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d14insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d14RTree) Remove(min, max [d14numDims]float64, dataId interface{}) { + var rect d14rectT + for axis := 0; axis < d14numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d14removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d14search rectangle +/// \param a_min Min of d14search bounding rect +/// \param a_max Max of d14search bounding rect +/// \param a_searchResult d14search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d14RTree) Search(min, max [d14numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d14rectT + for axis := 0; axis < d14numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d14search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d14RTree) Count() int { + var count int + d14countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d14RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d14nodeT{} +} + +func d14countRec(node *d14nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d14countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d14insertRectRec(branch *d14branchT, node *d14nodeT, newNode **d14nodeT, level int) bool { + // 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 + var otherNode *d14nodeT + //var newBranch d14branchT + + // find the optimal branch for this record + index := d14pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d14insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d14combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d14nodeCover(node.branch[index].child) + var newBranch d14branchT + newBranch.child = otherNode + newBranch.rect = d14nodeCover(otherNode) + + // 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. + return d14addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d14addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d14insertRect provides for splitting the root; +// 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. +// +func d14insertRect(branch *d14branchT, root **d14nodeT, level int) bool { + var newNode *d14nodeT + + if d14insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d14nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d14branchT + + // add old root node as a child of the new root + newBranch.rect = d14nodeCover(*root) + newBranch.child = *root + d14addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d14nodeCover(newNode) + newBranch.child = newNode + d14addBranch(&newBranch, newRoot, nil) + + // 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. +func d14nodeCover(node *d14nodeT) d14rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d14combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d14addBranch(branch *d14branchT, node *d14nodeT, newNode **d14nodeT) bool { + if node.count < d14maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d14splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d14disconnectBranch(node *d14nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d14pickBranch(rect *d14rectT, node *d14nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d14rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d14calcRectVolume(curRect) + tempRect = d14combineRect(rect, curRect) + increase = d14calcRectVolume(&tempRect) - area + 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 +func d14combineRect(rectA, rectB *d14rectT) d14rectT { + var newRect d14rectT + + for index := 0; index < d14numDims; index++ { + newRect.min[index] = d14fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d14fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d14splitNode(node *d14nodeT, branch *d14branchT, newNode **d14nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d14partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d14getBranches(node, branch, parVars) + + // Find partition + d14choosePartition(parVars, d14minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d14nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d14loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d14rectVolume(rect *d14rectT) float64 { + var volume float64 = 1 + for index := 0; index < d14numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d14rectT +func d14rectSphericalVolume(rect *d14rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d14numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d14numDims == 5 { + return (radius * radius * radius * radius * radius * d14unitSphereVolume) + } else if d14numDims == 4 { + return (radius * radius * radius * radius * d14unitSphereVolume) + } else if d14numDims == 3 { + return (radius * radius * radius * d14unitSphereVolume) + } else if d14numDims == 2 { + return (radius * radius * d14unitSphereVolume) + } else { + return (math.Pow(radius, d14numDims) * d14unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d14calcRectVolume(rect *d14rectT) float64 { + if d14useSphericalVolume { + return d14rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d14rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d14getBranches(node *d14nodeT, branch *d14branchT, parVars *d14partitionVarsT) { + // Load the branch buffer + for index := 0; index < d14maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d14maxNodes] = *branch + parVars.branchCount = d14maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d14maxNodes+1; index++ { + parVars.coverSplit = d14combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d14calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d14choosePartition(parVars *d14partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d14initParVars(parVars, parVars.branchCount, minFill) + d14pickSeeds(parVars) + + 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++ { + if d14notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d14combineRect(curRect, &parVars.cover[0]) + rect1 := d14combineRect(curRect, &parVars.cover[1]) + growth0 := d14calcRectVolume(&rect0) - parVars.area[0] + growth1 := d14calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d14classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d14notTaken == parVars.partition[index] { + d14classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d14loadNodes(nodeA, nodeB *d14nodeT, parVars *d14partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d14nodeT{nodeA, nodeB} + + // It is assured that d14addBranch here will not cause a node split. + d14addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d14partitionVarsT structure. +func d14initParVars(parVars *d14partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d14notTaken + } +} + +func d14pickSeeds(parVars *d14partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d14maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d14calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d14combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d14calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d14classify(seed0, 0, parVars) + d14classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d14classify(index, group int, parVars *d14partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d14combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d14calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d14rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d14removeRect provides for eliminating the root. +func d14removeRect(rect *d14rectT, id interface{}, root **d14nodeT) bool { + var reInsertList *d14listNodeT + + if !d14removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d14insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d14removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d14removeRectRec(rect *d14rectT, id interface{}, node *d14nodeT, listNode **d14listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d14overlap(*rect, node.branch[index].rect) { + if !d14removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d14minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d14nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d14reInsert(node.branch[index].child, listNode) + d14disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d14disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d14overlap. +func d14overlap(rectA, rectB d14rectT) bool { + for index := 0; index < d14numDims; index++ { + 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. +func d14reInsert(node *d14nodeT, listNode **d14listNodeT) { + newListNode := &d14listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d14search in an index tree or subtree for all data retangles that d14overlap the argument rectangle. +func d14search(node *d14nodeT, rect d14rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d14overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d14search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d14overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d15fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d15fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d15numDims = 15 + d15maxNodes = 8 + d15minNodes = d15maxNodes / 2 + d15useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d15unitSphereVolume = []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 +}[d15numDims] + +type d15RTree struct { + root *d15nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d15rectT struct { + min [d15numDims]float64 ///< Min dimensions of bounding box + max [d15numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d15branchT struct { + rect d15rectT ///< Bounds + child *d15nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d15nodeT for each branch level +type d15nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d15maxNodes]d15branchT ///< Branch +} + +func (node *d15nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d15nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d15listNodeT struct { + next *d15listNodeT ///< Next in list + node *d15nodeT ///< Node +} + +const d15notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d15partitionVarsT struct { + partition [d15maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d15rectT + area [2]float64 + + branchBuf [d15maxNodes + 1]d15branchT + branchCount int + coverSplit d15rectT + coverSplitArea float64 +} + +func d15New() *d15RTree { + // 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 &d15RTree{ + root: &d15nodeT{}, + } +} + +/// 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. +func (tr *d15RTree) Insert(min, max [d15numDims]float64, dataId interface{}) { + var branch d15branchT + branch.data = dataId + for axis := 0; axis < d15numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d15insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d15RTree) Remove(min, max [d15numDims]float64, dataId interface{}) { + var rect d15rectT + for axis := 0; axis < d15numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d15removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d15search rectangle +/// \param a_min Min of d15search bounding rect +/// \param a_max Max of d15search bounding rect +/// \param a_searchResult d15search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d15RTree) Search(min, max [d15numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d15rectT + for axis := 0; axis < d15numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d15search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d15RTree) Count() int { + var count int + d15countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d15RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d15nodeT{} +} + +func d15countRec(node *d15nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d15countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d15insertRectRec(branch *d15branchT, node *d15nodeT, newNode **d15nodeT, level int) bool { + // 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 + var otherNode *d15nodeT + //var newBranch d15branchT + + // find the optimal branch for this record + index := d15pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d15insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d15combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d15nodeCover(node.branch[index].child) + var newBranch d15branchT + newBranch.child = otherNode + newBranch.rect = d15nodeCover(otherNode) + + // 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. + return d15addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d15addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d15insertRect provides for splitting the root; +// 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. +// +func d15insertRect(branch *d15branchT, root **d15nodeT, level int) bool { + var newNode *d15nodeT + + if d15insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d15nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d15branchT + + // add old root node as a child of the new root + newBranch.rect = d15nodeCover(*root) + newBranch.child = *root + d15addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d15nodeCover(newNode) + newBranch.child = newNode + d15addBranch(&newBranch, newRoot, nil) + + // 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. +func d15nodeCover(node *d15nodeT) d15rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d15combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d15addBranch(branch *d15branchT, node *d15nodeT, newNode **d15nodeT) bool { + if node.count < d15maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d15splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d15disconnectBranch(node *d15nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d15pickBranch(rect *d15rectT, node *d15nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d15rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d15calcRectVolume(curRect) + tempRect = d15combineRect(rect, curRect) + increase = d15calcRectVolume(&tempRect) - area + 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 +func d15combineRect(rectA, rectB *d15rectT) d15rectT { + var newRect d15rectT + + for index := 0; index < d15numDims; index++ { + newRect.min[index] = d15fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d15fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d15splitNode(node *d15nodeT, branch *d15branchT, newNode **d15nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d15partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d15getBranches(node, branch, parVars) + + // Find partition + d15choosePartition(parVars, d15minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d15nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d15loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d15rectVolume(rect *d15rectT) float64 { + var volume float64 = 1 + for index := 0; index < d15numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d15rectT +func d15rectSphericalVolume(rect *d15rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d15numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d15numDims == 5 { + return (radius * radius * radius * radius * radius * d15unitSphereVolume) + } else if d15numDims == 4 { + return (radius * radius * radius * radius * d15unitSphereVolume) + } else if d15numDims == 3 { + return (radius * radius * radius * d15unitSphereVolume) + } else if d15numDims == 2 { + return (radius * radius * d15unitSphereVolume) + } else { + return (math.Pow(radius, d15numDims) * d15unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d15calcRectVolume(rect *d15rectT) float64 { + if d15useSphericalVolume { + return d15rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d15rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d15getBranches(node *d15nodeT, branch *d15branchT, parVars *d15partitionVarsT) { + // Load the branch buffer + for index := 0; index < d15maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d15maxNodes] = *branch + parVars.branchCount = d15maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d15maxNodes+1; index++ { + parVars.coverSplit = d15combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d15calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d15choosePartition(parVars *d15partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d15initParVars(parVars, parVars.branchCount, minFill) + d15pickSeeds(parVars) + + 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++ { + if d15notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d15combineRect(curRect, &parVars.cover[0]) + rect1 := d15combineRect(curRect, &parVars.cover[1]) + growth0 := d15calcRectVolume(&rect0) - parVars.area[0] + growth1 := d15calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d15classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d15notTaken == parVars.partition[index] { + d15classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d15loadNodes(nodeA, nodeB *d15nodeT, parVars *d15partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d15nodeT{nodeA, nodeB} + + // It is assured that d15addBranch here will not cause a node split. + d15addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d15partitionVarsT structure. +func d15initParVars(parVars *d15partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d15notTaken + } +} + +func d15pickSeeds(parVars *d15partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d15maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d15calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d15combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d15calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d15classify(seed0, 0, parVars) + d15classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d15classify(index, group int, parVars *d15partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d15combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d15calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d15rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d15removeRect provides for eliminating the root. +func d15removeRect(rect *d15rectT, id interface{}, root **d15nodeT) bool { + var reInsertList *d15listNodeT + + if !d15removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d15insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d15removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d15removeRectRec(rect *d15rectT, id interface{}, node *d15nodeT, listNode **d15listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d15overlap(*rect, node.branch[index].rect) { + if !d15removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d15minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d15nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d15reInsert(node.branch[index].child, listNode) + d15disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d15disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d15overlap. +func d15overlap(rectA, rectB d15rectT) bool { + for index := 0; index < d15numDims; index++ { + 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. +func d15reInsert(node *d15nodeT, listNode **d15listNodeT) { + newListNode := &d15listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d15search in an index tree or subtree for all data retangles that d15overlap the argument rectangle. +func d15search(node *d15nodeT, rect d15rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d15overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d15search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d15overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d16fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d16fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d16numDims = 16 + d16maxNodes = 8 + d16minNodes = d16maxNodes / 2 + d16useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d16unitSphereVolume = []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 +}[d16numDims] + +type d16RTree struct { + root *d16nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d16rectT struct { + min [d16numDims]float64 ///< Min dimensions of bounding box + max [d16numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d16branchT struct { + rect d16rectT ///< Bounds + child *d16nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d16nodeT for each branch level +type d16nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d16maxNodes]d16branchT ///< Branch +} + +func (node *d16nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d16nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d16listNodeT struct { + next *d16listNodeT ///< Next in list + node *d16nodeT ///< Node +} + +const d16notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d16partitionVarsT struct { + partition [d16maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d16rectT + area [2]float64 + + branchBuf [d16maxNodes + 1]d16branchT + branchCount int + coverSplit d16rectT + coverSplitArea float64 +} + +func d16New() *d16RTree { + // 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 &d16RTree{ + root: &d16nodeT{}, + } +} + +/// 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. +func (tr *d16RTree) Insert(min, max [d16numDims]float64, dataId interface{}) { + var branch d16branchT + branch.data = dataId + for axis := 0; axis < d16numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d16insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d16RTree) Remove(min, max [d16numDims]float64, dataId interface{}) { + var rect d16rectT + for axis := 0; axis < d16numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d16removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d16search rectangle +/// \param a_min Min of d16search bounding rect +/// \param a_max Max of d16search bounding rect +/// \param a_searchResult d16search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d16RTree) Search(min, max [d16numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d16rectT + for axis := 0; axis < d16numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d16search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d16RTree) Count() int { + var count int + d16countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d16RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d16nodeT{} +} + +func d16countRec(node *d16nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d16countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d16insertRectRec(branch *d16branchT, node *d16nodeT, newNode **d16nodeT, level int) bool { + // 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 + var otherNode *d16nodeT + //var newBranch d16branchT + + // find the optimal branch for this record + index := d16pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d16insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d16combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d16nodeCover(node.branch[index].child) + var newBranch d16branchT + newBranch.child = otherNode + newBranch.rect = d16nodeCover(otherNode) + + // 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. + return d16addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d16addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d16insertRect provides for splitting the root; +// 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. +// +func d16insertRect(branch *d16branchT, root **d16nodeT, level int) bool { + var newNode *d16nodeT + + if d16insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d16nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d16branchT + + // add old root node as a child of the new root + newBranch.rect = d16nodeCover(*root) + newBranch.child = *root + d16addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d16nodeCover(newNode) + newBranch.child = newNode + d16addBranch(&newBranch, newRoot, nil) + + // 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. +func d16nodeCover(node *d16nodeT) d16rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d16combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d16addBranch(branch *d16branchT, node *d16nodeT, newNode **d16nodeT) bool { + if node.count < d16maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d16splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d16disconnectBranch(node *d16nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d16pickBranch(rect *d16rectT, node *d16nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d16rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d16calcRectVolume(curRect) + tempRect = d16combineRect(rect, curRect) + increase = d16calcRectVolume(&tempRect) - area + 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 +func d16combineRect(rectA, rectB *d16rectT) d16rectT { + var newRect d16rectT + + for index := 0; index < d16numDims; index++ { + newRect.min[index] = d16fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d16fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d16splitNode(node *d16nodeT, branch *d16branchT, newNode **d16nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d16partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d16getBranches(node, branch, parVars) + + // Find partition + d16choosePartition(parVars, d16minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d16nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d16loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d16rectVolume(rect *d16rectT) float64 { + var volume float64 = 1 + for index := 0; index < d16numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d16rectT +func d16rectSphericalVolume(rect *d16rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d16numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d16numDims == 5 { + return (radius * radius * radius * radius * radius * d16unitSphereVolume) + } else if d16numDims == 4 { + return (radius * radius * radius * radius * d16unitSphereVolume) + } else if d16numDims == 3 { + return (radius * radius * radius * d16unitSphereVolume) + } else if d16numDims == 2 { + return (radius * radius * d16unitSphereVolume) + } else { + return (math.Pow(radius, d16numDims) * d16unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d16calcRectVolume(rect *d16rectT) float64 { + if d16useSphericalVolume { + return d16rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d16rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d16getBranches(node *d16nodeT, branch *d16branchT, parVars *d16partitionVarsT) { + // Load the branch buffer + for index := 0; index < d16maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d16maxNodes] = *branch + parVars.branchCount = d16maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d16maxNodes+1; index++ { + parVars.coverSplit = d16combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d16calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d16choosePartition(parVars *d16partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d16initParVars(parVars, parVars.branchCount, minFill) + d16pickSeeds(parVars) + + 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++ { + if d16notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d16combineRect(curRect, &parVars.cover[0]) + rect1 := d16combineRect(curRect, &parVars.cover[1]) + growth0 := d16calcRectVolume(&rect0) - parVars.area[0] + growth1 := d16calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d16classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d16notTaken == parVars.partition[index] { + d16classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d16loadNodes(nodeA, nodeB *d16nodeT, parVars *d16partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d16nodeT{nodeA, nodeB} + + // It is assured that d16addBranch here will not cause a node split. + d16addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d16partitionVarsT structure. +func d16initParVars(parVars *d16partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d16notTaken + } +} + +func d16pickSeeds(parVars *d16partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d16maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d16calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d16combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d16calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d16classify(seed0, 0, parVars) + d16classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d16classify(index, group int, parVars *d16partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d16combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d16calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d16rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d16removeRect provides for eliminating the root. +func d16removeRect(rect *d16rectT, id interface{}, root **d16nodeT) bool { + var reInsertList *d16listNodeT + + if !d16removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d16insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d16removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d16removeRectRec(rect *d16rectT, id interface{}, node *d16nodeT, listNode **d16listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d16overlap(*rect, node.branch[index].rect) { + if !d16removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d16minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d16nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d16reInsert(node.branch[index].child, listNode) + d16disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d16disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d16overlap. +func d16overlap(rectA, rectB d16rectT) bool { + for index := 0; index < d16numDims; index++ { + 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. +func d16reInsert(node *d16nodeT, listNode **d16listNodeT) { + newListNode := &d16listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d16search in an index tree or subtree for all data retangles that d16overlap the argument rectangle. +func d16search(node *d16nodeT, rect d16rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d16overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d16search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d16overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d17fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d17fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d17numDims = 17 + d17maxNodes = 8 + d17minNodes = d17maxNodes / 2 + d17useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d17unitSphereVolume = []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 +}[d17numDims] + +type d17RTree struct { + root *d17nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d17rectT struct { + min [d17numDims]float64 ///< Min dimensions of bounding box + max [d17numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d17branchT struct { + rect d17rectT ///< Bounds + child *d17nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d17nodeT for each branch level +type d17nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d17maxNodes]d17branchT ///< Branch +} + +func (node *d17nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d17nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d17listNodeT struct { + next *d17listNodeT ///< Next in list + node *d17nodeT ///< Node +} + +const d17notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d17partitionVarsT struct { + partition [d17maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d17rectT + area [2]float64 + + branchBuf [d17maxNodes + 1]d17branchT + branchCount int + coverSplit d17rectT + coverSplitArea float64 +} + +func d17New() *d17RTree { + // 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 &d17RTree{ + root: &d17nodeT{}, + } +} + +/// 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. +func (tr *d17RTree) Insert(min, max [d17numDims]float64, dataId interface{}) { + var branch d17branchT + branch.data = dataId + for axis := 0; axis < d17numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d17insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d17RTree) Remove(min, max [d17numDims]float64, dataId interface{}) { + var rect d17rectT + for axis := 0; axis < d17numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d17removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d17search rectangle +/// \param a_min Min of d17search bounding rect +/// \param a_max Max of d17search bounding rect +/// \param a_searchResult d17search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d17RTree) Search(min, max [d17numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d17rectT + for axis := 0; axis < d17numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d17search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d17RTree) Count() int { + var count int + d17countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d17RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d17nodeT{} +} + +func d17countRec(node *d17nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d17countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d17insertRectRec(branch *d17branchT, node *d17nodeT, newNode **d17nodeT, level int) bool { + // 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 + var otherNode *d17nodeT + //var newBranch d17branchT + + // find the optimal branch for this record + index := d17pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d17insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d17combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d17nodeCover(node.branch[index].child) + var newBranch d17branchT + newBranch.child = otherNode + newBranch.rect = d17nodeCover(otherNode) + + // 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. + return d17addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d17addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d17insertRect provides for splitting the root; +// 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. +// +func d17insertRect(branch *d17branchT, root **d17nodeT, level int) bool { + var newNode *d17nodeT + + if d17insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d17nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d17branchT + + // add old root node as a child of the new root + newBranch.rect = d17nodeCover(*root) + newBranch.child = *root + d17addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d17nodeCover(newNode) + newBranch.child = newNode + d17addBranch(&newBranch, newRoot, nil) + + // 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. +func d17nodeCover(node *d17nodeT) d17rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d17combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d17addBranch(branch *d17branchT, node *d17nodeT, newNode **d17nodeT) bool { + if node.count < d17maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d17splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d17disconnectBranch(node *d17nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d17pickBranch(rect *d17rectT, node *d17nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d17rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d17calcRectVolume(curRect) + tempRect = d17combineRect(rect, curRect) + increase = d17calcRectVolume(&tempRect) - area + 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 +func d17combineRect(rectA, rectB *d17rectT) d17rectT { + var newRect d17rectT + + for index := 0; index < d17numDims; index++ { + newRect.min[index] = d17fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d17fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d17splitNode(node *d17nodeT, branch *d17branchT, newNode **d17nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d17partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d17getBranches(node, branch, parVars) + + // Find partition + d17choosePartition(parVars, d17minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d17nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d17loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d17rectVolume(rect *d17rectT) float64 { + var volume float64 = 1 + for index := 0; index < d17numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d17rectT +func d17rectSphericalVolume(rect *d17rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d17numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d17numDims == 5 { + return (radius * radius * radius * radius * radius * d17unitSphereVolume) + } else if d17numDims == 4 { + return (radius * radius * radius * radius * d17unitSphereVolume) + } else if d17numDims == 3 { + return (radius * radius * radius * d17unitSphereVolume) + } else if d17numDims == 2 { + return (radius * radius * d17unitSphereVolume) + } else { + return (math.Pow(radius, d17numDims) * d17unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d17calcRectVolume(rect *d17rectT) float64 { + if d17useSphericalVolume { + return d17rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d17rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d17getBranches(node *d17nodeT, branch *d17branchT, parVars *d17partitionVarsT) { + // Load the branch buffer + for index := 0; index < d17maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d17maxNodes] = *branch + parVars.branchCount = d17maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d17maxNodes+1; index++ { + parVars.coverSplit = d17combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d17calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d17choosePartition(parVars *d17partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d17initParVars(parVars, parVars.branchCount, minFill) + d17pickSeeds(parVars) + + 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++ { + if d17notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d17combineRect(curRect, &parVars.cover[0]) + rect1 := d17combineRect(curRect, &parVars.cover[1]) + growth0 := d17calcRectVolume(&rect0) - parVars.area[0] + growth1 := d17calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d17classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d17notTaken == parVars.partition[index] { + d17classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d17loadNodes(nodeA, nodeB *d17nodeT, parVars *d17partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d17nodeT{nodeA, nodeB} + + // It is assured that d17addBranch here will not cause a node split. + d17addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d17partitionVarsT structure. +func d17initParVars(parVars *d17partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d17notTaken + } +} + +func d17pickSeeds(parVars *d17partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d17maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d17calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d17combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d17calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d17classify(seed0, 0, parVars) + d17classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d17classify(index, group int, parVars *d17partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d17combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d17calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d17rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d17removeRect provides for eliminating the root. +func d17removeRect(rect *d17rectT, id interface{}, root **d17nodeT) bool { + var reInsertList *d17listNodeT + + if !d17removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d17insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d17removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d17removeRectRec(rect *d17rectT, id interface{}, node *d17nodeT, listNode **d17listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d17overlap(*rect, node.branch[index].rect) { + if !d17removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d17minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d17nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d17reInsert(node.branch[index].child, listNode) + d17disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d17disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d17overlap. +func d17overlap(rectA, rectB d17rectT) bool { + for index := 0; index < d17numDims; index++ { + 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. +func d17reInsert(node *d17nodeT, listNode **d17listNodeT) { + newListNode := &d17listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d17search in an index tree or subtree for all data retangles that d17overlap the argument rectangle. +func d17search(node *d17nodeT, rect d17rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d17overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d17search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d17overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d18fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d18fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d18numDims = 18 + d18maxNodes = 8 + d18minNodes = d18maxNodes / 2 + d18useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d18unitSphereVolume = []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 +}[d18numDims] + +type d18RTree struct { + root *d18nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d18rectT struct { + min [d18numDims]float64 ///< Min dimensions of bounding box + max [d18numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d18branchT struct { + rect d18rectT ///< Bounds + child *d18nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d18nodeT for each branch level +type d18nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d18maxNodes]d18branchT ///< Branch +} + +func (node *d18nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d18nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d18listNodeT struct { + next *d18listNodeT ///< Next in list + node *d18nodeT ///< Node +} + +const d18notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d18partitionVarsT struct { + partition [d18maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d18rectT + area [2]float64 + + branchBuf [d18maxNodes + 1]d18branchT + branchCount int + coverSplit d18rectT + coverSplitArea float64 +} + +func d18New() *d18RTree { + // 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 &d18RTree{ + root: &d18nodeT{}, + } +} + +/// 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. +func (tr *d18RTree) Insert(min, max [d18numDims]float64, dataId interface{}) { + var branch d18branchT + branch.data = dataId + for axis := 0; axis < d18numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d18insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d18RTree) Remove(min, max [d18numDims]float64, dataId interface{}) { + var rect d18rectT + for axis := 0; axis < d18numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d18removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d18search rectangle +/// \param a_min Min of d18search bounding rect +/// \param a_max Max of d18search bounding rect +/// \param a_searchResult d18search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d18RTree) Search(min, max [d18numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d18rectT + for axis := 0; axis < d18numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d18search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d18RTree) Count() int { + var count int + d18countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d18RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d18nodeT{} +} + +func d18countRec(node *d18nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d18countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d18insertRectRec(branch *d18branchT, node *d18nodeT, newNode **d18nodeT, level int) bool { + // 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 + var otherNode *d18nodeT + //var newBranch d18branchT + + // find the optimal branch for this record + index := d18pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d18insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d18combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d18nodeCover(node.branch[index].child) + var newBranch d18branchT + newBranch.child = otherNode + newBranch.rect = d18nodeCover(otherNode) + + // 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. + return d18addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d18addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d18insertRect provides for splitting the root; +// 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. +// +func d18insertRect(branch *d18branchT, root **d18nodeT, level int) bool { + var newNode *d18nodeT + + if d18insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d18nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d18branchT + + // add old root node as a child of the new root + newBranch.rect = d18nodeCover(*root) + newBranch.child = *root + d18addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d18nodeCover(newNode) + newBranch.child = newNode + d18addBranch(&newBranch, newRoot, nil) + + // 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. +func d18nodeCover(node *d18nodeT) d18rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d18combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d18addBranch(branch *d18branchT, node *d18nodeT, newNode **d18nodeT) bool { + if node.count < d18maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d18splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d18disconnectBranch(node *d18nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d18pickBranch(rect *d18rectT, node *d18nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d18rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d18calcRectVolume(curRect) + tempRect = d18combineRect(rect, curRect) + increase = d18calcRectVolume(&tempRect) - area + 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 +func d18combineRect(rectA, rectB *d18rectT) d18rectT { + var newRect d18rectT + + for index := 0; index < d18numDims; index++ { + newRect.min[index] = d18fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d18fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d18splitNode(node *d18nodeT, branch *d18branchT, newNode **d18nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d18partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d18getBranches(node, branch, parVars) + + // Find partition + d18choosePartition(parVars, d18minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d18nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d18loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d18rectVolume(rect *d18rectT) float64 { + var volume float64 = 1 + for index := 0; index < d18numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d18rectT +func d18rectSphericalVolume(rect *d18rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d18numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d18numDims == 5 { + return (radius * radius * radius * radius * radius * d18unitSphereVolume) + } else if d18numDims == 4 { + return (radius * radius * radius * radius * d18unitSphereVolume) + } else if d18numDims == 3 { + return (radius * radius * radius * d18unitSphereVolume) + } else if d18numDims == 2 { + return (radius * radius * d18unitSphereVolume) + } else { + return (math.Pow(radius, d18numDims) * d18unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d18calcRectVolume(rect *d18rectT) float64 { + if d18useSphericalVolume { + return d18rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d18rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d18getBranches(node *d18nodeT, branch *d18branchT, parVars *d18partitionVarsT) { + // Load the branch buffer + for index := 0; index < d18maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d18maxNodes] = *branch + parVars.branchCount = d18maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d18maxNodes+1; index++ { + parVars.coverSplit = d18combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d18calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d18choosePartition(parVars *d18partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d18initParVars(parVars, parVars.branchCount, minFill) + d18pickSeeds(parVars) + + 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++ { + if d18notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d18combineRect(curRect, &parVars.cover[0]) + rect1 := d18combineRect(curRect, &parVars.cover[1]) + growth0 := d18calcRectVolume(&rect0) - parVars.area[0] + growth1 := d18calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d18classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d18notTaken == parVars.partition[index] { + d18classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d18loadNodes(nodeA, nodeB *d18nodeT, parVars *d18partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d18nodeT{nodeA, nodeB} + + // It is assured that d18addBranch here will not cause a node split. + d18addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d18partitionVarsT structure. +func d18initParVars(parVars *d18partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d18notTaken + } +} + +func d18pickSeeds(parVars *d18partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d18maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d18calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d18combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d18calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d18classify(seed0, 0, parVars) + d18classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d18classify(index, group int, parVars *d18partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d18combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d18calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d18rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d18removeRect provides for eliminating the root. +func d18removeRect(rect *d18rectT, id interface{}, root **d18nodeT) bool { + var reInsertList *d18listNodeT + + if !d18removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d18insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d18removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d18removeRectRec(rect *d18rectT, id interface{}, node *d18nodeT, listNode **d18listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d18overlap(*rect, node.branch[index].rect) { + if !d18removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d18minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d18nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d18reInsert(node.branch[index].child, listNode) + d18disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d18disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d18overlap. +func d18overlap(rectA, rectB d18rectT) bool { + for index := 0; index < d18numDims; index++ { + 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. +func d18reInsert(node *d18nodeT, listNode **d18listNodeT) { + newListNode := &d18listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d18search in an index tree or subtree for all data retangles that d18overlap the argument rectangle. +func d18search(node *d18nodeT, rect d18rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d18overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d18search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d18overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d19fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d19fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d19numDims = 19 + d19maxNodes = 8 + d19minNodes = d19maxNodes / 2 + d19useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d19unitSphereVolume = []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 +}[d19numDims] + +type d19RTree struct { + root *d19nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d19rectT struct { + min [d19numDims]float64 ///< Min dimensions of bounding box + max [d19numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d19branchT struct { + rect d19rectT ///< Bounds + child *d19nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d19nodeT for each branch level +type d19nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d19maxNodes]d19branchT ///< Branch +} + +func (node *d19nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d19nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d19listNodeT struct { + next *d19listNodeT ///< Next in list + node *d19nodeT ///< Node +} + +const d19notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d19partitionVarsT struct { + partition [d19maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d19rectT + area [2]float64 + + branchBuf [d19maxNodes + 1]d19branchT + branchCount int + coverSplit d19rectT + coverSplitArea float64 +} + +func d19New() *d19RTree { + // 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 &d19RTree{ + root: &d19nodeT{}, + } +} + +/// 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. +func (tr *d19RTree) Insert(min, max [d19numDims]float64, dataId interface{}) { + var branch d19branchT + branch.data = dataId + for axis := 0; axis < d19numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d19insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d19RTree) Remove(min, max [d19numDims]float64, dataId interface{}) { + var rect d19rectT + for axis := 0; axis < d19numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d19removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d19search rectangle +/// \param a_min Min of d19search bounding rect +/// \param a_max Max of d19search bounding rect +/// \param a_searchResult d19search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d19RTree) Search(min, max [d19numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d19rectT + for axis := 0; axis < d19numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d19search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d19RTree) Count() int { + var count int + d19countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d19RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d19nodeT{} +} + +func d19countRec(node *d19nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d19countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d19insertRectRec(branch *d19branchT, node *d19nodeT, newNode **d19nodeT, level int) bool { + // 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 + var otherNode *d19nodeT + //var newBranch d19branchT + + // find the optimal branch for this record + index := d19pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d19insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d19combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d19nodeCover(node.branch[index].child) + var newBranch d19branchT + newBranch.child = otherNode + newBranch.rect = d19nodeCover(otherNode) + + // 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. + return d19addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d19addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d19insertRect provides for splitting the root; +// 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. +// +func d19insertRect(branch *d19branchT, root **d19nodeT, level int) bool { + var newNode *d19nodeT + + if d19insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d19nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d19branchT + + // add old root node as a child of the new root + newBranch.rect = d19nodeCover(*root) + newBranch.child = *root + d19addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d19nodeCover(newNode) + newBranch.child = newNode + d19addBranch(&newBranch, newRoot, nil) + + // 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. +func d19nodeCover(node *d19nodeT) d19rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d19combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d19addBranch(branch *d19branchT, node *d19nodeT, newNode **d19nodeT) bool { + if node.count < d19maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d19splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d19disconnectBranch(node *d19nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d19pickBranch(rect *d19rectT, node *d19nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d19rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d19calcRectVolume(curRect) + tempRect = d19combineRect(rect, curRect) + increase = d19calcRectVolume(&tempRect) - area + 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 +func d19combineRect(rectA, rectB *d19rectT) d19rectT { + var newRect d19rectT + + for index := 0; index < d19numDims; index++ { + newRect.min[index] = d19fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d19fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d19splitNode(node *d19nodeT, branch *d19branchT, newNode **d19nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d19partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d19getBranches(node, branch, parVars) + + // Find partition + d19choosePartition(parVars, d19minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d19nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d19loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d19rectVolume(rect *d19rectT) float64 { + var volume float64 = 1 + for index := 0; index < d19numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d19rectT +func d19rectSphericalVolume(rect *d19rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d19numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d19numDims == 5 { + return (radius * radius * radius * radius * radius * d19unitSphereVolume) + } else if d19numDims == 4 { + return (radius * radius * radius * radius * d19unitSphereVolume) + } else if d19numDims == 3 { + return (radius * radius * radius * d19unitSphereVolume) + } else if d19numDims == 2 { + return (radius * radius * d19unitSphereVolume) + } else { + return (math.Pow(radius, d19numDims) * d19unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d19calcRectVolume(rect *d19rectT) float64 { + if d19useSphericalVolume { + return d19rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d19rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d19getBranches(node *d19nodeT, branch *d19branchT, parVars *d19partitionVarsT) { + // Load the branch buffer + for index := 0; index < d19maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d19maxNodes] = *branch + parVars.branchCount = d19maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d19maxNodes+1; index++ { + parVars.coverSplit = d19combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d19calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d19choosePartition(parVars *d19partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d19initParVars(parVars, parVars.branchCount, minFill) + d19pickSeeds(parVars) + + 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++ { + if d19notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d19combineRect(curRect, &parVars.cover[0]) + rect1 := d19combineRect(curRect, &parVars.cover[1]) + growth0 := d19calcRectVolume(&rect0) - parVars.area[0] + growth1 := d19calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d19classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d19notTaken == parVars.partition[index] { + d19classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d19loadNodes(nodeA, nodeB *d19nodeT, parVars *d19partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d19nodeT{nodeA, nodeB} + + // It is assured that d19addBranch here will not cause a node split. + d19addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d19partitionVarsT structure. +func d19initParVars(parVars *d19partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d19notTaken + } +} + +func d19pickSeeds(parVars *d19partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d19maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d19calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d19combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d19calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d19classify(seed0, 0, parVars) + d19classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d19classify(index, group int, parVars *d19partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d19combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d19calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d19rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d19removeRect provides for eliminating the root. +func d19removeRect(rect *d19rectT, id interface{}, root **d19nodeT) bool { + var reInsertList *d19listNodeT + + if !d19removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d19insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d19removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d19removeRectRec(rect *d19rectT, id interface{}, node *d19nodeT, listNode **d19listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d19overlap(*rect, node.branch[index].rect) { + if !d19removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d19minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d19nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d19reInsert(node.branch[index].child, listNode) + d19disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d19disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d19overlap. +func d19overlap(rectA, rectB d19rectT) bool { + for index := 0; index < d19numDims; index++ { + 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. +func d19reInsert(node *d19nodeT, listNode **d19listNodeT) { + newListNode := &d19listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d19search in an index tree or subtree for all data retangles that d19overlap the argument rectangle. +func d19search(node *d19nodeT, rect d19rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d19overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d19search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d19overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +} + +func d20fmin(a, b float64) float64 { + if a < b { + return a + } + return b +} +func d20fmax(a, b float64) float64 { + if a > b { + return a + } + return b +} + +const ( + d20numDims = 20 + d20maxNodes = 8 + d20minNodes = d20maxNodes / 2 + d20useSphericalVolume = true // Better split classification, may be slower on some systems +) + +var d20unitSphereVolume = []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 +}[d20numDims] + +type d20RTree struct { + root *d20nodeT ///< Root of tree +} + +/// Minimal bounding rectangle (n-dimensional) +type d20rectT struct { + min [d20numDims]float64 ///< Min dimensions of bounding box + max [d20numDims]float64 ///< Max dimensions of bounding box +} + +/// May be data or may be another subtree +/// The parents level determines this. +/// If the parents level is 0, then this is data +type d20branchT struct { + rect d20rectT ///< Bounds + child *d20nodeT ///< Child node + data interface{} ///< Data Id or Ptr +} + +/// d20nodeT for each branch level +type d20nodeT struct { + count int ///< Count + level int ///< Leaf is zero, others positive + branch [d20maxNodes]d20branchT ///< Branch +} + +func (node *d20nodeT) isInternalNode() bool { + return (node.level > 0) // Not a leaf, but a internal node +} +func (node *d20nodeT) isLeaf() bool { + return (node.level == 0) // A leaf, contains data +} + +/// A link list of nodes for reinsertion after a delete operation +type d20listNodeT struct { + next *d20listNodeT ///< Next in list + node *d20nodeT ///< Node +} + +const d20notTaken = -1 // indicates that position + +/// Variables for finding a split partition +type d20partitionVarsT struct { + partition [d20maxNodes + 1]int + total int + minFill int + count [2]int + cover [2]d20rectT + area [2]float64 + + branchBuf [d20maxNodes + 1]d20branchT + branchCount int + coverSplit d20rectT + coverSplitArea float64 +} + +func d20New() *d20RTree { + // 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 &d20RTree{ + root: &d20nodeT{}, + } +} + +/// 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. +func (tr *d20RTree) Insert(min, max [d20numDims]float64, dataId interface{}) { + var branch d20branchT + branch.data = dataId + for axis := 0; axis < d20numDims; axis++ { + branch.rect.min[axis] = min[axis] + branch.rect.max[axis] = max[axis] + } + d20insertRect(&branch, &tr.root, 0) +} + +/// 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. +func (tr *d20RTree) Remove(min, max [d20numDims]float64, dataId interface{}) { + var rect d20rectT + for axis := 0; axis < d20numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + d20removeRect(&rect, dataId, &tr.root) +} + +/// Find all within d20search rectangle +/// \param a_min Min of d20search bounding rect +/// \param a_max Max of d20search bounding rect +/// \param a_searchResult d20search result array. Caller should set grow size. Function will reset, not append to array. +/// \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 +func (tr *d20RTree) Search(min, max [d20numDims]float64, resultCallback func(data interface{}) bool) int { + var rect d20rectT + for axis := 0; axis < d20numDims; axis++ { + rect.min[axis] = min[axis] + rect.max[axis] = max[axis] + } + foundCount, _ := d20search(tr.root, rect, 0, resultCallback) + return foundCount +} + +/// Count the data elements in this container. This is slow as no internal counter is maintained. +func (tr *d20RTree) Count() int { + var count int + d20countRec(tr.root, &count) + return count +} + +/// Remove all entries from tree +func (tr *d20RTree) RemoveAll() { + // Delete all existing nodes + tr.root = &d20nodeT{} +} + +func d20countRec(node *d20nodeT, count *int) { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + d20countRec(node.branch[index].child, count) + } + } else { // A leaf node + *count += node.count + } +} + +// 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. +func d20insertRectRec(branch *d20branchT, node *d20nodeT, newNode **d20nodeT, level int) bool { + // 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 + var otherNode *d20nodeT + //var newBranch d20branchT + + // find the optimal branch for this record + index := d20pickBranch(&branch.rect, node) + + // recursively insert this record into the picked branch + childWasSplit := d20insertRectRec(branch, node.branch[index].child, &otherNode, level) + + if !childWasSplit { + // Child was not split. Merge the bounding box of the new record with the + // existing bounding box + node.branch[index].rect = d20combineRect(&branch.rect, &(node.branch[index].rect)) + 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 + node.branch[index].rect = d20nodeCover(node.branch[index].child) + var newBranch d20branchT + newBranch.child = otherNode + newBranch.rect = d20nodeCover(otherNode) + + // 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. + return d20addBranch(&newBranch, node, newNode) + } + } else if node.level == level { + // We have reached level for insertion. Add rect, split if necessary + return d20addBranch(branch, node, newNode) + } else { + // Should never occur + return false + } +} + +// Insert a data rectangle into an index structure. +// d20insertRect provides for splitting the root; +// 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. +// +func d20insertRect(branch *d20branchT, root **d20nodeT, level int) bool { + var newNode *d20nodeT + + if d20insertRectRec(branch, *root, &newNode, level) { // Root split + + // Grow tree taller and new root + newRoot := &d20nodeT{} + newRoot.level = (*root).level + 1 + + var newBranch d20branchT + + // add old root node as a child of the new root + newBranch.rect = d20nodeCover(*root) + newBranch.child = *root + d20addBranch(&newBranch, newRoot, nil) + + // add the split node as a child of the new root + newBranch.rect = d20nodeCover(newNode) + newBranch.child = newNode + d20addBranch(&newBranch, newRoot, nil) + + // 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. +func d20nodeCover(node *d20nodeT) d20rectT { + rect := node.branch[0].rect + for index := 1; index < node.count; index++ { + rect = d20combineRect(&rect, &(node.branch[index].rect)) + } + 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. +func d20addBranch(branch *d20branchT, node *d20nodeT, newNode **d20nodeT) bool { + if node.count < d20maxNodes { // Split won't be necessary + node.branch[node.count] = *branch + node.count++ + return false + } else { + d20splitNode(node, branch, newNode) + return true + } +} + +// Disconnect a dependent node. +// Caller must return (or stop using iteration index) after this as count has changed +func d20disconnectBranch(node *d20nodeT, index int) { + // Remove element by swapping with the last element to prevent gaps in array + node.branch[index] = node.branch[node.count-1] + node.branch[node.count-1].data = nil + node.branch[node.count-1].child = nil + 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. +func d20pickBranch(rect *d20rectT, node *d20nodeT) int { + var firstTime bool = true + var increase float64 + var bestIncr float64 = -1 + var area float64 + var bestArea float64 + var best int + var tempRect d20rectT + + for index := 0; index < node.count; index++ { + curRect := &node.branch[index].rect + area = d20calcRectVolume(curRect) + tempRect = d20combineRect(rect, curRect) + increase = d20calcRectVolume(&tempRect) - area + 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 +func d20combineRect(rectA, rectB *d20rectT) d20rectT { + var newRect d20rectT + + for index := 0; index < d20numDims; index++ { + newRect.min[index] = d20fmin(rectA.min[index], rectB.min[index]) + newRect.max[index] = d20fmax(rectA.max[index], rectB.max[index]) + } + + 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. +func d20splitNode(node *d20nodeT, branch *d20branchT, newNode **d20nodeT) { + // Could just use local here, but member or external is faster since it is reused + var localVars d20partitionVarsT + parVars := &localVars + + // Load all the branches into a buffer, initialize old node + d20getBranches(node, branch, parVars) + + // Find partition + d20choosePartition(parVars, d20minNodes) + + // Create a new node to hold (about) half of the branches + *newNode = &d20nodeT{} + (*newNode).level = node.level + + // Put branches from buffer into 2 nodes according to the chosen partition + node.count = 0 + d20loadNodes(node, *newNode, parVars) +} + +// Calculate the n-dimensional volume of a rectangle +func d20rectVolume(rect *d20rectT) float64 { + var volume float64 = 1 + for index := 0; index < d20numDims; index++ { + volume *= rect.max[index] - rect.min[index] + } + return volume +} + +// The exact volume of the bounding sphere for the given d20rectT +func d20rectSphericalVolume(rect *d20rectT) float64 { + var sumOfSquares float64 = 0 + var radius float64 + + for index := 0; index < d20numDims; index++ { + halfExtent := (rect.max[index] - rect.min[index]) * 0.5 + sumOfSquares += halfExtent * halfExtent + } + + radius = math.Sqrt(sumOfSquares) + + // Pow maybe slow, so test for common dims just use x*x, x*x*x. + if d20numDims == 5 { + return (radius * radius * radius * radius * radius * d20unitSphereVolume) + } else if d20numDims == 4 { + return (radius * radius * radius * radius * d20unitSphereVolume) + } else if d20numDims == 3 { + return (radius * radius * radius * d20unitSphereVolume) + } else if d20numDims == 2 { + return (radius * radius * d20unitSphereVolume) + } else { + return (math.Pow(radius, d20numDims) * d20unitSphereVolume) + } +} + +// Use one of the methods to calculate retangle volume +func d20calcRectVolume(rect *d20rectT) float64 { + if d20useSphericalVolume { + return d20rectSphericalVolume(rect) // Slower but helps certain merge cases + } else { // RTREE_USE_SPHERICAL_VOLUME + return d20rectVolume(rect) // Faster but can cause poor merges + } // RTREE_USE_SPHERICAL_VOLUME +} + +// Load branch buffer with branches from full node plus the extra branch. +func d20getBranches(node *d20nodeT, branch *d20branchT, parVars *d20partitionVarsT) { + // Load the branch buffer + for index := 0; index < d20maxNodes; index++ { + parVars.branchBuf[index] = node.branch[index] + } + parVars.branchBuf[d20maxNodes] = *branch + parVars.branchCount = d20maxNodes + 1 + + // Calculate rect containing all in the set + parVars.coverSplit = parVars.branchBuf[0].rect + for index := 1; index < d20maxNodes+1; index++ { + parVars.coverSplit = d20combineRect(&parVars.coverSplit, &parVars.branchBuf[index].rect) + } + parVars.coverSplitArea = d20calcRectVolume(&parVars.coverSplit) +} + +// 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. +func d20choosePartition(parVars *d20partitionVarsT, minFill int) { + var biggestDiff float64 + var group, chosen, betterGroup int + + d20initParVars(parVars, parVars.branchCount, minFill) + d20pickSeeds(parVars) + + 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++ { + if d20notTaken == parVars.partition[index] { + curRect := &parVars.branchBuf[index].rect + rect0 := d20combineRect(curRect, &parVars.cover[0]) + rect1 := d20combineRect(curRect, &parVars.cover[1]) + growth0 := d20calcRectVolume(&rect0) - parVars.area[0] + growth1 := d20calcRectVolume(&rect1) - parVars.area[1] + 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 + } + } + } + d20classify(chosen, betterGroup, parVars) + } + + // 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++ { + if d20notTaken == parVars.partition[index] { + d20classify(index, group, parVars) + } + } + } +} + +// Copy branches from the buffer into two nodes according to the partition. +func d20loadNodes(nodeA, nodeB *d20nodeT, parVars *d20partitionVarsT) { + for index := 0; index < parVars.total; index++ { + targetNodeIndex := parVars.partition[index] + targetNodes := []*d20nodeT{nodeA, nodeB} + + // It is assured that d20addBranch here will not cause a node split. + d20addBranch(&parVars.branchBuf[index], targetNodes[targetNodeIndex], nil) + } +} + +// Initialize a d20partitionVarsT structure. +func d20initParVars(parVars *d20partitionVarsT, maxRects, minFill int) { + 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++ { + parVars.partition[index] = d20notTaken + } +} + +func d20pickSeeds(parVars *d20partitionVarsT) { + var seed0, seed1 int + var worst, waste float64 + var area [d20maxNodes + 1]float64 + + for index := 0; index < parVars.total; index++ { + area[index] = d20calcRectVolume(&parVars.branchBuf[index].rect) + } + + worst = -parVars.coverSplitArea - 1 + for indexA := 0; indexA < parVars.total-1; indexA++ { + for indexB := indexA + 1; indexB < parVars.total; indexB++ { + oneRect := d20combineRect(&parVars.branchBuf[indexA].rect, &parVars.branchBuf[indexB].rect) + waste = d20calcRectVolume(&oneRect) - area[indexA] - area[indexB] + if waste > worst { + worst = waste + seed0 = indexA + seed1 = indexB + } + } + } + + d20classify(seed0, 0, parVars) + d20classify(seed1, 1, parVars) +} + +// Put a branch in one of the groups. +func d20classify(index, group int, parVars *d20partitionVarsT) { + parVars.partition[index] = group + + // Calculate combined rect + if parVars.count[group] == 0 { + parVars.cover[group] = parVars.branchBuf[index].rect + } else { + parVars.cover[group] = d20combineRect(&parVars.branchBuf[index].rect, &parVars.cover[group]) + } + + // Calculate volume of combined rect + parVars.area[group] = d20calcRectVolume(&parVars.cover[group]) + + parVars.count[group]++ +} + +// Delete a data rectangle from an index structure. +// Pass in a pointer to a d20rectT, the tid of the record, ptr to ptr to root node. +// Returns 1 if record not found, 0 if success. +// d20removeRect provides for eliminating the root. +func d20removeRect(rect *d20rectT, id interface{}, root **d20nodeT) bool { + var reInsertList *d20listNodeT + + if !d20removeRectRec(rect, id, *root, &reInsertList) { + // 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)? + d20insertRect(&tempNode.branch[index], root, tempNode.level) + } + 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... + if (*root).count == 1 && (*root).isInternalNode() { + tempNode := (*root).branch[0].child + *root = tempNode + } + return false + } else { + return true + } +} + +// Delete a rectangle from non-root part of an index structure. +// Called by d20removeRect. Descends tree recursively, +// merges branches on the way back up. +// Returns 1 if record not found, 0 if success. +func d20removeRectRec(rect *d20rectT, id interface{}, node *d20nodeT, listNode **d20listNodeT) bool { + if node.isInternalNode() { // not a leaf node + for index := 0; index < node.count; index++ { + if d20overlap(*rect, node.branch[index].rect) { + if !d20removeRectRec(rect, id, node.branch[index].child, listNode) { + if node.branch[index].child.count >= d20minNodes { + // child removed, just resize parent rect + node.branch[index].rect = d20nodeCover(node.branch[index].child) + } else { + // child removed, not enough entries in node, eliminate node + d20reInsert(node.branch[index].child, listNode) + d20disconnectBranch(node, index) // Must return after this call as count has changed + } + return false + } + } + } + return true + } else { // A leaf node + for index := 0; index < node.count; index++ { + if node.branch[index].data == id { + d20disconnectBranch(node, index) // Must return after this call as count has changed + return false + } + } + return true + } +} + +// Decide whether two rectangles d20overlap. +func d20overlap(rectA, rectB d20rectT) bool { + for index := 0; index < d20numDims; index++ { + 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. +func d20reInsert(node *d20nodeT, listNode **d20listNodeT) { + newListNode := &d20listNodeT{} + newListNode.node = node + newListNode.next = *listNode + *listNode = newListNode +} + +// d20search in an index tree or subtree for all data retangles that d20overlap the argument rectangle. +func d20search(node *d20nodeT, rect d20rectT, foundCount int, resultCallback func(data interface{}) bool) (int, bool) { + if node.isInternalNode() { + // This is an internal node in the tree + for index := 0; index < node.count; index++ { + if d20overlap(rect, node.branch[index].rect) { + var ok bool + foundCount, ok = d20search(node.branch[index].child, rect, foundCount, resultCallback) + if !ok { + // The callback indicated to stop searching + return foundCount, false + } + } + } + } else { + // This is a leaf node + for index := 0; index < node.count; index++ { + if d20overlap(rect, node.branch[index].rect) { + id := node.branch[index].data + foundCount++ + if !resultCallback(id) { + return foundCount, false // Don't continue searching + } + + } + } + } + return foundCount, true // Continue searching +}