2

I have a java aplication backed by a mysql database which contains events with locations (latitude/longitude), the location data is saved as POINT data type.

I nead to find the nearest events in some radius. I am already able to do this but the results are innacurate.

I'm also using hibernate spatial to make the query.

I'm using the folowing libraries : 1.) com.vividsolutions.jts ... for creating geometry types 2.) Geotools org.geotools ... for calculating distance between points

First I make a circle Geometry with a center placed in a current location this circle is given some radius. For example 500m if I want to find the events in the distance of 500m. The problem is that the Geometry construct takes neads the radius in degrees. If i'm not mistaken the distance in degrees changes based on a point on earth.

then I query the database with the within hibernate spatial function, but the results are unnacurate.

So I dont know how to calculate the distance in degrees based on location on earth. I think there should already be some library that is doing this, but for now I havent find an example. Can you advise me some code?

My Code:

//calculate the shape where the events should be 
Geometry circle = createCircle(currentLongitude,currentLatitude, radiusInKm);
//retrieve the events from database that are within the calculated shape
List<si.arctur.model.Event> seznam = find(circle.toString());


    //the methods
private static Geometry createCircle(double x, double y, final double RADIUS) {

          double latitude = 110.54;
          double longitude = 111.320;

          //TODO beter accuracy
          double radiusInDegreesLatitude = RADIUS / latitude;
          double radiusInDegreesLongitude = RADIUS / Math.abs((longitude * Math.cos(latitude)));

          GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
          shapeFactory.setNumPoints(1000);
          shapeFactory.setHeight(radiusInDegreesLatitude * 2);
          shapeFactory.setWidth(radiusInDegreesLongitude * 2);
          shapeFactory.setCentre(new Coordinate(x, y));//there are your coordinates
          Polygon shape = shapeFactory.createCircle();
          return shape; 
    }

    private List find(String wktFilter) {
        Geometry filter = wktToGeometry(wktFilter);
        Query query = em.createQuery("select e from Event e where within(e.location, :filter) = true", si.arctur.model.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;
    }
2

Yes, dealing with distance (or area) in unprojected latitude/longitude coordinates is fraught with peril. The length of a degree of latitude is always the same (60 nautical miles), but the length of a degree of longitude varies with the cosine of the latitude.

To do it properly, you want to project your coordinates into some plane coordinate system and do your comparisons in that. (Which plane coordinate system should you use? Not a simple answer, depends where on earth your stuff is.) Geotools must have a library for that, or since you're working in java, check out proj4j.

Alternatively, it's kind of a hack, but if all you are doing is calculating straight-line distances, you could create sort of pseudo-coordinates in meters where y=latitude*60*cf (where cf is the conversion factor to get from nautical miles to meters) and x=longitude*60*cf/cos(latitude). You're assuming a spherical earth, which it isn't. And it will severely break down if your distances are very big. But for 500m it ought to work. If you do it this way it might just be easier to calculate distance yourself, using d=sqr((x2-x1)^2 + (y2-y1)^2)).

Better would be to use Vincenty's formula, which doesn't assume a sphere. Poke around for that, you may find a library that will do it.

  • I had a mistake in my code in the formula for radiusInDegreesLongitude, in the cosine part I should give the radian of y parameter which is a latitude off the current point. I tested the shape returned in GooleEarth and it looks it is caclulated right. The porblem is that when I put this shape in the hibernate spatial query it is not so accurate and the results are for a few meters wrong it returns to much results also results that are for a few meters outside the circle. I will try to make a query as is and then programaticla filter the points of wrong distance until I find a beter solution. – simonC Jun 25 '14 at 11:23
  • in adition my stuff will be mostly placed in US territory which projection do you advise for that? – simonC Jun 25 '14 at 11:25
  • In order to get decent accuracy you probably need narrower projection zones than anything that would cover the whole US. Like a UTM zone. But try Vincenty's. – Jersey Andy Jun 28 '14 at 23:28
  • May be you can help me with this question too: gis.stackexchange.com/questions/156078/… – confile Jul 28 '15 at 11:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.