web-dev-qa-db-fra.com

Calculer l'angle (dans le sens des aiguilles d'une montre) entre deux points

Je n'utilise plus les mathématiques depuis longtemps et cela devrait être un problème simple à résoudre.

Supposons que j'ai deux points A: (1, 0) et B: (1, -1).

Je veux utiliser un programme (Python ou autre langage de programmation) pour calculer l'angle dans le sens des aiguilles d'une montre entre A, Origine (0, 0) et B. Cela ressemblera à ceci:

angle_clockwise(point1, point2)

Notez que l'ordre des paramètres est important. Puisque le calcul de l'angle se fera dans le sens des aiguilles d'une montre:

  • Si j'appelle angle_clockwise (A, B), il retourne 45.
  • Si j'appelle angle_clockwise (B, A), il retourne 315.

En d'autres termes, l'algorithme est comme ceci:

  1. Tracez une ligne (ligne 1) entre le premier point param avec (0, 0).
  2. Tracez une ligne (ligne 2) entre le deuxième point param avec (0, 0).
  3. Faites pivoter la ligne 1 autour de (0, 0) dans le sens des aiguilles d'une montre jusqu'à ce qu'elle chevauche la ligne 2.
  4. La ligne de distance angulaire 1 parcourue sera l'angle retourné.

Est-il possible de coder ce problème?

13
Eric

Utilisez le produit interne et le déterminant des deux vecteurs. C’est vraiment ce que vous devez comprendre si vous voulez comprendre comment cela fonctionne. Vous aurez besoin de connaître/lire sur les mathématiques vectorielles pour comprendre.

Voir: https://en.wikipedia.org/wiki/Dot_product et https://en.wikipedia.org/wiki/Determinant

from math import acos
from math import sqrt
from math import pi

def length(v):
    return sqrt(v[0]**2+v[1]**2)
def dot_product(v,w):
   return v[0]*w[0]+v[1]*w[1]
def determinant(v,w):
   return v[0]*w[1]-v[1]*w[0]
def inner_angle(v,w):
   cosx=dot_product(v,w)/(length(v)*length(w))
   rad=acos(cosx) # in radians
   return rad*180/pi # returns degrees
def angle_clockwise(A, B):
    inner=inner_angle(A,B)
    det = determinant(A,B)
    if det<0: #this is a property of the det. If the det < 0 then B is clockwise of A
        return inner
    else: # if the det > 0 then A is immediately clockwise of B
        return 360-inner

Dans le calcul du déterminant, vous concaténez les deux vecteurs pour former une matrice 2 x 2, pour laquelle vous calculez le déterminant.

9
Chris St Pierre

Numpy's arctan2(y, x) calculera l'angle dans le sens contraire des aiguilles d'une montre (une valeur en radians comprise entre -π et π) entre l'origine et le point (x, y).

Vous pouvez le faire pour vos points A et B, puis soustrayez le deuxième angle du premier pour obtenir la différence angulaire signée signée. Cette différence sera comprise entre -2π et 2π. Pour obtenir un angle positif entre 0 et 2π, vous pouvez alors prendre le modulo contre 2π. Enfin, vous pouvez convertir des radians en degrés en utilisant np.rad2deg .

import numpy as np

def angle_between(p1, p2):
    ang1 = np.arctan2(*p1[::-1])
    ang2 = np.arctan2(*p2[::-1])
    return np.rad2deg((ang1 - ang2) % (2 * np.pi))

Par exemple:

A = (1, 0)
B = (1, -1)

print(angle_between(A, B))
# 45.

print(angle_between(B, A))
# 315.

Si vous ne voulez pas utiliser numpy, vous pouvez utiliser math.atan2 à la place de np.arctan2 et utiliser math.degrees (ou simplement multiplier par 180 / math.pi) pour convertir les radians en degrés. Un des avantages de la version numpy est que vous pouvez également passer deux tableaux (2, ...) pour p1 et p2 afin de calculer les angles entre plusieurs paires de points de manière vectorielle.

18
ali_m

Voici une solution qui ne nécessite pas cmath.

import math

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

v1 = Vector(0, 1)
v2 = Vector(0, -1)

v1_theta = math.atan2(v1.y, v1.x)
v2_theta = math.atan2(v2.y, v2.x)

r = (v2_theta - v1_theta) * (180.0 / math.pi)

if r < 0:
    r += 360.0

print r
5
Colin Basnett

Découvrez la bibliothèque cmath python.

>>> import cmath
>>> a_phase = cmath.phase(complex(1,0))
>>> b_phase = cmath.phase(complex(1,-1))
>>> (a_phase - b_phase) * 180 / cmath.pi
45.0
>>> (b_phase - a_phase) * 180 / cmath.pi
-45.0

Vous pouvez vérifier si un nombre est inférieur à 0 et ajouter 360 si vous voulez également tous les angles positifs.

1
awmo

Chris St Pierre: lorsque vous utilisez votre fonction avec:

A = (x=1, y=0)
B = (x=0, y=1)

Ceci est supposé être un angle de 90 degré de A à B. Votre fonction retournera 270.

Y a-t-il une erreur dans la façon dont vous traitez le signe du det ou est-ce que je manque quelque chose?

1
Antoine

Une formule qui calcule un angle dans le sens des aiguilles d'une montre et qui est utilisée pour l'arpentage:

f(E,N)=pi()-pi()/2*(1+sign(N))* (1-sign(E^2))-pi()/4*(2+sign(N))*sign(E)

     -sign(N*E)*atan((abs(N)-abs(E))/(abs(N)+abs(E)))

La formule donne des angles de 0 à 2pi, partant du nord et

travaille pour toute valeur deNetE. ( N = N2-N1 et E = E2-E1 )

Pour N = E = 0 le résultat est indéfini.

0
theodore panagos