点定位(四):处理退化情况)
1. 退化情况
在前面几节,我们讲解了如何对梯形图和搜索结构进行拆解和更新,但是我们对输入做出了不少限制(即不允许退化情况),这一节我们就把关注点放在各种退化情况的处理上。总的来说,笔者总结的退化情况一共有三种:
- 输入线段端点发生重合,即有两条线段首尾或尾首相咬合;
- 有两个或数个端点的X坐标相同,即它们处于同一条垂直线上;
- 有线段端点在其他线段上;
它们的可视化结构依次如下:
第一种退化情况,我们已经在前几节已经详细讨论过了,所以这一节我们把重心放在后面两种退化情况上,通过完善这两种情况,我们的点定位算法将拥有处理所有退化情况的能力,并为后面Voronoi图高效进行空间查找铺平了道路。
2. 思路分析
2.1 倾斜变换
其实,处理第二和第三种退化情况的思路非常的简单直观:
将原本处于同一条垂直线上的端点变成不在同一条垂直线上。
比如下图展示的情况:
这个思路说起来简单,但是做起来可不简单,因为我们究竟如何去实现这个“倾斜”操作呢?根据教材上面的描述1,一共有两种方法:
- 将原图形进行旋转变换(Rotation Transformation);
- 对原图形进行斜切变换(Shear Transformation);
第一种方法不难理解,比如下图中的矩形输入(由四条线段组成):
这种方法虽然直观,但是会引入一个非常麻烦的问题:计算精度问题,也就是说我们需要极高的精度才能处理这种变换,所以显然这种方法是不太可靠的,计算机不可能提供无限精度的浮点数。那第二种方法是什么意思呢?其实也不难,下图展示了一个输入案例经过斜切处理后的结果1:
到这里可能有童鞋会问:应用这种变换不也会产生精度问题么?真的这样做确实会产生精度问题,但问题是实际计算当中我们没有必要真的应用斜切变换,我们只需要“假想应用了斜切变换”,这是什么意思呢?接下来我们就来看看如何应用对偶数的结构来巧妙“实现”斜切变换,但又不会产生计算精度问题。
2.2 真假斜切变换
假如斜切的偏移量为ε(ε > 0),偏移对象为x坐标,那么我们可以写出原来坐标值和发生斜切以后的坐标值1:
φ
:
(
x
y
)
⇒
(
x
+
ε
y
y
)
\varphi : \begin{pmatrix} x \\ y \\ \end{pmatrix} \Rightarrow \begin{pmatrix} x + \varepsilon y \\ y \\ \end{pmatrix}
φ:(xy)⇒(x+εyy)
但我们不需要真的去计算变换后的x坐标:x + εy。为什么呢?大家可以思考一下,我们需要在什么情况下,才真正需要斜切以后的坐标值呢?是的,只有当两个端点的x坐标相等的情况,我们才需要变换后的坐标,那么我们可以得到如下结论:
设任意两个端点坐标
P
1
(
x
1
,
y
1
)
,
P
2
(
x
2
,
y
2
)
,
(
1
)
如果
x
1
≠
x
2
,则我们正常比较
x
坐标的大小即可,即
x
1
>
x
2
,
P
1
在
P
2
的右边,反之在左边。
(
2
)
如果
x
1
=
x
2
,且
y
1
≠
y
2
,我们则比较
y
坐标的大小,即
y
1
>
y
2
,
P
1
在
P
2
的右边,反之在左边。
(
3
)
如果
x
1
=
x
2
,且
y
1
=
y
2
,则两端点重合,第二种退化情况退化为第一种退化情况。
设任意两个端点坐标P_{1}(x_{1}, y_{1}),P_{2}(x_{2}, y_{2}),\newline(1)\,如果x_{1} \neq x_{2},则我们正常比较x坐标的大小即可,即x_{1} > x_{2},P_{1}在P_{2}的右边,反之在左边。\newline (2)\,如果x_{1} = x_{2},且y_{1} \neq y_{2},我们则比较y坐标的大小,即y_{1} > y_{2},P_{1}在P_{2}的右边,反之在 左边。\newline (3)\,如果x_{1} = x_{2},且y_{1} = y_{2},则两端点重合,第二种退化情况退化为第一种退化情况。
设任意两个端点坐标P1(x1,y1),P2(x2,y2),(1)如果x1=x2,则我们正常比较x坐标的大小即可,即x1>x2,P1在P2的右边,反之在左边。(2)如果x1=x2,且y1=y2,我们则比较y坐标的大小,即y1>y2,P1在P2的右边,反之在左边。(3)如果x1=x2,且y1=y2,则两端点重合,第二种退化情况退化为第一种退化情况。
(1)和(3)比较容易理解,但为什么可以这样“投机取巧”地进行(2)的计算,我们可以简单证明一下:
现在有任意两个端点坐标
P
1
(
x
1
,
y
1
)
,
P
2
(
x
2
,
y
2
)
,且
x
1
=
x
2
,
y
1
≠
y
2
,那么斜切后的坐标为(
ε
>
0
):
φ
1
:
(
x
1
y
1
)
⇒
(
x
1
+
ε
y
1
y
1
)
φ
2
:
(
x
2
y
2
)
⇒
(
x
2
+
ε
y
2
y
2
)
因为我们需要比较
x
坐标,所以:
x
1
+
ε
y
1
−
(
x
2
+
ε
y
2
)
=
ε
(
y
1
−
y
2
)
因为
ε
>
0
,所以结果可以简化为
y
1
与
y
2
的大小比较。
现在有任意两个端点坐标P_{1}(x_{1}, y_{1}),P_{2}(x_{2}, y_{2}),且x_{1} = x_{2},y_{1} \neq y_{2},那么斜切后的坐标为(\varepsilon > 0):\newline \varphi_{1} : \begin{pmatrix} x_{1} \\ y_{1} \\ \end{pmatrix} \Rightarrow \begin{pmatrix} x_{1} + \varepsilon y_{1} \\ y_{1} \\ \end{pmatrix}\newline \varphi_{2} : \begin{pmatrix} x_{2} \\ y_{2} \\ \end{pmatrix} \Rightarrow \begin{pmatrix} x_{2} + \varepsilon y_{2} \\ y_{2} \\ \end{pmatrix}\newline 因为我们需要比较x坐标,所以:\newline x_{1} + \varepsilon y_{1} - ( x_{2} + \varepsilon y_{2} ) = \varepsilon ( y_{1} - y_{2} )\newline 因为\varepsilon > 0,所以结果可以简化为y_{1}与y_{2}的大小比较。
现在有任意两个端点坐标P1(x1,y1),P2(x2,y2),且x1=x2,y1=y2,那么斜切后的坐标为(ε>0):φ1:(x1y1)⇒(x1+εy1y1)φ2:(x2y2)⇒(x2+εy2y2)因为我们需要比较x坐标,所以:x1+εy1−(x2+εy2)=ε(y1−y2)因为ε>0,所以结果可以简化为y1与y2的大小比较。
那通过这样的“假想”处理,原来的梯形图究竟会变成什么样的呢?下图展示了进行“假想”斜切处理后的梯形图和对应搜索结构:
通过上图的例子,大家应该能明白“假想斜切”的意义了,即真实的梯形图中,我们没有进行任何斜切变换,也就是说图例中的灰色部分是不存在的,或者它们的面积其实为零。那么这些灰色区域产生的梯形究竟又是什么样子的呢?以梯形E为例,它的leftP = P2,rightP = P1,但两个端点的x坐标相同,所以整个梯形的面积依然为零。笔者称这样的梯形为虚梯形(Zero-area trapezoid),因为这样的梯形不真实存在,且面积为零。顺带一提,后面Voronoi图也会有一个相似的彩蛋:虚边(Zero-length edge),笔者就是借用这个的概念来类比面积为零的梯形。
并且我们可以发现其实经过“斜切”处理的梯形图比原来的更加复杂了,相应地,搜索结构也多了不少节点,而且理论上来说,我们不需要进行“假想斜切”也能得到正确的梯形图和搜索结构,也就说用上面的比较方法,但是没有灰色区域。很不幸地是,从实现层面上来说,这样会使代码逻辑异常复杂,笔者曾经尝试过,但是最终悻悻而归。
到此,我们就结束了对第二种退化情况的讨论,最后来看看第三种退化情况的处理思路:如何处理端点落在线段上的情况。
2.3 变幻莫测的端点
端点的退化情况除了端点重合(第一退化情况),还有就是端点出现在线段上面,比如下面这个例子(带有垂直线段):
通过图例中的分析,我们现在还剩一个问题:当端点在线段上,哪个方向的垂直线被线段截断了呢?我们先来看看左端点的情况:
通过上面的图例,我们得到下面的结论:
(1)裁剪梯形:当s1左端点落在s2上,s2往哪个方向移动,其反向的垂直线就会被截断。或者说,反向的梯形就会被左边的梯形合并;
(2)查找新插入线段横跨的梯形区域:si往哪个方向移动,si就横跨其反向的梯形;
相似地,当s2右端点落在s2上,也有同样的结论,如下图所示:
现在思路有了,但在具体代码实现的时候,我们需要在两个地方对这种情况进行区分:
- followSegment()中沿着邻居Trapezoid查找新插入线段横跨的梯形区域;
- addTrims()中,判断是上梯形被合并,还是下梯形被合并;
这部分内容的分析,我们就留到代码解析当中,下一节我们就来详细讨论如何用代码来实现上面所有的处理思路。
上一节:点定位:处理S
下一节:点定位:处理退化情况·续
系列汇总:塞尔达和计算几何 | Voronoi图详解文章汇总(含代码)
3. 参考资料
- Computational Geometry: Algorithms and Applications
- 计算几何 ⎯⎯ 算法与应用, 邓俊辉译,清华大学出版社
4. 免责声明
※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~
※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;