15

I am new to Hibernate Spatial, and am trying to perform a simple query of objects within a given radius. I've created a number of entries in my database with properties corresponding to a latitude and longitude, using data from Google Maps and other sources. This property is defined like this in my Entity class:

@Column
@Type(type = "org.hibernate.spatial.GeometryType")
private Point coordinates = null;

I'm now trying to figure out how to do a search of all entity objects that have coordinates that fall within a radius of x kilometers from a given point. For example, I'd like to find objects that fall within a 50 kilometer radius of the point (12.34567, -76.54321). However, I can't find any examples or tutorials that would explain how to do this in Hibernate Spatial.

Can anyone give me any information on how a query like this can be constructed?

Shadowman
  • 11,150
  • 19
  • 100
  • 198

1 Answers1

16

See this resource for a tutorial with "Spatial Queries", which a special dialect and the JTS library (Open Source).

Basically you do the following (copy/paste from the referenced page):

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import util.JPAUtil;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.Date;
import java.util.List;

.......

private List find(String wktFilter) {
    Geometry filter = wktToGeometry(wktFilter);
    EntityManager em = JPAUtil.createEntityManager();
    em.getTransaction().begin();
    Query query = em.createQuery("select e from Event e where within(e.location, :filter) = true", Event.class);
    query.setParameter("filter", filter);
    return query.getResultList();
}

private Geometry wktToGeometry(String wktPoint) {
    WKTReader fromText = new WKTReader();
    Geometry geom = null;
    try {
        geom = fromText.read(wktPoint);
    } catch (ParseException e) {
        throw new RuntimeException("Not a WKT string:" + wktPoint);
    }
    return geom;
}

For generating a circle, see this resource (search for "Arcs, Circles and Curves"). Again a copy/paste from there:

//this method replaces the above wktToGeometry() method
private static Geometry createCircle(double x, double y, final double RADIUS) {
  GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
  shapeFactory.setNumPoints(32);
  shapeFactory.setCentre(new Coordinate(x, y));//there are your coordinates
  shapeFactory.setSize(RADIUS * 2);//this is how you set the radius
  return shapeFactory.createCircle();
}

Besides you always have the workaround, in which to add some additional fields ( mapped withinsertable=false, updatable=false) to map to the same columns used by the org.hibernate.spatial.GeometryType and then use them in your query. For computing the distance, check the euclidian distance formula.

Mohammad Faisal
  • 5,783
  • 15
  • 70
  • 117
V G
  • 18,822
  • 6
  • 51
  • 89
  • The example shown on that page shows querying a point within a given polygon. Do I have to specify a polygon in my query? Ideally I'd be able to give it a point (lat/long) and a radius and use that in my query instead of a polygon. How can I declare that Geometry using JTS/Hibernate Spatial? – Shadowman Nov 22 '13 at 01:55
  • Well, a circle is a special Geometry, but not a Polygon. See my updated example to see how you create a circle. – V G Nov 22 '13 at 08:58
  • Okay, that all makes sense. I'll give it a shot. Unfortunately, though, I'm running into this error (http://stackoverflow.com/questions/20079825/hibernate-spatial-invalid-endian-flag-value-encountered-exception) which makes testing impossible until I get it resolved. – Shadowman Nov 22 '13 at 20:29
  • I have finally gotten past my error and began testing your answer. It all makes sense to me, but I think I'm having a problem setting the radius size. I want to query a particular latitude/longitude and get the objects within a 12 KM radius. How do I convert 12 KM to a unit of measure that the "shapeFactory.setSize()" line will properly interpret? My initial testing is indicating that I'm doing it wrong. – Shadowman Nov 29 '13 at 18:25
  • According to the referenced link you are doing it correctly. Try do debug the SQL queries with very little DB data in order to see if the queries are correct. – V G Nov 29 '13 at 19:06
  • Okay, I've done some detailed testing and it appears as though the shapeFactory.setSize(RADIUS * 2) line gives me inaccurate results. The radius ends up MUCH larger than I intended. After some trial and error, I found that I get somewhat more accurate results with shapeFactory.setSize((RADIUS * 2) / 100). I still find that it is still off by a considerable margin in some cases, however. Thoughts? – Shadowman Nov 30 '13 at 02:41
  • Thought: try changing the number of points... with `setNumPoints()` – V G Nov 30 '13 at 10:48
  • 1
    I nead the exact same thing...how can you determin that the radius is a unit of meter/kilometer and so on?? – simonC Jun 23 '14 at 13:22
  • @AndreiI Great solution but I still can'T see from your answer how I get a 50km search radius. Could you please add this to your answer? Thanks! – stephan1002 Jul 17 '15 at 21:37
  • @AndreiI I still don't get how do I set the radius in km? – Michael Jul 27 '15 at 23:13
  • @simonC Did you find any solution? – Michael Jul 27 '15 at 23:13
  • @confile Did you find the solution for the radius? – gabriel Nov 08 '16 at 10:08
  • 1
    This calculate the Euclidean distance, for the case of Earth coordinates, does not work – cdr89 Apr 25 '19 at 21:09