计算两条无限线的2D截距点

时间:2018-12-15 23:41:20

标签: python math 2d

使用公式y = mx + b,我编写了以下代码来求解两条无限线的交点,而无需使用任何依赖项(例如numpy)。我特别希望实现一种无依赖解决方案。

不幸的是,在求解每行的Y截距时,它始终会返回错误的结果,因此,其后的所有结果都将是错误的。经过几天的努力之后,大约需要将它放到这里供其他人查看。

这些线由原点和倾斜方向的弧度定义。请注意,我故意删除了与Y轴平行的线(此类线没有坡度)和其他边缘的检查在此示例中可以提高可读性。

为进一步清晰起见,该代码使用长格式变量编写。我已经看过许多关于类似问题的问题,其他网站和答案几乎总是用数学符号编纂而成,假设您知道变量代表什么,或者假设操作者知道如何求解未知变量/平衡方程。我对这类事情了解甚少,我基本上不得不重新自学代数以尝试解决这个问题。我的目的是提供最大的清晰度,以便其他有此问题的人可以理解如何采用该公式并将其作为Python代码解决。

import math

origin_a = [0.9292893218813453, 0.07071]
origin_b = [3.121320343559643, 2.121320343559643]

radian_a = math.pi/4
radian_b = 2.748893571891069

X = 0
Y = 1
Z = 2


"""Returns Vector2 around a circle"""
def get_position_from_radian(radian, radius):
    rotated_pos = [0.0, 0.0, 0.0]
    rotated_pos[X] = math.cos(math.pi-radian) * radius
    rotated_pos[Y] = math.sin(math.pi-radian) * radius
    return(rotated_pos)


"""Returns Vector2"""
def get_slope_from_radian(radian):
    slope = (get_position_from_radian(radian, 1)) #Get a position along line to calculate slope from
    #We want slope to be scalar for simplicity, so we will divide Y by X and assume X=1
    slope = slope[Y] / slope[X]
    return(slope)


"""Returns Vector2 where two 2D rays intersect using y=mx+b (slope intercept)"""
def get_position_from_line_intersect_2d(origin_a, radian_a, origin_b, radian_b):
    #Slope is the 'm' in y=mx+b
    slope_a = get_slope_from_radian(radian_a)
    slope_b = get_slope_from_radian(radian_b)

    #Trig to find the slope of our lines. We assume length x=1 
    angle_a = math.pi - math.pi/2 - radian_a
    angle_b = math.pi - math.pi/2 - radian_b
    #We must determine if angle is + or - X
    if radian_a > math.pi:
        slope_a *= -1 
    if radian_b > math.pi:  
        slope_b *= -1
    print("SLOPE", slope_a, slope_b)

    #These represent the Y intercept
    intercept_y_a = origin_a[Y] + -(slope_a * origin_a[X])
    intercept_y_b = origin_b[Y] + -(slope_b * origin_b[X])
    print("Y INTERCEPT", intercept_y_a, intercept_y_b)

    #These represent the X intercept
    intercept_x_a = slope_a * intercept_y_a
    intercept_x_b = slope_b * intercept_y_b
    print("X INTERCEPT", intercept_x_a, intercept_x_b)

    #This is the position at which our two lines intersect
    intercept = [0.0, 0.0]
    intercept[X] = ((intercept_y_a*-1) + intercept_y_b) / (slope_a (slope_b*-1))
    intercept[Y] = ((intercept_x_a*-1) + intercept_x_b) / (slope_a (slope_b*-1))

    return(intercept)

print(get_position_from_line_intersect_2d(origin_a, radian_a, origin_b, radian_b))

2 个答案:

答案 0 :(得分:0)

这是我将从您的代码开始实施的方法

import math

origin_a = [0.9292893218813453, 0.07071]
origin_b = [3.121320343559643, 2.121320343559643]

radian_a = math.pi/4
radian_b = 2.748893571891069

X = 0
Y = 1
Z = 2

