/**
* KDNearestSearch.java
*/
package rampancy.util.data.kdTree;
import java.util.*;
import rampancy.util.RDistanceFunction;
/**
* @author Matthew Chun-Lum
*
*/
public class KDNearestSearch<T extends KDPoint> {
public T target;
public int k;
public List<T> nearestNeighbors;
public ArrayList<Double> distances;
public double furthestDistance;
public KDNearestSearch(T target, int k) {
this.k = k;
this.target = target;
nearestNeighbors = new ArrayList<T>();
distances = new ArrayList<Double>();
furthestDistance = -1;
}
/**
* Attempts to add the candidate point to the nearest neighbor list
* @param candidate
* @return {@code true} if the candidate was added
*/
public boolean attemptToAdd(T candidate) {
double dist = candidate.distanceTo(target);
if(nearestNeighbors.size() < k) {
nearestNeighbors.add(candidate);
furthestDistance = Math.max(dist, furthestDistance);
return true;
} else if(dist < furthestDistance) {
furthestDistance = (furthestDistance - dist) / 2.0;
nearestNeighbors.add(candidate);
return true;
}
return false;
}
/**
* @param candidate
* @return {@code true} if the candidate could be added to the neighbors list
*/
public boolean canTraverse(T candidate) {
return (nearestNeighbors.size() < k || candidate.distanceTo(target) <= furthestDistance);
}
/**
* @return Return only the K nearest neighbors
*/
public List<T> getNearestNeighbors() {
sortNeighbors();
return nearestNeighbors.subList(0, Math.min(nearestNeighbors.size(), k));
}
// ------------ Private ------------- //
/**
* Sort the nearest neighbors
*/
private void sortNeighbors() {
Collections.sort(nearestNeighbors, new Comparator<T>() {
public int compare(T o1, T o2) {
double dist1 = o1.distanceTo(target);
double dist2 = o2.distanceTo(target);
if(dist1 == dist2)
return 0;
else if(dist1 < dist2)
return -1;
else
return 1;
}
});
}
}