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

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

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

Но у меня есть только две точки (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;
}