Skip to content

Commit

Permalink
Add sample/test of circle query with a radius of 100km
Browse files Browse the repository at this point in the history
  • Loading branch information
kungfoo committed Jul 14, 2017
1 parent fe25bee commit 3ebab20
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 16 deletions.
6 changes: 3 additions & 3 deletions src/main/java/ch/hsr/geohash/GeoHash.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@

@SuppressWarnings("javadoc")
public final class GeoHash implements Comparable<GeoHash>, Serializable {
private static final int MAX_BIT_PRECISION = 64;
private static final int MAX_CHARACTER_PRECISION = 12;
public static final int MAX_BIT_PRECISION = 64;
public static final int MAX_CHARACTER_PRECISION = 12;

private static final long serialVersionUID = -8553214249630252175L;
private static final int[] BITS = { 16, 8, 4, 2, 1 };
private static final int BASE32_BITS = 5;
public static final long FIRST_BIT_FLAGGED = 0x8000000000000000l;
private static final long FIRST_BIT_FLAGGED = 0x8000000000000000l;
private static final char[] base32 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };

Expand Down
26 changes: 13 additions & 13 deletions src/main/java/ch/hsr/geohash/queries/GeoHashCircleQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@
import ch.hsr.geohash.util.VincentyGeodesy;

/**
* represents a radius search around a specific point via geohashes.
* represents a radiusInMetres search around a specific point via geohashes.
* Approximates the circle with a square!
*/
public class GeoHashCircleQuery implements GeoHashQuery, Serializable {
private static final long serialVersionUID = 1263295371663796291L;
private double radius;
private double radiusInMetres;
private GeoHashBoundingBoxQuery query;
private WGS84Point center;

/**
* create a {@link GeoHashCircleQuery} with the given center point and a
* radius in meters.
* radiusInMetres in meters.
*/
public GeoHashCircleQuery(WGS84Point center, double radius) {
this.radius = radius;
public GeoHashCircleQuery(WGS84Point center, double radiusInMetres) {
this.radiusInMetres = radiusInMetres;
this.center = center;
WGS84Point northEast = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 0, radius), 90,
radius);
WGS84Point southWest = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 180, radius),
270, radius);
WGS84Point northEast = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 0, radiusInMetres), 90,
radiusInMetres);
WGS84Point southWest = VincentyGeodesy.moveInDirection(VincentyGeodesy.moveInDirection(center, 180, radiusInMetres),
270, radiusInMetres);
BoundingBox bbox = new BoundingBox(northEast, southWest);
query = new GeoHashBoundingBoxQuery(bbox);
}
Expand All @@ -58,14 +58,14 @@ public List<GeoHash> getSearchHashes() {

@Override
public String toString() {
return "Cicle Query [center=" + center + ", radius=" + getRadiusString() + "]";
return "Cicle Query [center=" + center + ", radiusInMetres=" + getRadiusString() + "]";
}

private String getRadiusString() {
if (radius > 1000) {
return radius / 1000 + "km";
if (radiusInMetres > 1000) {
return radiusInMetres / 1000 + "km";
} else {
return radius + "m";
return radiusInMetres + "m";
}
}

Expand Down
58 changes: 58 additions & 0 deletions src/test/java/ch/hsr/geohash/GeoHashCircleQueryTest.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
package ch.hsr.geohash;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import ch.hsr.geohash.util.RandomWGS84Points;
import ch.hsr.geohash.util.VincentyGeodesy;
import org.hamcrest.CoreMatchers;
import org.junit.Test;

import ch.hsr.geohash.queries.GeoHashCircleQuery;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class GeoHashCircleQueryTest {

private static final int NUMBER_OF_RANDOM_POINTS = 1000000;

@Test
public void testIssue3WithCircleQuery() throws Exception {
WGS84Point center = new WGS84Point(39.86391280373075, 116.37356590048701);
Expand All @@ -20,4 +34,48 @@ public void testIssue3WithCircleQuery() throws Exception {
assertTrue(query.contains(test1));
assertTrue(query.contains(test2));
}

@Test
public void testStoringManyPointsAndPerformingCircleQuery() throws Exception {
List<GeoHash> hashes = createRandomHashes();
WGS84Point queryPoint = RandomWGS84Points.get();

GeoHashCircleQuery oneHundredKilometresQuery = new GeoHashCircleQuery(queryPoint, 100 * 1000);
assertThat(oneHundredKilometresQuery.toString(), containsString("100.0km"));

// filter points/hashes based on prefix, no expensive vincenty math here.
long t1 = System.currentTimeMillis();
List<GeoHash> contained = new ArrayList<>();
for(GeoHash hash: hashes) {
if(oneHundredKilometresQuery.contains(hash)) {
contained.add(hash);
}
}
long t2 = System.currentTimeMillis();

System.out.println(String.format("Checking %d hashes took %dms", NUMBER_OF_RANDOM_POINTS, t2-t1));

// let's argue at least one point should have been contained
assertThat(contained.size(), is(not(0)));
System.out.println(String.format("Number of points matched by query: %d", contained.size()));

for(GeoHash hash: contained) {
double actualDistanceInMeters = VincentyGeodesy.distanceInMeters(queryPoint, hash.getPoint());
System.out.println(String.format("Actual distance: %.2fkm", actualDistanceInMeters / 1000));
}
}

private List<GeoHash> createRandomHashes() {
List<WGS84Point> points = RandomWGS84Points.get(NUMBER_OF_RANDOM_POINTS);
List<GeoHash> result = new ArrayList<>(NUMBER_OF_RANDOM_POINTS);

for(WGS84Point point : points) {
result.add(
GeoHash.withBitPrecision(point.getLatitude(), point.getLongitude(), GeoHash.MAX_BIT_PRECISION)
);
}
return result;
}


}
29 changes: 29 additions & 0 deletions src/test/java/ch/hsr/geohash/util/RandomWGS84Points.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ch.hsr.geohash.util;

import ch.hsr.geohash.WGS84Point;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class RandomWGS84Points {
private static final Random RAND = new Random(System.currentTimeMillis());

public static WGS84Point get() {
return createRandomPoint();
}

public static List<WGS84Point> get(int n) {
List<WGS84Point> result = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
result.add(createRandomPoint());
}
return result;
}

private static WGS84Point createRandomPoint() {
double latitude = (RAND.nextDouble() - 0.5) * 180;
double longitude = (RAND.nextDouble() - 0.5) * 360;
return new WGS84Point(latitude, longitude);
}
}

0 comments on commit 3ebab20

Please sign in to comment.