Рассчитать угол между двумя точками широты и долготы - PullRequest
24 голосов
/ 14 октября 2010

Можно ли рассчитать угол между двумя точками широты / долготы?

То, чего я пытаюсь достичь, это знать, куда направляется пользователь. Например, пользователь направляется на север, юг, .... юго-восток и т. Д.

Но у меня есть только две точки (Lng / Ltd)

Thx

Ответы [ 16 ]

39 голосов
/ 11 сентября 2013

с использованием этой ссылки для вычисления угла:

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;
}
21 голосов
/ 22 февраля 2013

Вы можете просто использовать Google Maps ComputeHeading:

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);
9 голосов
/ 25 марта 2013

Общая формула для расчета угла (направления) между двумя точками выглядит следующим образом:

θ = 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 голосов
/ 31 июля 2017

Основываясь на ответе Наянеша Гупте, вот реализация Python, если кому-то это нужно:

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

Где угол в 0 градусов указывает на направление на север.

3 голосов
/ 30 октября 2018

В Javascript я создаю имя функции angleFromCoordinate, в котором я передаю два лат / лнг. Эта функция вернет ангела между этими двумя значениями широта / долгота

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>
3 голосов
/ 28 октября 2014

Пример кода JavaScript, если расстояние между точками меньше -

brng = Math.atan2(newLat - oldLat, newLong - oldLong);
brng = brng * (180 / Math.PI);
brng = (brng + 360) % 360;
brng = 360 - brng;
2 голосов
/ 19 июля 2018

Если вы используете 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 - угол. Предположим, у вас есть значок автомобиля и поверните его в соответствии с направлением движения. Здесь его от 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

2 голосов
/ 19 июня 2017
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;

}
2 голосов
/ 14 октября 2010

Я думаю, вам нужны расчеты для Великого круга с подшипником .

1 голос
/ 23 июля 2018

Если вам требуется точный метод для эллипсоида вращения (т. Е. 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 - постоянный угол между точками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...