2011-09-28 176 views
236

在編程語言(Python,C#等)中,我需要確定如何計算線條與橫軸之間的角度?如何計算直線和橫軸之間的角度?

我認爲圖像描述了最好的,我想:

no words can describe this

鑑於(P1 X,P1 ÿ)和(P2 X,P2 ÿ)是什麼計算這個角度的最好方法?起源在前面,只有正象限被使用。

回答

376

首先找到起點和終點之間的差異(這裏,這是更多的有向線段,而不是「線」,因爲線無限延伸並且不在特定點開始)。

deltaY = P2_y - P1_y 
deltaX = P2_x - P1_x 

然後計算角度(從X軸正方向在P1到正Y軸在P1運行)。

angleInDegrees = arctan(deltaY/deltaX) * 180/PI 

但是arctan可能不是理想的,因爲將所述差異這種方式將擦除區分哪個象限的角度所需的區別是在(見下文)。改用如果你的語言包括atan2功能如下:

angleInDegrees = atan2(deltaY, deltaX) * 180/PI 

EDIT(2017年2月22日):在一般情況下,然而,呼籲atan2(deltaY,deltaX)只是爲了得到正確的角度cossin可能是不雅。在這些情況下,您可以經常執行以下操作:

  1. (deltaX, deltaY)作爲向量。
  2. 將該矢量標準化爲單位矢量。爲了這樣做,由向量的長度(sqrt(deltaX*deltaX+deltaY*deltaY))劃分deltaXdeltaY,除非長度爲0
  3. 之後,deltaX現在將是矢量和水平軸之間的角度的餘弦(從方向正數X到正數Y軸,位於P1)。
  4. deltaY現在將是該角度的正弦。
  5. 如果矢量的長度爲0,則它​​與橫軸之間不存在角度(所以它不會有有意義的正弦和餘弦)。

EDIT(2017年2月28日):即使沒有正常化(deltaX, deltaY)

  • deltaX符號會告訴你在步驟3中描述的餘弦值是正還是負。
  • deltaY的符號會告訴您步驟4中描述的正弦是正值還是負值。
  • deltaXdeltaY跡象會告訴你哪個象限的角度在,相對於正X軸在P1
    • +deltaX+deltaY:0至90度。
    • -deltaX,+deltaY:90到180度。
    • -deltaX,-deltaY:180至270度(-180至-90度)。
    • +deltaX,-deltaY:270至360度(-90至0度)。

使用弧度(由Eric Leschinski,誰編輯我的答案提供了2015年7月19日)在Python的實現:

from math import * 
def angle_trunc(a): 
    while a < 0.0: 
     a += pi * 2 
    return a 

def getAngleBetweenPoints(x_orig, y_orig, x_landmark, y_landmark): 
    deltaY = y_landmark - y_orig 
    deltaX = x_landmark - x_orig 
    return angle_trunc(atan2(deltaY, deltaX)) 

angle = getAngleBetweenPoints(5, 2, 1,4) 
assert angle >= 0, "angle must be >= 0" 
angle = getAngleBetweenPoints(1, 1, 2, 1) 
assert angle == 0, "expecting angle to be 0" 
angle = getAngleBetweenPoints(2, 1, 1, 1) 
assert abs(pi - angle) <= 0.01, "expecting angle to be pi, it is: " + str(angle) 
angle = getAngleBetweenPoints(2, 1, 2, 3) 
assert abs(angle - pi/2) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle) 
angle = getAngleBetweenPoints(2, 1, 2, 0) 
assert abs(angle - (pi+pi/2)) <= 0.01, "expecting angle to be pi+pi/2, it is: " + str(angle) 
angle = getAngleBetweenPoints(1, 1, 2, 2) 
assert abs(angle - (pi/4)) <= 0.01, "expecting angle to be pi/4, it is: " + str(angle) 
angle = getAngleBetweenPoints(-1, -1, -2, -2) 
assert abs(angle - (pi+pi/4)) <= 0.01, "expecting angle to be pi+pi/4, it is: " + str(angle) 
angle = getAngleBetweenPoints(-1, -1, -1, 2) 
assert abs(angle - (pi/2)) <= 0.01, "expecting angle to be pi/2, it is: " + str(angle) 

