Geo { public static double distanceInMeters(@Nonnull final GeoPoint p1, @Nonnull final GeoPoint p2) { final boolean wrappedOnLongSide = p1.getLon() > p2.getLon(); double deltaLonDegrees; if (wrappedOnLongSide) { deltaLonDegrees = 360.0 - (p1.getLon() - p2.getLon()); } else { deltaLonDegrees = p2.getLon() - p1.getLon(); } if (deltaLonDegrees > 180.0) { deltaLonDegrees = 360.0 - deltaLonDegrees; } assert MathUtils.isBetween(deltaLonDegrees, 0.0, 180.0) : "|p1.lon - p2.lon| should be be in [0, 180], but is " + deltaLonDegrees; final double deltaLatDegrees = Math.abs(p1.getLat() - p2.getLat()); assert MathUtils.isBetween(deltaLatDegrees, 0.0, 180.0) : "|p1.lat - p2.lat| should be be in [0, 180], but is " + deltaLatDegrees; final double avgLat = p1.getLat() + ((p2.getLat() - p1.getLat()) / 2.0); final double deltaXMeters = degreesLonToMetersAtLat(deltaLonDegrees, avgLat); final double deltaYMeters = degreesLatToMeters(deltaLatDegrees); Double deltaElevationMeters = p1.getElevationMetersOrNaN() - p2.getElevationMetersOrNaN(); if (deltaElevationMeters.isNaN()) { deltaElevationMeters = 0.0; } final double len = Math.sqrt((deltaXMeters * deltaXMeters) + (deltaYMeters * deltaYMeters) + (deltaElevationMeters * deltaElevationMeters)); assert len >= 0.0; return len; } private  Geo(); @Nonnull static GeoRectangle grow(@Nullable final GeoRectangle rectangle, @Nonnull final GeoPoint point); static double degreesLatToMeters(final double latDegrees); static double degreesLonToMetersAtLat(final double lonDegrees, final double lat); static double metersToDegreesLat(final double northMeters); static double metersToDegreesLonAtLat(final double eastMeters, final double lat); static double distanceInMeters(@Nonnull final GeoPoint p1, @Nonnull final GeoPoint p2); static double mapToLat(final double lat); static double mapToLon(final double value); @Nonnull static Duration estimatedMinTravelTime(
            @Nonnull final GeoPoint from,
            @Nonnull final GeoPoint to); @Nonnull static Duration estimatedMinTravelTime(
            @Nonnull final GeoPoint from,
            @Nonnull final GeoPoint to,
            final int roundToMeters); static final double EARTH_RADIUS_X_METERS; static final double EARTH_RADIUS_Y_METERS; static final double EARTH_CIRCUMFERENCE_X; static final double EARTH_CIRCUMFERENCE_Y; static final double METERS_PER_DEGREE_LAT; static final double METERS_PER_DEGREE_LON_EQUATOR; static final double LON180; }
@Test public void testDistanceInMeters() { LOG.info("testDistanceInMeters"); assertEquals(METERS_PER_DEGREE_LAT, distanceInMeters( new GeoPoint(-0.5, 0.0), new GeoPoint(0.5, -0.0)), DELTA); assertEquals(METERS_PER_DEGREE_LAT, distanceInMeters( new GeoPoint(80.0, 0.0), new GeoPoint(81.0, 0.0)), DELTA); assertTrue((abs(METERS_PER_DEGREE_LAT * 2) - distanceInMeters( new GeoPoint(0.0, 59.0), new GeoPoint(0.0, 61.0))) < DELTA); assertTrue((abs(METERS_PER_DEGREE_LAT * 1.4142135623731) - distanceInMeters( new GeoPoint(-1.0, -1.0), new GeoPoint(1.0, 1.0))) < DELTA); assertEquals(METERS_PER_DEGREE_LON_EQUATOR, distanceInMeters( new GeoPoint(0.0, -0.5), new GeoPoint(0.0, 0.5)), DELTA); assertEquals(METERS_PER_DEGREE_LON_EQUATOR, distanceInMeters( new GeoPoint(0.0, 80.0), new GeoPoint(0.0, 81.0)), DELTA); assertEquals(METERS_PER_DEGREE_LON_EQUATOR / 2.0, distanceInMeters( new GeoPoint(60.0, 80.0), new GeoPoint(60.0, 81.0)), DELTA); assertEquals(METERS_PER_DEGREE_LON_EQUATOR * 2, distanceInMeters( new GeoPoint(0.0, -1.0), new GeoPoint(0.0, 1.0)), DELTA); assertEquals(METERS_PER_DEGREE_LAT, distanceInMeters(new GeoPoint(-0.5, 0.0), new GeoPoint(0.5, 0.0)), DELTA); assertEquals(METERS_PER_DEGREE_LON_EQUATOR, distanceInMeters(new GeoPoint(0.0, -0.5), new GeoPoint(0.0, 0.5)), DELTA); assertEquals(2.0, distanceInMeters(new GeoPoint(0.0, 0.0, 0.0), new GeoPoint(0.0, 0.0, 2.0)), DELTA); assertEquals(sqrt((METERS_PER_DEGREE_LAT * METERS_PER_DEGREE_LAT) + (METERS_PER_DEGREE_LON_EQUATOR * METERS_PER_DEGREE_LON_EQUATOR)), distanceInMeters(new GeoPoint(-0.5, -0.5), new GeoPoint(0.5, 0.5)), DELTA); assertEquals(sqrt((METERS_PER_DEGREE_LAT * METERS_PER_DEGREE_LAT) + (METERS_PER_DEGREE_LON_EQUATOR * METERS_PER_DEGREE_LON_EQUATOR) + (2.0 * 2.0)), distanceInMeters(new GeoPoint(-0.5, -0.5, 0.0), new GeoPoint(0.5, 0.5, 2.0)), DELTA); assertTrue((distanceInMeters(new GeoPoint(0.0, -1.0), new GeoPoint(0.0, 1.0)) - distanceInMeters(new GeoPoint(0.0, 1.0), new GeoPoint(0.0, -1.0))) < DELTA); assertTrue((distanceInMeters(new GeoPoint(0.0, -180.0), new GeoPoint(0.0, LON180)) - distanceInMeters(new GeoPoint(0.0, LON180), new GeoPoint(0.0, -180.0))) < DELTA); assertTrue((distanceInMeters(new GeoPoint(0.0, -180.0), new GeoPoint(0.0, 0.0)) - distanceInMeters(new GeoPoint(0.0, -180.0), new GeoPoint(0.0, 0.0))) < DELTA); }