package org.wikibrain.spatial.util;
import ags.utils.dataStructures.MaxHeap;
import ags.utils.dataStructures.trees.thirdGenKD.KdTree;
import ags.utils.dataStructures.trees.thirdGenKD.SquareEuclideanDistanceFunction;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import org.geotools.referencing.GeodeticCalculator;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Creates a spherical approximation of the closest points to a particular point.
* This class is threadsafe for multiple readers or writers (but not both).
*
*
* @author Shilad Sen
*/
public class ClosestPointIndex implements Serializable {
private final KdTree<Result> index = new KdTree<Result>(3);
public ClosestPointIndex() {}
/**
* Insert a geometry into the index and associate it with a particular id.
* If the geometry is not a point, uses WikiBrainSpatialUtils.getCenter to
* convert it to a single point.
*
* @param id
* @param geometry
*/
public void insert(int id, Geometry geometry) {
Point p = WikiBrainSpatialUtils.getCenter(geometry);
Result r = new Result(id, geometry, p);
synchronized (index) {
index.addPoint(WikiBrainSpatialUtils.get3DPoints(p), r);
}
}
/**
* Return the closest points to the specified point.
* The returned distances are estimated using the Haversine formula.
* @param query
* @param maxNeighbors
* @return
*/
public List<Result> query(Geometry query, int maxNeighbors) {
final Point c = WikiBrainSpatialUtils.getCenter(query);
final double[] c1 = WikiBrainSpatialUtils.get3DPoints(c);
MaxHeap<Result> heap = index.findNearestNeighbors(
c1,
maxNeighbors,
new SquareEuclideanDistanceFunction());
List<Result> results = new ArrayList<Result>();
while (heap.size() > 0) {
Result r = heap.getMax();
heap.removeMax();
double d = WikiBrainSpatialUtils.haversine(c, r.point);
results.add(new Result(r.id, r.geometry, r.point, d));
}
Collections.reverse(results);
return results;
}
public int size() {
return index.size();
}
public static class Result implements Serializable {
public final int id;
public final Geometry geometry;
public final Point point;
public final double distance;
public Result(int id, Geometry geometry, Point point) {
this(id, geometry, point, -1);
}
public Result(int id, Geometry geometry, Point point, double distance) {
this.id = id;
this.geometry = geometry;
this.point = point;
this.distance = distance;
}
}
}