Calculer l'angle entre deux points de Latitude / Longitude
Existe-t-il un moyen de calculer l'angle entre deux points de Latitude/Longitude?
ce que j'essaie de faire, c'est de savoir où va l'utilisateur. Par exemple, l'utilisateur se dirige vers le Nord, le Sud,.... Sud-Est, etc.
Mais j'ai seulement deux points (Gnl/Ltd)
Thx
15 réponses
en utilisant reference to calculate Angle:
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;
}
Vous ne pouvez utiliser les cartes 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);
la formule générale pour calculer l'angle (relèvement) entre deux points est la suivante:
θ = atan2(sin(Δlong)*cos(lat2), cos(lat1)*sin(lat2) − sin(lat1)*cos(lat2)*cos(Δlong))
Notez que l'angle(θ) doivent être convertis en radians avant d'utiliser cette formule et Δlong = long2-long1.
atan2 est une fonction commune dans presque tous les langages de programmation (principalement dans le paquet de Maths/bibliothèque). Habituellement, il ya aussi des fonctions pour la conversion entre les degrés et les radians(également dans le paquet de mathématiques/bibliothèque).
Rappelez-vous que atan2 Renvoie des valeurs dans l'intervalle de-π ... +π, pour convertir le résultat en relèvement de compas, vous devez multiplier θ par 180/π puis utiliser (θ+360) % 360, où % est opération de division de module retournant le reste de la division.
le lien suivant est une bonne ressource pour les formules impliquant des latitudes et des longitudinales. Ils fournissent également L'implémentation Javascript de leurs formules. En fait, cette réponse est basée sur les informations de ce page:
exemple de code javascript si la distance entre les points est moindre -
brng = Math.atan2(newLat - oldLat, newLong - oldLong);
brng = brng * (180 / Math.PI);
brng = (brng + 360) % 360;
brng = 360 - brng;
basé sur la réponse de Nayanesh Gupte, voici une implémentation Python Si quelqu'un en a besoin:
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
où un angle de 0 degrés indique un cap Nord.
je pense que vous voulez pour le calcul des grand cercle portant.
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;
}
c'est Peut-être ce que vous voulez:
cos(say) = (cosd(90-lat(1))) * (cos(90-lat(2)))
+ (sin(90-lat(1))) * (sind(90-lat(2)) * (cosd(abs(Landa(2)-landa(1)))));
pour ceux qui utilisent C / C++, voici le code testé:
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)));
}
En cas de besoin de quelqu'un PHP
code pour cette fonctionnalité:
/**
* 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);
}
pour fournir le cap, vous devez calculer le roulement.
Pour comprendre roulement à lire cet article.
selon ceci l'article (section portant) la formule est la suivante :
θ = 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`
Voici un exemple sur la façon de calculer l'angle (en degrés) entre deux points exprimés en Lat/Lon. (fait en C#)
disons Point
est une classe simple avec deux double
attributs X (pour la longitude) et Y (pour latitude.)
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 θ;
}
en Utilisant les méthodes suivantes :
public double degreeToRadian(double angle)
{
return Math.PI * angle / 180.0;
}
public double radianToDegree(double angle)
{
return angle * (180.0 / Math.PI);
}
En utilisant ComputeBearing
vous obtiendrez facilement un angle exprimé en degrés facilement utilisable comme Cap
si vous utilisez google maps, il y a un moyen facile - Utilisez SpericalUtil
double angle = SphericalUtil.computeHeading(fromLatLng, toLatLng);
Considérons que nous avons 2 points et ses lat et de gnl Puis créer son objet Latlng
LatLng latlng = new LatLng(latValue, lngValue);
après avoir obtenu Latlng de 2 points, utilisez Sperical util pour obtenir l'angle
//import com.google.maps.android.SphericalUtil;
double sphericalValue = SphericalUtil.computeHeading(latLng1, latLng2);
SpericalValue est l'angle. Considérez que vous avez une icône de voiture et tourner à la direction de sa va. Voici son de latLng1 à latLng2 puis
Bitmap vehiclePin = rotateIconBitmap(sphericalValue);
mMap.addMarker(new MarkerOptions().anchor(0.5f, 0.5f).position(latLng2))
.setIcon(BitmapDescriptorFactory.fromBitmap(vehiclePin));
utiliser la méthode ci-dessous pour faire pivoter
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);
}
façon facile d'obtenir uber comme les icônes rotated
Remarque:- Vous pouvez avoir à ajouter un décalage de 90 degrés si l'icône de marque n'est pas fait au degré zéro
Assurez-vous que c'est une ligne de rhumb portant pas un grand cercle portant comme le changement de rapport initial en fonction de la distance
double angle= Math.min((pbearingf-tbearingf) < 0 ? pbearingf-tbearingf+360:pbearingf-tbearingf, (tbearingf-pbearingf)<0?tbearingf-pbearingf+360:tbearingf-pbearingf);
Considérant Nayanesh Gupte's réponse et de ses commentaires. J'ai changé une partie du code et l'a écrit dans PHP
.
- parallèle et longitude ont été convertis radians à l'intérieur de la fonction.
Voici la fonction:
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;
}
si vous avez besoin d'une méthode précise sur un ellipsoïde de révolution (i.e. WGS 84), le algorithmes obtenir vraiment lourd. Vous pouvez bénéficier d' GeographicLib, qui a été implémenté en C / C++, Java, JavaScript, Python, Matlab/Octave, et autres.
pour la question, il y a soit un géodésique et ligne de rhumb entre la première et la deuxième point.
Géodésique
un géodésique est le chemin le plus court entre deux points sur une surface courbée. C'est l'interprétation la plus courante de l'endroit où un "utilisateur se dirige" (à partir de la question), puisqu'elle est la plus courte et la plus directe. Un calcul géodésique inverse peut être résolu en utilisant GeodSolve. Vous pouvez également utiliser le interface en ligne. Cet outil a l'entrée/sortie:
lat1 lon1 lat2 lon2 → azi1 azi2 S12
Où lat1 lon1 est la paire de coordonnées pour le premier point, et lat2 lon2 est la paire de coordonnées pour le second point. Toutes les unités sont en degrés (pas en radians). Le résultat, azi1 ou α1, est l'Azimut(A. K. A. relèvement) à partir du point de départ, en degrés dans le sens des aiguilles d'une montre à partir du Nord. Le deuxième azimut est au deuxième point, parce que l'angle entre les deux points le long d'un géodésique n'est pas constante. Et s12 est la distance entre les deux points, en mètres, avec une précision de 15 nm.
ligne de Rhumb
une ligne de rhumb relie deux points de coordonnées avec un azimut constant (ou relèvement). Un calcul inverse de la ligne de rhumb peut être résolu en utilisant Rumbsolve. Vous pouvez également utiliser le interface en ligne. Cet outil a l'entrée/sortie:
lat1 lon1 lat2 lon2 → azi12 s12
Ces paramètres sont les mêmes que GeodSolve, sauf que azi12 est un angle constant entre les points.