如何计算一条线和横轴之间的angular度?

在编程语言(Python,C#等)中,我需要确定如何计算一条线和水平轴之间的angular度?

我认为一个图像描述最好的我想要的:

没有词可以描述这一点

给定(P1 x ,P1 y )和(P2 x ,P2 y )什么是计算这个angular度的最好方法? 起源在前面,只有正象限被使用。

首先find起点和终点之间的区别(在这里,更多的是有向线段,而不是“线”,因为线无限延伸而不是从特定点开始)。

deltaY = P2_y - P1_y deltaX = P2_x - P1_x 

然后计算angular度(从P1的正X轴到P1的正Y轴)。

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

但是arctan可能并不理想,因为通过这种方式来区分差异将会消除区分angular度所在的angular度所需的区别(见下文)。 如果您的语言包含atan2函数,请使用以下代码:

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

编辑(2017年2月22日):但是,一般来说,调用atan2(deltaY,deltaX)只是为了得到cossin的正确的angular度可能是不够的。 在这些情况下,您可以经常执行以下操作:

  1. (deltaX, deltaY)当作一个向量。
  2. 将该vector归一化为单位vector。 为此,除非长度为0,否则将deltaXdeltaY除以向量的长度( sqrt(deltaX*deltaX+deltaY*deltaY) )。
  3. 之后, deltaX现在是vector与水平轴之间angular度的余弦(在P1处从正X轴到正Y轴的方向)。
  4. 现在, deltaY将成为这个angular度的正弦。
  5. 如果vector的长度为0,那么它和横轴之间就没有angular度(所以它不会有一个有意义的正弦和余弦)。

编辑(2017年2月28日):即使没有正常化(deltaX, deltaY)

  • deltaX的符号会告诉你步骤3中描述的余弦是正数还是负数。
  • deltaY的符号会告诉你在步骤4中描述的正弦是正的还是负的。
  • deltaXdeltaY会告诉你哪个angular度所在的象限,相对于P1处的正X轴:
    • +deltaX+deltaY :0到90度。
    • -deltaX+deltaY :90至180度。
    • -deltaX-deltaY :180至270度(-180至-90度)。
    • +deltaX-deltaY :270到360度(-90到0度)。

Python中使用弧度的实现(由Eric Leschinski编辑我的答案于2015年7月19日提供):

 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) 

所有testing通过。 请参阅https://en.wikipedia.org/wiki/Unit_circle

对不起,但我很肯定彼得的答案是错的。 请注意,y轴向下(在graphics中常见)。 因此,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计算的顺序,并正常工作。

我find了一个很好的Python解决scheme!

 from math import atan2,degrees def GetAngleOfLineBetweenTwoPoints(p1, p2): return degrees(atan2(p2 - p1, 1)) print GetAngleOfLineBetweenTwoPoints(1,3) 

考虑到确切的问题,把我们放在一个“特殊的”坐标系中,其中正轴意味着向下移动(如屏幕或界面视图),您需要像这样调整这个函数,并且减去Y坐标:

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 } 

这个函数给出了一个正确的答案。 答案是弧度,所以用度来度量angular度的用法是:

 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 

基于参考“彼得O”..这里是Java版本

 private static final float angleBetweenPoints(PointF a, PointF b) { float deltaY = by - ay; float deltaX = bx - ax; return (float) (Math.atan2(deltaY, deltaX)); } 
 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; 

matlabfunction:

 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