2

Is there a simple method in geotools or JTS to conclude the direction between two geospatial points?

I would like to conclude if point A is (north, south, east, west, NW, NE, SW, SE) when compared with point B?

Or would I need to manually compute the angle between the points (possibly similar to http://docs.geotools.org/stable/userguide/library/referencing/calculator.html) and bin it into the aforementioned directions?

1 Answer 1

3

As it happens I have some code lying around that does most of this, so this should do what you need.

import java.util.ArrayList;

import org.geotools.geometry.DirectPosition2D;
import org.geotools.referencing.GeodeticCalculator;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.util.factory.GeoTools;
import org.locationtech.jts.geom.Point;
import org.opengis.referencing.operation.TransformException;

import com.ianturton.cookbook.utilities.GenerateRandomData;

/**
 * given a direction in degrees (from North) return the Compass Point on an 8
 * element compass rose.
 * 
 * @author ian
 */

public class CompassRose8 {
  private static final int SIZE = 8;
  static final float STEP = 360f / SIZE;
  static final float HALF_STEP = STEP / 2.0f;
  static final GeodeticCalculator gc = new GeodeticCalculator();

  static final String points[] = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "N" };
  static ArrayList<Direction> directions = new ArrayList<>();

  static {
    int k = 0;
    for (float i = 0; i <= 360; i += (360.0 / SIZE), k++) {
      Direction d = new Direction(points[k], i);
      directions.add(d);
    }
  }

  public static String getDirection(Point p1, Point p2) throws TransformException {
    gc.setStartingPosition(new DirectPosition2D(DefaultGeographicCRS.WGS84, p1.getX(), p1.getY()));
    gc.setDestinationPosition(new DirectPosition2D(DefaultGeographicCRS.WGS84, p2.getX(), p2.getY()));
    float heading = (float) (gc.getAzimuth() + 180.0f);
    return getDirection(heading);
  }

  public static String getDirection(float heading) {
    while (heading < 0) {
      heading += 360;
    }
    while (heading > 360) {
      heading -= 360;
    }
    for (Direction d : directions) {
      if (d.contains(heading)) {
        return d.name;
      }
    }
    return "bad heading " + heading;
  }

  public static void main(String[] args) throws TransformException {
    // Make sure we know our axis order (doesn't matter which we pick)
    System.setProperty(GeoTools.FORCE_LONGITUDE_FIRST_AXIS_ORDER, "true");
    Point p1 = GenerateRandomData.createRandomPoint();
    Point p2 = GenerateRandomData.createRandomPoint();
    System.out.println(p1 + " is " + CompassRose8.getDirection(p1, p2) + " of " + p2);
  }

  static public class Direction {
    private float start;
    private float end;
    private float centre;
    final String name;

    Direction(String name, float centre) {
      this.name = name;
      this.centre = centre;
      start = this.centre - HALF_STEP;
      end = this.centre + HALF_STEP;
    }

    public boolean contains(float degree) {
      return (start < degree && end > degree);
    }
  }

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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