package mil.nga.giat.geowave.analytic.distance; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.CRS; import org.geotools.referencing.GeodeticCalculator; import org.geotools.referencing.datum.DefaultEllipsoid; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vividsolutions.jts.geom.Coordinate; public class CoordinateCircleDistanceFn implements DistanceFn<Coordinate> { private static final Logger LOGGER = LoggerFactory.getLogger(CoordinateCircleDistanceFn.class); /** * */ private static final long serialVersionUID = -1245559892132762143L; protected static final CoordinateReferenceSystem DEFAULT_CRS; static { try { DEFAULT_CRS = CRS.decode( "EPSG:4326", true); } catch (final FactoryException e) { throw new RuntimeException( "Failed to load default EPSG:4326 coordinate reference system", e); } } @Override public double measure( final Coordinate c1, final Coordinate c2 ) { try { return JTS.orthodromicDistance( c1, c2, getCRS()); } catch (final TransformException e) { throw new RuntimeException( "Failed to transform coordinates to provided CRS", e); } catch (final java.lang.AssertionError ae) { // weird error with orthodromic distance..when distance is too close // (0.05 meter), it fails the tolerance test LOGGER.info( "when distance is too close(0.05 meter), it fails the tolerance test", ae); final GeodeticCalculator calc = new GeodeticCalculator( getCRS()); calc.setStartingGeographicPoint( c1.x, c1.y); calc.setDestinationGeographicPoint( c2.x, c2.y); return ((DefaultEllipsoid) calc.getEllipsoid()).orthodromicDistance( calc.getStartingGeographicPoint().getX(), calc.getStartingGeographicPoint().getY(), calc.getDestinationGeographicPoint().getX(), calc.getDestinationGeographicPoint().getY()); } } protected CoordinateReferenceSystem getCRS() { return DEFAULT_CRS; } }