You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@lucene.apache.org by gs...@apache.org on 2010/04/13 21:21:20 UTC
svn commit: r933754 - in /lucene/dev/trunk/lucene/contrib: ./
spatial/src/java/org/apache/lucene/spatial/geometry/
spatial/src/java/org/apache/lucene/spatial/geometry/shape/
spatial/src/java/org/apache/lucene/spatial/tier/
spatial/src/java/org/apache/l...
Author: gsingers
Date: Tue Apr 13 19:21:20 2010
New Revision: 933754
URL: http://svn.apache.org/viewvc?rev=933754&view=rev
Log:
LUCENE-2366, LUCENE-2367, LUCENE-2359: Fix a bunch of issues related to spatial
Modified:
lucene/dev/trunk/lucene/contrib/CHANGES.txt
lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java
lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java
lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java
lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java
lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java
lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java
lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java
Modified: lucene/dev/trunk/lucene/contrib/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/CHANGES.txt?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/contrib/CHANGES.txt Tue Apr 13 19:21:20 2010
@@ -66,7 +66,11 @@ Bug fixes
not an indexed field. Note, this change affects the APIs. (Grant Ingersoll)
* LUCENE-2359: Fix bug in CartesianPolyFilterBuilder related to handling of behavior around
- the 180th meridian (Grant Ingersoll)
+ the 180th meridian (Grant Ingersoll, Nicolas Hellinger)
+
+ * LUCENE-2366: Fix LLRect issue with properly calculating box points (Nicolas Hellinger via Grant Ingersoll)
+
+
API Changes
Modified: lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java (original)
+++ lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java Tue Apr 13 19:21:20 2010
@@ -30,6 +30,19 @@ package org.apache.lucene.spatial.geomet
*/
public abstract class LatLng {
+ public final static int LONGITUDE_DEGREE_RANGE = 360;
+ public final static int LONGITUDE_DEGREE_MIN = -LONGITUDE_DEGREE_RANGE / 2;
+ public final static int LONGITUDE_DEGREE_MAX = LONGITUDE_DEGREE_RANGE / 2;
+ public final static int LATITUDE_DEGREE_RANGE = 180;
+ public final static int LATITUDE_DEGREE_MIN = -LATITUDE_DEGREE_RANGE / 2;
+ public final static int LATITUDE_DEGREE_MAX = LATITUDE_DEGREE_RANGE / 2;
+
+ public final static int HEADING_NORTH= 0;
+ public final static int HEADING_SOUTH= 180;
+ public final static int HEADING_EAST= 90;
+ public final static int HEADING_WEST= 270;
+
+
public abstract boolean isNormalized();
public abstract boolean isFixedPoint();
@@ -69,6 +82,47 @@ public abstract class LatLng {
);
}
+ public static LatLng computeDestination(LatLng startPoint, double distance,
+ double heading) {
+ return computeDestination(startPoint, distance, heading,
+ DistanceUnits.MILES);
+ }
+
+ /**
+ * Utility method for calculating a target point given a start, a heading (in degrees), a distance and a distance unit
+ * @param startPoint
+ * beginning point of the path
+ * @param distance
+ * distance to be travel from the starting point
+ * @param heading
+ * heading in degrees to follow during the travel
+ * @param distanceUnit
+ * unit of the distance to to travel
+ * @return arrival point of the described travel
+ */
+ public static LatLng computeDestination(LatLng startPoint, double distance, double heading, DistanceUnits distanceUnit) {
+ double startPointLatitude = startPoint.getLat();
+ double startPointLongitude = startPoint.getLng();
+ double earthRadius = distanceUnit.earthRadius();
+ double headingRad = Math.toRadians(heading);
+ double startPointLatitudeRad = Math.toRadians(startPointLatitude);
+ double startPointLongitudeRad = Math.toRadians(startPointLongitude);
+
+ // Haversine formula (http://www.movable-type.co.uk/scripts/latlong.html)
+ double destinationLatitudeRad = Math.asin(Math.sin(startPointLatitudeRad)
+ * Math.cos(distance / earthRadius) + Math.cos(startPointLatitudeRad)
+ * Math.sin(distance / earthRadius) * Math.cos(headingRad));
+
+ double destinationLongitudeRad = startPointLongitudeRad
+ + Math.atan2(Math.sin(headingRad) * Math.sin(distance / earthRadius)
+ * Math.cos(startPointLatitudeRad), Math.cos(distance / earthRadius)
+ - Math.sin(startPointLatitudeRad)
+ * Math.sin(destinationLatitudeRad));
+
+ return new FloatLatLng(Math.toDegrees(destinationLatitudeRad), Math
+ .toDegrees(destinationLongitudeRad));
+ }
+
/**
* The inverse of toCartesian(). Always returns a FixedLatLng.
* @param pt
Modified: lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java (original)
+++ lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/geometry/shape/LLRect.java Tue Apr 13 19:21:20 2010
@@ -17,6 +17,7 @@
package org.apache.lucene.spatial.geometry.shape;
+import org.apache.lucene.spatial.geometry.DistanceUnits;
import org.apache.lucene.spatial.geometry.FloatLatLng;
import org.apache.lucene.spatial.geometry.LatLng;
@@ -74,14 +75,34 @@ public class LLRect {
* @param heightMi
*/
public static LLRect createBox(LatLng center, double widthMi, double heightMi) {
- double d = widthMi;
- LatLng ur = boxCorners(center, d, 45.0); // assume right angles
- LatLng ll = boxCorners(center, d, 225.0);
-
- //System.err.println("boxCorners: ur " + ur.getLat() + ',' + ur.getLng());
- //System.err.println("boxCorners: cnt " + center.getLat() + ',' + center.getLng());
- //System.err.println("boxCorners: ll " + ll.getLat() + ',' + ll.getLng());
- return new LLRect(ll, ur);
+ double minLat;
+ double maxLat;
+ double minLng;
+ double maxLng;
+ double radius= Math.max(widthMi, heightMi);
+
+ if (radius > center.arcDistance(new FloatLatLng(LatLng.LATITUDE_DEGREE_MAX, LatLng.HEADING_NORTH))) {
+ maxLat = LatLng.LATITUDE_DEGREE_MAX;
+ } else {
+ maxLat = LatLng.computeDestination(center, radius, LatLng.HEADING_NORTH).getLat();
+
+ }
+ if (radius > center.arcDistance(new FloatLatLng(LatLng.LATITUDE_DEGREE_MIN, LatLng.HEADING_NORTH))) {
+ minLat = LatLng.LATITUDE_DEGREE_MIN;
+ } else {
+ minLat = LatLng.computeDestination(center, radius, LatLng.HEADING_SOUTH).getLat();
+ }
+
+ if((radius > 2 * Math.PI * DistanceUnits.MILES.earthRadius() * Math.cos(Math.toRadians(minLat))) ||
+ (radius > 2 * Math.PI * DistanceUnits.MILES.earthRadius() * Math.cos(Math.toRadians(maxLat)))) {
+ maxLng = LatLng.LONGITUDE_DEGREE_MAX;
+ minLng = LatLng.LONGITUDE_DEGREE_MIN;
+ } else {
+ maxLng = LatLng.computeDestination(new FloatLatLng(Math.max(Math.abs(minLat), Math.abs(maxLat)), center.getLng()), radius, LatLng.HEADING_EAST).getLng();
+ minLng = LatLng.computeDestination(new FloatLatLng(Math.max(Math.abs(minLat), Math.abs(maxLat)), center.getLng()), radius, LatLng.HEADING_WEST).getLng();
+ }
+
+ return new LLRect((new FloatLatLng(minLat, minLng).normalize()), (new FloatLatLng(maxLat, maxLng)).normalize());
}
/**
Modified: lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java (original)
+++ lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java Tue Apr 13 19:21:20 2010
@@ -17,9 +17,6 @@
package org.apache.lucene.spatial.tier;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-
import org.apache.lucene.search.Filter;
import org.apache.lucene.spatial.tier.projections.CartesianTierPlotter;
import org.apache.lucene.spatial.tier.projections.IProjector;
@@ -64,121 +61,71 @@ public class CartesianPolyFilterBuilder
miles = MILES_FLOOR;
}
LLRect box1 = LLRect.createBox( new FloatLatLng( latitude, longitude ), miles, miles );
- LatLng ll = box1.getLowerLeft();
- LatLng ur = box1.getUpperRight();
+ LatLng lowerLeft = box1.getLowerLeft();
+ LatLng upperRight = box1.getUpperRight();
- double latY = ur.getLat();
- double latX = ll.getLat();
- double longY = ur.getLng();
- double longX = ll.getLng();
- double longX2 = 0.0;
- //These two if checks setup us up to deal with issues around the prime meridian and the 180th meridian
- //In these two cases, we need to get tiles (tiers) from the lower left up to the meridian and then
- //from the meridan to the upper right
- //Are we crossing the 180 deg. longitude, if so, we need to do some special things
- if (ur.getLng() < 0.0 && ll.getLng() > 0.0) {
- longX2 = ll.getLng();
- longX = -180.0;
- }
- //are we crossing the prime meridian (0 degrees)? If so, we need to account for it and boxes on both sides
- if (ur.getLng() > 0.0 && ll.getLng() < 0.0) {
- longX2 = ll.getLng();
- longX = 0.0;
+ double latUpperRight = upperRight.getLat();
+ double latLowerLeft = lowerLeft.getLat();
+ double longUpperRight = upperRight.getLng();
+ double longLowerLeft = lowerLeft.getLng();
+
+ CartesianTierPlotter ctp = new CartesianTierPlotter( miles, projector, tierPrefix );
+ Shape shape = new Shape(ctp.getTierLevelId());
+
+ if (longUpperRight < longLowerLeft) { // Box cross the 180 meridian
+ addBoxes(shape, ctp, latLowerLeft, longLowerLeft, latUpperRight, LatLng.LONGITUDE_DEGREE_MAX);
+ addBoxes(shape, ctp, latLowerLeft, -LatLng.LONGITUDE_DEGREE_MIN, latUpperRight, longUpperRight);
+ } else {
+ addBoxes(shape, ctp, latLowerLeft, longLowerLeft, latUpperRight, longUpperRight);
}
-
- //System.err.println("getBoxShape:"+latY+"," + longY);
- //System.err.println("getBoxShape:"+latX+"," + longX);
- CartesianTierPlotter ctp = new CartesianTierPlotter(2, projector,tierPrefix);
- int bestFit = ctp.bestFit(miles);
- if (bestFit < minTier){
- bestFit = minTier;
- } else if (bestFit > maxTier){
- bestFit = maxTier;
- }
-
- ctp = new CartesianTierPlotter(bestFit, projector,tierPrefix);
- Shape shape = new Shape(ctp.getTierFieldName());
-
- // generate shape
- // iterate from startX->endX
- // iterate from startY -> endY
- // shape.add(currentLat.currentLong);
- //for the edge cases (prime meridian and the 180th meridian), this call handles all tiles East of the meridian
- //for all other cases, it handles the whole set of tiles
- shape = getShapeLoop(shape,ctp,latX,longX,latY,longY);
- if (longX2 != 0.0) {
- if (longX == 0.0) {
- longX = longX2;
- longY = 0.0;
- //handles the lower left longitude to the prime meridian
- //shape = getShapeLoop(shape, ctp, latX, longX, latY, longY);
- } else {
- //this clause handles the lower left longitude up to the 180 meridian
- longX = longX2;
- longY = 180.0;
- }
- shape = getShapeLoop(shape, ctp, latX, longX, latY, longY);
-
- //System.err.println("getBoxShape2:"+latY+"," + longY);
- //System.err.println("getBoxShape2:"+latX+"," + longX);
- }
-
return shape;
}
- public Shape getShapeLoop(Shape shape, CartesianTierPlotter ctp, double latX, double longX, double latY, double longY)
- {
-
- //System.err.println("getShapeLoop:"+latY+"," + longY);
- //System.err.println("getShapeLoop:"+latX+"," + longX);
- double beginAt = ctp.getTierBoxId(latX, longX);
- double endAt = ctp.getTierBoxId(latY, longY);
- if (beginAt > endAt){
- double tmp = beginAt;
- beginAt = endAt;
- endAt = tmp;
- }
- double tierVert = ctp.getTierVerticalPosDivider();
- //System.err.println(" | "+ beginAt+" | "+ endAt);
-
- double startX = beginAt - (beginAt %1);
- double startY = beginAt - startX ; //should give a whole number
-
- double endX = endAt - (endAt %1);
- double endY = endAt -endX; //should give a whole number
-
- int scale = (int)Math.log10(tierVert);
- endY = new BigDecimal(endY).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
- startY = new BigDecimal(startY).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
- double xInc = 1.0d / tierVert;
- xInc = new BigDecimal(xInc).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
-
- //System.err.println("go from startX:"+startX+" to:" + endX);
- for (; startX <= endX; startX++){
-
- double itY = startY;
- //System.err.println("go from startY:"+startY+" to:" + endY);
- while (itY <= endY){
- //create a boxId
- // startX.startY
- double boxId = startX + itY ;
+ private void addBoxes(Shape shape, CartesianTierPlotter tierPlotter, double lat1, double long1, double lat2, double long2) {
+ double boxId1 = tierPlotter.getTierBoxId(lat1, long1);
+ double boxId2 = tierPlotter.getTierBoxId(lat2, long2);
+
+ double tierVert = tierPlotter.getTierVerticalPosDivider();
+
+ int LongIndex1 = (int) Math.round(boxId1);
+ int LatIndex1 = (int) Math.round((boxId1 - LongIndex1) * tierVert);
+
+ int LongIndex2 = (int) Math.round(boxId2);
+ int LatIndex2 = (int) Math.round((boxId2 - LongIndex2) * tierVert);
+
+ int startLong, endLong;
+ int startLat, endLat;
+
+ if (LongIndex1 > LongIndex2) {
+ startLong = LongIndex2;
+ endLong = LongIndex1;
+ } else {
+ startLong = LongIndex1;
+ endLong = LongIndex2;
+ }
+
+ if (LatIndex1 > LatIndex2) {
+ startLat = LatIndex2;
+ endLat = LatIndex1;
+ } else {
+ startLat = LatIndex1;
+ endLat = LatIndex2;
+ }
+
+ int LatIndex, LongIndex;
+ for (LongIndex = startLong; LongIndex <= endLong; LongIndex++) {
+ for (LatIndex = startLat; LatIndex <= endLat; LatIndex++) {
+ // create a boxId
+ double boxId = LongIndex + LatIndex / tierVert;
shape.addBox(boxId);
- //System.err.println("----"+startX+" and "+itY);
- //System.err.println("----"+boxId);
- itY += xInc;
-
- // java keeps 0.0001 as 1.0E-1
- // which ends up as 0.00011111
- itY = new BigDecimal(itY).setScale(scale, RoundingMode.HALF_EVEN).doubleValue();
}
}
- return shape;
}
public Filter getBoundingArea(double latitude, double longitude, double miles)
{
Shape shape = getBoxShape(latitude, longitude, miles);
- return new CartesianShapeFilter(shape, shape.getTierId());
+ return new CartesianShapeFilter(shape, tierPrefix + shape.getTierId());
}
}
Modified: lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java (original)
+++ lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java Tue Apr 13 19:21:20 2010
@@ -29,9 +29,9 @@ import java.util.List;
public class Shape implements Serializable{
private List<Double> area = new ArrayList<Double>();
- private String tierId;
+ private int tierId;
- public Shape (String tierId){
+ public Shape (int tierId){
this.tierId = tierId;
}
@@ -43,7 +43,7 @@ public class Shape implements Serializab
return area;
}
- public String getTierId(){
+ public int getTierId(){
return tierId;
}
Modified: lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java (original)
+++ lucene/dev/trunk/lucene/contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java Tue Apr 13 19:21:20 2010
@@ -17,6 +17,8 @@
package org.apache.lucene.spatial.tier.projections;
+import org.apache.lucene.spatial.geometry.DistanceUnits;
+
/**
* <p><font color="red"><b>NOTE:</b> This API is still in
* flux and might change in incompatible ways in the next
@@ -33,6 +35,8 @@ public class CartesianTierPlotter {
final String fieldPrefix;
Double idd = Double.valueOf(180);
+ private static final double LOG_2 = Math.log(2);
+
public CartesianTierPlotter (int tierLevel, IProjector projector, String fieldPrefix) {
this.tierLevel = tierLevel;
@@ -43,6 +47,11 @@ public class CartesianTierPlotter {
setTierBoxes();
setTierVerticalPosDivider();
}
+
+ public CartesianTierPlotter(double radius, IProjector projector,
+ String fieldPrefix) {
+ this(CartesianTierPlotter.bestFit(radius), projector, fieldPrefix);
+ }
private void setTierLength (){
this.tierLength = (int) Math.pow(2 , this.tierLevel);
@@ -133,17 +142,15 @@ public class CartesianTierPlotter {
* Distances less than a mile return 15, finer granularity is
* in accurate
*/
- public int bestFit(double miles){
-
- //28,892 a rough circumference of the earth
- int circ = 28892;
-
- double r = miles / 2.0;
-
- double corner = r - Math.sqrt(Math.pow(r, 2) / 2.0d);
- double times = circ / corner;
- int bestFit = (int)Math.ceil(log2(times)) + 1;
-
+ static public int bestFit(double range) {
+ return bestFit(range, DistanceUnits.MILES);
+ }
+
+ static public int bestFit(double range, DistanceUnits distanceUnit) {
+ double times = distanceUnit.earthCircumference() / (2.0d * range);
+
+ int bestFit = (int) Math.ceil(log2(times));
+
if (bestFit > 15) {
// 15 is the granularity of about 1 mile
// finer granularity isn't accurate with standard java math
@@ -153,12 +160,23 @@ public class CartesianTierPlotter {
}
/**
- * a log to the base 2 formula
- * <code>Math.log(value) / Math.log(2)</code>
+ * Computes log to base 2 of the given value
+ *
* @param value
+ * Value to compute the log of
+ * @return Log_2 of the value
*/
- public double log2(double value) {
-
- return Math.log(value) / Math.log(2);
+ public static double log2(double value) {
+ return Math.log(value) / LOG_2;
+ }
+
+ /**
+ * Returns the ID of the tier level plotting is occuring at
+ *
+ * @return ID of the tier level plotting is occuring at
+ */
+ public int getTierLevelId() {
+ return this.tierLevel;
}
+
}
Modified: lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java (original)
+++ lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesian.java Tue Apr 13 19:21:20 2010
@@ -141,6 +141,8 @@ public class TestCartesian extends Lucen
addPoint(writer, "Wonga Wongue Reserve, Gabon", -0.546562,9.459229);
addPoint(writer,"Midway Island",25.7, -171.7);
addPoint(writer,"North Pole Way",55.0, 4.0);
+ addPoint(writer,"Close to the North Pole",89.9, 4.0);
+ addPoint(writer,"Close to the North Pole, other side",89.9, -176.0);
writer.commit();
writer.close();
@@ -362,8 +364,8 @@ public class TestCartesian extends Lucen
System.out.println("Results should be 18 "+ results);
}
- assertEquals(18, distances.size()); // fixed a store of only needed distances
- assertEquals(18, results);
+ assertEquals(20, distances.size()); // fixed a store of only needed distances
+ assertEquals(20, results);
double lastDistance = 0;
for(int i =0 ; i < results; i++){
Document d = searcher.doc(scoreDocs[i].doc);
@@ -383,6 +385,103 @@ public class TestCartesian extends Lucen
lastDistance = geo_distance;
}
}
+
+ public void testPoles() throws IOException, InvalidGeoException {
+ searcher = new IndexSearcher(directory, true);
+
+ final double miles = 50.0;
+ lat = 89.99;
+ lng = 4;
+
+ if (VERBOSE) System.out.println("testPoleFlipping");
+
+ // create a distance query
+ final DistanceQueryBuilder dq = new DistanceQueryBuilder(lat, lng, miles,
+ latField, lngField, CartesianTierPlotter.DEFALT_FIELD_PREFIX, true, 2, 15);
+
+ if (VERBOSE) System.out.println(dq);
+ //create a term query to search against all documents
+ Query tq = new TermQuery(new Term("metafile", "doc"));
+
+ FieldScoreQuery fsQuery = new FieldScoreQuery("geo_distance", Type.FLOAT);
+
+ CustomScoreQuery customScore = new CustomScoreQuery(dq.getQuery(tq),fsQuery){
+
+ @Override
+ protected CustomScoreProvider getCustomScoreProvider(IndexReader reader) {
+ return new CustomScoreProvider(reader) {
+ @Override // TODO: broken, as reader is not used!
+ public float customScore(int doc, float subQueryScore, float valSrcScore){
+ if (VERBOSE) System.out.println(doc);
+ if (dq.distanceFilter.getDistance(doc) == null)
+ return 0;
+
+ double distance = dq.distanceFilter.getDistance(doc);
+ // boost score shouldn't exceed 1
+ if (distance < 1.0d)
+ distance = 1.0d;
+ //boost by distance is invertly proportional to
+ // to distance from center point to location
+ float score = (float) ((miles - distance) / miles );
+ return score * subQueryScore;
+ }
+ };
+ }
+
+ };
+ // Create a distance sort
+ // As the radius filter has performed the distance calculations
+ // already, pass in the filter to reuse the results.
+ //
+ DistanceFieldComparatorSource dsort = new DistanceFieldComparatorSource(dq.distanceFilter);
+ Sort sort = new Sort(new SortField("foo", dsort,false));
+
+ // Perform the search, using the term query, the serial chain filter, and the
+ // distance sort
+ TopDocs hits = searcher.search(customScore.createWeight(searcher),null, 1000, sort);
+ int results = hits.totalHits;
+ ScoreDoc[] scoreDocs = hits.scoreDocs;
+
+ // Get a list of distances
+ Map<Integer,Double> distances = dq.distanceFilter.getDistances();
+
+ // distances calculated from filter first pass must be less than total
+ // docs, from the above test of 20 items, 12 will come from the boundary box
+ // filter, but only 5 are actually in the radius of the results.
+
+ // Note Boundary Box filtering, is not accurate enough for most systems.
+
+
+ if (VERBOSE) {
+ System.out.println("Distance Filter filtered: " + distances.size());
+ System.out.println("Results: " + results);
+ System.out.println("=============================");
+ System.out.println("Distances should be 18 "+ distances.size());
+ System.out.println("Results should be 18 "+ results);
+ }
+
+ assertEquals(2, distances.size()); // fixed a store of only needed distances
+ assertEquals(2, results);
+ double lastDistance = 0;
+ for(int i =0 ; i < results; i++){
+ Document d = searcher.doc(scoreDocs[i].doc);
+ String name = d.get("name");
+ double rsLat = Double.parseDouble(d.get(latField));
+ double rsLng = Double.parseDouble(d.get(lngField));
+ Double geo_distance = distances.get(scoreDocs[i].doc);
+
+ double distance = DistanceUtils.getInstance().getDistanceMi(lat, lng, rsLat, rsLng);
+ double llm = DistanceUtils.getInstance().getLLMDistance(lat, lng, rsLat, rsLng);
+ if (VERBOSE) System.out.println("Name: "+ name +", Distance "+ distance); //(res, ortho, harvesine):"+ distance +" |"+ geo_distance +"|"+ llm +" | score "+ hits.score(i));
+ assertTrue(Math.abs((distance - llm)) < 1);
+ if (VERBOSE) System.out.println("checking limit "+ distance + " < " + miles);
+ assertTrue((distance < miles ));
+ if (VERBOSE) System.out.println("checking sort "+ geo_distance + " >= " + lastDistance);
+ assertTrue(geo_distance >= lastDistance);
+ lastDistance = geo_distance;
+ }
+ }
+
public void testRange() throws IOException, InvalidGeoException {
searcher = new IndexSearcher(directory, true);
Modified: lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java?rev=933754&r1=933753&r2=933754&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java (original)
+++ lucene/dev/trunk/lucene/contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java Tue Apr 13 19:21:20 2010
@@ -30,7 +30,7 @@ import junit.framework.TestCase;
public class TestCartesianShapeFilter extends TestCase {
public void testSerializable() throws IOException {
- CartesianShapeFilter filter = new CartesianShapeFilter(new Shape("1"),
+ CartesianShapeFilter filter = new CartesianShapeFilter(new Shape(1),
"test");
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();