【问题标题】:Determining if a point lies between two bearings from a central point确定一个点是否位于中心点的两个方位之间
【发布时间】:2020-04-29 12:04:14
【问题描述】:

我正在尝试确定一个点是否位于中心点的两个方位之间。

下图试图解释事情

  • 我有一个标记为 A 的中心点
  • 我有两个点(标记为 B 和 C)提供搜索区域的边界(仅基于方位 - 不需要距离元素)。
  • 我正在尝试确定 D 点是否在 A-B 和 A-C 形成的扇区内
  • 我已经计算了从 A 到每个 B 和 C 的方位
  • 在我的真实场景中,轴承之间创建的角度可以是 0 到 360 之间的任何值。

有一些similar questions & answers 但是在我的情况下,我对将搜索限制在圆的半径不感兴趣。而且似乎在角度大小和顺时针与逆时针方面的点位置方面存在一些实现问题

理论上看起来很简单,但我的数学显然达不到标准:(

任何建议或伪代码将不胜感激。

【问题讨论】:

  • 我应该在上图中指出,我正在考虑北 = 0 度的方位的映射上下文

标签: math geometry computational-geometry intersection


【解决方案1】:

这是我的方法:

  1. 计算第一个方位角 X
  2. 计算第二个方位角Y
  3. 计算朝向点 D 的角度 Z
  4. 如果 X

在您的示例中,您似乎要计算 Z ~ 90deg 并找到 45

您可以在任何您使用的语言中使用类似“atan2”的功能。这是基本反正切函数的扩展,它不仅采用斜率,还采用上升和运行,而不是仅返回 180 度范围内的角度,而是返回 360 度范围内的真实角度。所以

Z = atan2(Dy, Dx)

应该为您提供可以与您的方位进行比较的角度(可能以弧度为单位;小心),以判断您是否在搜索范围内。请注意,X 和 Y 的顺序很重要,因为顺序决定了搜索区域中两个部分中的哪一个(X 到 Y 在您的图片中给出了 ~90 度,但 Y 到 X 给出了 ~270 度)。

【讨论】:

  • 感谢@Patrick87,使用度数是有意义的。我来自映射背景,因此为什么我沿着我注意到 315 的方位路径走下去。我必须对你的方法进行的唯一修改是添加一些逻辑,说明角度 X 小于角度 Y。这是一个要点展示我的最终方法gist.github.com/rowanwins/3edee82cd2b1acc4cee125e9a014fe40
【解决方案2】:

您可以计算和比较向量 (AB X BD) 和 (AC X CD) 的叉积。

if (AB X BD) > 0,你有逆时针转
if (AC X CD) < 0,你有顺时针转
如果以上两个测试都为真,那么点 D 在扇区BAC

这使您可以完全避免使用昂贵的三角函数。

class Point:
    """small class for point arithmetic convenience
    """

    def __init__(self, x: float = 0, y: float = 0) -> None:
        self.x = x
        self.y = y

    def __sub__(self, other: 'Point') -> 'Vector':
        return Vector(self.x - other.x, self.y - other.y)


class Vector:
    """small class for vector arithmetic convenience
    """
    def __init__(self, x: float = 0, y: float = 0) -> None:
        self.x = x
        self.y = y

    def cross(self, other: 'Vector') -> float:
        return (self.x * other.y) - (self.y * other.x)


def in_sector(A: Point, B: Point, C: Point, D: Point) -> bool:

    # construct vectors:
    ab = B - A
    bd = D - B
    ac = C - A
    cd = D - C

    print(f'ab x bc = {ab.cross(bd)}, ac x cd = {ac.cross(cd)}')

    return ab.cross(bd) > 0 and ac.cross(cd) < 0


if __name__ == '__main__':

    A = Point(0, 0)
    B = Point(1, 1)
    C = Point(-1, 1)
    D = Point(0, 1)

print(f'D in sector ABC: {in_sector(A, B, C, D)}', end='\n\n')
print(f'D in sector ACB: {in_sector(A, C, B, D)}')  # inverting the sector definition so D is now outside

输出:

ab x bc = 1, ac x cd = -1
D in sector ABC: True

ab x bc = -1, ac x cd = 1
D in sector ACB: False

【讨论】:

  • 我试过这个来实现这种方法,但是我的结果似乎不正确,我不确定我是否误解了你的建议。这是我对我的实现提出的要点gist.github.com/rowanwins/f665fa7be671827e0def6d6d475d926a
  • 你是对的,我在测试@rowanwins 中发现了叉积倒置的迹象,谢谢!我修复了它并添加了一个 python 实现
猜你喜欢
  • 1970-01-01
  • 2012-07-20
  • 2012-08-08
  • 1970-01-01
  • 2020-02-03
  • 2017-06-26
  • 1970-01-01
  • 2023-03-08
  • 2014-10-20
相关资源
最近更新 更多