Средняя точка между двумя широтой и долготой
Я пытаюсь преобразовать фрагмент кода, приведенный в этом http://www.movable-type.co.uk/scripts/latlong.html в Java. Но я не получаю тот же результат, что и на сайте. Вот мой код, чтобы найти среднюю точку между двумя точками, где даны их широта и долгота
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 );
}
Я не уверен, что Длон прав или нет. Поэтому, пожалуйста, помогите мне, ребята, понять это. PS Мне нужно найти широту и долготу средней точки
7 ответов
Вам нужно конвертировать в радианы. Измените это на следующее:
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));
}
Еще проще с Android Google Maps Utilities:
LatLngBounds bounds = new LatLngBounds(start, dest);
bounds.getCenter();
Обновление: лучше использовать конструктор (почему см. " Ответ плохим неудачникам"):
LatLngBounds.builder().include(start).include(dest).build().getCenter();
Пожалуйста, используйте LatLngBounds со строителем, а не конструктором, если вы хотите правильно обработать нарушение антимеридиана (долгота +/-180).
Вот тест, иллюстрирующий проблему:
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();
}
Фактические результаты:
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)
Техника конструктора выдает центральную долготу на 180 градусов!
Вам нужно также преобразовать значения широт и долгот, используемые в других формулах, в радианы. Вы можете увидеть это в коде ~3/5 пути вниз по странице. Подсказка была дана в конце сферического закона формулы косинуса расстояния:
(Обратите внимание, что здесь и во всех последующих фрагментах кода для простоты я не показываю преобразования из градусов в радианы; см. Полные версии ниже).
Вот @dogbane
Java
код, преобразованный в
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}`
);
}
Ниже приводится @dogbane
java
код преобразован в
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;
}
В своей последней работе я создал модуль отслеживания и использовал эту формулу для вычисления расстояния между двумя координатами.
//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..
Вы можете получить среднюю точку, деля расстояние на 2.
Ах, эта другая формула тоже работает:
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