I have to get distance from different markers on the map to the current location of the device and the pick up the shortest one. I have the lat and long for the markers and
Here is my implementation of a so called KDTree, consisting of 3 classes: KDTree, KDTNode and KDTResult. What you finally need is to create the KDTree using KDTree.createTree(), which returns the rootNode of the tree and gets all your fixed points passed in. Then use KDTree.findNearestWp() to find the nearest Waypoint to the given location.
KDTree:
public class KDTree {
private Comparator latComparator = new LatLonComparator(true);
private Comparator lonComparator = new LatLonComparator(false);;
/**
* Create a KDTree from a list of Destinations. Returns the root-node of the
* tree.
*/
public KDTNode createTree(List recList) {
return createTreeRecursive(0, recList);
}
/**
* Traverse the tree and find the nearest WP.
*
* @param root
* @param wp
* @return
*/
static public LatLng findNearestWp(KDTNode root, LatLng wp) {
KDTResult result = new KDTResult();
findNearestWpRecursive(root, wp, result);
return result.nearestDest;
}
private static void findNearestWpRecursive(KDTNode node, LatLng wp,
KDTResult result) {
double lat = wp.latitude;
double lon = wp.longitude;
/* If a leaf node, calculate distance and return. */
if (node.isLeaf) {
LatLng dest = node.wp;
double latDiff = dest.latitude - lat;
double lonDiff = dest.longitude - lon;
double squareDist = latDiff * latDiff + lonDiff * lonDiff;
// Replace a previously found nearestDest only if the new one is
// nearer.
if (result.nearestDest == null
|| result.squareDistance > squareDist) {
result.nearestDest = dest;
result.squareDistance = squareDist;
}
return;
}
boolean devidedByLat = node.depth % 2 == 0;
boolean goLeft;
/* Check whether left or right is more promising. */
if (devidedByLat) {
goLeft = lat < node.splitValue;
} else {
goLeft = lon < node.splitValue;
}
KDTNode child = goLeft ? node.left : node.right;
findNearestWpRecursive(child, wp, result);
/*
* Check whether result needs to be checked also against the less
* promising side.
*/
if (result.squareDistance > node.minSquareDistance) {
KDTNode otherChild = goLeft ? node.right : node.left;
findNearestWpRecursive(otherChild, wp, result);
}
}
private KDTNode createTreeRecursive(int depth, List recList) {
KDTNode node = new KDTNode();
node.depth = depth;
if (recList.size() == 1) {
// Leafnode found
node.isLeaf = true;
node.wp = recList.get(0);
return node;
}
boolean divideByLat = node.depth % 2 == 0;
sortRecListByDimension(recList, divideByLat);
List leftList = getHalfOf(recList, true);
List rightList = getHalfOf(recList, false);
// Get split point and distance to last left and first right point.
LatLng lastLeft = leftList.get(leftList.size() - 1);
LatLng firstRight = rightList.get(0);
double minDistanceToSplitValue;
double splitValue;
if (divideByLat) {
minDistanceToSplitValue = (firstRight.latitude - lastLeft.latitude) / 2;
splitValue = lastLeft.latitude + Math.abs(minDistanceToSplitValue);
} else {
minDistanceToSplitValue = (firstRight.longitude - lastLeft.longitude) / 2;
splitValue = lastLeft.longitude + Math.abs(minDistanceToSplitValue);
}
node.splitValue = splitValue;
node.minSquareDistance = minDistanceToSplitValue
* minDistanceToSplitValue;
/** Call next level */
depth++;
node.left = createTreeRecursive(depth, leftList);
node.right = createTreeRecursive(depth, rightList);
return node;
}
/**
* Return a sublist representing the left or right half of a List. Size of
* recList must be at least 2 !
*
* IMPORTANT !!!!! Note: The original list must not be modified after
* extracting this sublist, as the returned subList is still backed by the
* original list.
*/
List getHalfOf(List recList, boolean leftHalf) {
int mid = recList.size() / 2;
if (leftHalf) {
return recList.subList(0, mid);
} else {
return recList.subList(mid, recList.size());
}
}
private void sortRecListByDimension(List recList, boolean sortByLat) {
Comparator comparator = sortByLat ? latComparator
: lonComparator;
Collections.sort(recList, comparator);
}
class LatLonComparator implements Comparator {
private boolean byLat;
public LatLonComparator(boolean sortByLat) {
this.byLat = sortByLat;
}
@Override
public int compare(LatLng lhs, LatLng rhs) {
double diff;
if (byLat) {
diff = lhs.latitude - rhs.latitude;
} else {
diff = lhs.longitude - rhs.longitude;
}
if (diff > 0) {
return 1;
} else if (diff < 0) {
return -1;
} else {
return 0;
}
}
}
}
KDTNode:
/** Node of the KDTree */
public class KDTNode {
KDTNode left;
KDTNode right;
boolean isLeaf;
/** latitude or longitude of the nodes division line. */
double splitValue;
/** Distance between division line and first point. */
double minSquareDistance;
/**
* Depth of the node in the tree. An even depth devides the tree in the
* latitude-axis, an odd depth devides the tree in the longitude-axis.
*/
int depth;
/** The Waypoint in case the node is a leaf node. */
LatLng wp;
}
KDTResult:
/** Holds the result of a tree traversal. */
public class KDTResult {
LatLng nearestDest;
// I use the square of the distance to avoid square-root operations.
double squareDistance;
}
Please note, that I am using a simplified distance calculation, which works in my case, as I am only interested in very nearby waypoints. For points further apart, this may result in getting not exactly the nearest point. The absolute difference of two longitudes expressed as east-west distance in meters, depends on the latitude, where this difference is measured. This is not taken into account in my algorithm and I am not sure about the relevance of this effect in your case.