Geo: fixes circle radius calculation

This change fixes the creation circle shapes o it calculates it correctly instead of essentially using the diameter as the radius.  The radius has to be converted into degrees but calculating the ratio of the desired radius to the circumference of the earth and then multiplying it by 360 (number of degrees around the earths circumference).  This issue here was that it was only multiplied by 180 making the result out by a factor of 2.  Also made the test for circles actually check to make sure it has the correct centre and radius.

Closes #7301
This commit is contained in:
Colin Goodheart-Smithe 2014-08-19 15:56:25 +01:00
parent e2311d5da4
commit f7ae4d9d86
2 changed files with 27 additions and 8 deletions

View File

@ -19,12 +19,12 @@
package org.elasticsearch.common.geo.builders; package org.elasticsearch.common.geo.builders;
import com.spatial4j.core.shape.Circle;
import com.vividsolutions.jts.geom.Coordinate;
import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.unit.DistanceUnit.Distance; import org.elasticsearch.common.unit.DistanceUnit.Distance;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import com.spatial4j.core.shape.Circle;
import com.vividsolutions.jts.geom.Coordinate;
import java.io.IOException; import java.io.IOException;
public class CircleBuilder extends ShapeBuilder { public class CircleBuilder extends ShapeBuilder {
@ -109,7 +109,7 @@ public class CircleBuilder extends ShapeBuilder {
@Override @Override
public Circle build() { public Circle build() {
return SPATIAL_CONTEXT.makeCircle(center.x, center.y, 180 * radius / unit.getEarthCircumference()); return SPATIAL_CONTEXT.makeCircle(center.x, center.y, 360 * radius / unit.getEarthCircumference());
} }
@Override @Override

View File

@ -19,9 +19,11 @@
package org.elasticsearch.common.geo; package org.elasticsearch.common.geo;
import com.spatial4j.core.shape.Circle;
import com.spatial4j.core.shape.Point; import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Rectangle; import com.spatial4j.core.shape.Rectangle;
import com.spatial4j.core.shape.Shape; import com.spatial4j.core.shape.Shape;
import com.spatial4j.core.shape.impl.PointImpl;
import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.Polygon;
@ -161,11 +163,28 @@ public class ShapeBuilderTests extends ElasticsearchTestCase {
@Test @Test
public void testGeoCircle() { public void testGeoCircle() {
ShapeBuilder.newCircleBuilder().center(0, 0).radius("100m").build(); double earthCircumference = 40075016.69;
ShapeBuilder.newCircleBuilder().center(+180, 0).radius("100m").build(); Circle circle = ShapeBuilder.newCircleBuilder().center(0, 0).radius("100m").build();
ShapeBuilder.newCircleBuilder().center(-180, 0).radius("100m").build(); assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
ShapeBuilder.newCircleBuilder().center(0, 90).radius("100m").build(); assertEquals((Point) new PointImpl(0, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
ShapeBuilder.newCircleBuilder().center(0, -90).radius("100m").build(); circle = ShapeBuilder.newCircleBuilder().center(+180, 0).radius("100m").build();
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
assertEquals((Point) new PointImpl(180, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
circle = ShapeBuilder.newCircleBuilder().center(-180, 0).radius("100m").build();
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
assertEquals((Point) new PointImpl(-180, 0, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
circle = ShapeBuilder.newCircleBuilder().center(0, 90).radius("100m").build();
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
assertEquals((Point) new PointImpl(0, 90, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
circle = ShapeBuilder.newCircleBuilder().center(0, -90).radius("100m").build();
assertEquals((360 * 100) / earthCircumference, circle.getRadius(), 0.00000001);
assertEquals((Point) new PointImpl(0, -90, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
double randomLat = (randomDouble() * 180) - 90;
double randomLon = (randomDouble() * 360) - 180;
double randomRadius = randomIntBetween(1, (int) earthCircumference / 4);
circle = ShapeBuilder.newCircleBuilder().center(randomLon, randomLat).radius(randomRadius + "m").build();
assertEquals((360 * randomRadius) / earthCircumference, circle.getRadius(), 0.00000001);
assertEquals((Point) new PointImpl(randomLon, randomLat, ShapeBuilder.SPATIAL_CONTEXT), circle.getCenter());
} }
@Test @Test