直线与矩形相交的特例
Posted
技术标签:
【中文标题】直线与矩形相交的特例【英文标题】:A special case of intersection of line and rectrangle 【发布时间】:2019-07-23 13:32:00 【问题描述】:如何检查一条线是否与矩形相交经常被问到,例如How to know if a line intersects a rectangle。解决方案的基本思想是检查是否
矩形的四个线段中的任何一个都与这条线相交 这个矩形包含这条线的起点和终点但是这种方法无法处理特殊情况,这种情况在我的应用程序中不应被视为交集:
在这里,线通过角点,而整个 MBR 位于该线的一侧。那么,如何检查这种特殊情况呢?
【问题讨论】:
你不告诉我们这是否被认为是一个交叉路口。 这种情况不被视为交集@YvesDaoust 所以似乎足以将比较r < 0
和类似的更改为r<=0
等等以排除侧端。
【参考方案1】:
我设计了一个可行的解决方案来检查这种特殊情况。当整个 MBR 位于线的一侧时,会发生这种特殊情况。
我们需要一个辅助方法来获取一个点的位置:
# p is the query point, (a, b) is the line
def position(p, a, b):
return np.sign((b.x - a.x) * (p.y - a.y) - (p.x - a.x) * (b.y - a.y))
然后我们得到四个角的所有位置:
# left_bottom ... are corners
# (start, end) is the line
f = lambda m: position(m, start, end)
vf = np.vectorize(f)
positions = vf(np.array([left_bottom, right_bottom, left_top, right_top]))
特殊情况发生在位置之一等于0,并且所有位置都为-1或1时:
if len(np.where(positions == 0)) == 1 and abs(np.sum(positions)) == 3:
return False
【讨论】:
【参考方案2】:如果坐标表示为浮点实数,由于截断错误,线段在拐角处的精确重合很少且有些随机。人们可能想知道,担心这些“极端情况”有什么好处。
根据应用程序,处理退化的交叉点(即单点而不是线段)可能更尴尬而不是有用。
需要更多上下文才能以有意义的方式回答您的问题。
【讨论】:
【参考方案3】:为方便起见,我们假设表示为OP
的段从原点开始。 (如果没有,翻译所有点。)
线段OP
的一个点由向量表达式给出
t.P
t
在[0, 1]
中。
这样一个点在[X0, X1] x [Y0, Y1]
时属于封闭矩形
X0 ≤ Px.t ≤ X1
Y0 ≤ Py.t ≤ Y1
为了讨论这些不等式,我们必须根据Px
和Py
的符号来区分九种情况。
让我们处理两个肯定的情况。然后我们写
Py.X0 ≤ Px.Py.t ≤ Py.X1
Px.Y0 ≤ Px.Py.t ≤ Px.Y1
一起
0 ≤ Px.Py.t ≤ Px.Py
表示段的限制。
那么条件下的解集不为空
Max(Py.X0, Px.Y0, 0) ≤ Min(Py.X1, Px.Y1, Px.Py)
其他情况可以类似处理。计算成本是
6 initial subtractions
2 3-way sign tests
5 multiplications
5 comparisons
(当初始比较得出相等时,表达式会简化一点*并且成本更低)。
请注意,为了提高效率,此公式避免了除法。正如我在另一个答案中所说,<
与 ≤
的相关性是值得商榷的(可能用区间算术处理)。
*设Py=0
,那么我们把不等式写成
X0 ≤ Px.t ≤ X1
Y0 ≤ 0 ≤ Y1
0 ≤ Px.t ≤ Px
条件是
Max(X0, 0) ≤ Min(X1, Px) and Y0 ≤ 0 ≤ Y1.
显然,Px=Py=0
解决了
X0 ≤ 0 ≤ X1 and Y0 ≤ 0 ≤ Y1.
【讨论】:
以上是关于直线与矩形相交的特例的主要内容,如果未能解决你的问题,请参考以下文章
Save Money for Your Company 最小矩形覆盖(非计算几何)/找出N条直线相交点的边缘点/ find the dominating points of N lines
Save Money for Your Company 最小矩形覆盖(非计算几何)/找出N条直线相交点的边缘点/ find the dominating points of N lines