Index: contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java =================================================================== --- contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java (révision 930484) +++ contrib/spatial/src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java (copie de travail) @@ -30,7 +30,7 @@ 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(); Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java (révision 930484) +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java (copie de travail) @@ -17,6 +17,8 @@ package org.apache.lucene.spatial.tier.projections; +import org.apache.lucene.spatial.geometry.DistanceUnits; + /** *

NOTE: This API is still in * flux and might change in incompatible ways in the next @@ -33,6 +35,8 @@ 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 @@ 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 @@ * 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 @@ } /** - * a log to the base 2 formula - * Math.log(value) / Math.log(2) + * 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; + } + } Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java (révision 930484) +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/Shape.java (copie de travail) @@ -29,9 +29,9 @@ public class Shape implements Serializable{ private List area = new ArrayList(); - private String tierId; + private int tierId; - public Shape (String tierId){ + public Shape (int tierId){ this.tierId = tierId; } @@ -43,7 +43,7 @@ return area; } - public String getTierId(){ + public int getTierId(){ return tierId; } Index: contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java (révision 930484) +++ contrib/spatial/src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java (copie de travail) @@ -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 @@ 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; - } - - //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); + double latUpperRight = upperRight.getLat(); + double latLowerLeft = lowerLeft.getLat(); + double longUpperRight = upperRight.getLng(); + double longLowerLeft = lowerLeft.getLng(); - //System.err.println("getBoxShape2:"+latY+"," + longY); - //System.err.println("getBoxShape2:"+latX+"," + longX); - } - + 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_RANGE / 2); + addBoxes(shape, ctp, latLowerLeft, -LatLng.LONGITUDE_DEGREE_RANGE / 2, latUpperRight, longUpperRight); + } else { + addBoxes(shape, ctp, latLowerLeft, longLowerLeft, latUpperRight, longUpperRight); + } 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()); } } Index: contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java =================================================================== --- contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java (révision 930484) +++ contrib/spatial/src/java/org/apache/lucene/spatial/geometry/LatLng.java (copie de travail) @@ -30,6 +30,13 @@ */ 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 abstract boolean isNormalized(); public abstract boolean isFixedPoint();