使用math.atan2计算线段之间的角度(Python) [英] Calculating angles between line segments (Python) with math.atan2

查看:715
本文介绍了使用math.atan2计算线段之间的角度(Python)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在研究空间分析问题,该工作流程的一部分是计算连接的线段之间的角度。

I am working on a spatial analysis problem and part of this workflow is to calculate the angle between connected line segments.

每个线段仅由两个点组成,并且每个点都有一对XY坐标(笛卡尔)。这是来自GeoGebra的图像。 我总是想获得0到180度范围内的正角。但是,根据输入线段中顶点的顺序,我得到各种角度。

Each line segment is composed of only two points, and each point has a pair of XY coordinates (Cartesian). Here is the image from GeoGebra. I am always interested in getting a positive angle in 0 to 180 range. However, I get all kind of angles depending on the order of vertices in input line segments.

我使用的输入数据以坐标元组形式提供。根据顶点的创建顺序,每个线段的最后一个端点可以不同。这是Python代码中的一些情况。我得到它们的线段的顺序是随机的,但是在一个元组的元组中,第一个元素是起点,第二个元素是终点。例如, DE 线段将具有(((1,1.5),(2,2))(1,1.5)是起点,因为它在坐标元组中具有第一个位置。

The input data I work with is provided as tuples of coordinates. Depending on the vertex creation order, the last/end point for each line segment can be different. Here are some of the cases in Python code. The order of line segments in which I get them is random, but in a tuple of tuples, the first element is the start point and the second one is the end point. DE line segment, for instance, would have ((1,1.5),(2,2)) and the (1,1.5) is the start point because it has the first position in the tuple of coordinates.

I但是需要确保我在 DE,DF ED,DF 之间得到相同的角度,依此类推。 / p>

I however need to make sure I will get the same angle between DE,DF and ED,DF and so forth.

vertexType = "same start point; order 1"
            #X, Y    X Y coords
lineA = ((1,1.5),(2,2)) #DE
lineB = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "same start point; order 2"
lineB = ((1,1.5),(2,2)) #DE
lineA = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)

vertexType = "same end point; order 1"
lineA = ((2,2),(1,1.5)) #ED
lineB = ((2.5,0.5),(1,1.5)) #FE
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "same end point; order 2"
lineB = ((2,2),(1,1.5)) #ED
lineA = ((2.5,0.5),(1,1.5)) #FE
calcAngle(lineA, lineB,vertexType)

vertexType = "one line after another - down; order 1"
lineA = ((2,2),(1,1.5)) #ED
lineB = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "one line after another - down; order 2"
lineB = ((2,2),(1,1.5)) #ED
lineA = ((1,1.5),(2.5,0.5)) #DF
calcAngle(lineA, lineB,vertexType)

vertexType = "one line after another - up; line order 1"
lineA = ((1,1.5),(2,2)) #DE
lineB = ((2.5,0.5),(1,1.5)) #FD
calcAngle(lineA, lineB,vertexType)
#flip lines order
vertexType = "one line after another - up; line order 2"
lineB = ((1,1.5),(2,2)) #DE
lineA = ((2.5,0.5),(1,1.5)) #FD
calcAngle(lineA, lineB,vertexType)

我写了一个小函数,将行的组合作为args并计算它们之间的角度。我正在使用 math.atan2 ,它似乎最适合于此。

I have written a tiny function that takes combinations of the lines as args and calculates the angle between them. I am using the math.atan2 which seemed to be best suited for this.

def calcAngle(lineA,lineB,vertexType):
    line1Y1 = lineA[0][1]
    line1X1 = lineA[0][0]
    line1Y2 = lineA[1][1]
    line1X2 = lineA[1][0]

    line2Y1 = lineB[0][1]
    line2X1 = lineB[0][0]
    line2Y2 = lineB[1][1]
    line2X2 = lineB[1][0]

    #calculate angle between pairs of lines
    angle1 = math.atan2(line1Y1-line1Y2,line1X1-line1X2)
    angle2 = math.atan2(line2Y1-line2Y2,line2X1-line2X2)
    angleDegrees = (angle1-angle2) * 360 / (2*math.pi)
    print angleDegrees, vertexType

输出I得到的是:

> -299.744881297 same start point; order 1
> 299.744881297 same start point; order 2
> 60.2551187031 same end point; order 1
> -60.2551187031 same end point; order 2
> -119.744881297 one line after another - down; order 1
> 119.744881297 one line after another - down; order 2
> -119.744881297 one line after another - up; line order 1
> 119.744881297 one line after another - up; line order 2

如您所见,我得到的值取决于a中顶点的顺序线段和线段顺序。我试图通过找出源线与线之间的关系,翻转线,编辑角度等方法来对角度进行后处理。我结束了许多此类情况,并在某些时候它们开始重叠,无法再找出-119.744应该变为60.255(锐角)还是保留为119.744(钝角)等。

As you can see, I am getting different values depending on the order of vertices in a line segment and line segments order. I have tried to post-process the angles by finding out what kind of relation the source line had and flipping the lines, editing the angle etc. I've ended with a dozen of such cases and at some point they start to overlap and I cannot any longer find out whether -119.744 should become 60.255 (acute angle) or be left as 119.744 (obtuse angle) etc.

是否有任何离散的方法可以处理我从 math.atan2 接收到的输出角度值,只得到0到180范围内的正值? 如果不是,还有其他什么类型

Is there any discrete way to process the output angle values I receive from math.atan2 to get only a positive value in 0 to 180 range? If not, what kind of other approach should I take?

推荐答案

解决此问题的最简单,最合乎逻辑的方法是使用点号-产品。

The easiest and most logically way to get at this problem is using the dot-product.

尝试以下代码(我几乎评论了所有内容):

Try this code (I've commented practically everything):

import math
def dot(vA, vB):
    return vA[0]*vB[0]+vA[1]*vB[1]
def ang(lineA, lineB):
    # Get nicer vector form
    vA = [(lineA[0][0]-lineA[1][0]), (lineA[0][1]-lineA[1][1])]
    vB = [(lineB[0][0]-lineB[1][0]), (lineB[0][1]-lineB[1][1])]
    # Get dot prod
    dot_prod = dot(vA, vB)
    # Get magnitudes
    magA = dot(vA, vA)**0.5
    magB = dot(vB, vB)**0.5
    # Get cosine value
    cos_ = dot_prod/magA/magB
    # Get angle in radians and then convert to degrees
    angle = math.acos(dot_prod/magB/magA)
    # Basically doing angle <- angle mod 360
    ang_deg = math.degrees(angle)%360

    if ang_deg-180>=0:
        # As in if statement
        return 360 - ang_deg
    else: 

        return ang_deg

现在尝试您的变化lineA和lineB的值都应该给出相同的答案。

Now try your variations of lineA and lineB and all should give the same answer.

这篇关于使用math.atan2计算线段之间的角度(Python)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