[英]Calculate angle (clockwise) between two points
我已經很長時間沒有使用數學了,這應該是一個很容易解決的問題。
假設我有兩個點 A: (1, 0) 和 B: (1, -1)。
我想使用一個程序(Python 或任何編程語言)來計算 A、原點 (0, 0) 和 B 之間的順時針角度。它會是這樣的:
angle_clockwise(point1, point2)
請注意,參數的順序很重要。 由於角度計算將是順時針的:
換句話說,算法是這樣的:
有什么辦法可以解決這個問題嗎?
Numpy 的arctan2(y, x)
將計算原點和點(x, y)
之間的逆時針角度(-π 和 π 之間的弧度值(x, y)
。
您可以為點A
和B
執行此操作,然后從第一個角度減去第二個角度以獲得帶符號的順時針角度差。 這種差異將在 -2π 和 2π 之間,因此為了獲得 0 和 2π 之間的正角,您可以對 2π 取模。 最后,您可以使用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))
例如:
A = (1, 0)
B = (1, -1)
print(angle_between(A, B))
# 45.
print(angle_between(B, A))
# 315.
如果您不想使用 numpy,則可以使用math.atan2
代替np.arctan2
,並使用math.degrees
(或僅乘以180 / math.pi
)以將弧度轉換為度數。 numpy 版本的一個優點是您還可以為p1
和p2
傳遞兩個(2, ...)
數組,以便以矢量化方式計算多對點之間的角度。
使用兩個向量的內積和行列式。 如果您想了解其工作原理,這確實是您應該了解的內容。 您需要了解/閱讀矢量數學才能理解。
請參閱: https : //en.wikipedia.org/wiki/Dot_product和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
在行列式計算中,您將兩個向量連接起來形成一個 2 x 2 矩陣,您正在為其計算行列式。
這是一個不需要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
經過驗證的 0° 到 360° 解決方案
這是一個舊線程,但對我來說其他解決方案效果不佳,所以我實現了自己的版本。
我的函數將返回屏幕上兩點的 0 到 360(不包括 360)之間的數字(即“y”從頂部開始並向底部增加),其中結果就像指南針一樣,頂部為 0°,順時針增加:
def angle_between_points(p1, p2):
d1 = p2[0] - p1[0]
d2 = p2[1] - p1[1]
if d1 == 0:
if d2 == 0: # same points?
deg = 0
else:
deg = 0 if p1[1] > p2[1] else 180
elif d2 == 0:
deg = 90 if p1[0] < p2[0] else 270
else:
deg = math.atan(d2 / d1) / pi * 180
lowering = p1[1] < p2[1]
if (lowering and deg < 0) or (not lowering and deg > 0):
deg += 270
else:
deg += 90
return deg
查看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
如果您想要所有正角度,您也可以檢查數字是否小於 0 並添加 360。
Chris St Pierre:將您的函數用於:
A = (x=1, y=0)
B = (x=0, y=1)
這應該是從A
到B
的90
度角。 您的函數將返回270
。
您處理 det 符號的方式是否有錯誤,或者我是否遺漏了什么?
以弧度為單位,順時針,從 0 到 PI * 2
static angle(center:Coord, p1:Coord, p2:Coord) {
var a1 = Math.atan2(p1.y - center.y, p1.x - center.x);
var a2 = Math.atan2(p2.y - center.y, p2.x -center.x);
a1 = a1 > 0 ? a1 : Math.PI * 2 + a1;//make angle from 0 to PI * 2
a2 = a2 > 0 ? a2 : Math.PI * 2 + a2;
if(a1 > a2) {
return a1 - a2;
} else {
return Math.PI * 2 - (a2 - a1)
}
}
順時針計算角度的公式,用於測量:
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)))
該公式給出了從 0 到 2pi 的角度,從北開始,然后
正在為N和E 的任何值工作。 ( N=N2-N1 和 E=E2-E1 )
對於N=E=0 ,結果未定義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.