How to calculate the angle between a line and the horizontal axis?
在编程语言(python、c_等)中,我需要确定如何计算直线和水平轴之间的角度?
我认为图片最能描述我想要的:
给定(p1x,p1y)和(p2x,p2y)计算此角度的最佳方法是什么?原点在左上角,仅使用正象限。
首先找出起点和终点之间的区别(这里,这更像是一条有向的线段,而不是一条"线",因为直线无限延伸,而不是从一个特定的点开始)。
1 2 | deltaY = P2_y - P1_y deltaX = P2_x - P1_x |
然后计算角度(从EDOCX1的正x轴(0)到EDOCX1的正y轴(0))。
1 | angleInDegrees = arctan(deltaY / deltaX) * 180 / PI |
但是
编辑(2017年2月22日):但是,一般来说,打电话给
编辑(2017年2月28日):即使没有规范化
deltaX 的符号将告诉您步骤3中描述的余弦是正的还是负的。deltaY 的符号将告诉您步骤4中描述的正弦是正的还是负的。deltaX 和deltaY 的符号将告诉您,相对于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日提供,他编辑了我的答案):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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
对不起,但我很确定彼得的回答是错的。请注意,Y轴沿页面向下移动(在图形中很常见)。因此,Deltay的计算必须颠倒,否则你会得到错误的答案。
考虑:
1 2 3 4 | 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))); |
给予
1 2 3 4 | 45.0 -45.0 135.0 -135.0 |
因此,如果在上面的例子中,p1是(1,1),p2是(2,2)[因为y在页面下方增加],上面的代码将给出所示例子的45.0度,这是错误的。更改Deltay计算的顺序,它可以正常工作。
考虑到这个确切的问题,把我们放在一个"特殊"的坐标系中,正轴意味着向下移动(如屏幕或界面视图),您需要像这样调整这个函数,而Y坐标则为负:
Swift 2.0中的示例
1 2 3 4 5 6 7 8 9 | 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 } |
此函数给出了问题的正确答案。答案是以弧度表示的,所以用度数表示角度的用法是:
1 2 3 4 5 | 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 |
我在python中找到了一个运行良好的解决方案!
1 2 3 4 5 6 | from math import atan2,degrees def GetAngleOfLineBetweenTwoPoints(p1, p2): return degrees(atan2(p2 - p1, 1)) print GetAngleOfLineBetweenTwoPoints(1,3) |
从0到2pi的角度的公式。
有x=x2-x1和y=y2-y1。公式适用于
x和y的任何值。对于x=y=0,结果未定义。
f(x,y)=pi()-pi()/2*(1+符号(x))*(1-符号(y^2))
1 2 3 | -pi()/4*(2+sign(x))*sign(y) -sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y))) |
matlab函数:
1 2 3 4 5 6 7 8 9 10 | 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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; |
基于参考文献"Peter O"…这里是Java版本
1 2 3 4 | 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)); } |