/// <summary> /// This method was written by Ted Dunsford by restructuring the nearest neighbor /// algorithm presented by Andrew and Bjoern /// </summary> /// <param name="kd">Since this is recursive, this represents the current node</param> /// <param name="target">The target is the HPoint that we are trying to calculate the farthest distance from</param> /// <param name="hr">In this case, the hr is the hyper rectangle bounding the region that must contain the furthest point.</param> /// <param name="maxDistSqd">The maximum distance that we have calculated thus far, and will therefore be testing against.</param> /// <param name="lev">The integer based level of that we have recursed to in the tree</param> /// <param name="k">The dimensionality of the kd tree</param> /// <param name="fnl">A list to contain the output, prioritized by distance</param> public static void FarthestNeighbor(KdNode kd, HPoint target, HRect hr, double maxDistSqd, int lev, int k, FarthestNeighborList fnl) { // 1. if kd is empty then set dist-sqd to infinity and exit. if (kd == null) { return; } // 2. s := split field of kd int s = lev % k; // 3. pivot := dom-elt field of kd HPoint pivot = kd._k; double pivotToTarget = HPoint.SquareDistance(pivot, target); // 4. Cut hr into to sub-hyperrectangles left-hr and right-hr. // The cut plane is through pivot and perpendicular to the s // dimension. HRect leftHr = hr; // optimize by not cloning HRect rightHr = hr.Copy(); leftHr._max[s] = pivot[s]; rightHr._min[s] = pivot[s]; // 5. target-in-left := target_s <= pivot_s bool targetInLeft = target[s] < pivot[s]; KdNode nearerKd; HRect nearerHr; KdNode furtherKd; HRect furtherHr; // 6. if target-in-left then // 6.1. nearer-kd := left field of kd and nearer-hr := left-hr // 6.2. further-kd := right field of kd and further-hr := right-hr if (targetInLeft) { nearerKd = kd._left; nearerHr = leftHr; furtherKd = kd._right; furtherHr = rightHr; } // // 7. if not target-in-left then // 7.1. nearer-kd := right field of kd and nearer-hr := right-hr // 7.2. further-kd := left field of kd and further-hr := left-hr else { nearerKd = kd._right; nearerHr = rightHr; furtherKd = kd._left; furtherHr = leftHr; } // 8. Recursively call Nearest Neighbor with paramters // (nearer-kd, target, nearer-hr, max-dist-sqd), storing the // results in nearest and dist-sqd //FarthestNeighbor(nearer_kd, target, nearer_hr, max_dist_sqd, lev + 1, K, nnl); // This line changed by Ted Dunsford to attempt to find the farther point FarthestNeighbor(furtherKd, target, furtherHr, maxDistSqd, lev + 1, k, fnl); //KDNode nearest = (KDNode)nnl.Highest; double distSqd; if (!fnl.IsCapacityReached) { //dist_sqd = 1.79769e+30;// Double.MaxValue; distSqd = 0; } else { distSqd = fnl.MinimumPriority; } // 9. max-dist-sqd := minimum of max-dist-sqd and dist-sqd //max_dist_sqd = Math.Min(max_dist_sqd, dist_sqd); maxDistSqd = Math.Max(maxDistSqd, distSqd); // 10. A nearer point could only lie in further-kd if there were some // part of further-hr within distance sqrt(max-dist-sqd) of // target. If this is the case then // HPoint closest = further_hr.Closest(target); HPoint furthest = nearerHr.Farthest(target); //if (HPoint.EuclideanDistance(closest, target) < Math.Sqrt(max_dist_sqd)) if(HPoint.EuclideanDistance(furthest, target) > Math.Sqrt(maxDistSqd)) { // 10.1 if (pivot-target)^2 < dist-sqd then if (pivotToTarget > distSqd) { // 10.1.1 nearest := (pivot, range-elt field of kd) //nearest = kd; // 10.1.2 dist-sqd = (pivot-target)^2 distSqd = pivotToTarget; // add to nnl if (!kd.IsDeleted) { fnl.Insert(kd, distSqd); } // 10.1.3 max-dist-sqd = dist-sqd // max_dist_sqd = dist_sqd; if (fnl.IsCapacityReached) { maxDistSqd = fnl.MinimumPriority; } else { // max_dist_sqd = 1.79769e+30;//Double.MaxValue; maxDistSqd = 0; } } // 10.2 Recursively call Nearest Neighbor with parameters // (further-kd, target, further-hr, max-dist_sqd), // storing results in temp-nearest and temp-dist-sqd FarthestNeighbor(nearerKd, target, nearerHr, maxDistSqd, lev + 1, k, fnl); KdNode tempFarthest = (KdNode)fnl.Farthest; double tempDistSqd = fnl.MinimumPriority; // 10.3 If tmp-dist-sqd < dist-sqd then if (tempDistSqd > distSqd) { // 10.3.1 nearest := temp_nearest and dist_sqd := temp_dist_sqd distSqd = tempDistSqd; } } // SDL: otherwise, current point is nearest else if (pivotToTarget < maxDistSqd) { distSqd = pivotToTarget; } }
/// <summary> /// If the specified HRect does not intersect this HRect, this returns null. Otherwise, /// this will return a smaller rectangular region that represents the intersection /// of the two bounding regions. /// </summary> /// <param name="region">Another HRect object to intersect with this one.</param> /// <returns>The HRect that represents the intersection area for the two bounding boxes.</returns> /// <remarks>currently unused</remarks> public HRect Intersection(HRect region) { HPoint newmin = new HPoint(_min.NumOrdinates); HPoint newmax = new HPoint(_min.NumOrdinates); for (int i = 0; i < _min.NumOrdinates; ++i) { newmin[i] = Math.Max(_min[i], region._min[i]); newmax[i] = Math.Min(_max[i], region._max[i]); if (newmin[i] >= newmax[i]) return null; } return new HRect(newmin, newmax); }