web-dev-qa-db-fra.com

Obtenir lat/long compte tenu du point actuel, de la distance et du relèvement

Etant donné un point existant en lat/long, une distance en (en KM) et un relèvement (en degrés convertis en radians), j'aimerais calculer le nouveau lat/long. This site surgit maintes et maintes fois, mais je ne peux tout simplement pas faire en sorte que la formule fonctionne pour moi. 

Les formules telles que prises ci-dessus sont les suivantes:

lat2 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(θ))

lon2 = lon1 + atan2(sin(θ)*sin(d/R)*cos(lat1), cos(d/R)−sin(lat1)*sin(lat2))

La formule ci-dessus s’applique à MSExcel où- 

asin          = arc sin()   
d             = distance (in any unit)   
R             = Radius of the earth (in the same unit as above)  
and hence d/r = is the angular distance (in radians)  
atan2(a,b)    = arc tan(b/a)  
θ is the bearing (in radians, clockwise from north);  

Voici le code que j'ai en Python.

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2  52.20444 - the lat result I'm hoping for
#lon2  0.36056 - the long result I'm hoping for.

lat1 = 52.20472 * (math.pi * 180) #Current lat point converted to radians
lon1 = 0.14056 * (math.pi * 180) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
             math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
                     math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

print(lat2)
print(lon2)

Je reçois 

lat2 = 0.472492248844 
lon2 = 79.4821662373
53
David M

Nécessaire pour convertir les réponses de radians en degrés. Code de travail ci-dessous:

import math

R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km

#lat2  52.20444 - the lat result I'm hoping for
#lon2  0.36056 - the long result I'm hoping for.

lat1 = math.radians(52.20472) #Current lat point converted to radians
lon1 = math.radians(0.14056) #Current long point converted to radians

lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
     math.cos(lat1)*math.sin(d/R)*math.cos(brng))

lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
             math.cos(d/R)-math.sin(lat1)*math.sin(lat2))

lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)

print(lat2)
print(lon2)
56
David M

La bibliothèque geopy supporte ceci:

import geopy
from geopy.distance import VincentyDistance

# given: lat1, lon1, b = bearing in degrees, d = distance in kilometers

Origin = geopy.Point(lat1, lon1)
destination = VincentyDistance(kilometers=d).destination(Origin, b)

lat2, lon2 = destination.latitude, destination.longitude

Trouvé via https://stackoverflow.com/a/4531227/37610

23
elliot42

Peut-être un peu tard pour répondre, mais après avoir testé les autres réponses, il apparaît qu'elles ne fonctionnent pas correctement. Voici un code PHP que nous utilisons pour notre système. Travailler dans toutes les directions.

Code PHP:

lat1 = latitude du point de départ en degrés

long1 = longitude du point de départ en degrés

d = distance en km

angle = relèvement en degrés

function get_gps_distance($lat1,$long1,$d,$angle)
{
    # Earth Radious in KM
    $R = 6378.14;

    # Degree to Radian
    $latitude1 = $lat1 * (M_PI/180);
    $longitude1 = $long1 * (M_PI/180);
    $brng = $angle * (M_PI/180);

    $latitude2 = asin(sin($latitude1)*cos($d/$R) + cos($latitude1)*sin($d/$R)*cos($brng));
    $longitude2 = $longitude1 + atan2(sin($brng)*sin($d/$R)*cos($latitude1),cos($d/$R)-sin($latitude1)*sin($latitude2));

    # back to degrees
    $latitude2 = $latitude2 * (180/M_PI);
    $longitude2 = $longitude2 * (180/M_PI);

    # 6 decimal for Leaflet and other system compatibility
   $lat2 = round ($latitude2,6);
   $long2 = round ($longitude2,6);

   // Push in array and get back
   $tab[0] = $lat2;
   $tab[1] = $long2;
   return $tab;
 }
9
Peter

lon1 et lat1 en degrés

brng = roulement en radians

d = distance en km

R = rayon de la Terre en km

lat2 = math.degrees((d/R) * math.cos(brng)) + lat1
long2 = math.degrees((d/(R*math.sin(math.radians(lat2)))) * math.sin(brng)) + long1

J'ai implémenté votre algorithme et le mien dans PHP et je l'ai analysé. Cette version a fonctionné environ 50% du temps. Les résultats générés étaient identiques, il semble donc être mathématiquement équivalent.

Je n'ai pas testé le code python ci-dessus, il pourrait donc y avoir des erreurs de syntaxe.

3
Chris

Également en retard, mais pour ceux qui pourraient le trouver, vous obtiendrez des résultats plus précis en utilisant la bibliothèque -ographicallib . Consultez les descriptions de problèmes géodésiques et les exemples JavaScript pour une introduction facile à l'utilisation de la réponse à la question sur le sujet, ainsi que pour de nombreuses autres. Implémentations dans une variété de langages, y compris Python. Bien mieux que de coder le vôtre si vous vous souciez de la précision; mieux que VincentyDistance dans la recommandation "utilisez une bibliothèque" antérieure. Comme le dit la documentation: "L'accent est mis sur le retour de résultats précis avec des erreurs proches de l'arrondi (environ 5-15 nanomètres)."

1
jwd630

Manière rapide en utilisant geopy

