我们有一条光线从点A(X, Y)
开始,并在给定的点B(X, Y) != A
下永远持续下去。我们有一个由点K,L,M,N
定义的矩形,每个点都有(X, Y)
。
我想知道如何检测我们的光线是否与矩形的任何点相交(得到bool
,而不是精确坐标)?什么是计算这样的值的算法?
答案 0 :(得分:3)
让我直截了当。您有一个向导v
朝(b_x - a_x, b_y - a_y)
方向前进,从(a_x, a_y)
开始。
考虑向量w = (b_y - a_y, a_x - b_x)
。它与第一个成直角。 (使用点积进行验证。)因此,对于任何点(p_x, p_y)
,您可以通过(p_x - a_x, p_y - a_y)
和w
的点积来查看它所在的矢量的哪一侧并查看登录。
因此,将该点积与矩形的所有四个角一起使用。如果任何给出一个0点积,它们就在矢量上,如果符号改变就有一个交点,如果符号总是相同则没有交点。
答案 1 :(得分:0)
您可以使用扫描线算法来执行此操作。
答案 2 :(得分:0)
您可能想要计算与矩形相交的光线AB
的线段(如果有)。如果您的矩形是轴对齐的,那么从数字意义上来说这将更容易计算,但逻辑应该是相似的。
您可以将有向行L
表示为[a, b, c]
,以便点P
为(X, Y)
:
let L(P) = a*X + b*Y + c
then, if L(P) == 0, point P is on L
if L(P) > 0, point P is to the left of L
if L(P) < 0, point P is to the right of L
请注意,这是多余的,因为任何k > 0
,[k * a,k * b,k * c]代表同一行(此属性使其成为一个homogeneous coordinate system)。我们还可以通过用第三个坐标增加它们来表示具有齐次坐标的点:
2D point P = (X, Y)
-> homogeneous coordinates [x, y, w] for P are [X, Y, 1]
L(P) = L.a*P.x + L.b*P.y + L.c*P.w == a*X + b*Y + c*1
在任何情况下,如果给定矩形的两个角(例如P
和Q
),则可以通过P
和Q
计算直线的齐次坐标使用其齐次坐标的三维交叉积:
homogeneous coordinates for line PQ are: [P.X, P.Y, 1] cross [Q.X, Q.Y, 1]
-> PQ.a = P.Y - Q.Y
PQ.b = Q.X - P.X
PQ.c = P.X*Q.Y - Q.X*P.Y
您可以在数学上验证点P和Q都在上述PQ行上。
要表示与矩形相交的线AB
的线段,请先计算向量V = B - A
,如@ btilly的答案。对于齐次坐标,其工作原理如下:
A = [A.X, A.Y, 1]
B = [B.X, B.Y, 1]
-> V = B - A = [B.X-A.X, B.Y-A.Y, 0]
for any point C on AB: homogeneous coordinates for C = u*A + v*V
(where u and v are not both zero)
只有当C
和u
都是非负数时,点v
才会出现在该行的光线部分。 (与C = A + lambda * V
的通常表述相比,这种表示可能看起来模糊不清,但这样做可以避免不必要的除零情况......)
现在,我们可以计算光线交点:我们用每个端点的参数AB
坐标表示线[u,v]
的一部分:{ start = [start.u, start.v]; end = [end.u, end.v] }
。
我们以逆时针方向计算矩形的边缘,以便矩形内的点位于每条边的左侧/正侧(L(P)>0
)。
Starting segment is entire ray:
start.u = 1; start.v = 0
end.u = 0; end.v = 1
for each counterclockwise-directed edge L of the rectangle:
compute:
L(A) = L.a*A.X + L.b*A.Y + L.c
L(V) = L.a*V.X + L.b*V.Y
L(start) = start.u * L(A) + start.v * L(V)
L(end) = end.u * L(A) + end.v * L(V)
if L(start) and L(end) are both less than zero:
exit early: return "no intersection found"
if L(start) and L(end) are both greater or equal to zero:
do not update the segment; continue with the next line
else, if L(start) < 0:
update start coordinates:
start.u := L(V)
start.v := -L(A)
else, if L(end) < 0:
update end coordinates:
end.u := -L(V)
end.v := L(A)
on normal loop exit, the ray does intersect the rectangle;
the part of the ray inside the rectangle is the segment between points:
homog_start = start.u * A + start.v * V
homog_end = end.u * A + end.v * V
return "intersection found":
intersection_start.X = homog_start.x/homog_start.w
intersection_start.Y = homog_start.y/homog_start.w
intersection_end.X = homog_end.x/homog_end.w
intersection_end.Y = homog_end.y/homog_end.w
请注意,这适用于任意凸多边形,而不仅仅是矩形;以上实际上是一般的射线/凸多边形交叉算法。对于矩形,您可以展开for循环;并且,如果矩形是轴对齐的,则可以大大简化算法。但是,内部循环中的4个案例决策对于每个边缘应保持相同。
答案 3 :(得分:0)
一种不那么聪明但概念上更简单的方法:当且仅当它与至少一个边相交时,光线与矩形相交。因此,对于矩形的每一边,找到通过光束AB通过端点的线的交点(如果有的话);然后它只是一个范围检查,以确定该交叉点是否是矩形边界上的线段的一部分,或者它是否在外面。