python - 有向线段之间的符号角

标签 python angle

我有一个算法,需要计算出图中边之间的有符号角度(-180 到 180)。我做了一些研究并找到了很多具体的答案,但无法弄清楚如何将它们与我的情况联系起来(例如 this 使用 atan2 的问题,但是OP只想要正角度) 我尝试过实现几种不同的方法(使用atan2或arccos),但我很难将这些示例与我的具体问题联系起来。我尝试将边缘视为向量,但得到了奇怪的结果。

给定一个包含点(A、B、C、D、E)的图表,以及这些点的平均值(avg)...我如何找到其中一个点(例如 A)和其他点(例如 B、C、D、E),将当前原点 (A) 到“avg”点的角度设为 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 的结果。正如它的论点...

def calc(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

我认为这更容易阅读,尽管行数更多。

完整的最终功能:

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 一起上课和y属性。 另外,上面的示例图只有正值,但我相当确定这也适用于涉及负值的图。

最佳答案

我读了你的问题陈述如下:给定 2 个点 AB,以及一个中心 O,找到角度 AB 作为向量 A→OA→B 之间的角度,如果逆时针,则为正。

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

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

附录

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

In [18]: from math import atan2, pi
In [21]: class Point():
    ...:     def __init__(self, x, y):
    ...:         self.x, self.y = x, y
    ...:     def __repr__(self):
    ...:         return '(%s, %s)'%(self.x, self.y)
In [22]: A = Point(0.0, 0.0)
In [23]: B = Point(-2.0, 2.0)
In [24]: O = Point(0.0, -3.0)
In [25]: AhAB = atan2((B.y-A.y), (B.x-A.x)) ; print(3/4, AhAB/pi)
0.75 0.75
In [26]: AhAO = atan2((O.y-A.y), (O.x-A.x)) ; print(-1/2, AhAO/pi)
-0.5 -0.5
In [27]: AB = AhAB - AhAO ; print(5/4, AB/pi)
1.25 1.25
In [28]: AB = AB + ( 2*pi if AB < pi else (-2*pi if AB> pi else 0)) ; print(AB/pi)
-0.75
In [29]: 

最后一行标准化你的结果 AB在正确的范围内-π < AB ≤ π ,加或减这不会改变测量角度的含义。

关于python - 有向线段之间的符号角,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52571812/

相关文章:

Python ctypes 回调函数给出 "TypeError: invalid result type for callback function"

python - 识别 pandas 中由多列组成的组中的第一个非零元素

Javascript Canvas 如何从旋转物体进行 360* 拍摄

javascript - 将 CSS Matrix3d 变换转换为欧拉 Angular

Java Math.cos(Math.toRadians(<angle>)) 返回奇怪的值

python - 为什么我不能迭代通过 __getattr__ 委托(delegate)给可迭代对象的对象?

python - 类型错误 : Positional Arguments with pandas. 适用

python - 如何修复不起作用的 Python Try/Except 语句

将度数转换为弧度时,Swift-Binary 运算符不能应用于操作数

android - 在android中以一定角度绘制图像