"""Returns Vector2 where two 2D rays intersect using y=mx+b (slope intercept)"""
def get_position_from_line_intersect_2d(origin_a, radian_a, origin_b, radian_b):
    #Slope is the 'm' in y=mx+b
    m1 = math.tan( radian_a) # get_slope_from_radian(radian_a)
    m2 = math.tan( radian_b) # get_slope_from_radian(radian_b)

    print("SLOPE", m1, m2)

    #These represent the Y intercept
    b1 = origin_a[Y] - (m1 * origin_a[X])
    b2 = origin_b[Y] - (m2 * origin_b[X])
    print("Y INTERCEPT", b1, b2)

    #This is the position at which our two lines intersect
    iX = (b2 - b1) / ( m1 - m2)
    iY = m1 * iX + b1

    return( iX, iY)

a,b = get_position_from_line_intersect_2d(origin_a, radian_a, origin_b, radian_b)

在您的实现中有几处地方尚不清楚:

  • 您为什么使用math.pi-radian而不是radian。如果这是您的预期行为,那么就我如何根据tan(pi - a) = -tan(a)
  • 定义它们而言,您可以仅使用-m1和-m2。
  • 无需检查大于pi的角度。斜率将始终定义为角度的切线
  • 您只需要求解y1= b1*x + m1, y2= b2*x + m2,然后求解y1=y2 --> x_intercept=(b2-b1)/(m1-m2),最后求解y_intercept = m1 *x_i +b1 = m2 *x_i + b2,就无需计算x = 0的截距

enter image description here

带有pi - rad定义的情况:

enter image description here

答案 1 :(得分:0)

有关“ 如何实现此”的答案,请查看我的第一个答案。 在这里,我将尝试从数学的角度解释为什么您的实现无法正常工作

首先检查
math.pi-radian 实际上是您的预期行为(等同于将所有角度定义为负)

def get_position_from_radian(radian, radius):
    rotated_pos = [0.0, 0.0, 0.0]
    rotated_pos[X] = math.cos(math.pi-radian) * radius
    rotated_pos[Y] = math.sin(math.pi-radian) * radius
    return(rotated_pos)

您还应该删除它。

if radian_a > math.pi:
    slope_a *= -1 
if radian_b > math.pi:  
    slope_b *= -1

获取斜率的正确方法是m = tan(angle) = sin(angle)/cos(angle)
为了简单起见,我们放b=0,现在让我们假设您有一个pi / 4角。您会得到m = sqrt(2)/2 > 0,这很不错,因为0 < angle < pi or pi < angle < 3/2 * pi将在绘图的第一部分和第三部分中定义一条线。
现在,让角度为pi + pi/4。这将为您提供与之前完全相同的线,并且切线仍将为您提供m = sqrt(2)/2 > 0,因为在第三部分中,cos和sin均为负。如果您因为angle>pi而将符号反转,那么实际上会得到错误的结果。

现在您正在做的是求解此方程组:

y = m1 * x + b1
y = m2 * x + b2

指向x_itercept = (b2-b1) / (m1-m2)
到目前为止,您的公式似乎是正确的(在实现中缺少+的地方)intercept[X] = ((intercept_y_a*-1) + intercept_y_b) / (slope_a (slope_b*-1))

当您尝试切换轴并对y截距使用完全相同的公式时,问题就开始了。
为此,我们需要对y(x) --> x(y)行的方程求逆(我们可以这样做,因为这是一个单调函数,每个x都有一个 distinct 值y。

x = (y - b1) / m1
x = (y - b2) / m2

让我们更改一些名称,使其以x =斜率* y + b的最常见形式出现

m' = 1/m
b' = -b/m
x = m1' * y + b1'
x = m2' * y + b2'

现在,我们可以像第一个系统一样完全求解该系统,并获得

y_intercept = (b2' - b1') / (m1' - m2')

公式的结构与您使用的结构相同,但是您可以看到其中的变量不同!!!!!!!
计算x轴直线的截距时,得到的b1'和b2'正确,但是仍然使用m1和m2作为斜率,而不是1 / m1和1 / m2