from geopy import distance
#distance.distance(unit=15).destination((lat,lon),bering) 
#Exemples
distance.distance(nautical=15).destination((-24,-42),90) 
distance.distance(miles=15).destination((-24,-42),90)
distance.distance(kilometers=15).destination((-24,-42),90) 

Il suffit d'échanger les valeurs dans la fonction atan2 (y, x). Pas atan2 (x, y)!

1
Asrat

J'ai porté la réponse de Brad à la réponse JS de Vanilla, sans dépendance de cartes Bing

https://jsfiddle.net/kodisha/8a3hcjtd/

// ----------------------------------------
// Calculate new Lat/Lng from original points
// on a distance and bearing (angle)
// ----------------------------------------
let llFromDistance = function(latitude, longitude, distance, bearing) {
  // taken from: https://stackoverflow.com/a/46410871/13549 
  // distance in KM, bearing in degrees

  const R = 6378.1; // Radius of the Earth
  const brng = bearing * Math.PI / 180; // Convert bearing to radian
  let lat = latitude * Math.PI / 180; // Current coords to radians
  let lon = longitude * Math.PI / 180;

  // Do the math magic
  lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng));
  lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance / R) - Math.sin(lat) * Math.sin(lat));

  // Coords back to degrees and return
  return [(lat * 180 / Math.PI), (lon * 180 / Math.PI)];

}

let pointsOnMapCircle = function(latitude, longitude, distance, numPoints) {
  const points = [];
  for (let i = 0; i <= numPoints - 1; i++) {
    const bearing = Math.round((360 / numPoints) * i);
    console.log(bearing, i);
    const newPoints = llFromDistance(latitude, longitude, distance, bearing);
    points.Push(newPoints);
  }
  return points;
}


const points = pointsOnMapCircle(41.890242042122836, 12.492358982563019, 0.2, 8);


let geoJSON = {
  "type": "FeatureCollection",
  "features": []
};
points.forEach((p) => {
  geoJSON.features.Push({
    "type": "Feature",
    "properties": {},
    "geometry": {
      "type": "Point",
      "coordinates": [
        p[1],
        p[0]
      ]
    }
  });
});



document.getElementById('res').innerHTML = JSON.stringify(geoJSON, true, 2);

En outre, j’ai ajouté l’exportation geoJSON afin que vous puissiez simplement coller le résultat geoJSON dans http://geojson.io/#map=17/41.89017/12.49171 et voir les résultats instantanément.

Résultat:  geoJSON Screenshot

1
kodisha

J'ai porté la réponse de @David M à Java si quelqu'un le souhaitait ... J'ai un résultat légèrement différent, 52.20462299620793, 0.360433887489931

    double R = 6378.1;  //Radius of the Earth
    double brng = 1.57;  //Bearing is 90 degrees converted to radians.
    double d = 15;  //Distance in km

    double lat2 = 52.20444; // - the lat result I'm hoping for
    double lon2 = 0.36056; // - the long result I'm hoping for.

    double lat1 = Math.toRadians(52.20472); //Current lat point converted to radians
    double lon1 = Math.toRadians(0.14056); //Current long point converted to radians

    lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) +
            Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng));

    lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1),
            Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));

    lat2 = Math.toDegrees(lat2);
    lon2 = Math.toDegrees(lon2);

    System.out.println(lat2 + ", " + lon2);
0
Alessandro

J'ai porté le Python en Javascript. Cela retourne un objet Bing Maps Location, que vous pouvez modifier comme bon vous semble.

getLocationXDistanceFromLocation: function(latitude, longitude, distance, bearing) {
    // distance in KM, bearing in degrees

    var R = 6378.1,                         // Radius of the Earth
        brng = Math.radians(bearing)       // Convert bearing to radian
        lat = Math.radians(latitude),       // Current coords to radians
        lon = Math.radians(longitude);

    // Do the math magic
    lat = Math.asin(Math.sin(lat) * Math.cos(distance / R) + Math.cos(lat) * Math.sin(distance / R) * Math.cos(brng));
    lon += Math.atan2(Math.sin(brng) * Math.sin(distance / R) * Math.cos(lat), Math.cos(distance/R)-Math.sin(lat)*Math.sin(lat));

    // Coords back to degrees and return
    return new Microsoft.Maps.Location(Math.degrees(lat), Math.degrees(lon));

},
0
Brad Mathews

Voici une version PHP basée sur Ed Williams Aviation Formulary. Modulus est traité un peu différemment en PHP. Cela fonctionne pour moi.

function get_new_waypoint ( $lat, $lon, $radial, $magvar, $range )
{

   // $range in nm.
   // $radial is heading to or bearing from    
   // $magvar for local area.

   $range = $range * pi() /(180*60);
   $radial = $radial - $magvar ;

   if ( $radial < 1 )
     {
        $radial = 360 + $radial - $magvar; 
     }
   $radial =  deg2rad($radial);
   $tmp_lat = deg2rad($lat);
   $tmp_lon = deg2rad($lon);
   $new_lat = asin(sin($tmp_lat)* cos($range) + cos($tmp_lat) * sin($range) * cos($radial));
   $new_lat = rad2deg($new_lat);
   $new_lon = $tmp_lon - asin(sin($radial) * sin($range)/cos($new_lat))+ pi() % 2 * pi() -  pi();
   $new_lon = rad2deg($new_lon);

   return $new_lat." ".$new_lon;

}
0
Bruce