通過了所有測試。見https://en.wikipedia.org/wiki/Unit_circle

+31

如果您發現了這一點,你是通過JavaScript這是非常重要的注意Math.sin和Math。cos採用弧度,因此您無需將結果轉換爲度數!所以忽略* 180/PI位。 花了我4個小時才發現。 :) – sidonaldson

+0

應該用什麼來計算沿垂直軸的角度? – ZeMoon

+3

@akashg:'90 - angleInDegrees'? – jbaums

47

對不起,但我很確定彼得的答案是錯誤的。請注意,y軸沿頁面向下(在圖形中常見)。因此,deltaY計算必須顛倒過來,否則你會得到錯誤的答案。

考慮:

System.out.println (Math.toDegrees(Math.atan2(1,1))); 
System.out.println (Math.toDegrees(Math.atan2(-1,1))); 
System.out.println (Math.toDegrees(Math.atan2(1,-1))); 
System.out.println (Math.toDegrees(Math.atan2(-1,-1))); 

給出

45.0 
-45.0 
135.0 
-135.0 

因此,如果在上述示例中,P1是(1,1),P2爲(2,2)[由於對Y增加了網頁],上面的代碼將給出45.0度的示例,這是錯誤的。更改deltaY計算的順序,它可以正常工作。

+3

我按照你的建議反轉了它,並且我的旋轉反向。 –

+8

如果您能夠以正確的方式顯示,那會很好。 –

+1

在我的代碼中我修復了這個問題: 'double arc = Math.atan2(mouse.y - obj.getPy(),mouse.x - obj.getPx()); \t \t degrees = Math.toDegrees(arc); \t \t if(degrees <0) \t \t \t degrees + = 360; \t \t else if(度數> 360) \t \t \t degree - = 360; ' –

1

我發現了一個運行良好的Python解決方案!

from math import atan2,degrees 

def GetAngleOfLineBetweenTwoPoints(p1, p2): 
    return degrees(atan2(p2 - p1, 1)) 

print GetAngleOfLineBetweenTwoPoints(1,3) 
0

基於參考「彼得·」。這裏是java版本

private static final float angleBetweenPoints(PointF a, PointF b) { 
float deltaY = b.y - a.y; 
float deltaX = b.x - a.x; 
return (float) (Math.atan2(deltaY, deltaX)); } 
1

考慮確切的問題,把我們在一個「特殊」的地方正軸指向下移動座標系(如的屏幕或接口視圖),則需要適應這樣的這個功能,和負的Y座標:

實施例中夫特2.0

func angle_between_two_points(pa:CGPoint,pb:CGPoint)->Double{ 
    let deltaY:Double = (Double(-pb.y) - Double(-pa.y)) 
    let deltaX:Double = (Double(pb.x) - Double(pa.x)) 
    var a = atan2(deltaY,deltaX) 
    while a < 0.0 { 
     a = a + M_PI*2 
    } 
    return a 
} 

此功能給出了正確的答案。答案是弧度,這樣的使用情況,以度視角,方法是:

let p1 = CGPoint(x: 1.5, y: 2) //estimated coords of p1 in question 
let p2 = CGPoint(x: 2, y : 3) //estimated coords of p2 in question 

print(angle_between_two_points(p1, pb: p2)/(M_PI/180)) 
//returns 296.56 
0
deltaY = Math.Abs(P2.y - P1.y); 
deltaX = Math.Abs(P2.x - P1.x); 

angleInDegrees = Math.atan2(deltaY, deltaX) * 180/PI 

if(p2.y > p1.y) // Second point is lower than first, angle goes down (180-360) 
{ 
    if(p2.x < p1.x)//Second point is to the left of first (180-270) 
    angleInDegrees += 180; 
    else (270-360) 
    angleInDegrees += 270; 
} 
else if (p2.x < p1.x) //Second point is top left of first (90-180) 
    angleInDegrees += 90; 
0

matlab函數:

function [lineAngle] = getLineAngle(x1, y1, x2, y2) 
    deltaY = y2 - y1; 
    deltaX = x2 - x1; 

    lineAngle = rad2deg(atan2(deltaY, deltaX)); 

    if deltaY < 0 
     lineAngle = lineAngle + 360; 
    end 
end 
相關問題