Converting lat/long to JTS?
Asked Answered
A

5

23

I am trying to integrate hibernate spatial with JPA for Geo searches. I have been referencing the tutorial on the official site (I am not associated with hibernatespatial).

The tutorial, unfortunately, does not cover how to create a Point instance from a latitude/longitude pair. I'm attempting to do this here, but I am still not sure if this is this the right way to convert a latitude/longitude pair to a JTS Point instance:

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.hibernate.annotations.Type;
import javax.persistence.*;

@Entity
public class Location {

    private Double latitude;

    private Double longitude;

    @Type(type = "org.hibernatespatial.GeometryUserType")
    private Point coordinates;

    private final GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);

    @PrePersist
    @PreUpdate
    public void updateCoordinate() {
        if (this.latitude == null || this.longitude == null) {
            this.coordinates = null;
        } else {
            this.coordinates = geometryFactory.createPoint(new Coordinate(latitude, longitude));
        }
    }

    public Double getLatitude() {
        return latitude;
    }

    public void setLatitude(Double latitude) {
        this.latitude = latitude;
    }

    public Double getLongitude() {
        return longitude;
    }

    public void setLongitude(Double longitude) {
        this.longitude = longitude;
    }
}
Audryaudrye answered 6/12, 2011 at 17:25 Comment(2)
I don't know; you might get more traction over at Geographic Information Systems. Also, please try to not have more than one question per post; point one here is complex enough!Lynwoodlynx
Unfortunately the link to the tutorial for this question is now dead.Tryst
E
32

JTS doesn't care what your point's units or coordinate system is.

However, it does assume that the coordinates are on a Cartesian plane, so some geometry operations such as distance calculations may be inaccurate over long distances. (They don't yet support geodetic calculations.)

It should be fine for simple storage uses.

However, an important point to note is that the longitude is the X value and the latitude the Y value. So we say "lat/long", but JTS will expect it in the order "long/lat". So you should be using geometryFactory.createPoint(new Coordinate(longitude, latitude))

Evangelistic answered 8/12, 2011 at 14:59 Comment(3)
Gnat is right! Remember that "longitude" correspondes to the "X-axis" in general use.Machiavellian
if you use long/lat to create a Coordinate, what unit does the buffer need to be in?Premier
@Premier Buffering needs to be in the same units as the coordinates. If your coordinates are in degrees, you can either use degrees to buffer, or project to metres first (e.g. using Proj4)Evangelistic
A
3

To sum up what others said, when converting to Coordinate there are 3 main things to take care of:

  • Projection. JTS works in a Cartesian plane, so all distortion from e.g. Mercator propagates into your calculation. Thus, you should only use it on quite short-ranged area. I'm not sure about the precise magnitude, but I think everything below a degree of expansion should be fine. Stay below 0.1 degree and you're definitely on the safe side.
  • Units. You can put perfectly any unit into JTS. The trouble is you can't tell JTS whether you're using meters, or degrees, or anything else. So you must take care yourself that you either stick to one unit, or convert wherever necessary.
  • Standard. The ISO standard states that geospatial coordinates are provided lat first. However, it competes with the GeoJSON/WKT standards which both state lon first, so reverse. Both standard groups have applications sticking to them (for instance, Apache Lucene switched standards between releases without changing the method signature, thus causing headaches to hundreds of users wondering why their maps all of a sudden were flipped), and JTS is holding on the GeoJSON/WKT version. Pay attention to that wherever you pass the data from another library - it may follow GeoJSON and WKT, or ISO, you should inform yourself in advance. (Believe me. I already had trouble with this, and it can be really annoying going through the entire code and flipping the order.)

So, no that's not right. You're straight walking into the third problem. JTS is lon first.

Also, you might consider using Neo4j Spatial instead of hibernate. It uses the graph querying speed of Neo4j, and has built-in JTS support. It also has one of the most comfortable Java APIs around IMHO.

Anthropocentric answered 22/6, 2016 at 15:42 Comment(0)
E
2

Here is how to create your coordinate in WGS-84 :

    double EARTH_RADIUS = 6378137.0;
    double x = longitude * EARTH_RADIUS * Math.PI / 180.;
    double y = EARTH_RADIUS * Math.sin(Math.toRadians(latitude));
    return new Coordinate(x,y,0.);

Cheers

Engvall answered 12/7, 2013 at 7:47 Comment(2)
How reverse it ? I mean convert back from coordinate(x,y,0) to long/LatDingman
That calculation isn't correct.... Earth is an ellipsoid and WGS 84 takes that into account. Some intro info can be seen here en.wikipedia.org/wiki/World_Geodetic_System#WGS_84Flouncing
T
2

Here is a copy-paste solution to create JTS Points with given latitude and longitude values.

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.PrecisionModel;

public class GeometriesFactory {

    private static GeometryFactory factory4326 
        = new GeometryFactory(new PrecisionModel(PrecisionModel.FLOATING), 4326);

    public static Point createPoint(Double pLatitude, Double pLongitude){
        // inverted parameters are OK
        return factory4326.createPoint(new Coordinate(pLongitude, pLatitude));
    }
    
    public static LineString createLineString(Coordinate[] pCoordsArray){
        return factory4326.createLineString(pCoordsArray);
    }
    
}

Source

Tem answered 6/10, 2021 at 15:56 Comment(0)
S
0

I have had the same problem here and I translated the coords from Lat/Long to UTM (see http://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system).

Basically you convert from Lat/Long to an (X,Y) pair, but the interesting fact is that those X and Y are real meters, so you can make accurate calculations which depend on distance. (Actually, you must account for a small distortion, but negligible when talking about meter-scale accuracy).

I wasn't really happy with the LatLong2UTM functions that existing Java frameworks provided, so I rolled out my own. I ported one from some online javascript converter without much trouble.

Schweitzer answered 14/6, 2013 at 12:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.