How to Measure Distance and Create a Bounding Box Based on Two Latitude+Longitude Points in Java

How can I measure distance and create a bounding box based on two latitude+longitude points in Java?

We've had some success using OpenMap to plot a lot of positional data. There's a LatLonPoint class that has some basic functionality, including distance.

How to advance X distance (meters) between two points of latitude and longitude?

So you know latA, lngA, latB, lngB. From your question, I assume that you know the speed, it's constant, v = 3 m/s. You can get the start time LocalDateTime tA = LocalDateTime.now(); You want to know your coordinates at some moment of time tX.

In order to do this, I would introduce coefLat and coefLng coefficients for transforming coordinates into meters and back. They use mean radius of Earth and translate degrees into radians:

double coefLat = 180 / Math.PI / 6371000;
double coefLng = coefLat / Math.cos(Math.PI * (latA + latB) / 360);

Then calculate distances by Lat and Lng axis and full distance in meters:

double distLat = (latB - latA) / coefLat;
double distLng = (lngB - lngA) / coefLng;
double dist = Math.sqrt(distLat * distLat + distLng * distLng);

Sample Image

double fullTime = dist / v; // Full time needed to pass from A to B in seconds

After some time of moving, find duration and get current coordinates:

LocalDateTime tX = LocalDateTime.now(); // get current time
long dT = Duration.between(tA, tX).getSeconds(); // in seconds
double ratio = dT / fullTime;

double latX = latA + coefLat * ratio * distLat;
double lngX = lngA + coefLng * ratio * distLng;

Please also see this answer

The full code:

public class GetCurrentCoords {

public static void main(String[] args) {

LocalDateTime tA = LocalDateTime.now();
double latA = 51.504870000000004;
double lngA = -0.21533000000000002;
double latB = 51.50475;
double lngB = -0.21571;

double coefLat = 180 / Math.PI / 6371000;
double coefLng = coefLat / Math.cos(Math.PI * (latA + latB) / 360);

double distLat = (latB - latA) / coefLat; // meters
double distLng = (lngB - lngA) / coefLng; // meters

double dist = Math.sqrt(distLat * distLat + distLng * distLng);
System.out.println("distLat = " + distLat + "m; distLng = " + distLng + "m; full dist from A to B = " + dist + "m");
double v = 3;

double fullTime = dist / v; // seconds
System.out.println("full time from A to B = " + fullTime + "s");

// let's move for 4 seconds
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException ex) {
Logger.getLogger(GetCurrentCoords.class.getName()).log(Level.SEVERE, null, ex);
}

LocalDateTime tX = LocalDateTime.now();
long dT = Duration.between(tA, tX).getSeconds();
double ratio = dT / fullTime;

double latX = latA + coefLat * ratio * distLat;
double lngX = lngA + coefLng * ratio * distLng;

System.out.println("Moving " + dT + " seconds; latX = " + latX + "; lngX = " + lngX);
}
}

Calculating bounding box a certain distance away from a lat/long coordinate in Java

I wrote an article about finding the bounding coordinates:

http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates

The article explains the formulae and also provides a Java implementation. (It also shows why IronMan's formula for the min/max longitude is inaccurate.)

Java - New Point, X Distance from Latitude / Longitude point

This may be worth reading: Finding Points Within a Distance of a Latitude/Longitude Using Bounding Coordinates. It gives a short theoretical background on spherical coordinates and provides some java code.

The link is borrowed from the accepted answer to this thread on SO:
Calculating bounding box a certain distance away from a lat/long coordinate in Java

Calculate distance in meters when you know longitude and latitude in java

Based on another question on stackoverflow, I got this code.. This calculates the result in meters, not in miles :)

 public static float distFrom(float lat1, float lng1, float lat2, float lng2) {
double earthRadius = 6371000; //meters
double dLat = Math.toRadians(lat2-lat1);
double dLng = Math.toRadians(lng2-lng1);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLng/2) * Math.sin(dLng/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
float dist = (float) (earthRadius * c);

return dist;
}

Bounding Box Given 4 Lat/Long and Bearing

So looking around and even asking on probably a more appropriate site (here), I found a solution based on something by Chris Veness (here) to find the intersection point given two points and their bearings. So to get the corners of the bounding box I just take each combination of top/bottom and left/right (1 & 3, 1 & 4, 2 & 3, 2 & 4) and find the intersections using the known bearing and adjusting accordingly. For example to find the bottom right of the image I'd calculate the intersection of points 1 & 3 using the bearing + 90 for the direction of point 1 and the bearing - 180 for the direction of point 3.

I can take no credit for the algorithm or even really explain it in terms of how it works geometrically, but its worked in my testing. Below is my java translation from the javascript version provided by Chris

public static CoordD getIntersection(CoordD point1, double bearing1, CoordD point2, double bearning2) {
double lat1 = rad(point1.latitude); double lon1 = rad(point1.longitude);
double lat2 = rad(point2.latitude); double lon2 = rad(point2.longitude);
double bearing13 = rad(bearing1); double bearing 23 = rad(bearing2);
double dLat = lat2 - lat1; double dLon = lon2 - lon1;

double dist12 = 2 * Math.asin( Math.sqrt( Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLon / 2) * Math.sin(dLon / 2) ) );
if (dist12 == 0) return null;

