有向线段之间的符号角

2024-09-30 22:22:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个算法,需要计算出图中边之间的有符号角(-180到180)。我做了一些研究,找到了很多具体的答案,但却不知道如何将它们与我的情况联系起来(例如,使用atan2this问题,然而OP只想要正面的角度) 我尝试过几种不同的实现方法(使用atan2或arccos),但是我很难将这些示例与我的具体问题联系起来。我试过把边当作向量来处理,但是得到了奇怪的结果。在

给出一个有点(a,B,C,D,E)的图,以及这些点的平均值(avg)。。。如何找到其中一个点(如A)和其他点(如B、C、D、e)之间的有符号角,从当前原点(A)到“平均”点的角度等于0度。下面的例子。。。在

enter image description here

…在这个例子中,从(A,avg)到(A,B)的逆时针角度应该是正的(介于0和180之间),而从(A,avg)到(A,E)的角度应该是负的(介于0和-180之间)。在

理想情况下,我需要一个公式,我也可以应用它来定义任何一个点作为原点,例如以C点为原点。。“零角”为(C,avg),(C,avg)和(C,A)之间的角度为负(0到-180),(C,avg)和(C,E)之间的角度为正(0到180)。在

高中毕业后我还没学过数学,所以我发现很难用我不懂的符号来解方程式。在

更新:我想我会清理一下,让它更明显的结论是什么。 我对接受的答案做了两个小改动,得到了下面的片段:

def angle(vertex, start, dest):
    AhAB = math.atan2((dest.y - vertex.y), (dest.x - vertex.x))
    AhAO = math.atan2((start.y - vertex.y), (start.x - vertex.x))
    AB = AhAB - AhAO
    # in between 0-math.pi = do nothing, more than math.pi = +(-2 * math.pi), less than zero = do nothing
    AB = math.degrees(AB + (-2 * math.pi if AB > math.pi else (2 * math.pi if AB < 0 - math.pi else 0)))
    return AB

…在几个月没有处理这个问题之后,最后一个一行程序可能有点难以理解,所以我把它变成了它自己的函数,把AB = AhAB - AhAO的结果作为它的参数。。。在

^{pr2}$

我觉得读起来更清楚一点,虽然有更多的台词。在

最后的功能是:

def angle(vertex, start, dest):
    """Calculates the signed angle between two edges with the same origin. 
       Origin is the 'vertex' argument, 'start' is the bounding point of the edge to calculate the angle from.
       Positively signed result means anti-clockwise rotation about the vertex."""

    def calc_radians(ab):
        if ab > math.pi:
            return ab + (-2 * math.pi)
        else:
            if ab < 0 - math.pi:
                return ab + (2 * math.pi)
            else:
                return ab + 0

    AhAB = math.atan2((dest.y - vertex.y), (dest.x - vertex.x))
    AhAO = math.atan2((start.y - vertex.y), (start.x - vertex.x))

    res = calc_radians(AhAB - AhAO)

    return math.degrees(res)

注意:函数假设这三个参数都是一个典型的Point类的实例,该类具有x和{}属性。 另外,上面的示例图只有正值,但我相当肯定这也适用于包含负值的图形。在


Tags: thereturnabpimathstartdestavg
3条回答

我把你的问题陈述读了如下:给定2个点,一个中心点,求出两个向量之间的夹角,如果是逆时针的话,就是正的。在

如果我的前提是正确的,那么你可以

  • 求出A→B与穿过A的水平向右线之间的夹角
  • 求出A→O与穿过A的水平向右线之间的夹角
  • 求出角度AB作为所述角度的差
  • 规范化结果范围,使其介于-π和+π之间。在

我所说的可以想象如下

enter image description here 或者在代码中(假设一个Point类,具有xy属性)

AhAB = math.atan2((B.y-A.y), (B.x-A.x)) # -π < AhAB ≤ +π
AhAO = math.atan2((O.y-A.y), (O.x-A.x)) # -π < AhA) ≤ +π
AB = AhAB - AhAO                        # -2π < AB ≤ +2π
AB = AB + ( 2*math.pi if AB < math.pi else (-2*math.pi if AB> math.pi else 0))

附录

这里是一个小的代码示例,点的位置与您在图片中看到的类似

^{pr2}$

最后一行规范化结果AB在正确的范围-π < AB ≤ π,加上或减去{},这不会改变测量角度的意义。在

正负角的定义很大程度上取决于参考系或参考点。尽管它的定义是“正确的”,但基本的计算基本上可以根据两点之间的slope和由此产生的倾斜角来完成,该倾角可以通过对坡度应用tan来计算。在

在编程中应用inverse tan可能有点烦人,因为许多编程语言为此提供了两种不同的函数:

无论math模块或numpy包中的实现如何,这两个函数都会返回以弧度表示的计算角度,该角度基本上是基于数字Pi而不是度数,因此需要进行进一步的转换。这可以手动完成,也可以通过应用^{}这样的函数来完成。为了获得数据点的基本概念,并对计算结果进行一些眼花缭乱的估计,我建议使用matplotlib绘制数据点。在

将前面提到的所有注意事项粘在代码中可以如下所示:

import pandas as pd
import matplotlib
import numpy as np

%matplotlib inline
import matplotlib.pyplot as plt


# Define some sample data points
coords = {
'A': (1.5, 3.0),
'B': (3.0, 5.0),
'C': (5.5, 4.5),
'D': (5.8, 2.2),
'E': (2.8, 1.2)
}

# Extract data values from `coords` dict
values = np.array(list(coords.values()))

# Calculate the averaged point of all data points
avg = np.mean(values, axis=0)

# Plot sample data for better overview
for k, v in coords.items():
    plt.plot(*v, marker='o', linestyle='')
    plt.text(*v, k)
plt.plot(*avg, marker='o', linestyle='')
plt.text(*avg, 'avg')
plt.show()

# For further information about slope and angle of incline
# see Wikipedia (https://en.wikipedia.org/wiki/Slope).
# Calculating the angle from `avg` to each point. Please adopt
# to your own needs if needed for other pairs of points.

# Calculate the distance in x- and y-direction from each point to point `avg`
distances_x_y = (values - avg)

# Depending on your definition of the 'reference point' consider using
# distances_x_y = (avg - values)

# For further explanation on `atan` and `atan2` see
# https://stackoverflow.com/q/35749246/3991125 and
# https://en.wikipedia.org/wiki/Atan2 .
# Using a for loop instead of numpy's array/vectors is not very elegant,
# but easy to understand and therefore has potential for improvements.
# Calculate angle from point `avg` to each other point based on distances 
angle_radians = np.array([np.arctan2(element[1], element[0]) for element in distances_x_y])

# since `.arctan2()` or `.arctan()` return the angle in radians,
# we need to convert to degrees
angle_degrees = np.rad2deg(angle_radians)

# print results
print(angle_degrees)

如果考虑坐标x0=xavg-xAy0=yavg-yA和{},则公式f(x,y)给出正逆时针方向的有符号角。在

f(x,y)=pi()/2*((1+sign(x0))* (1-sign(y0^2))-(1+sign(x))* (1-sign(y^2)))

     +pi()/4*((2+sign(x0))*sign(y0)-(2+sign(x))*sign(y))

     +sign(x0*y0)*atan((abs(x0)-abs(y0))/(abs(x0)+abs(y0)))

    -sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))

相关问题 更多 >