Calcul de distances

Afin de pouvoir évaluer des distances, puis des vitesses à partir des coordonnées GPS contenues dans un fichier GPX, nous allons nous intéresser aux fonctions mathématiques, notamment trigonométriques, du module math.

Ce chapitre sera aussi l'occasion d'aborder la création de fonctions au sens informatique.

Le module math

Ce module est préinstallé avec Python, donc pas besoin d'opération particulière pour l'utiliser. Parmi les fonctions les plus courantes, on peut citer :

Fonction Description
floor(x) plus grand entier inférieur à x
ceil(x) plus petit entier supétieur à x
fabs(x) valeur absolue de x
sqrt(x) racine carrée de x
pow(x,y) x à la puissance y
degrees(x) conversion de l'angle x des radians en degrés
radians(x) conversion de l'angle x des degrés en radians
cos(x) cosinus de l'angle x exprimé en radians
sin(x) sinus de l'angle x exprimé en radians
tan(x) tangente de l'angle x exprimé en radians
acos(x) arc cosinus de x, le résultat est exprimé en radians
asin(x) arc sinus de x, le résultat est exprimé en radians
atan(x) arc tangente de x, le résultat est exprimé en radians
atan2(y,x) atan(y/x)
from math import *

# Calcul de l'hypoténuse d'un triangle rectangle
a = 3
b = 4
c = sqrt(a**2 + b**2)

Définition de fonctions

Nous avons vu que nous pouvions utiliser des modules en Python pour accéder à de nouvelles fonctions. Mais il est aussi possible de créer ses propres fonctions à l'aide de la clause def.

from math import *

# Définition de la fonction distance
def distance(x1, y1, z1, x2, y2, z2):
    dx = x2 - x1
    dy = y2 - y1
    dz = z2 - z1
    return sqrt( dx*dx + dy*dy + dz*dz )

# Utilisation de la fonction distance
d = distance(0, 0, 0.5, 1, 2, -4.5)

Les valeurs entre parenthèses, séparées par une virgule, qui suivent le nom de la fonction sont ses paramètres : ils sont utilisés comme des variables locales au sein de la fonction.

Exercice

Écrivez un script gpsutils.py au sein duquel vous définirez une fonction great_circle_distance(lat1, lon1, lat2, lon2) qui calcule la distance géodésique entre deux points de coordoonées polaires (lat1,lon1) et (lat2,lon2) en utilisant la formule de Vincenty.

Attention !

Les latitudes et longitudes sont exprimées en degrés dans un fichier GPX alors que les fonctions trigonométriques de Python manipulent des angles en radians. La fonction radians() devrait vous dépanner.

Info

Pour plus de précision, vous utiliserez le rayon moyen de la Terre dans vos calculs.
Correction
from math import *

#
# Rayon de la Terre au niveau de l'équateur (en mètres)
# a = 6378137
#
# Rayon de la Terre au niveau des pôles (en mètres)
# b = 6356752 
#
# Rayon moyen de la Terre (en mètres)
# R = (2*a+b)/3 = 6371009
#
def great_circle_distance(lat1, lon1, lat2, lon2):
    lat1 = radians(lat1)
    lat2 = radians(lat2)
    dLon = radians(fabs(lon2-lon1))

    cosLat1 = cos(lat1)
    sinLat1 = sin(lat1)
    cosLat2 = cos(lat2)
    sinLat2 = sin(lat2)
    cosDLon = cos(dLon)
    sinDLon = sin(dLon)

    A = cosLat2*sinDLon
    B = cosLat1*sinLat2 - sinLat1*cosLat2*cosDLon

    return 6371009 * atan2(sqrt(A*A + B*B),
                     sinLat1*sinLat2 + cosLat1*cosLat2*cosDLon)

Pour utliser cette nouvelle fonction dans un autre script Python, nous pouvons l'importer comme un module :

from gpsutils import *

d = great_circle_distance(49.5, 4.9, 48, 7.12)

Exercice

Complétez le script gpxplorer.py en ajoutant une liste distance qui contiendra, après parcours de l'arborescence XML, les distances cumulées le long du parcours évaluées à l'aide de la fonction great_circle_distance().

Correction
from bs4 import BeautifulSoup
from gpsutils import *

# Liste des latitudes exprimées en degrés
latitude  = []

# Liste des longitudes exprimées en degrés
longitude = []

# Liste des altitudes exprimées en mètres
elevation = []

# Liste des distances cumulées
distance  = []

# Chargement du fichier GPX
content = open('RATJ2012-21km-herve.schely.gpx')

# Construction de l'arborescnce
soup = BeautifulSoup(content, 'lxml')

for point in soup.find_all('trkpt'):
    latitude.append(float(point['lat']))
    longitude.append(float(point['lon']))
    for param in point.children:
        if param.name == 'ele':
            elevation.append(float(param.string))

distance.append(0)
for i in range(1,len(latitude)):
    d = great_circle_distance(latitude[i-1], longitude[i-1],
                              latitude[i], longitude[i])
    distance.append(distance[i-1]+d)

print('Distance parcourue :', round(distance[-1]), 'm')

Félicitations, il semble que rien ne vous arrête ! Penchons-nous maintenant sur la gestion du temps afin d'enrichir notre script avec le calcul de la vitesse moyenne par exemple. On se donne rendez-vous au chapitre suivant dans quelques dixièmes de secondes...