I'm trying to figure out how to represent geographic locations, and I can't seem to find any relevant classes in the SE documentation.
I would like to do something like this:
Location locA = new Location(aa.aaaaaaa, bb.bbbbbbb); //lat/long coordinates
Location locB = .....
int meters = locA.distanceTo(locB);
Ideally I would want something like the Android Location since most of my location data will be sent from android devices anyway. From my understanding it contains information about accuracy, latitude and speed, which would be useful (but not required).
I have an idea of how to implement it myself, but an open source alternative would save me some time.
It would also be extremely helpful if I could do some IP/Location lookup. But I guess that's a whole other issue.
Here is a method to calculate distance between 2 points, taken from Android Location class with small modification. It looks a little bit complicated--this is because it uses Vincenty's formulae to perform iterative calculations on WGS84 ellipsoid:
/** distance between 2 geographic points on Earth, in km **/
public static double geoDistance(GeoPoint gp1, GeoPoint gp2) {
// Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
// using the "Inverse Formula" (section 4)
int MAXITERS = 20;
// Convert lat/long to radians
double lat1 = gp1.getLat() * Math.PI / 180.0;
double lat2 = gp2.getLat() * Math.PI / 180.0;
double lon1 = gp1.getLon() * Math.PI / 180.0;
double lon2 = gp2.getLon() * Math.PI / 180.0;
double a = 6378.137; // WGS84 major axis
double b = 6356.7523142; // WGS84 semi-major axis
double f = (a - b) / a;
double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
double L = lon2 - lon1;
double A = 0.0;
double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
double cosU1 = Math.cos(U1);
double cosU2 = Math.cos(U2);
double sinU1 = Math.sin(U1);
double sinU2 = Math.sin(U2);
double cosU1cosU2 = cosU1 * cosU2;
double sinU1sinU2 = sinU1 * sinU2;
double sigma = 0.0;
double deltaSigma = 0.0;
double cosSqAlpha = 0.0;
double cos2SM = 0.0;
double cosSigma = 0.0;
double sinSigma = 0.0;
double cosLambda = 0.0;
double sinLambda = 0.0;
double lambda = L; // initial guess
for (int iter = 0; iter < MAXITERS; iter++) {
double lambdaOrig = lambda;
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
double t1 = cosU2 * sinLambda;
double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
double sinSqSigma = t1 * t1 + t2 * t2; // (14)
sinSigma = Math.sqrt(sinSqSigma);
cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
sigma = Math.atan2(sinSigma, cosSigma); // (16)
double sinAlpha = (sinSigma == 0) ? 0.0 :
cosU1cosU2 * sinLambda / sinSigma; // (17)
cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
cos2SM = (cosSqAlpha == 0) ? 0.0 :
cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
A = 1 + (uSquared / 16384.0) * // (3)
(4096.0 + uSquared *
(-768 + uSquared * (320.0 - 175.0 * uSquared)));
double B = (uSquared / 1024.0) * // (4)
(256.0 + uSquared *
(-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
double C = (f / 16.0) *
cosSqAlpha *
(4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
double cos2SMSq = cos2SM * cos2SM;
deltaSigma = B * sinSigma * // (6)
(cos2SM + (B / 4.0) *
(cosSigma * (-1.0 + 2.0 * cos2SMSq) -
(B / 6.0) * cos2SM *
(-3.0 + 4.0 * sinSigma * sinSigma) *
(-3.0 + 4.0 * cos2SMSq)));
lambda = L +
(1.0 - C) * f * sinAlpha *
(sigma + C * sinSigma *
(cos2SM + C * cosSigma *
(-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
double delta = (lambda - lambdaOrig) / lambda;
if (Math.abs(delta) < 1.0e-12) {
break;
}
}
return b * A * (sigma - deltaSigma);
}
GeoPoint class looks like the following:
/**
* Immutable point in geo coordinates (latitude, longitude) with accuracy in km
*/
public class GeoPoint {
private final double lat;
private final double lon;
private final double accuracy;
/**
* New geo point without accuracy
*/
public GeoPoint(double lat, double lon){
this(lat, lon, -1d);
}
/**
* New geo point with specified accuracy
* #param accuracy accuracy in km
*/
public GeoPoint(double lat, double lon, double accuracy){
this.lat = lat;
this.lon = lon;
this.accuracy = accuracy < 0 ? -1d : accuracy;
}
public double getLat(){
return this.lat;
}
public double getLon(){
return this.lon;
}
/**
* #return accuracy in km. If < 0, accuracy is not defined
*/
public double getAccuracy(){
return this.accuracy;
}
#Override
public String toString(){
return "lat = " + this.lat + "; lon = " + this.lon + (this.accuracy < 0 ? "" : ("; accuracy = " + this.accuracy));
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GeoPoint) || o == null) return false;
GeoPoint g = (GeoPoint) o;
return g.lat == this.lat && g.lon == this.lon && g.accuracy == this.accuracy;
}
}
Related
I am writing a java program to generate a all the longitude and latitude with a fixed distance from my my given point. the distance must be exact 2000km, not withub 2000km.
this is my code
public static void getLocation(double x0, double y0, int meters) {
Random random = new Random();
// Convert radius from meters to degrees
double radiusInDegrees = meters / 111000f;
double u = random.nextDouble();
double v = random.nextDouble();
double w = radiusInDegrees * Math.sqrt(u);
double t = 2 * Math.PI * v;
double x = w * Math.cos(t);
double y = w * Math.sin(t);
// Adjust the x-coordinate for the shrinking of the east-west distances
// double new_x = x / Math.cos(Math.toRadians(y0));
double foundLongitude = x + x0;
double foundLatitude = y + y0;
System.out.println("Longitude: " + foundLongitude + " Latitude: " + foundLatitude );
}
How do I make all the point generate equal distance from the geo point, like forming a circle?
public static void generatePoint(double latitude, double longitude, double distanceInMetres, double bearing) {
Random random = new Random();
//int bear = random.nextInt(360);
double brngRad = Math.toRadians(bearing);
double latRad = Math.toRadians(latitude);
double lonRad = Math.toRadians(longitude);
int earthRadiusInMetres = 6371000;
double distFrac = distanceInMetres / earthRadiusInMetres;
double latitudeResult = Math.asin(Math.sin(latRad) * Math.cos(distFrac) + Math.cos(latRad) * Math.sin(distFrac) * Math.cos(brngRad));
double a = Math.atan2(Math.sin(brngRad) * Math.sin(distFrac) * Math.cos(latRad), Math.cos(distFrac) - Math.sin(latRad) * Math.sin(latitudeResult));
double longitudeResult = (lonRad + a + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
System.out.println("bearing: "+bearing+ ", latitude: " + Math.toDegrees(latitudeResult) + ", longitude: " + Math.toDegrees(longitudeResult));
}
need to add bearing
For anyone looking, this is how I implemented this code in JavaScript:
function generatePoint(
latitude,
longitude,
distanceInMetres,
bearing = Math.floor(Math.random() * (360 - 1) + 1)
) {
const brngRad = deg2Rad(bearing);
const latRad = deg2Rad(latitude);
const lonRad = deg2Rad(longitude);
const EARTH_RADIUS_IN_METRES = 6371000;
const distFrac = distanceInMetres / EARTH_RADIUS_IN_METRES;
const latitudeResult = Math.asin(
Math.sin(latRad) * Math.cos(distFrac) +
Math.cos(latRad) * Math.sin(distFrac) * Math.cos(brngRad)
);
const a = Math.atan2(
Math.sin(brngRad) * Math.sin(distFrac) * Math.cos(latRad),
Math.cos(distFrac) - Math.sin(latRad) * Math.sin(latitudeResult)
);
const longitudeResult =
((lonRad + a + 3 * Math.PI) % (2 * Math.PI)) - Math.PI;
return {
latitude: rad2Deg(latitudeResult),
longitude: rad2Deg(longitudeResult),
bearing,
};
}
function deg2Rad(deg) {
return deg * (Math.PI / 180);
}
function rad2Deg(rad) {
return rad * (180 / Math.PI);
}
It will also generate a random bearing if none is provided
I'm not really good with mathematics but I need to calculate the distance of two different locations of the markers. Something like this:
public double CalculationByDistance(double initialLat, double initialLong, double finalLat, double finalLong){
return distance;
}
Or is there any alternative ways that I can calculate the distance of two markers, also I tried to google for answers.. but couldn't find any.
Reference:
http://en.wikipedia.org/wiki/Haversine_formula
Comments are appreciated :) Thanks!!
Try this, much simpler than Haversine!
Location me = new Location("");
Location dest = new Location("");
me.setLatitude(myLat);
me.setLongitude(myLong);
dest.setLatitude(destLat);
dest.setLongitude(destLong);
float dist = me.distanceTo(dest);
If you want to stick with Haversine, something like this:
public double CalculationByDistance(double initialLat, double initialLong,
double finalLat, double finalLong){
int R = 6371; // km (Earth radius)
double dLat = toRadians(finalLat-initialLat);
double dLon = toRadians(finalLong-initialLong);
initialLat = toRadians(initialLat);
finalLat = toRadians(finalLat);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(initialLat) * Math.cos(finalLat);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
public double toRadians(double deg) {
return deg * (Math.PI/180);
}
Also, you need to create a method toRadians() that convert values from degrees to radians, which is quite easy.
Hope it helps!
From your wikipedia link, applying the formula directly you can do the following:
public double CalculationByDistance(double initialLat, double initialLong, double finalLat, double finalLong){
/*PRE: All the input values are in radians!*/
double latDiff = finalLat - initialLat;
double longDiff = finalLong - initialLong;
double earthRadius = 6371; //In Km if you want the distance in km
double distance = 2*earthRadius*Math.asin(Math.sqrt(Math.pow(Math.sin(latDiff/2.0),2)+Math.cos(initialLat)*Math.cos(finalLat)*Math.pow(Math.sin(longDiff/2),2)));
return distance;
}
Use the below method for calculating the distance of two different locations.
public double getKilometers(double lat1, double long1, double lat2, double long2) {
double PI_RAD = Math.PI / 180.0;
double phi1 = lat1 * PI_RAD;
double phi2 = lat2 * PI_RAD;
double lam1 = long1 * PI_RAD;
double lam2 = long2 * PI_RAD;
return 6371.01 * acos(sin(phi1) * sin(phi2) + cos(phi1) * cos(phi2) * cos(lam2 - lam1));
}
try this
/**
* This is the implementation Haversine Distance Algorithm between two places
* #author ananth
* R = earth’s radius (mean radius = 6,371km)
Δlat = lat2− lat1
Δlong = long2− long1
a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
c = 2.atan2(√a, √(1−a))
d = R.c
*
*/
public class HaversineDistance {
/**
* #param args
* arg 1- latitude 1
* arg 2 — latitude 2
* arg 3 — longitude 1
* arg 4 — longitude 2
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final int R = 6371; // Radious of the earth
Double lat1 = Double.parseDouble(args[0]);
Double lon1 = Double.parseDouble(args[1]);
Double lat2 = Double.parseDouble(args[2]);
Double lon2 = Double.parseDouble(args[3]);
Double latDistance = toRad(lat2-lat1);
Double lonDistance = toRad(lon2-lon1);
Double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
Double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
Double distance = R * c;
System.out.println(“The distance between two lat and long is::” + distance);
}
private static Double toRad(Double value) {
return value * Math.PI / 180;
}
}
import java.util.Scanner;
public class Hw4Problem1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
double X1 = 35.2270869;
double Y1 = -80.8431267;
double X2 = 32.0835407;
double Y2 = -81.0998342;
double X3 = 28.5383355;
double Y3 = -81.3792365;
double X4 = 33.7489954;
double Y4 = -84.3879824;
//Radius*************************]
double radius= 6731.01;
// distance=(radius)arccos(sin(x1)sin(x2)+cos(x1)cos(x2)cos( y1−y2))
double charlotteToSavannah = (radius)* Math.acos(Math.sin(X1) * Math.sin(X2)+ Math.cos(X1) * Math.cos(X2)
* Math.cos(Y1 - Y2));
double savannahToAtlanta = (radius)
* Math.acos(Math.sin(X2) * Math.sin(X4)
+ Math.cos(X2) * Math.cos(X4)
* Math.cos(Y2 - Y4));
// Get distance
// distance=(radius)arccos(sin(x1)sin(x2)+cos(x1)cos(x2)cos( y1−y2))
double atlantaToCharlotte= (radius)
* Math.acos(Math.sin(X4) * Math.sin(X1)
+ Math.cos(X4) * Math.cos(X1)
* Math.cos(Y4 - Y1));
// ******************************************************************************2
double savannahToOrlando = (radius)
* Math.acos(Math.sin(X2) * Math.sin(X3)
+ Math.cos(X2) * Math.cos(X3)
* Math.cos(Y2 - Y3));
double orlandoToAtlanta = (radius)
* Math.acos(Math.sin(X3) * Math.sin(X4)
+ Math.cos(X3) * Math.cos(X4)
* Math.cos(Y3 - Y4));
double atlantaToSavannah =
(radius)
* Math.acos(Math.sin(X4) * Math.sin(X2)
+ Math.cos(X4) * Math.cos(X2)
* Math.cos(Y4 - Y2));
// System.out.println("distance: "+distance03);
double rodistance1 = (charlotteToSavannah);
double rodistance2 = (savannahToAtlanta);
double rodistance3 = (atlantaToCharlotte);
double rodistance01 = (savannahToOrlando);
double rodistance02 = (orlandoToAtlanta);
double rodistance03 = (atlantaToSavannah);
double s1 = (rodistance1 + rodistance2 + rodistance3) / 2;
double s2 = (rodistance01 + rodistance02 + rodistance03) / 2;
//=√ s(s−side 1)(s−side 2)(s−side3)
double area1 = Math.sqrt(s1 * (s1 - rodistance1) * (s1 - rodistance2)
* (s1 - rodistance3));
double area2 = Math.sqrt(s2 * (s2 - rodistance01) * (s2 - rodistance02)
* (s2 - rodistance03));
double totalArea = (area1 + area2);
System.out.println("The area is: " + totalArea);
}
}
compute the area of land surrounded by the polygon created by these cities.
Radius: 6,371.01 km
s= (side 1+side 2+side3)/2
area_of_triangle=√ s(s−side 1)(s−side 2)(s−side3)
I am having trouble with this program I am geting the wrong answer, I am getting 7.048521505923942E7
After changing the scale to 3 and rounding is 17516629.000
It should be: 117863.342
I already try different ways and I am still getting the same answers.
Goal... Given a Zip code and a number of miles... get all zip codes within N miles.
Found one utility here in .NET: http://www.codeproject.com/Articles/9198/ZIP-Code-Utility
Found another utility in PHP.
Also found this: http://api.geonames.org/findNearbyPostalCodes?postalcode=53714&country=USA&radius=50&username=demo
Is there such a client in java?
UPDATE: I couldn't find one and no one responded, so I went ahead and created one.
I went ahead and wrote one.
package ndd;
public class RadiusBox {
static final Double kEarthRadiusMiles = 3956.0;
public static RadiusBox create(Double latitude, Double longitude, Double radiusInMiles)
{
/*
A point {lat,lon} is a distance d out on the tc radial from point 1 if:
lat = asin (sin (lat1) * cos (d) + cos (lat1) * sin (d) * cos (tc))
dlon = atan2 (sin (tc) * sin (d) * cos (lat1), cos (d) - sin (lat1) * sin (lat))
lon = mod (lon1 + dlon + pi, 2 * pi) - pi
Where:
* d is the distance in radians (an arc), so the desired radius divided by
the radius of the Earth.
* tc = 0 is N, tc = pi is S, tc = pi/2 is E, tc = 3*pi/2 is W.
*/
double lat;
double dlon;
double dLatInRads = latitude * (Math.PI / 180.0);
double dLongInRads = longitude * (Math.PI / 180.0);
double dDistInRad = radiusInMiles / kEarthRadiusMiles;
RadiusBox box = new RadiusBox ();
box.setRadius(radiusInMiles);
// N (tc == 0):
// lat = asin (sin(lat1)*cos(d) + cos(lat1)*sin(d))
// = asin (sin(lat1 + d))
// = lat1 + d
// Unused:
// lon = lon1, because north-south lines follow lines of longitude.
box.setTopLine((dLatInRads + dDistInRad) * (180.0 / Math.PI));
// S (tc == pi):
// lat = asin (sin(lat1)*cos(d) - cos(lat1)*sin(d))
// = asin (sin(lat1 - d))
// = lat1 - d
// Unused:
// lon = lon1, because north-south lines follow lines of longitude.
box.setBottomLine((dLatInRads - dDistInRad) * (180.0 / Math.PI));
// E (tc == pi/2):
// lat = asin (sin(lat1)*cos(d))
// dlon = atan2 (sin(tc)*sin(d)*cos(lat1), cos(d) - sin(lat1)*sin(lat))
// lon = mod (lon1 + dlon + pi, 2*pi) - pi
lat = Math.asin (Math.sin(dLatInRads) * Math.cos (dDistInRad));
dlon = Math.atan2 (Math.sin(Math.PI / 2.0) * Math.sin (dDistInRad) * Math.cos (dLatInRads), Math.cos (dDistInRad) - Math.sin (dLatInRads)* Math.sin (lat));
box.setRightLine( (((dLongInRads + dlon + Math.PI) % (2.0 * Math.PI)) - Math.PI) * (180.0 / Math.PI));
// W (tc == 3*pi/2):
// lat = asin (sin(lat1)*cos(d))
// dlon = atan2 (sin(tc)*sin(d)*cos(lat1), cos(d) - sin(lat1)*sin(lat))
// lon = mod (lon1 + dlon + pi, 2*pi) - pi
dlon = Math.atan2 (Math.sin (3.0 * Math.PI / 2.0) * Math.sin (dDistInRad) * Math.cos (dLatInRads), Math.cos (dDistInRad) - Math.sin (dLatInRads)* Math.sin (lat));
box.setLeftLine((((dLongInRads + dlon + Math.PI) % (2.0 * Math.PI)) - Math.PI) * (180.0 / Math.PI));
return box;
}
private double bottomLine;
private double topLine;
private double leftLine;
private double rightLine;
private double radius;
public double getBottomLine() {
return bottomLine;
}
public void setBottomLine(double bottomLine) {
this.bottomLine = bottomLine;
}
public double getTopLine() {
return topLine;
}
public void setTopLine(double topLine) {
this.topLine = topLine;
}
public double getLeftLine() {
return leftLine;
}
public void setLeftLine(double leftLine) {
this.leftLine = leftLine;
}
public double getRightLine() {
return rightLine;
}
public void setRightLine(double rightLine) {
this.rightLine = rightLine;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
#Override
public String toString() {
return "RadiusBox [bottomLine=" + bottomLine + ", leftLine=" + leftLine
+ ", radius=" + radius + ", rightLine=" + rightLine
+ ", topLine=" + topLine + "]";
}
public String getSqlQuery() {
StringBuilder sb = new StringBuilder();
sb.append ("SELECT * FROM ZIP_CODES WHERE ");
sb.append ("LATITUDE >= ");
sb.append(bottomLine);
sb.append (" AND LATITUDE <= ");
sb.append(topLine);
sb.append (" AND LONGITUDE >= ");
sb.append(leftLine);
sb.append (" AND LONGITUDE <= ");
sb.append(rightLine);
sb.append (" ORDER BY CITY, STATE, ZIP");
return sb.toString();
}
}
I am trying to convert the code snippet given in this http://www.movable-type.co.uk/scripts/latlong.html into java. But I am not getting same result as that of site. Here is my code to find the midpoint between two points where their latitudes and longitudes are given
midPoint(12.870672,77.658964,12.974831,77.60935);
public static void midPoint(double lat1,double lon1,double lat2,double lon2)
{
double dLon = Math.toRadians(lon2-lon1);
double Bx = Math.cos(lat2) * Math.cos(dLon);
double By = Math.cos(lat2) * Math.sin(dLon);
double lat3 = Math.atan2(Math.sin(lat1)+Math.sin(lat2),Math.sqrt( (Math.cos(lat1)+Bx)*(Math.cos(lat1)+Bx) + By*By) );
double lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
System.out.print(lat3 +" " + lon3 );
}
I am not sure whethe dLon is correct or not. So please help me guys to figure it out. P.S.I need to find the latitude and longitude of the midpoint
You need to convert to radians. Change it to the following:
public static void midPoint(double lat1,double lon1,double lat2,double lon2){
double dLon = Math.toRadians(lon2 - lon1);
//convert to radians
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);
lon1 = Math.toRadians(lon1);
double Bx = Math.cos(lat2) * Math.cos(dLon);
double By = Math.cos(lat2) * Math.sin(dLon);
double lat3 = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By));
double lon3 = lon1 + Math.atan2(By, Math.cos(lat1) + Bx);
//print out in degrees
System.out.println(Math.toDegrees(lat3) + " " + Math.toDegrees(lon3));
}
Even easier with Android Google Maps Utilities:
LatLngBounds bounds = new LatLngBounds(start, dest);
bounds.getCenter();
Update:
Better use the builder (for why see Bad Losers Answer):
LatLngBounds.builder().include(start).include(dest).build().getCenter();
Please use LatLngBounds with the builder rather than the constructor if you want to correctly handle transgression of the antimeridian (longitude +/-180).
Here is the test illustrating the problem:
LatLng mp = midPoint(new LatLng(-43.95139,-176.56111),new LatLng(-36.397816,174.663496));
public static LatLng midPoint (LatLng SW, LatLng NE) {
LatLngBounds bounds = new LatLngBounds(SW, NE);
Log.d("BAD!", bounds.toString() + " CENTRE: " + bounds.getCenter().toString());
bounds = LatLngBounds.builder().include(SW).include(NE).build();
Log.d("GOOD", bounds.toString() + " CENTRE: " + bounds.getCenter().toString());
return bounds.getCenter();
}
Actual results:
BAD!: LatLngBounds{southwest=lat/lng: (-43.95139,-176.56111), northeast=lat/lng: (-36.397816,174.663496)} CENTRE: lat/lng: (-40.174603,-0.948807)
GOOD: LatLngBounds{southwest=lat/lng: (-43.95139,174.663496), northeast=lat/lng: (-36.397816,-176.56111)} CENTRE: lat/lng: (-40.174603,179.051193)
The constructor technique produces a central longitude out by 180 degrees!
You need to convert you lat and lon values used in the other formulas to Radians also. You can see this in the code ~3/5ths of the way down the page. The clue was given at the end of the spherical law of cosines distance formula:
(Note that here and in all subsequent code fragments, for simplicity I do not show conversions from degrees to radians; see below for complete versions).
Here's #dogbane's Java code converted to TypeScript.
type LatLng = {
lat: number;
lng: number;
};
function calculateMidPoint(latLngA: LatLng, latLngB: LatLng) {
function toRadians(degress: number): number {
return degress * (Math.PI / 180);
}
function toDegrees(radians: number): string {
return (radians * (180 / Math.PI)).toFixed(4);
}
const lngDiff = toRadians(latLngB.lng - latLngA.lng);
const latA = toRadians(latLngA.lat);
const latB = toRadians(latLngB.lat);
const lngA = toRadians(latLngA.lng);
const bx = Math.cos(latB) * Math.cos(lngDiff);
const by = Math.cos(latB) * Math.sin(lngDiff);
const latMidway = toDegrees(
Math.atan2(
Math.sin(latA) + Math.sin(latB),
Math.sqrt((Math.cos(latA) + bx) * (Math.cos(latA) + bx) + by * by)
)
);
const lngMidway = toDegrees(lngA + Math.atan2(by, Math.cos(latA) + bx));
console.log(
`Midway point between ${latLngA} and ${latLngB} is: Lat: ${latMidway}, lng: ${lngMidway}`
);
}
Following is #dogbane 's java code converted to Kotlin:
private fun midPoint(lat1: Double, lon1: Double, lat2: Double, lon2: Double) : String {
var lat1 = lat1
var lon1 = lon1
var lat2 = lat2
val dLon: Double = Math.toRadians(lon2 - lon1)
//convert to radians
lat1 = Math.toRadians(lat1)
lat2 = Math.toRadians(lat2)
lon1 = Math.toRadians(lon1)
val Bx: Double = Math.cos(lat2) * Math.cos(dLon)
val By: Double = Math.cos(lat2) * Math.sin(dLon)
val lat3: Double = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) * (Math.cos(lat1) + Bx) + By * By))
val lon3: Double = lon1 + Math.atan2(By, Math.cos(lat1) + Bx)
var result: String = ""
result = Math.toDegrees(lat3).toString() + "," + Math.toDegrees(lon3).toString()
return result;
}
My last job I made a tracking module and I was using this formula to calculate the distance between 2 coordinates.
//Location lat and lon
double locLat = -23.548333;
double locLon = -46.636111;
//Destination lat and lon
double dstLat = -22.902778;
double dstLon = -43.206667;
double arcoAB = 90 - (dstLat);
double arcoAC = 90 - (locLat);
double difLon = locLon - (dstLon);
double cosA = Math.cos(Math.toRadians(arcoAC)) * Math.cos(Math.toRadians(arcoAB)) + Math.sin(Math.toRadians(arcoAC)) * Math.sin(Math.toRadians(arcoAB)) * Math.cos(Math.toRadians(difLon));
double acosCosA = Math.toDegrees(Math.acos(cosA));
double raio = 2 * Math.PI * 6371;
double distance = (raio * acosCosA) / 360;
return distance; //Distance in KM, convert to anything else (miles, meters..) if you need..
You can get the mid point dividing the distance by 2.
Ah, this another formula works too:
double dLat = Math.toRadians(dstLat - locLat);
double dLon = Math.toRadians(dstLon - locLon);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(locLat)) * Math.cos(Math.toRadians(dstLat))
* Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = 6371 * c;
return d; //Distance in KM