diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Box.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Box.java new file mode 100644 index 000000000..0035b7663 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Box.java @@ -0,0 +1,97 @@ +/* + * Copyright 2010-2011 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.document.mongodb.geo; + +/** + * Represents a geospatial box value + * @author Mark Pollack + * + */ +public class Box { + + + private double xmin; + + private double ymin; + + private double xmax; + + private double ymax; + + public Box(Point lowerLeft, Point upperRight) { + xmin = lowerLeft.getX(); + ymin = lowerLeft.getY(); + xmax = upperRight.getX(); + ymax = upperRight.getY(); + } + + public Box(double[] lowerLeft, double[] upperRight) { + xmin = lowerLeft[0]; + ymin = lowerLeft[1]; + xmax = upperRight[0]; + ymax = upperRight[1]; + } + + public Point getLowerLeft() { + return new Point(xmin, ymin); + } + + public Point getUpperRight() { + return new Point(xmax, ymax); + } + @Override + public String toString() { + return "Box [xmin=" + xmin + ", ymin=" + ymin + ", xmax=" + xmax + + ", ymax=" + ymax + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + long temp; + temp = Double.doubleToLongBits(xmax); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(xmin); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(ymax); + result = prime * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(ymin); + result = prime * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Box other = (Box) obj; + if (Double.doubleToLongBits(xmax) != Double.doubleToLongBits(other.xmax)) + return false; + if (Double.doubleToLongBits(xmin) != Double.doubleToLongBits(other.xmin)) + return false; + if (Double.doubleToLongBits(ymax) != Double.doubleToLongBits(other.ymax)) + return false; + if (Double.doubleToLongBits(ymin) != Double.doubleToLongBits(other.ymin)) + return false; + return true; + } + +} diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java index d6cff2a70..203b292d3 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/geo/Point.java @@ -22,38 +22,36 @@ package org.springframework.data.document.mongodb.geo; */ public class Point { - private double latitude; + private double x; - private double longitude; + private double y; - public Point(double latitude, double longitude) { - this.latitude = latitude; - this.longitude = longitude; + public Point(double x, double y) { + this.x = x; + this.y = y; } public Point(Point point) { - this.latitude = point.latitude; - this.longitude = point.longitude; + this.x = point.x; + this.y = point.y; } - public double getLatitude() { - return latitude; + public double getX() { + return x; } - public double getLongitude() { - return longitude; + public double getY() { + return y; } - - @Override public int hashCode() { final int prime = 31; int result = 1; long temp; - temp = Double.doubleToLongBits(latitude); + temp = Double.doubleToLongBits(x); result = prime * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(longitude); + temp = Double.doubleToLongBits(y); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @@ -67,18 +65,18 @@ public class Point { if (getClass() != obj.getClass()) return false; Point other = (Point) obj; - if (Double.doubleToLongBits(latitude) != Double - .doubleToLongBits(other.latitude)) + if (Double.doubleToLongBits(x) != Double + .doubleToLongBits(other.x)) return false; - if (Double.doubleToLongBits(longitude) != Double - .doubleToLongBits(other.longitude)) + if (Double.doubleToLongBits(y) != Double + .doubleToLongBits(other.y)) return false; return true; } @Override public String toString() { - return "Point [latitude=" + latitude + ", longitude=" + longitude + "]"; + return "Point [latitude=" + x + ", longitude=" + y + "]"; } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java index 4837d821f..ae4635d5f 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/document/mongodb/query/Criteria.java @@ -23,6 +23,7 @@ import java.util.List; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import org.springframework.data.document.InvalidDocumentStoreApiUsageException; +import org.springframework.data.document.mongodb.geo.Box; import org.springframework.data.document.mongodb.geo.Circle; import org.springframework.data.document.mongodb.geo.Point; @@ -231,11 +232,11 @@ public class Criteria implements CriteriaDefinition { /** - * Creates a geospatial criterion using a $within operation + * Creates a geospatial criterion using a $within $center operation * @param circle * @return */ - public Criteria within(Circle circle) { + public Criteria withinCenter(Circle circle) { LinkedList list = new LinkedList(); list.addLast(circle.getCenter()); list.add(circle.getRadius()); @@ -243,13 +244,49 @@ public class Criteria implements CriteriaDefinition { return this; } + /** + * Creates a geospatial criterion using a $within $center operation. This is only available for Mongo 1.7 and higher. + * @param circle + * @return + */ + public Criteria withinCenterSphere(Circle circle) { + LinkedList list = new LinkedList(); + list.addLast(circle.getCenter()); + list.add(circle.getRadius()); + criteria.put("$within", new BasicDBObject("$centerSphere", list)); + return this; + } + + /** + * Creates a geospatial criterion using a $within $box operation + * @param circle + * @return + */ + public Criteria withinBox(Box box) { + LinkedList list = new LinkedList(); + list.addLast(new double[]{ box.getLowerLeft().getX(), box.getLowerLeft().getY()} ); + list.addLast(new double[]{ box.getUpperRight().getX(), box.getUpperRight().getY()} ); + criteria.put("$within", new BasicDBObject("$box", list)); + return this; + } + /** * Creates a geospatial criterion using a $near operation * @param point * @return */ public Criteria near(Point point) { - criteria.put("$near", new double[]{point.getLatitude(), point.getLongitude()}); + criteria.put("$near", new double[]{point.getX(), point.getY()}); + return this; + } + + /** + * Creates a geospatial criterion using a $nearSphere operation. This is only available for Mongo 1.7 and higher. + * @param point + * @return + */ + public Criteria nearSphere(Point point) { + criteria.put("$nearSphere", new double[]{point.getX(), point.getY()}); return this; } diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialTests.java index 85562025b..33bd2d29b 100644 --- a/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialTests.java +++ b/spring-data-mongodb/src/test/java/org/springframework/data/document/mongodb/GeoSpatialTests.java @@ -31,8 +31,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.dao.DataAccessException; +import org.springframework.data.document.mongodb.geo.Box; import org.springframework.data.document.mongodb.geo.Circle; import org.springframework.data.document.mongodb.geo.Point; +import org.springframework.data.document.mongodb.monitor.ServerInfo; import org.springframework.data.document.mongodb.query.Criteria; import org.springframework.data.document.mongodb.query.GeospatialIndex; import org.springframework.data.document.mongodb.query.Query; @@ -57,10 +59,12 @@ public class GeoSpatialTests { ApplicationContext applicationContext; MongoTemplate template; + ServerInfo serverInfo; @Before public void setUp() throws Exception { Mongo mongo = new Mongo(); + serverInfo = new ServerInfo(mongo); DB db = mongo.getDB("geospatial"); for (String coll : collectionsToDrop) { db.getCollection(coll).drop(); @@ -90,20 +94,53 @@ public class GeoSpatialTests { template.insert(new Venue("Maplewood, NJ", -74.2713, 40.73137)); } + /* + public void geoNear() { + GeoNearResult geoNearResult = template.geoNear(new Query(Criteria.where("type").is("Office")), Venue.class, + GeoNearCriteria.near(2,3).num(10).maxDistance(10).distanceMultiplier(10).spherical(true)); + }*/ + @Test - public void withinCircle() { + public void withinCenter() { Circle circle = new Circle(-73.99171, 40.738868, 0.01); - List venues = template.find(new Query(Criteria.where("location").within(circle)), Venue.class); + List venues = template.find(new Query(Criteria.where("location").withinCenter(circle)), Venue.class); assertThat(venues.size(), equalTo(7)); } + @Test + @Ignore("run only on v 1.7.0 server or greater") + public void withinCenterSphere() { + Circle circle = new Circle(-73.99171, 40.738868, 0.003712240453784); + List venues = template.find(new Query(Criteria.where("location").withinCenterSphere(circle)), Venue.class); + assertThat(venues.size(), equalTo(11)); + } + + + @Test + public void withinBox() { + Box box = new Box(new Point(-73.99756, 40.73083), new Point(-73.988135, 40.741404)); + //Box box = newBox.lowerLeft(x,y).upperRight(x,y); + List venues = template.find(new Query(Criteria.where("location").withinBox(box)), Venue.class); + assertThat(venues.size(), equalTo(4)); + } + @Test public void nearPoint() { Point point = new Point(-73.99171, 40.738868); List venues = template.find(new Query(Criteria.where("location").near(point).maxDistance(0.01)), Venue.class); assertThat(venues.size(), equalTo(7)); } + + @Test + @Ignore("run only on v 1.7.0 server or greater") + public void nearSphere() { + Point point = new Point(-73.99171, 40.738868); + List venues = template.find(new Query(Criteria.where("location").nearSphere(point).maxDistance(0.003712240453784)), Venue.class); + assertThat(venues.size(), equalTo(11)); + } + + @Test public void searchAllData() { diff --git a/spring-data-mongodb/src/test/resources/geospatial.xml b/spring-data-mongodb/src/test/resources/geospatial.xml index 6e0f70e77..527eaa3c2 100644 --- a/spring-data-mongodb/src/test/resources/geospatial.xml +++ b/spring-data-mongodb/src/test/resources/geospatial.xml @@ -6,8 +6,9 @@ http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd"> + - +