private static ISpatialIndexNode <IExtents, TItem> findLeastExpandedChild( IEnumerable <ISpatialIndexNode <IExtents, TItem> > children, ComputationExtents currentBounds, Double leastExpandedArea, Double leastExpandedChildArea) { ISpatialIndexNode <IExtents, TItem> leastExpandedChild = null; foreach (ISpatialIndexNode <IExtents, TItem> child in children) { ComputationExtents childBounds = child.Bounds != null ? new ComputationExtents(child.Bounds) : new ComputationExtents(); ComputationExtents candidateRegion = childBounds.Union(currentBounds); Double candidateRegionArea = candidateRegion.Area; Double childArea = childBounds.Area; Double expandedArea = candidateRegionArea - childArea; if (expandedArea < leastExpandedArea) { leastExpandedChild = child; leastExpandedChildArea = childArea; leastExpandedArea = expandedArea; } else if (expandedArea == leastExpandedArea && childArea < leastExpandedChildArea) { leastExpandedChild = child; leastExpandedChildArea = childArea; } } return(leastExpandedChild); }
public ComputationExtents Intersection(ComputationExtents other) { if (XMin > other.XMax || XMax < other.XMin || YMin > other.YMax || YMax < other.YMin) { return new ComputationExtents(); } return new ComputationExtents( Math.Max(XMin, other.XMin), Math.Max(YMin, other.YMin), Math.Min(XMax, other.XMax), Math.Min(YMax, other.YMax)); }
public ComputationExtents Intersection(ComputationExtents other) { if (XMin > other.XMax || XMax < other.XMin || YMin > other.YMax || YMax < other.YMin) { return(new ComputationExtents()); } return(new ComputationExtents( Math.Max(XMin, other.XMin), Math.Max(YMin, other.YMin), Math.Min(XMax, other.XMax), Math.Min(YMax, other.YMax))); }
private ComputationExtents computeBounds(IBoundable <IExtents>[] entries, Int32 count) { ComputationExtents bounds = new ComputationExtents(); for (Int32 i = 0; i < count; i++) { if (bounds.IsEmpty) { bounds = new ComputationExtents(entries[i].Bounds); } else { bounds = bounds.Union(new ComputationExtents(entries[i].Bounds)); } } return(bounds); }
public ComputationExtents Union(ComputationExtents other) { if (other.IsEmpty) { return this; } if (IsEmpty) { return other; } return new ComputationExtents( Math.Min(XMin, other.XMin), Math.Min(YMin, other.YMin), Math.Max(XMax, other.XMax), Math.Max(YMax, other.YMax)); }
public ComputationExtents Union(ComputationExtents other) { if (other.IsEmpty) { return(this); } if (IsEmpty) { return(other); } return(new ComputationExtents( Math.Min(XMin, other.XMin), Math.Min(YMin, other.YMin), Math.Max(XMax, other.XMax), Math.Max(YMax, other.YMax))); }
private GroupBoundsLeastEnlarged pickNext(IList <IBoundable <IExtents> > entries, ComputationExtents group1Bounds, ComputationExtents group2Bounds, out IBoundable <IExtents> entry) { Double maxArealDifference = -1; GroupBoundsLeastEnlarged group = GroupBoundsLeastEnlarged.Tie; IBoundable <IExtents> nextEntry = null; foreach (IBoundable <IExtents> e in entries) { ComputationExtents bounds = new ComputationExtents(e.Bounds); ComputationExtents group1Join = bounds.Union(group1Bounds); ComputationExtents group2Join = bounds.Union(group2Bounds); Double arealDifferenceGroup1 = Math.Abs( group1Join.Area - group1Bounds.Area); Double arealDifferenceGroup2 = Math.Abs( group2Join.Area - group2Bounds.Area); Double differenceInAreas = Math.Abs(arealDifferenceGroup1 - arealDifferenceGroup2); if (differenceInAreas > maxArealDifference) { maxArealDifference = differenceInAreas; nextEntry = e; if (arealDifferenceGroup1 < arealDifferenceGroup2) { group = GroupBoundsLeastEnlarged.Group1; } else if (arealDifferenceGroup2 < arealDifferenceGroup1) { group = GroupBoundsLeastEnlarged.Group2; } } } entries.Remove(nextEntry); entry = nextEntry; return(group); }
private void distribute(IList <IBoundable <IExtents> > entries, IBoundable <IExtents>[] group1, IBoundable <IExtents>[] group2, IndexBalanceHeuristic heuristic, ref Int32 group1Count, ref Int32 group2Count) { // recursion halting case #1 if (entries.Count == 0) { return; } // recursion halting case #2 if (group1Count == heuristic.TargetNodeCount || group2Count == heuristic.TargetNodeCount) { return; } IBoundable <IExtents> entry; ComputationExtents group1Bounds = computeBounds(group1, group1Count); ComputationExtents group2Bounds = computeBounds(group2, group2Count); GroupBoundsLeastEnlarged group = pickNext(entries, group1Bounds, group2Bounds, out entry); switch (group) { case GroupBoundsLeastEnlarged.Group1: group1[group1Count++] = entry; break; case GroupBoundsLeastEnlarged.Group2: group2[group2Count++] = entry; break; case GroupBoundsLeastEnlarged.Tie: Double group1BoundsArea = group1Bounds.Area; Double group2BoundsArea = group2Bounds.Area; if (group1BoundsArea < group2BoundsArea) { group1[group1Count++] = entry; } else if (group2BoundsArea < group1BoundsArea) { group2[group2Count++] = entry; } else if (group1Count < group2Count) { group1[group1Count++] = entry; } else if (group2Count < group1Count) { group2[group2Count++] = entry; } else if (_random.Next(0, 2) == 0) // generates 0 or 1 randomly { group1[group1Count++] = entry; } else { group2[group2Count++] = entry; } break; default: throw new InvalidOperationException("Unknown group."); } distribute(entries, group1, group2, heuristic, ref group1Count, ref group2Count); }
private static void pickSeeds(IList <IBoundable <IExtents> > items, IBoundable <IExtents>[] group1, IBoundable <IExtents>[] group2) { Int32 group1Count = 0, group2Count = 0; Double largestWaste = -1; ComputationExtents[] allExtents = new ComputationExtents[items.Count]; Int32 itemCount = items.Count; // read the bounds into local structures only once // for speed for (Int32 i = 0; i < itemCount; i++) { allExtents[i] = new ComputationExtents(items[i].Bounds); } Int32 seed1Index = -1, seed2Index = -1; for (Int32 i = 0; i < itemCount; i++) { for (int j = 0; j < itemCount; j++) { if (i == j) { continue; } ComputationExtents e1 = allExtents[i]; ComputationExtents e2 = allExtents[j]; ComputationExtents minBoundingRectangle = e1.Union(e2); ComputationExtents intersection = e1.Intersection(e2); Double minBoundingArea = minBoundingRectangle.Area; Double entry1Area = e1.Area; Double entry2Area = e2.Area; Double waste = (minBoundingArea - entry1Area - entry2Area) + intersection.Area; if (group1Count == 0 && group2Count == 0) { group1[group1Count++] = items[i]; group2[group2Count++] = items[j]; seed1Index = i; seed2Index = j; largestWaste = waste; continue; } if (waste > largestWaste) { group1[0] = items[i]; group2[0] = items[j]; seed1Index = i; seed2Index = j; largestWaste = waste; } } } if (seed1Index > seed2Index) { items.RemoveAt(seed1Index); items.RemoveAt(seed2Index); } else { items.RemoveAt(seed2Index); items.RemoveAt(seed1Index); } }
//private Int32 _tempSplitCount = 0; public void Insert(IExtents bounds, TItem entry, ISpatialIndexNode <IExtents, TItem> node, INodeSplitStrategy <IExtents, TItem> nodeSplitStrategy, IndexBalanceHeuristic heuristic, out ISpatialIndexNode <IExtents, TItem> newSiblingFromSplit) { newSiblingFromSplit = null; // Terminating case if (node.IsLeaf) { node.Add(entry); // Handle node overflow if (node.ItemCount > heuristic.NodeItemMaximumCount) { // Split the node using the given strategy newSiblingFromSplit = nodeSplitStrategy.SplitNode(node, heuristic); //if (++_tempSplitCount % 100 == 0) //{ // Debug.Print("Node split # {0}", _tempSplitCount); //} } } else { // NOTE: Descending the tree recursively here // can make for a very expensive build of a tree, // even for moderate amounts of data. Double leastExpandedArea = Double.MaxValue; Double leastExpandedChildArea = Double.MaxValue; ComputationExtents currentBounds = new ComputationExtents(bounds); ISpatialIndexNode <IExtents, TItem> leastExpandedChild; leastExpandedChild = findLeastExpandedChild(node.SubNodes, currentBounds, leastExpandedArea, leastExpandedChildArea); Debug.Assert(leastExpandedChild != null); // Found least expanded child node - insert into it Insert(bounds, entry, leastExpandedChild, nodeSplitStrategy, heuristic, out newSiblingFromSplit); RTreeNode <TItem> rNode = node as RTreeNode <TItem>; // Adjust this node... rNode.Bounds.ExpandToInclude(bounds); // Check for overflow and add to current node if it occured if (newSiblingFromSplit != null) { // Add new sibling node to the current node node.Add(newSiblingFromSplit); newSiblingFromSplit = null; // Split the current node, since the child count is too high, // and return the split to the caller if (node.SubNodeCount > heuristic.NodeItemMaximumCount) { newSiblingFromSplit = nodeSplitStrategy.SplitNode(node, heuristic); } } } }