[GIS] How to calculate whether a point is in a shape using geodetic calculations

geotoolspoint-in-polygon

I’m new to GIS so forgive me if my terminology isn’t completely correct. Really liking the options available in the GeoTools library but I’ve hit a stumbling block that I’m hoping someone will be able to advise on. I’ve looked at the classes in the library but can’t find a method that is giving me what I need. I have a scenario where I have a point and a polygon defined by latitude and longitude (WGS84). I need to determine whether the point is in (or on the boundary) of the polygon.

I have tried using the Intersects method but it looks to be treating the polygon as if it is on a 2D plane. The bottom left and right corners of my polygon have the same latitude value but they are spaced longitudinally by 10 degrees, so it’s quite a long edge. There are no intermediate points along this edge of the polygon. The Intersects method appears to use a straight line between these two points, effectively taking this bottom edge under ground when on a globe.

What I need is for this polygon’s edges to be interpreted as great circle lines between points on the surface of the globe, thereby creating slight curves, so when we determine whether a point is in the polygon, we are using the shape with slightly curved edges. Obviously the greater distance between polygon points the greater the curve.

Is there a method to achieve this in the GeoTools library? If not, does anyone have alternative open source Java libraries that can solve what must be a common request?

Best Answer

You need the JTS Densifier which takes a geometry and returns the same line but with more points in it.

    GeometryFactory gf = new GeometryFactory();
    LineString l = gf.createLineString(new Coordinate[] {new Coordinate(-10, 50),new Coordinate(10, 50)});
    WKTWriter2 writer = new WKTWriter2();
    System.out.println(writer.writeFormatted(l));
    LineString dl = (LineString) Densifier.densify(l, 1);
    System.out.println(writer.writeFormatted(dl));

Which gives you the following:

LINESTRING (-10 50, 10 50)
LINESTRING (-10 50, -9.047619047619047 50, -8.095238095238095 50, -7.142857142857143 50, -6.190476190476191 50, -5.238095238095238 50, -4.2857142857142865 50, -3.333333333333334 50, -2.3809523809523814 50, -1.4285714285714288 50, -0.4761904761904763 50, 0.4761904761904763 50, 1.428571428571427 50, 2.3809523809523796 50, 3.333333333333332 50, 4.285714285714285 50, 5.238095238095237 50, 6.19047619047619 50, 7.142857142857142 50, 8.095238095238095 50, 9.047619047619047 50, 10 50)

How these appear on your map will depend on your projection, if you are using a plate carree projection (e.g 4326) then they are identical if however you use a Transverse Mercator like OSGB (27700) the 2nd one is curved.

enter image description here

Related Question