double bearingA = Math.acos( ( Math.sin(lat2) - Math.sin(lat1) * Math.cos(dist12) ) /
( Math.sin(dist12) * Math.cos(lat1) ) );
double bearingB = Math.acos( ( Math.sin(lat1) - Math.sin(lat2) * Math.cos(dist12) ) /
( Math.sin(dist12) * Math.cos(lat2) ) );
if (Double.isNaN(bearingA)) bearingA = 0;
if (Double.isNaN(bearingB)) bearingB = 0;

double bearing12, bearing21;
if (Math.sin(dLon) > 0) {
bearing12 = bearingA;
bearing21 = 2 * Math.PI - bearingB;
} else {
bearing12 = 2 * Math.PI - bearingA;
bearing21 = bearingB;
}

double alpha1 = (bearing13 - bearing12 + Math.PI) % (2 * Math.PI) - Math.PI; // Angle 2-1-3
double alpha2 = (bearing21 - bearing23 + Math.PI) % (2 * Math.PI) - Math.PI; // Angle 1-2-3

if (Math.sin(alpha1) == 0 && Math.sin(alpha2) == 0) return null; // Infinite intersections
if (Math.sin(alpha1) * Math.sin(alpha2) < 0) return null; // Ambiguous intersection

// needed?
// alpha1 = Math.abs(alpha1);
// alpha2 = Math.abs(alpha2);

double alpha3 = Math.acos( -Math.cos(alpha1) * Math.cos(alpha2) +
Math.sin(alpha1) * Math.sin(alpha2) * Math.cos(dist12) );
double dist13 = Math.atan2( Math.sin(dist12) * Math.sin(alpha1) * Math.sin(alpha2),
Math.cos(alpha2) + Math.cos(alpha1) * Math.cos(alpha3) );

double lat3 = Math.asin( Math.sin(lat1) * Math.cos(dist13) +
Math.cos(lat1) * Math.sin(dist13) * Math.cos(bearing13) );

double dLon13 = Math.atan2( Math.sin(bearing13) * Math.sin(dist13) * Math.cos(lat1),
Math.cos(dist13) - Math.sin(lat1) * Math.sin(lat3) );
double lon3 = lon1 + dLon3;
lon3 = (lon3 + 3 * Math.PI) % ( 2* Math.PI) - Math.PI // normalize to +/-180

return new CoordD(deg(lat3), deg(lon3));
}

rad() and deg() are just helper functions that translate between radians and degrees. CoordD is a helper class that just contains two double to store a lat/long point.

How to calculate the bounding box for a given lat/lng location?

I suggest to approximate locally the Earth surface as a sphere with radius given by the WGS84 ellipsoid at the given latitude. I suspect that the exact computation of latMin and latMax would require elliptic functions and would not yield an appreciable increase in accuracy (WGS84 is itself an approximation).

My implementation follows (It's written in Python; I have not tested it):

# degrees to radians
def deg2rad(degrees):
return math.pi*degrees/180.0
# radians to degrees
def rad2deg(radians):
return 180.0*radians/math.pi

# Semi-axes of WGS-84 geoidal reference
WGS84_a = 6378137.0 # Major semiaxis [m]
WGS84_b = 6356752.3 # Minor semiaxis [m]

# Earth radius at a given latitude, according to the WGS-84 ellipsoid [m]
def WGS84EarthRadius(lat):
# http://en.wikipedia.org/wiki/Earth_radius
An = WGS84_a*WGS84_a * math.cos(lat)
Bn = WGS84_b*WGS84_b * math.sin(lat)
Ad = WGS84_a * math.cos(lat)
Bd = WGS84_b * math.sin(lat)
return math.sqrt( (An*An + Bn*Bn)/(Ad*Ad + Bd*Bd) )

# Bounding box surrounding the point at given coordinates,
# assuming local approximation of Earth surface as a sphere
# of radius given by WGS84
def boundingBox(latitudeInDegrees, longitudeInDegrees, halfSideInKm):
lat = deg2rad(latitudeInDegrees)
lon = deg2rad(longitudeInDegrees)
halfSide = 1000*halfSideInKm

# Radius of Earth at given latitude
radius = WGS84EarthRadius(lat)
# Radius of the parallel at given latitude
pradius = radius*math.cos(lat)

latMin = lat - halfSide/radius
latMax = lat + halfSide/radius
lonMin = lon - halfSide/pradius
lonMax = lon + halfSide/pradius

return (rad2deg(latMin), rad2deg(lonMin), rad2deg(latMax), rad2deg(lonMax))

EDIT: The following code converts (degrees, primes, seconds) to degrees + fractions of a degree, and vice versa (not tested):

def dps2deg(degrees, primes, seconds):
return degrees + primes/60.0 + seconds/3600.0

def deg2dps(degrees):
intdeg = math.floor(degrees)
primes = (degrees - intdeg)*60.0
intpri = math.floor(primes)
seconds = (primes - intpri)*60.0
intsec = round(seconds)
return (int(intdeg), int(intpri), int(intsec))


Related Topics



Leave a reply



Submit