Index: src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java =================================================================== --- src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java (révision 1035291) +++ src/test/org/apache/lucene/spatial/tier/TestCartesianShapeFilter.java (copie de travail) @@ -31,7 +31,7 @@ public class TestCartesianShapeFilter extends LuceneTestCase { 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: src/test/org/apache/lucene/spatial/tier/TestCartesian.java =================================================================== --- src/test/org/apache/lucene/spatial/tier/TestCartesian.java (révision 1035291) +++ src/test/org/apache/lucene/spatial/tier/TestCartesian.java (copie de travail) @@ -581,4 +581,31 @@ } searcher.close(); } + + public void testGetBoxShape() { + CartesianPolyFilterBuilder cpfb= new CartesianPolyFilterBuilder("_tier_",0,15); + + IProjector projector = new SinusoidalProjector(); + CartesianTierPlotter ctp = new CartesianTierPlotter(8, projector,"_tier_"); + + Shape shape= cpfb.getBoxShape(40.0, 120.0, 400.0); + + assertTrue("testGetBoxShape : The shape should have a non empty list of Areas", shape.getArea().size()!=0); + + } + + public void testGetShapeLoop() { + CartesianPolyFilterBuilder cpfb= new CartesianPolyFilterBuilder("_tier_",0,15); + + IProjector projector = new SinusoidalProjector(); + CartesianTierPlotter ctp = new CartesianTierPlotter(8, projector,"_tier_"); + + Shape shape= new Shape(ctp.getTierLevelId()); + + cpfb.addBoxes(shape, ctp, -20, 140, 60, 180); + + assertTrue("testGetShapeLoop : The shape should have a non empty list of Areas", shape.getArea().size()!=0); + + } } + Index: src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java =================================================================== --- src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java (révision 1035291) +++ src/java/org/apache/lucene/spatial/tier/projections/CartesianTierPlotter.java (copie de travail) @@ -17,15 +17,17 @@ 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 * release. */ + public class CartesianTierPlotter { - public static final String DEFALT_FIELD_PREFIX = "_tier_"; + public static final String DEFAULT_FIELD_PREFIX = "_tier_"; - private static final double LOG_2 = Math.log(2); final int tierLevel; @@ -47,6 +49,11 @@ 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); } @@ -136,17 +143,15 @@ * Distances less than a mile return 15, finer granularity is * in accurate */ - public int bestFit(double miles){ + 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)); - //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; - if (bestFit > 15) { // 15 is the granularity of about 1 mile // finer granularity isn't accurate with standard java math Index: src/java/org/apache/lucene/spatial/tier/Shape.java =================================================================== --- src/java/org/apache/lucene/spatial/tier/Shape.java (révision 1035291) +++ 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: src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java =================================================================== --- src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java (révision 1035291) +++ src/java/org/apache/lucene/spatial/tier/CartesianPolyFilterBuilder.java (copie de travail) @@ -63,119 +63,69 @@ 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(); - //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; - } + CartesianTierPlotter ctp = new CartesianTierPlotter( miles, projector, tierPrefix ); + Shape shape = new Shape(ctp.getTierLevelId()); - 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); + 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 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); - public Shape getShapeLoop(Shape shape, CartesianTierPlotter ctp, double latX, double longX, double latY, double longY) { + double tierVert = tierPlotter.getTierVerticalPosDivider(); - //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); + int LongIndex1 = (int) Math.round(boxId1); + int LatIndex1 = (int) Math.round((boxId1 - LongIndex1) * tierVert); - double startX = beginAt - (beginAt % 1); - double startY = beginAt - startX; //should give a whole number + int LongIndex2 = (int) Math.round(boxId2); + int LatIndex2 = (int) Math.round((boxId2 - LongIndex2) * tierVert); - double endX = endAt - (endAt % 1); - double endY = endAt - endX; //should give a whole number + int startLong, endLong; + int startLat, endLat; - 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(); + if (LongIndex1 > LongIndex2) { + startLong = LongIndex2; + endLong = LongIndex1; + } else { + startLong = LongIndex1; + endLong = LongIndex2; + } - //System.err.println("go from startX:"+startX+" to:" + endX); - for (; startX <= endX; startX++) { + if (LatIndex1 > LatIndex2) { + startLat = LatIndex2; + endLat = LatIndex1; + } else { + startLat = LatIndex1; + endLat = LatIndex2; + } - double itY = startY; - //System.err.println("go from startY:"+startY+" to:" + endY); - while (itY <= endY) { - //create a boxId - // startX.startY - double boxId = startX + itY; - 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(); + 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); } } - 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: src/java/org/apache/lucene/spatial/geometry/LatLng.java =================================================================== --- src/java/org/apache/lucene/spatial/geometry/LatLng.java (révision 1035291) +++ 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();