/// <summary> /// Collects the elements in quadrant that pass the intersection test. /// </summary> /// <param name="lockedQuadrant">A quadrant on which the current thread /// holds a shared lock.</param> /// <param name="intersectionTest">An predicate P such that if a /// rectangle B contains a rectangle A, then P(A) implies P(B).</param> /// <param name="output">The output collection where to place the elements.</param> void CollectElementsInQuadrantThatAreInRegion(Quadrant lockedQuadrant, Predicate <Rect> intersectionTest, ICollection <IElement> output) { Debug.Assert(lockedQuadrant.Lock.ThreadOwnsSharedLock); if (lockedQuadrant.IsLeaf) { foreach (var datum in lockedQuadrant.Data) { Rect datumRect = new Rect(datum.Coordinates.Longitude, datum.Coordinates.Latitude, 0, 0); if (intersectionTest(datumRect)) { output.Add(datum); } } lockedQuadrant.Lock.ExitSharedLock(); } else { // Lock all children. Do this before releasing the lock // on the parent to prevent the parent from performing a join. for (int childIdx = 0; childIdx < 4; ++childIdx) { lockedQuadrant.GetChild(childIdx).Lock.EnterSharedLock(); } // Exit the lock on the parent before recursion to avoid // holding a shared lock on every quadrant all the way down. lockedQuadrant.Lock.ExitSharedLock(); // Check each child. for (int childIdx = 0; childIdx < 4; ++childIdx) { Quadrant child = lockedQuadrant.GetChild(childIdx); if (intersectionTest(child.Bounds)) { CollectElementsInQuadrantThatAreInRegion(child, intersectionTest, output); } else { child.Lock.ExitSharedLock(); } } } }
void SubdivideWithoutLocking(Quadrant quadrant) { if (quadrant.SubdivisionLevel >= maxSubdivisionLevel) { return; } if (quadrant.Data.Count <= maxLeafCapacity) { return; } if (!quadrant.TrySubdivide()) { return; } for (int childIdx = 0; childIdx < 4; ++childIdx) { Quadrant child = quadrant.GetChild(childIdx); foreach (var datum in child.Data) { elementsToNodes[datum] = child; } if (child.Data.Count > maxLeafCapacity) { SubdivideWithoutLocking(child); } } }
/// <summary> /// Gets the depth of the tree rooted at this quadrant. For efficiency, /// this performs no locking. Because of this, the return value should be /// regarded as an approximation. /// </summary> int GetApproximateLargestSubdivisionLevel(Quadrant quadrant) { if (quadrant.IsLeaf) { return(0); } int maxLevel = 1; for (int childIdx = 0; childIdx < 4; ++childIdx) { try { int childLevel = 1 + GetApproximateLargestSubdivisionLevel(quadrant.GetChild(childIdx)); if (childLevel > maxLevel) { maxLevel = childLevel; } } catch (ApplicationException) { // This can happen if the quadrant becomes a leaf due to // a join operation (since we didn't lock it). break; } } return(maxLevel); }