Вычислить угол между двумя точками широты/долготы
Есть ли способ вычислить угол между двумя точками широты/долготы?
То, что я пытаюсь достичь, - это знать, куда движется пользователь. Например, пользователь движется на север, юг, юго-восток и т.д.
Но у меня есть только две точки (Lng/Ltd)
спасибо
Ответы
Ответ 1
используя эту ссылку для расчета угла:
private double angleFromCoordinate(double lat1, double long1, double lat2,
double long2) {
double dLon = (long2 - long1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(dLon);
double brng = Math.atan2(y, x);
brng = Math.toDegrees(brng);
brng = (brng + 360) % 360;
brng = 360 - brng; // count degrees counter-clockwise - remove to make clockwise
return brng;
}
Ответ 2
Вы просто можете использовать карты google для расчета:
var point1 = new google.maps.LatLng(lat1, lng1);
var point2 = new google.maps.LatLng(lat2, lng2);
var heading = google.maps.geometry.spherical.computeHeading(point1,point2);
Ответ 3
Общая формула для вычисления угла (подшипника) между двумя точками выглядит следующим образом:
θ = atan2(sin(Δlong)*cos(lat2), cos(lat1)*sin(lat2) − sin(lat1)*cos(lat2)*cos(Δlong))
Обратите внимание, что угол (θ) должен быть преобразован в радианы перед использованием этой формулы и
Δlong = long2 - long1.
atan2 - общая функция, встречающаяся почти во всех языках программирования (в основном в Math-пакете/библиотеке). Обычно существуют также функции преобразования между градусами и радианами (также в Math-пакете/библиотеке).
Помните, что atan2 возвращает значения в диапазоне -π... + π, чтобы преобразовать результат в компас, вам нужно умножить θ на 180/π, затем используйте (θ + 360)% 360, где% является операцией деления модуля, возвращающей остальную часть деления.
Следующая ссылка является хорошим ресурсом для формул, включающих широты и долготы. Они также предоставляют Javascript реализацию своих формул. Фактически, этот ответ основан на информации с этой страницы:
http://www.yourhomenow.com/house/haversine.html
Ответ 4
Основываясь на ответе Nayanesh Gupte, ниже приведена реализация на Python того, как рассчитать angular между двумя точками, определяемыми их широтой и долготой:
def angleFromCoordinate(lat1, long1, lat2, long2):
dLon = (long2 - long1)
y = math.sin(dLon) * math.cos(lat2)
x = math.cos(lat1) * math.sin(lat2) - math.sin(lat1) * math.cos(lat2) * math.cos(dLon)
brng = math.atan2(y, x)
brng = math.degrees(brng)
brng = (brng + 360) % 360
brng = 360 - brng # count degrees clockwise - remove to make counter-clockwise
return brng
Где angular 0 градусов указывает направление на север.
Ответ 5
Пример кода javascript, если расстояние между точками меньше -
brng = Math.atan2(newLat - oldLat, newLong - oldLong);
brng = brng * (180 / Math.PI);
brng = (brng + 360) % 360;
brng = 360 - brng;
Ответ 6
В Javascript я создаю имя функции angleFromCoordinate
в котором я angleFromCoordinate
два значения lat/lng. Эта функция будет возвращать ангела между этими двумя широтами
function angleFromCoordinate(lat1,lon1,lat2,lon2) {
var p1 = {
x: lat1,
y: lon1
};
var p2 = {
x: lat2,
y: lon2
};
// angle in radians
var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
// angle in degrees
var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
console.log(angleDeg);
return angleDeg;
}
Фрагмент рабочего кода
function angleFromCoordinate(lat1,lon1,lat2,lon2) {
var p1 = {
x: lat1,
y: lon1
};
var p2 = {
x: lat2,
y: lon2
};
// angle in radians
var angleRadians = Math.atan2(p2.y - p1.y, p2.x - p1.x);
// angle in degrees
var angleDeg = Math.atan2(p2.y - p1.y, p2.x - p1.x) * 180 / Math.PI;
document.getElementById('rotation').innerHTML ="Rotation : "+ angleDeg;
return angleDeg;
}
angleFromCoordinate(37.330604,-122.028947,37.3322109,-122.0329665);
<html>
<p id="rotation">Rotation : </p>
</html>
Ответ 7
Я думаю, что вам нужны вычисления для Great Circle.
Ответ 8
function calculateAngle(lat, lng) {
var checkLengthInterval = 2;
// Calculate Angle
//If ObjFeed == [] add first object.
if (ObjFeed.length == 0) {
ObjFeed.push({ 'lat': lat, 'lng': lng });
} else {
// Get last object from list to calculate angle betwn last and latest.
var tempNode = ObjFeed[ObjFeed.length - 1];
// If last lat and lng is same as current it will always return 0 angle.so only push lat lng in obj which is diff than last one.
if (!(tempNode.lat == lat && tempNode.lng == lng)) {
ObjFeed.push({ 'lat': lat, 'lng': lng });
} else {
console.log('exact match for lat lng');
}
}
// this is for to keep only few objects in the list and remove other
if (ObjFeed.length >= checkLengthInterval) {
// calculating angle only if previous data point is available
ObjFeed = ObjFeed.slice(-1 * checkLengthInterval); // remove all items in array except last two
var point1 = ObjFeed[ObjFeed.length - checkLengthInterval];
var point2 = ObjFeed[ObjFeed.length - 1];
console.log('previous point1', point1);
console.log('next point2', point2);
var dLng = (point2.lng - point1.lng);
var dLat = (point2.lat - point1.lat);
dLng = dLng * 10000;
dLat = dLat * 10000;
var dlat_by_dlan = 0;
try {
dlat_by_dlan = dLng / dLat;
} catch (err) {
dlat_by_dlan = NaN;
console.log('Exception: dLat == 0');
}
var angleDegreeBearing = 0, angleBearingRad = 0;
angleBearingRad = Math.atan(dlat_by_dlan);
angleDegreeBearing = angleBearingRad * 180 / Math.PI;
if (dLat < 0 && dLng < 0) {
angleDegreeBearing = angleDegreeBearing + 180;
} else if (dLat < 0 && dLng > 0) {
angleDegreeBearing = angleDegreeBearing + 180;
} else if (dLat == 0 && dLng == 0) {
angleDegreeBearing = prevVechicleAngle;
} else if (dlat_by_dlan == NaN) {
angleDegreeBearing = prevVechicleAngle;
}
console.log('angleDegreeBearing', angleDegreeBearing);
} else {
// setting up default angle to 0 if previous data point is not available to calculate actual anglle
console.log('feedArray default angle 0');
angleDegreeBearing = 0;
}
prevVechicleAngle = angleDegreeBearing;
return angleDegreeBearing;
}
Ответ 9
Если вы используете Google Maps (Android), есть простой способ - использовать SphericalUtil
double angle = SphericalUtil.computeHeading(fromLatLng, toLatLng);
Рассмотрим, что у нас есть 2 точки и его широта и долгота
Затем создайте его объект Latlng
LatLng latlng = new LatLng(latValue, lngValue);
После получения 2 очков, используйте sperical util для определения угла
//import com.google.maps.android.SphericalUtil;
double sphericalValue = SphericalUtil.computeHeading(latLng1, latLng2);
SpericalValue - это angular.
Предположим, у вас есть значок автомобиля и поверните его в соответствии с направлением движения. Здесь его от latLng1 до latLng2 затем
Bitmap vehiclePin = rotateIconBitmap(sphericalValue);
mMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).position(latLng2))
.setIcon(BitmapDescriptorFactory.fromBitmap(vehiclePin));
используйте метод ниже, чтобы повернуть
Bitmap rotateIconBitmap(double angle) {
Bitmap source = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_vehicle_say_car);
Matrix matrix = new Matrix();
matrix.postRotate((float) angle);
return Bitmap.createBitmap(source, 0, 0,
source.getWidth(), source.getHeight(), matrix, true);
}
![enter image description here]()
Простой способ получить убер как вращающиеся иконки
Примечание. - Возможно, вам придется добавить смещение, скажем, 90 градусов, если значок маркера не направлен на ноль градусов
Android sphericalutil с открытым исходным кодом, если вы используете Java, обратитесь к нему, вы можете использовать его.
https://github.com/googlemaps/android-maps-utils/blob/master/library/src/com/google/maps/android/SphericalUtil.java
Ответ 10
Возможно, это то, что вы хотите:
cos(say) = (cosd(90-lat(1))) * (cos(90-lat(2)))
+ (sin(90-lat(1))) * (sind(90-lat(2)) * (cosd(abs(Landa(2)-landa(1)))));
Ответ 11
Для тех, кто использует C/С++, ниже приведен протестированный код:
static const auto PI = 3.14159265358979323846, diameterOfEarthMeters = 6371.0 * 2 * 1000;
double degreeToRadian (double degree) { return (degree * PI / 180); };
double radianToDegree (double radian) { return (radian * 180 / PI); };
double CoordinatesToAngle (const double latitude1,
const double longitude1,
const double latitude2,
const double longitude2)
{
const auto longitudeDifferenceRadians = degreeToRadian(longitude2 - longitude1);
auto latitude1Radian = degreeToRadian(latitude1),
latitude2Radian = degreeToRadian(latitude2);
const auto x = std::cos(latitude1Radian) * std::sin(latitude2Radian) -
std::sin(latitude1Radian) * std::cos(latitude2Radian) *
std::cos(longitudeDifferenceRadians);
const auto y = std::sin(longitudeDifferenceRadians) * std::cos(latitude2Radian);
return radianToDegree(std::atan2(y, x));
}
double CoordinatesToMeters (const double latitude1,
const double longitude1,
const double latitude2,
const double longitude2)
{
auto latitude1Radian = degreeToRadian(latitude1),
longitude1Radian = degreeToRadian(longitude1),
latitude2Radian = degreeToRadian(latitude2),
longitude2Radian = degreeToRadian(longitude2);
auto x = std::sin((latitude2Radian - latitude1Radian) / 2),
y = std::sin((longitude2Radian - longitude1Radian) / 2);
return diameterOfEarthMeters *
std::asin(std::sqrt((x * x) +
(std::cos(latitude1Radian) * std::cos(latitude2Radian) * y * y)));
}
Ответ 12
Если кому-то нужен код PHP
для этой функции:
/**
* Calculate angle between 2 given latLng
* @param float $lat1
* @param float $lat2
* @param float $lng1
* @param float $lng2
* @return integer
*/
function angle($lat1, $lat2, $lng1, $lng2) {
$dLon = $lng2 - $lng1;
$y = sin($dLon) * cos($lat2);
$x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dLon);
return 360 - ((rad2deg(atan2($y, $x)) + 360) % 360);
}
Ответ 13
Чтобы предоставить заголовок, вам нужно вычислить несущий.
Чтобы понять значение подшипника, прочитайте в этой статье.
В соответствии с этой статьей (раздел подшипника) формула:
θ = atan2( sin Δλ ⋅ cos φ2 , cos φ1 ⋅ sin φ2 − sin φ1 ⋅ cos φ2 ⋅ cos Δλ )
where φ1, λ1 is the start point,
φ2, λ2 the end point,
Δλ is the difference in longitude`
Вот пример того, как вычислить угол (в градусах) между двумя точками, выраженный в Lat/Lon. (сделано на С#)
Скажем, Point
- простой класс с двумя атрибутами double
X (для долготы) и Y (для широты).
public double ComputeBearing(Point start,Point end)
{
var φ1 = start.Y; //latitude 1
var λ1 = start.X; //longitude 1
var φ2 = end.Y; //latitude 2
var λ2 = end.X; //longitude 2
var y = Math.Sin(this.degreeToRadian(λ2 - λ1)) * Math.Cos(this.degreeToRadian(φ2));
var x = Math.Cos(this.degreeToRadian(φ1)) * Math.Sin(this.degreeToRadian(φ2)) - Math.Sin(this.degreeToRadian(φ1)) * Math.Cos(this.degreeToRadian(φ2)) * Math.Cos(this.degreeToRadian(λ2 - λ1));
var θ = Math.Atan2(y, x);
θ = this.radianToDegree(θ);
return θ;
}
Используя следующие методы:
public double degreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
public double radianToDegree(double angle)
{
return angle * (180.0 / Math.PI);
}
Используя ComputeBearing
, вы легко получите угол, выраженный в градусах, легко используемых в качестве заголовка
Ответ 14
Если вам требуется точный метод для эллипсоида вращения (т.е. WGS 84), алгоритмы становятся действительно тяжелыми. Вы можете воспользоваться GeographicLib, которая была реализована в C/C++, Java, JavaScript, Python, Matlab/Octave и других.
На вопрос, есть ли геодезическая или прямая линия между первой и второй точкой.
геодезический
Геодезическая - это кратчайший путь между двумя точками на изогнутой поверхности. Это наиболее распространенная интерпретация того, куда "направляется пользователь" (из вопроса), поскольку она является самой короткой и наиболее прямой. Обратный геодезический расчет можно решить с помощью GeodSolve. Вы также можете использовать онлайн-интерфейс. Этот инструмент имеет вход/выход:
lat1 lon1 lat2 lon2 → azi1 azi2 s12
Где lat1 lon1 - пара координат для первой точки, а lat2 lon2 - пара координат для второй точки. Все единицы даны в градусах (не в радианах). Результат, azi1 или α 1, представляет собой азимут (он же азимут) от начальной точки в градусах по часовой стрелке с севера. Второй азимут находится во второй точке, поскольку угол между двумя точками вдоль геодезической не является постоянным. А s12 - это расстояние между двумя точками в метрах с точностью до 15 нм.
Прямая линия
Прямая линия соединяет две координатные точки с постоянным азимутом (или азимутом). Вычисление обратной прямой линии может быть решено с помощью RhumbSolve. Вы также можете использовать онлайн-интерфейс. Этот инструмент имеет вход/выход:
lat1 lon1 lat2 lon2 → azi12 s12
Эти параметры такие же, как у GeodSolve, за исключением того, что azi12 является постоянным углом между точками.
Ответ 15
Удостоверьтесь в том, что его нисходящая линия не имеет большого радиуса начальные изменения подшипника в зависимости от расстояния
double angle= Math.min((pbearingf-tbearingf) < 0 ? pbearingf-tbearingf+360:pbearingf-tbearingf, (tbearingf-pbearingf)<0?tbearingf-pbearingf+360:tbearingf-pbearingf);
Ответ 16
Рассмотрение ответа Nayanesh Gupte и его комментариев. Я изменил часть кода и написал его в PHP
.
- широта и долгота были преобразованы в радиан внутри функции.
Вот функция:
function angleFromCoordinate($lat1, $long1, $lat2, $long2) {
$lat1 = deg2rad($lat1);
$lat2 = deg2rad($lat2);
$long1 = deg2rad($long1);
$long2 = deg2rad($long2);
$dLon = $long2 - $long1;
$y = sin($dLon) * cos($lat2);
$x = cos($lat1) * sin($lat2) - sin($lat1) * cos($lat2) * cos($dLon);
$brng = atan2($y, $x);
$brng = $brng * 180 / pi();
$brng = fmod($brng + 360, 360);
return $brng;
}