2011-09-28 63 views
236

Trong ngôn ngữ lập trình (Python, C#, v.v ...) tôi cần xác định cách tính góc giữa đường kẻ và trục ngang?Cách tính góc giữa một đường thẳng và trục ngang?

Tôi nghĩ rằng một hình ảnh mô tả tốt nhất những gì tôi muốn:

no words can describe this

Given (P1 x, P1 y) và (P2 x, P2 y) là những gì cách tốt nhất để tính toán góc này? Nguồn gốc nằm ở phía trước và chỉ có góc phần tư dương được sử dụng.

Trả lời

376

Đầu tiên tìm sự khác biệt giữa điểm bắt đầu và điểm kết thúc (ở đây, đây là phân đoạn đường dẫn chứ không phải là "dòng", vì các dòng mở rộng vô hạn và không bắt đầu tại một điểm cụ thể).

deltaY = P2_y - P1_y 
deltaX = P2_x - P1_x 

Sau đó tính toán góc (mà chạy từ trục X tích cực tại P1 với trục Y tích cực tại P1).

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

Nhưng arctan có thể không lý tưởng, bởi vì cách chia khác biệt theo cách này sẽ xóa sự phân biệt cần thiết để phân biệt mà Quadrant góc là trong (xem dưới đây). Sử dụng sau đây thay vì nếu ngôn ngữ của bạn bao gồm một atan2 chức năng:

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

EDIT (22 Tháng Hai 2017): Nói chung, tuy nhiên, gọi atan2(deltaY,deltaX) chỉ để có được một góc thích hợp cho cossin có thể thanh nha. Trong những trường hợp đó, bạn có thể thực hiện những việc sau thay thế:

  1. Điều trị (deltaX, deltaY) làm vector.
  2. Bình thường hóa vectơ đó thành vectơ đơn vị. Để làm như vậy, hãy chia deltaXdeltaY theo chiều dài của vectơ (sqrt(deltaX*deltaX+deltaY*deltaY)), trừ khi độ dài là 0,
  3. Sau đó, deltaX bây giờ sẽ là cosin của góc giữa vectơ và trục hoành (theo hướng từ tích cực X đến trục Y dương tại P1).
  4. deltaY giờ sẽ là sin của góc đó.
  5. Nếu chiều dài của vectơ là 0, nó sẽ không có một góc giữa nó và trục hoành (vì vậy nó sẽ không có sin và cosin có ý nghĩa).

EDIT (28 tháng 2 năm 2017): Mặc dù không bình thường (deltaX, deltaY):

  • Các dấu hiệu của deltaX sẽ cho bạn biết cosin mô tả trong bước 3 là tích cực hay tiêu cực.
  • Dấu hiệu của deltaY sẽ cho bạn biết liệu sin được mô tả trong bước 4 là dương hay âm.
  • Các dấu hiệu của deltaXdeltaY sẽ cho bạn biết Quadrant góc trong, liên quan đến trục X tích cực tại P1:
    • +deltaX, +deltaY: 0 đến 90 độ.
    • -deltaX, +deltaY: 90 đến 180 độ.
    • -deltaX, -deltaY: 180 đến 270 độ (-180 đến -90 độ).
    • +deltaX, -deltaY: 270 đến 360 độ (-90 đến 0 độ).

An thực hiện bằng Python sử dụng radian (được cung cấp trên 19 tháng 7 năm 2015 bởi Eric Leschinski, người sửa câu trả lời của tôi):

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) 

Tất cả các bài kiểm tra qua. Xem https://en.wikipedia.org/wiki/Unit_circle

+31

Nếu bạn thấy điều này và bạn đang sử dụng JavaScript nó là rất quan trọng đối với lưu ý rằng Math.sin và Toán.cos lấy radian để bạn không cần phải chuyển đổi kết quả thành độ! Vì vậy, bỏ qua * 180/PI bit. Tôi mất 4 giờ để tìm ra điều đó. :) – sidonaldson

+0

Điều gì sẽ được sử dụng để tính toán góc dọc theo trục thẳng đứng? – ZeMoon

+3

@akashg: '90 - angleInDegrees'? – jbaums

47

Xin lỗi, nhưng tôi chắc rằng câu trả lời của Peter là sai. Lưu ý rằng trục y đi xuống trang (phổ biến trong đồ họa). Như vậy tính toán deltaY phải được đảo ngược, hoặc bạn nhận được câu trả lời sai.

xem xét:

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))); 

cho

45.0 
-45.0 
135.0 
-135.0 

Vì vậy, nếu trong ví dụ trên, P1 là (1,1) và P2 là (2,2) [vì Y tăng xuống trang ], mã ở trên sẽ cho 45.0 độ cho ví dụ được hiển thị, điều này là sai. Thay đổi thứ tự của phép tính deltaY và nó hoạt động đúng.

+3

Tôi đảo ngược nó như bạn đã đề xuất và vòng xoay của tôi đã bị lùi. –

+8

Sẽ tốt nếu bạn có thể hiển thị đúng cách. –

+1

Trong mã của tôi, tôi sửa lỗi này với: 'double arc = Math.atan2 (mouse.y - obj.getPy(), mouse.x - obj.getPx()); \t \t degrees = Math.toDegrees (arc); \t \t nếu (độ <0) \t \t \t độ + = 360; \t \t khác nếu (độ> 360) \t \t \t độ - = 360; ' –

1

Tôi đã tìm thấy một giải pháp bằng Python hoạt động tốt!

from math import atan2,degrees 

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

print GetAngleOfLineBetweenTwoPoints(1,3) 
0

Dựa trên tài liệu tham khảo "Peter O" .. Dưới đây là phiên bản 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

Xét câu hỏi chính xác, đặt chúng trong một "đặc biệt" phối hệ thống nơi trục dương tính có nghĩa là di chuyển XUỐNG (như một màn hình hoặc một cái nhìn giao diện), bạn cần phải thích nghi với chức năng này như thế này, và tiêu cực được toạ độ Y:

Ví dụ trong Swift 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 
} 

Chức năng này cung cấp câu trả lời đúng cho câu hỏi. Câu trả lời là trong radian, vì vậy việc sử dụng, để xem góc theo độ, là:

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 chức năng:

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 
Các vấn đề liên quan