算法的故事 / 第一季第二季目录0 / 30 章已读

第二季 · 第 42 章

谁离你最近?

《算法的故事》第二季 · 第三篇:让机器理解空间——沃罗诺伊图、空间的分割与距离背后的数学秩序1908年,欧洲。一位数学家正在研究一个与城市规划看起来毫不相关的问题。他关心的是数论、二次型,以及高维空间中那些能够重复排列的几何区域。在他的研究里,空间不再只是一个无边无际的整体。它可以按照距离关系,被划分成许多彼此相邻的区域。每一个区域都围绕一个特殊的点。当我们站在这个区域里的任何位置时,离我们最近的那个指定点,始终是同一个。越过某条边界,最近的点就改变了。走到三条边界相遇的地方,可能会发现自己距离三个指定点完全一样远。这种几何结构如此简单,以至于一名小学生也可以在纸上画出基本形状。但它又如此深刻,以至于后来成为计算机图形学、空间分析、机器人技术以及科学计算的重要工具。研究它的数学家叫作格奥尔基·沃罗诺伊(Georgy Voronoi)。而这种分割后来以他的名字广为人知:沃罗诺伊图(Voronoi Diagram)。不过,它的历史其实比1908年更早。至少在1850年,德国数学家狄利克雷就已经在数论研究中使用了相关的空间划分思想。再往后,1934年,另一位数学家提出了与之密切相关的三角剖分结构。到了1980年代,贝尔实验室的研究人员甚至发现,可以让一条想象中的直线扫过平面,在 O(nlog⁡n)O(n\log n) 时间内构造整张图。而在今天,我们只需要打开一个地图程序,就能够理解这项数学的现实意义。想象一座城市。里面有十家医院。每家医院都希望知道,哪些地点距离自己最近。如果你站在某条街道上,应该去哪家医院才能走最短的直线距离?如果你向东走了二百米,这个答案会不会改变?如果又开设了一家新医院,原来十家医院的服务区域将怎样重新分配?这些问题背后其实只有一个数学规则:将空间里的每一个位置,交给距离它最近的站点。只要重复这条规则,一幅复杂而有序的几何图案就会自然出现。今天,我们要弄清楚的,就是这幅图案究竟从何而来。

第一幕:一张医院地图,把城市分成了许多看不见的领地

地理信息系统中的沃罗诺伊分割示意。每个站点周围的多边形,表示在所采用的距离度量下,距离该站点不超过其他站点的区域。[QGIS Documentation documentation]我们先不讨论一百多年前的数学家。而是从一个今天就能理解的情境开始。假设某座虚构城市里,只有三家医院。我们把它们记为:A,B,CA,\quad B,\quad C医院的位置已经标注在地图上。现在,一位居民住在城市的某个位置 PP。我们想确定:d(P,A),d(P,B),d(P,C)d(P,A),\quad d(P,B),\quad d(P,C)哪一个最小?如果A最近,那么P就属于A的最近服务区域。如果B最近,就属于B的区域。如果C最近,就属于C的区域。对一个居民,判断很简单。只要计算三次距离即可。但如果我们想知道整座城市的每一个位置应该归谁服务呢?

无穷多个位置,不可能逐个检查

数学上的平面包含无穷多个点。我们无法列出每一位居民未来可能站立的全部位置。也无法在计算机里保存无限长的“位置—医院”对应表。因此,我们需要换一种表示方式。不是分别记录每个位置的答案。而是直接求出:哪些位置属于A?哪些位置属于B?哪些位置属于C?这些区域之间的边界在哪里?如果边界能够被精确描述,那么无论居民站在什么位置,我们都可以通过区域判断找到相应的医院。这就是沃罗诺伊图的基本思路。

边界并不是随意画出来的

假设城市里只有A和B两家医院。那么,一个点P究竟离谁更近,只取决于:d(P,A)与d(P,B)d(P,A)\quad\text{与}\quad d(P,B)的大小。如果P靠近A,就应该分给A。如果P靠近B,就应该分给B。但是在两家医院之间,必定有一条特殊的边界。站在边界上的人,距离两家医院完全相同。也就是说:d(P,A)=d(P,B)\boxed{d(P,A)=d(P,B)}在普通二维欧几里得距离下,满足这个条件的全部点,恰好构成AB线段的垂直平分线。
图42-1:只有两家医院时,空间怎样分割?
AB等距边界更靠近 A更靠近 B
查看 SVG 配图原件
示意图原件 42-003-8cc89a806281.svg
42-003-8cc89a806281.svg · 点击查看大图
蓝色和绿色代表两个最近站点区域。中间虚线上的所有点与A、B等距。此处两家医院只是虚构站点,不对应真实地图。
你会发现,我们已经取得了一项重要进展。虽然平面上有无穷多个位置,但判断最近站点不需要给每个位置单独保存一个结果。只需要一条直线,就能描述两个站点之间的完整分界。如果医院变成三家呢?每一对医院,都拥有一条垂直平分线。三条分界关系相互作用,空间就会被划分出更多区域。如果医院增加到十家、五十家甚至上千家,区域结构会变得复杂。但每一条边界,依然服从一个明确的距离规则。

从医院到消防站

同样的思想可以用于消防站、仓库、物流网点或移动通信基站。不过,这里必须立刻加上一个条件:我们现在计算的是欧几里得直线距离下的最近站点。它不一定等于现实道路里的最快到达地点。如果两家医院隔着一条河,一家直线距离更近,却需要绕行十公里才能过桥,那么现实中另一家医院可能更容易到达。真正的应急服务规划,还需要考虑:道路网络。交通时间。医院容量。医疗服务等级。救护车位置。以及各类特殊约束。因此,简单沃罗诺伊图非常适合表达几何距离关系,却不能直接替代完整的医疗服务规划模型。我们这章要研究的,正是其中最基本、最清晰的数学结构。而它的历史,必须从一位比沃罗诺伊出生更早的德国数学家讲起。

第二幕:1850年,狄利克雷已经看到了空间分割的秘密

彼得·古斯塔夫·勒热讷·狄利克雷(Peter Gustav Lejeune Dirichlet,1805—1859)。1850年,他在研究正定二次型的过程中使用了与后来的沃罗诺伊区域密切相关的几何划分。[NIST数学与统计科学][Wiley Online Library]1850年,沃罗诺伊还没有出生。当时的数学界,已经拥有一位著名的数论研究者。他的名字是狄利克雷。他出生于1805年,早年在巴黎接触过当时欧洲重要的数学研究。后来,他先后在布雷斯劳、柏林以及哥廷根从事学术工作。在数学分析、数论与数学物理领域,他都留下了重要贡献。今天,数学里仍然有许多概念以他的名字命名。例如:狄利克雷函数。狄利克雷级数。狄利克雷边界条件。以及本章要介绍的:狄利克雷区域(Dirichlet Region)。

数论为什么会需要几何图案?

在十九世纪,数学家对二次型具有浓厚兴趣。例如:Q(x,y)=ax2+bxy+cy2Q(x,y)=ax^2+bxy+cy^2这种表达式不仅是普通代数函数。它还与整数点、整数的表示方式,以及数论中的若干深刻问题有关。为了研究这些关系,数学家常常需要把整数点排列成一种规则结构。想象平面上所有坐标为整数的点:(m,n),m,n∈Z(m,n),\qquad m,n\in\mathbb Z它们形成一个无限延伸的方格点阵。现在,我们选中原点:O=(0,0)O=(0,0)然后问:平面上的哪些位置,距离O不超过距离其他整数点的距离?对于普通正方形点阵,答案非常整齐。它是:−12≤x≤12-\frac12\le x\le\frac12−12≤y≤12-\frac12\le y\le\frac12也就是一个以原点为中心的正方形。
图42-2:无限整数点阵中的狄利克雷区域
O正方形点阵中,原点的最近点区域
查看 SVG 配图原件
示意图原件 42-005-9cca50e075b4.svg
42-005-9cca50e075b4.svg · 点击查看大图
蓝点表示整数格点,绿色正方形是中心点的最近点区域。图中只显示无限点阵的一小部分。
如果我们为点阵里的每一个整数点,都建立这样的区域,那么整个平面会被无数个正方形无缝铺满。没有空隙。也没有内部重叠。每个区域围绕一个整数点。而该区域内的点,都至少与这个整数点一样接近,而不会更接近其他格点。这种划分,与今天的沃罗诺伊图属于同一类几何结构。在其他格子形状的点阵中,区域也可能呈现不同的凸多边形。例如,规则三角点阵对应的最近点区域,会出现正六边形。

1850年的论文

狄利克雷在1850年发表了关于含三个整数变量的正定二次型约化研究:Über die Reduktion der positiven quadratischen Formen mit drei unbestimmten ganzen Zahlen这项工作与后来所谓狄利克雷镶嵌(Dirichlet Tessellation)有直接的历史联系。[NIST数学与统计科学][Wolfram MathWorld]但我们不能由此说:1850年,狄利克雷已经在研究现代城市医院的服务区域。他的研究背景是数论与二次型。他所考虑的点往往具有规则的数学结构。今天广泛使用的任意散点最近区域划分,是后来逐渐发展起来的更一般问题。这段历史最重要的地方,恰恰在于:一种原本服务于抽象数论研究的几何结构,后来成为现代空间计算的基础工具。

更早的影子:笛卡尔与宇宙空间

如果继续追溯,某些数学史研究甚至将相关的空间划分直觉联系到1644年的笛卡尔。在其自然哲学著作《哲学原理》中,笛卡尔曾使用看起来与空间镶嵌相似的图示,描述宇宙空间中的结构。但需要谨慎。这些早期图示并不等于后来严格定义的沃罗诺伊图。我们不能把所有看起来像不规则多边形拼图的历史图画,都称为现代意义上的沃罗诺伊算法。比较准确的描述是:笛卡尔留下了具有类似视觉特征的早期空间图示。狄利克雷在十九世纪研究了具有明确数学含义的最近点区域。而沃罗诺伊则在二十世纪初,对相关结构作出了重要的高维推广和系统研究。[Wiley Online Library][cosy.sbg.ac.at]这是一条跨越几百年的研究线索。但它并不是一群数学家始终围坐在同一张医院地图前的连续合作。每一位研究者,都在自己的问题与时代中,发现了这项几何结构的不同侧面。

第三幕:1908年,一位四十岁数学家留下了自己的名字

格奥尔基·费奥多西耶维奇·沃罗诺伊(1868—1908)。他的研究集中于数论、二次型和数的几何,并成为后世纪念其数学贡献的重要原因。[MacTutor History of Mathematics][乌克兰百科全书]1868年4月28日,格奥尔基·沃罗诺伊出生于当时俄罗斯帝国波尔塔瓦省的茹拉夫卡。这一地点位于今天的乌克兰境内。他的家庭重视教育。父亲曾担任学校教师和校长。年轻的沃罗诺伊很早就表现出对数学的兴趣。1884年,基辅大学教授瓦西里·叶尔马科夫(Vasily Ermakov)在数学刊物中提出了一道有关多项式因式分解的问题。当时还是中学生的沃罗诺伊提交了解答。他的研究随后发表于1885年的《初等数学杂志》。[mathsoc.spb.ru][MacTutor History of Mathematics]这是一项值得记住的真实经历。因为它说明,沃罗诺伊很早就开始接触专业数学研究。但这不意味着他少年时期已经想到今天以他名字命名的空间划分图。那是多年之后,完全不同的研究成果。

从圣彼得堡到华沙

1885年,沃罗诺伊进入圣彼得堡大学。他受到数论研究传统的影响,并与包括安德烈·马尔可夫(Andrey Markov)在内的数学家产生学术联系。1894年,他开始在华沙大学任教。1897年获得数学博士学位后,继续从事研究和教学。在十九世纪末到二十世纪初,他主要研究代数数论、正定二次型、格点结构以及相关的分析数论问题。[乌克兰百科全书][MacTutor History of Mathematics]他的学术生涯并不漫长。从1894年到1908年,只有十几年。但这十几年里,他发表了一系列具有重要影响的论文。后来的数学史文献指出,他发表的研究成果数量并不多,却在多个方向产生了深远影响。[mathsoc.spb.ru]

1908年的研究,究竟在讨论什么?

沃罗诺伊1908年法语论文的历史资料。论文第二部分研究原始平行多面体(primitive parallelohedra)及相关几何结构,不是一篇现代意义上的城市最近医院算法论文。[数字对象标识符]1908年,沃罗诺伊在《纯粹与应用数学杂志》(又称 Crelle's Journal)发表了研究:Nouvelles applications des paramètres continus à la théorie des formes quadratiques《连续参数在二次型理论中的新应用》。其中第二篇研究讨论了原始平行多面体。该部分发表于第134卷,第198—287页。另一相关部分后来继续发表于1909年的第136卷,第67—182页。[数字对象标识符][几何曲线]论文标题里最醒目的词,并不是“最近医院”。甚至也不是现代计算机科学里的“Voronoi Diagram”。它讨论的是二次型与高维几何结构。这与我们第一幕中的地图故事,似乎相距很远。但沃罗诺伊推进了一项重要的数学研究:将相关区域划分思想扩展到更一般的高维数学背景,研究这些区域如何围绕格点、如何与空间镶嵌和二次型相互联系。今天,我们把一组指定点所诱导的最近点区域叫作沃罗诺伊单元。而整组单元形成的空间分割,就叫作沃罗诺伊图。

一段令人惋惜的生命终点

1908年11月20日,沃罗诺伊在华沙去世。年仅四十岁。他的去世发生在那项重要研究发表的同一年。一部分相关论文因此是在他去世之后才正式见刊。后来的数学界继续发展他的工作。他的名字也逐渐传播到更多学科。其中最为广泛使用的,就是沃罗诺伊图。[ЕСУ][MacTutor History of Mathematics]但是,我们仍然应当保留一个重要的历史区别。沃罗诺伊没有在1908年发明一套专门为当代GIS软件绘制城市分区的程序。彼时现代电子计算机尚未诞生。他留下的是更深层的数学结构。而后来计算机科学家所做的,是将这套几何思想转化为能够处理大量数字坐标的算法。那么,最重要的问题来了:我们今天能否只用小学几何与一些代数运算,就把这张图真正构造出来?可以。而答案,竟然始于一条垂直平分线。

第四幕:一条垂直平分线,怎样变成一座城市的边界?

三个站点形成的沃罗诺伊图。两两等距的边界位于垂直平分线上,三条区域边界会在三站点等距的位置相遇。现在,我们终于开始真正的数学推导。先不要使用复杂的几何库。也不要依赖计算机绘图。只使用三个站点:A=(2,2)A=(2,2)B=(8,2)B=(8,2)C=(5,8)C=(5,8)我们想知道,平面上的任意位置:P=(x,y)P=(x,y)应该归属于哪一个站点。

第一步:比较P与A、B的距离

按照欧几里得距离:d(P,A)=(x−2)2+(y−2)2d(P,A)=\sqrt{(x-2)^2+(y-2)^2}d(P,B)=(x−8)2+(y−2)2d(P,B)=\sqrt{(x-8)^2+(y-2)^2}如果我们想知道P是否至少和A一样接近:d(P,A)≤d(P,B)d(P,A)\le d(P,B)可以两边平方。因为距离非负,平方不会改变大小关系。得到:(x−2)2+(y−2)2≤(x−8)2+(y−2)2(x-2)^2+(y-2)^2 \le (x-8)^2+(y-2)^2两边相同的项可以消去。展开:x2−4x+4≤x2−16x+64x^2-4x+4\le x^2-16x+64因此:12x≤6012x\le60最终:x≤5\boxed{x\le5}这是一个惊人的简化。我们原本在比较两条含有平方根的距离公式。但经过整理,只剩下一个一次不等式。它表示:所有位于直线 x=5x=5 左侧的点,都至少与A一样接近,而不会更接近B。反过来:x≥5x\ge5的区域,至少与B一样接近。边界就是:x=5\boxed{x=5}一条垂直平分线。

第二步:比较A与C

现在比较:d(P,A)≤d(P,C)d(P,A)\le d(P,C)平方后:(x−2)2+(y−2)2≤(x−5)2+(y−8)2(x-2)^2+(y-2)^2 \le (x-5)^2+(y-8)^2展开并消去共同项:−4x−4y+8≤−10x−16y+89-4x-4y+8\le-10x-16y+89所以:6x+12y≤81\boxed{6x+12y\le81}又得到一个线性不等式!这次,它对应平面中的一个斜半平面。其中所有位置,都满足:距离A不超过距离C。

第三步:取两个条件的交集

现在,P如果想归属于A,就必须同时满足:d(P,A)≤d(P,B)d(P,A)\le d(P,B)和:d(P,A)≤d(P,C)d(P,A)\le d(P,C)因此,A的完整最近点区域是:V(A)={(x,y):x≤56x+12y≤81}\boxed{ V(A)= \left\{ (x,y): \begin{array}{l} x\le5\\ 6x+12y\le81 \end{array} \right\} }这就是我们想要的沃罗诺伊单元。
图42-3:A的区域由两个半平面相交得到
ABC两种条件都成立x = 5
查看 SVG 配图原件
示意图原件 42-009-5428bd484c56.svg
42-009-5428bd484c56.svg · 点击查看大图
概念示意:绿色区域表示A相对于其他两个站点的最近区域。真正的沃罗诺伊单元在无限平面上可能无界,图中只显示有限画布。
到这里,一项非常重要的数学事实出现了。点与点之间的欧几里得距离比较,经过平方展开后,可以转化为线性不等式。每个线性不等式,定义一个半平面。把相对于其他所有站点的半平面取交集,就得到某个站点的沃罗诺伊单元。

一般公式

给定某个站点:pi=(ai,bi)p_i=(a_i,b_i)以及另一站点:pj=(aj,bj)p_j=(a_j,b_j)我们希望确定所有满足:∥x−pi∥≤∥x−pj∥\|x-p_i\|\le\|x-p_j\|的位置 x=(x,y)x=(x,y)。两边平方、展开之后:2(aj−ai)x+2(bj−bi)y≤aj2+bj2−ai2−bi2\boxed{ 2(a_j-a_i)x+ 2(b_j-b_i)y \le a_j^2+b_j^2-a_i^2-b_i^2 }这是一个半平面不等式。因此,对于整个站点集合:S={p1,p2,…,pn}S=\{p_1,p_2,\ldots,p_n\}站点 pip_i 的沃罗诺伊单元可以写成:Vi=⋂j≠i{x:∥x−pi∥≤∥x−pj∥}\boxed{ V_i= \bigcap_{j\ne i} \{x:\|x-p_i\|\le\|x-p_j\|\} }这里的每一个集合都是半平面。而任意多个凸集的交集仍然是凸集。所以,在平面欧几里得距离下,普通点站点的沃罗诺伊单元一定是凸的。这与上一章的凸包产生了直接联系。上一章,我们研究怎样用一个最小凸区域包住所有点。这一章,我们用许多个凸区域,把整个平面分割开。一个关注整体外边界。另一个关注各个站点之间的内部分界。但它们都建立在凸几何之上。

第五幕:三家医院同时等距的地方,为什么是一座三角形的外心?

三角形的外心,是三条边的垂直平分线交点。它到三个顶点的距离相等,同时也是普通三站点沃罗诺伊图的一个顶点。现在继续研究:A=(2,2),B=(8,2),C=(5,8)A=(2,2),\quad B=(8,2),\quad C=(5,8)我们已经知道:A与B的等距边界是:x=5x=5A与C的等距边界是:6x+12y=816x+12y=81如果一个点同时位于这两条边界上,那么它距离A和B一样远,也距离A和C一样远。因此,它距离三家医院一样远。把:x=5x=5代入:6x+12y=816x+12y=81得到:30+12y=8130+12y=81所以:12y=5112y=51于是:y=4.25\boxed{y=4.25}三家医院等距的位置是:O=(5,4.25)\boxed{O=(5,4.25)}

验证这个结果

计算O到A的距离平方:d(O,A)2=(5−2)2+(4.25−2)2d(O,A)^2 =(5-2)^2+(4.25-2)^2=9+2.252=9+2.25^2=14.0625=14.0625计算O到B的距离平方:d(O,B)2=(5−8)2+(4.25−2)2d(O,B)^2 =(5-8)^2+(4.25-2)^2同样等于:14.062514.0625O到C:d(O,C)2=(5−5)2+(4.25−8)2d(O,C)^2 =(5-5)^2+(4.25-8)^2=3.752=3.75^2也是:14.062514.0625所以:d(O,A)=d(O,B)=d(O,C)=3.75\boxed{d(O,A)=d(O,B)=d(O,C)=3.75}它确实距离三个站点完全相同。

这个点还有另一个身份

在初等几何中,我们知道:三角形三条边的垂直平分线,会相交于同一个点。这个点叫作三角形的外心(Circumcenter)。它是三角形外接圆的圆心。所以,刚才求出的O,不只是“离三家医院一样远的位置”。它同时是三角形ABC的外心。
图42-4:沃罗诺伊顶点与外接圆
ABCO:三站点等距三条垂直平分线交于外心
查看 SVG 配图原件
示意图原件 42-011-e4e4af342b92.svg
42-011-e4e4af342b92.svg · 点击查看大图
几何关系示意。外接圆经过A、B、C,圆心O到三个点等距;图形布局不按上文精确坐标比例绘制。
这意味着,沃罗诺伊图中那些由三个区域相遇形成的普通顶点,可以通过三角形外心来理解。当然,必须补充一项条件。它不只是三点等距。它们还必须是该位置附近最近的站点。如果附近有第四家医院,比这三家都近,那么这个外心就不一定成为整张沃罗诺伊图的顶点。因此,沃罗诺伊顶点还与另一个几何性质有关:空圆性质(Empty-Circle Property)。想象以O为圆心,画一条通过A、B、C的圆。如果没有其他站点严格位于圆内部,那么O才有资格成为这些站点共同的最近区域交点。这项发现,给我们提供了通往另一个重要几何结构的道路。而它与一位1934年发表论文的数学家有关。在那之前,我们先真正实现一次沃罗诺伊单元的构造。

怎样让计算机求出一个完整区域?

如果输入有四十个站点。我们想计算A的最近区域。不需要先画出全部40个站点之间的所有垂直平分线。我们可以从一个足够大的矩形开始。将它作为研究范围。然后,逐一加入约束。首先,保留比B更接近A的半平面。然后,在保留下来的区域中,进一步只保留比C更接近A的部分。接着考虑D。再考虑E。直到所有其他站点都处理完毕。每次操作,实际上都是:用一个半平面裁剪当前的凸多边形。
图42-5:逐次裁剪一个站点的服务区域
原始矩形
第一项距离约束
继续加入距离约束
每次只保留满足新约束的部分。由于半平面的交集仍然凸,最终获得的区域仍然是凸多边形。
对于一个只有几十个站点的小型问题,这种做法非常直观。我们不需要一开始就学习复杂的专业算法。只要实现:多边形与半平面的求交。就能够构造完整的有限画布沃罗诺伊图。不过,对于成千上万个站点,如果对每个站点都逐一与其他所有站点比较,并重复执行多边形裁剪,计算量仍然可能很大。后来计算几何研究者便继续追问:有没有更快的方法?答案就是我们将在第八幕认识的扫描线算法。但在此之前,历史还要先走到1934年。

第六幕:1934年,另一位数学家将区域变成了三角形

鲍里斯·德劳内(Boris Delaunay,又常按俄语拼写为 Delone,1890—1980)。1934年,他发表了著名的《论空球》,并在标题中纪念沃罗诺伊。1908年,沃罗诺伊去世。但他的几何思想并没有随他而消失。一位年轻的后来者,继续发展相关问题。他叫鲍里斯·尼古拉耶维奇·德劳内。1890年,他出生于圣彼得堡。在少年时期,他曾接触过沃罗诺伊所处的华沙数学研究圈。数学史研究指出,沃罗诺伊给年轻的德劳内留下了深刻印象。不过,需要特别纠正一种后来的传记误写:德劳内不能简单地被描述为沃罗诺伊正式指导并完成博士论文的学生。沃罗诺伊1908年去世时,德劳内还非常年轻;两人的学术联系,不等于存在一段已经完成的正式博士指导关系。[gkfweb.math.illinois.edu]

1934年,《论空球》

1934年,德劳内发表了一篇法语论文:Sur la sphère vide. À la mémoire de Georges Voronoï可以译作:《论空球——纪念格奥尔基·沃罗诺伊》。论文发表于苏联科学院相关学术刊物,第793—800页。[数学网]1934年原始论文的标题明确包含“À la mémoire de Georges Voronoï”(纪念沃罗诺伊),显示两项几何研究之间的历史联系。德劳内研究的一个重要思想,是所谓的空球性质。在二维平面里,这可以直观地变成空圆性质。如果我们用若干条不相交的边,将点集的凸包分成许多三角形,那么怎样判断这些三角形是否具有良好的几何结构?一种非常重要的要求是:对于每一个三角形,经过它三个顶点的外接圆,其内部不能包含其他输入点。满足这种条件的三角剖分,便是今天所说的:德劳内三角剖分(Delaunay Triangulation)。

沃罗诺伊图与德劳内三角剖分,竟然是同一枚硬币的两面

沃罗诺伊图与德劳内三角剖分的对偶关系:站点之间的三角网,与站点的最近区域边界形成两种相互联系的几何结构。[2D Triangulations: User Manual]请注意两个结构之间的关系。在沃罗诺伊图中,我们以站点为中心,将平面划分成若干区域。在德劳内三角剖分中,我们不再关心区域归属,而是直接把站点连接成一个三角形网络。但是,并不是随便连接。在一般位置下,如果两个站点对应的沃罗诺伊区域,共享一段具有非零长度的边界,那么这两个站点之间就有一条对应的德劳内边。反过来,一条德劳内边,对应一条与其垂直的沃罗诺伊边界。这就是两者的几何对偶关系(Geometric Duality)。
图42-6:一条区域边界,对应一条站点连接
AB沃罗诺伊边德劳内边 A—B两种边彼此垂直
查看 SVG 配图原件
示意图原件 42-017-c366669d1c1f.svg
42-017-c366669d1c1f.svg · 点击查看大图
这种联系十分奇妙。沃罗诺伊图回答:某个位置距离哪个站点最近?德劳内三角剖分则回答:哪些站点在最近区域结构中拥有相邻关系?一边是空间的分割。另一边是站点之间的连接。但它们可以相互转化。

一个沃罗诺伊顶点,对应一座三角形

回到三家医院:A,B,CA,\quad B,\quad C它们的三个最近区域可能在外心O相遇。因为:d(O,A)=d(O,B)=d(O,C)d(O,A)=d(O,B)=d(O,C)如果没有其他站点更接近O,那么以O为圆心、经过A、B、C的圆,就是一个没有其他站点落在内部的空圆。这正好满足德劳内三角形的条件。因此,在不存在特殊退化情况时:一个由三个沃罗诺伊区域相遇形成的顶点,对应一个德劳内三角形;那个顶点就是三角形的外心。但是,如果有四个站点恰好位于同一个圆上,就会出现特殊情况。四个沃罗诺伊区域可能在同一点相遇。而德劳内三角剖分的对角线选择,也可能不唯一。因此,并不是所有沃罗诺伊顶点,都必定只对应唯一的三个站点。CGAL 的德劳内三角剖分文档,正是通过“空圆性质”和“没有四点共圆时的唯一性”,解释这种关系。[2D Triangulations: User Manual]

为什么这项对偶关系具有实际价值?

假设我们拥有大量空间采样点。我们想研究每个点与哪些点具有几何邻接关系。不一定需要检查所有:(n2)\binom n2组点对。我们可以先构造德劳内三角剖分,再使用其边集表达一张较为稀疏的空间邻接网络。如果希望求沃罗诺伊图,也可以利用德劳内三角形的外心及相邻关系构造区域边界。反过来,如果已经拥有沃罗诺伊图,也可以通过相邻单元关系得到相应的德劳内结构。这就是计算几何里非常重要的一种设计方式。有时候,一个问题在原来的几何表示下很难。但转换到它的对偶结构之后,反而变得简单。这种思想与前面章节的线性规划对偶、最大流最小割、匹配与覆盖定理,都有某种深刻的共通之处。同一组数学关系,可能从两个截然不同的方向被理解。

第七幕:比沃罗诺伊更早的伦敦地图,以及雨量站画出的多边形

1854年伦敦霍乱暴发相关的历史地图。约翰·斯诺后来提交的1855年修订地图中,出现了按步行距离划分的水泵服务范围边界。[epi-snow.ph.ucla.edu][Historia Medica]我们刚刚见证了数学史的一条研究主线。狄利克雷。沃罗诺伊。德劳内。但如果以为最近点区域的思想,只存在于数学家的论文里,就会错过另一段更加戏剧性的历史。1854年,伦敦发生严重的霍乱暴发。医生约翰·斯诺(John Snow)怀疑疾病传播与受污染的饮用水有关。他调查居民的用水来源。记录病例与死亡位置。研究不同水泵与居民住址之间的关系。后来的流行病学史,常常将这段经历作为空间调查的重要案例。

那张地图真的包含沃罗诺伊图吗?

这是一个特别容易被误写的历史细节。流传最广的斯诺霍乱地图,主要展示死亡位置与水泵分布。它并不是一张完整的现代欧几里得沃罗诺伊图。但是,斯诺后来提交给圣詹姆斯教区调查委员会的修订地图中,确实增加了一条边界。那条边界大致圈出:按照道路步行距离,距离布罗德街水泵比其他水泵更近的区域。现代数学家会把这种思想与网络距离下的最近设施区域联系起来。医学史研究也讨论了它与沃罗诺伊类划分的关系。[epi-snow.ph.ucla.edu][ScienceDirect]这里必须特别说明两件事。第一,斯诺当时并没有使用后来以沃罗诺伊命名的现代计算机算法。第二,不能讲成“斯诺先画出一张沃罗诺伊图,才发现霍乱与水泵有关”。历史研究表明,斯诺关于饮水传播的判断及相关调查,早于那些著名地图的最终发表。地图更多承担了展示、解释和支持调查结论的作用。而非整个发现过程唯一的起点。这段真实历史,比简单地讲述“一张图改变了医学”更加复杂,也更加值得理解。

为什么步行距离与直线距离不同?

想象两口水井。一口水井在街道对面。但中间有一堵无法穿过的围墙。另一口水井虽然直线距离更远,却可以直接沿道路走到。如果我们使用欧几里得距离,可能认为第一口井最近。如果使用道路最短步行距离,结果则可能完全相反。因此,斯诺修订地图里的步行距离区域,并不等于普通平面点站点沃罗诺伊图中的直线垂直平分线结构。这种区别,在现代 GIS 中仍然非常重要。如果站点距离沿道路网络测量,得到的可能是网络沃罗诺伊划分。如果使用地理投影平面上的欧几里得距离,得到的是另一种几何模型。两者不能简单混用。

1911年:雨量站也需要自己的领地

泰森多边形(Thiessen Polygons)常用于把雨量站周围的区域按最近站点原则划分。它与普通点站点沃罗诺伊图具有相同的几何形式。假设某片地区有五座雨量站。每座雨量站测得的降雨量不同。现在,我们希望估计整片地区的平均降雨量。最简单的办法,是将五个数字直接平均。但如果雨量站分布不均匀,这种方法可能产生问题。有些雨量站彼此非常接近。有些雨量站则代表很大一片没有其他观测站的区域。因此,我们可以先将整个地区按最近雨量站划分。每个站点对应一个服务多边形。然后,用各区域面积作为权重,计算空间加权平均:Pˉ=∑i=1nAiPi∑i=1nAi\boxed{ \bar P=\frac{\sum_{i=1}^{n}A_i P_i}{\sum_{i=1}^{n}A_i} }其中:Ai=第 i 个区域面积A_i=\text{第 }i\text{ 个区域面积}Pi=第 i 个雨量站的观测值P_i=\text{第 }i\text{ 个雨量站的观测值}这类方法在水文学和地理信息系统中,与**泰森多边形(Thiessen Polygons)**紧密联系。它们以美国气象学家 Alfred H. Thiessen 的名字命名,相关研究可以追溯到1911年前后的降雨估计工作。[Wiley Online Library][fpl.cs.depaul.edu]不过,这并不意味着最近雨量站的降雨量,就一定能够准确代表整个区域。实际降雨分布可能受到地形、海拔、风向和局部气候影响。泰森多边形法是一种明确、简单的空间估计模型。它的局限也必须与计算结果一起理解。

为什么同一种结构有如此多种名字?

今天,这种几何划分可能被称为:
名称常见研究语境
Dirichlet Tessellation数论、格点与数学几何
Voronoi Diagram计算几何、空间算法
Thiessen Polygons水文学、气象学、GIS
Wigner–Seitz Cell晶体学、凝聚态物理
这些名称背后,反映的是不同学科的历史发展过程。研究者可能因为完全不同的问题,独立地遇见同一种几何结构。数论研究者看到格点之间的区域。气象学家看到观测站的空间权重。物理学家看到晶格的基本空间单元。计算机科学家看到最近邻查询与几何数据结构。它们面对的实际对象不同。但在相应的欧几里得最近点定义下,数学结构可以相同。这是一项特别迷人的科学事实。世界上的不同问题,有时只是在使用不同的语言,描述同一种数学关系。

第八幕:1986年,贝尔实验室让一条直线扫过整个平面

20世纪80年代的贝尔实验室研究背景。Steven Fortune 在此工作期间发展了著名的沃罗诺伊图扫描线算法。回到现代计算机科学。现在,我们已经知道了如何构造沃罗诺伊单元。对于每个站点:依次与全部其他站点比较。得到半平面约束。然后不断裁剪。最终获得最近区域。这种方法概念上非常简单。但如果有几十万个站点,逐一构造全部区域,可能需要大量计算。因此,计算机科学家开始寻找更快的通用方法。

一位研究者重新思考“扫过去”的含义

1986年,AT&T贝尔实验室的 Steven Fortune 在第二届计算几何年会上发表了研究:A Sweepline Algorithm for Voronoi Diagrams《沃罗诺伊图的一种扫描线算法》。1987年,扩展论文发表于《Algorithmica》第2卷,第153—174页。[数字对象标识符][ibr.cs.tu-bs.de]他希望解决的问题,是怎样以更简单的方式达到:O(nlog⁡n)O(n\log n)的最坏情况时间复杂度。此前,研究人员已经知道可以采用分治法高效构造普通点站点的沃罗诺伊图。但分治算法需要将两个子问题的区域分割结果合并。这个合并过程,几何处理相对复杂。Fortune 则探索另一种方向。让一条水平直线,逐渐扫过整个平面。当它遇到某个站点时,处理一个事件。当几何结构发生特殊变化时,再处理另一个事件。于是,复杂的二维空间划分,被转化成按顺序执行的一系列离散事件。

为什么普通扫描线并不直接适用?

假设扫描线从上向下移动。我们希望在扫描线经过某个站点以后,才开始处理它的最近区域。但问题是:某个站点的沃罗诺伊区域,可能在扫描线尚未遇到这个站点之前,就已经延伸到了扫描线经过的位置。因此,直接在真实沃罗诺伊边界上进行扫描,会产生时序上的困难。Fortune 的关键创新,是构造一种几何变换。让算法维护一条由抛物线弧段组成的前沿。这条前沿通常被称为:海滩线(Beach Line)。
图42-7:扫描线与海滩线的概念
扫描线ABC蓝色为不同抛物线弧段构成的示意前沿
查看 SVG 配图原件
示意图原件 42-021-03df38778232.svg
42-021-03df38778232.svg · 点击查看大图
概念图而非某次算法迭代的精确数值曲线。真实海滩线由与已处理站点及当前扫描线等距的抛物线弧段构成。

为什么突然出现抛物线?

这是一项很美丽的几何联系。在初等几何中,抛物线可以定义为:平面上到某个固定点与某条固定直线距离相等的点的集合。固定点叫作焦点(Focus)。固定直线叫作准线(Directrix)。在 Fortune 算法中:已扫描到的一个站点,可以看成抛物线焦点。当前扫描线,可以看成抛物线准线。与二者等距的位置,就形成一条抛物线。随着扫描线移动,这些抛物线不断变化。不同抛物线的可见弧段共同形成海滩线。算法不必直接维护整张尚未完成的沃罗诺伊图。只需要处理海滩线发生变化的关键时刻。

两种事件,驱动整个算法

Fortune 算法的事件主要有两类。第一类:站点事件(Site Event)。扫描线到达一个新站点。这个站点开始影响海滩线。对应的抛物线弧段被加入当前结构。第二类:圆事件(Circle Event)。随着扫描线移动,海滩线上某个弧段可能逐渐缩小,最终消失。这个事件对应一个新的沃罗诺伊顶点的形成。它与三个站点的外接圆关系密切相关。还记得第五幕里的三角形外心吗?它在这里再次出现。这种几何联系,让算法能够把连续变化的空间结构,转化成有限个事件。

算法怎样管理这些事件?

Fortune 算法通常需要两类数据结构。一类是优先队列。它按照扫描线的顺序管理尚未处理的站点事件和圆事件。另一类用于维护海滩线弧段的有序关系,例如平衡搜索树。当新事件到来时,程序更新对应的数据结构,并记录正在形成的沃罗诺伊边界。对于普通点站点的二维沃罗诺伊图,它可以达到:O(nlog⁡n) 时间\boxed{O(n\log n)\text{ 时间}}以及:O(n) 空间\boxed{O(n)\text{ 空间}}的复杂度界限。[ibr.cs.tu-bs.de]Fortune 的研究还讨论了线段站点及某些带权站点的扩展情况。这里的关键价值,并不只是把一个算法写得更快。而在于一种新的思路:不要试图一次性处理整个连续空间,而是找出真正会改变结构的有限事件。这项思想,为下一章的“平面扫描算法”埋下了一个伏笔。同样的扫描线思想,还可以用于:线段相交检测。几何范围查询。平面区域分割。以及许多其他计算几何问题。但现在,我们先不急着进入下一章。我们已经拥有足够的数学工具,可以让自己的程序真正画出一张沃罗诺伊图。

第九幕:互动实验室——移动一家医院,整座城市如何重新分割?

同一组站点只要有一个改变位置,其对应的最近区域边界就会改变。某些站点可能因此获得更大的区域,另一些则可能失去部分区域。现在,我们终于可以亲自操作这项数学结构。下面是一座虚构的方形城市。地图的横纵坐标都从0到100。你可以控制:
  • 城市里有几家医院。
  • B医院所在的位置。
  • 一位居民的当前位置。
  • 是否显示全部最近区域,或者逐项构造某一家医院的区域。
程序并不是通过彩色像素近似猜测边界。它使用前面推导的半平面公式,计算区域与有限画布的几何交集。因此,显示出的多边形边界,来自实际的几何计算。

实验一:移动站点,观察区域边界

图42-8:可计算的最近医院区域地图中的医院和居民都是虚构坐标;距离单位为地图单位,不代表真实公里或驾车时间。
74
25
ABCDP彩色点是医院位置;金色P是居民。分割边界按欧几里得距离精确计算,并裁剪在100×100的方形画布内。
移动居民P,查看最近医院
54
48
按直线距离最近的医院

医院 B

最短距离

30.48

若恰好与多个站点等距,演示按字母顺序选取其中一个;几何上该位置可以同时属于多个闭合沃罗诺伊单元。
站点坐标P到站点距离
医院 A(20, 24)41.62
医院 B(74, 25)30.48
医院 C(29, 78)39.05
医院 D(77, 72)33.24

观察一:把B向A移动

将B医院的横坐标逐渐向左移动。随着两家医院越来越接近,它们之间的分界线也会移动。如果附近还有其他站点,B的区域可能逐渐受到其他区域挤压。从整体上看,一家医院改变位置,可能导致多条区域边界同时发生变化。

观察二:只剩两家医院时,边界是什么?

把站点数量改为两家。只保留A与B。此时,完整沃罗诺伊图一定由两块半平面构成。它们的共同边界是一条垂直平分线。无论怎样移动B,只要两个站点位置不重合,这条边界都会保持直线形状。

观察三:逐步裁剪A的区域

切换到“逐步裁剪”。选择A。当加入的距离约束数量为0时,绿色区域覆盖整张画布。加入B之后,绿色区域被一条垂直平分线裁剪。继续加入C,区域可能进一步缩小。再加入D,得到最终完整区域。这一步演示了一个非常重要的事实。构造沃罗诺伊图,并不一定需要先计算所有区域之间的交点。我们也可以对每个站点,独立执行一系列半平面交集运算。只不过,这种实现虽然清晰,却不适合无限扩大到所有大规模数据。因为它没有利用整张沃罗诺伊图的全局结构来避免重复计算。

第十幕:真正写出一套沃罗诺伊图算法

现代计算程序可以直接从站点坐标生成沃罗诺伊单元。教学实现可以使用半平面裁剪;实际大规模系统则经常采用专门的几何算法库。在前面的互动实验中,我们已经亲手调整站点并观察区域变化。现在,我们把其中的核心计算过程写成 Python。这一次,我们不直接调用现成的沃罗诺伊函数。而是从数学公式开始:∥x−pi∥≤∥x−pj∥\|x-p_i\|\le\|x-p_j\|通过半平面裁剪,逐个构造站点的最近区域。这份程序特别适合教学。因为代码里的每一步,都能与第四幕和第五幕的几何推导对应起来。

第一步:实现多边形与半平面的裁剪

假设当前有一个多边形。我们希望只保留其中满足:ax+by≤cax+by\le c的部分。做法是沿着多边形的边逐段检查。如果一条边的两个端点都满足条件,那么这段边继续保留。如果两个端点都在允许区域外部,这段边就被舍弃。如果边跨越半平面边界,则计算交点,用交点连接保留部分。这就是经典的多边形裁剪思想。对于凸多边形,与半平面求交之后,结果仍然是凸多边形。

第二步:完整 Python 实现

下面的代码只需要 Python 标准库和 Matplotlib 绘图。如果环境里尚未安装 Matplotlib,可以先使用:
bash
pip install matplotlib
python

import math
import matplotlib.pyplot as plt
from matplotlib.patches import Polygon


def clip_halfplane(polygon, a, b, c):
    """
    将多边形裁剪到 ax + by <= c 的半平面内。

    polygon: [(x, y), ...]
    返回裁剪后的多边形顶点。
    """
    if not polygon:
        return []

    def f(p):
        return a * p[0] + b * p[1] - c

    def inside(p):
        return f(p) <= 1e-9

    result = []

    for i in range(len(polygon)):
        p = polygon[i]
        q = polygon[(i + 1) % len(polygon)]

        fp, fq = f(p), f(q)
        pin, qin = inside(p), inside(q)

        # 一条边穿过半平面边界
        if pin != qin:
            t = fp / (fp - fq)

            intersection = (
                p[0] + t * (q[0] - p[0]),
                p[1] + t * (q[1] - p[1])
            )

            result.append(intersection)

        # 边的终点在允许区域中
        if qin:
            result.append(q)

    return result


def voronoi_cell(site, sites, bounds):
    """
    计算某个站点的裁剪后沃罗诺伊单元。

    bounds: (xmin, ymin, xmax, ymax)
    """

    xmin, ymin, xmax, ymax = bounds

    polygon = [
        (xmin, ymin),
        (xmax, ymin),
        (xmax, ymax),
        (xmin, ymax)
    ]

    sx, sy = site

    for tx, ty in sites:
        if (sx, sy) == (tx, ty):
            continue

        # 距离平方比较:
        # (x-sx)^2+(y-sy)^2
        # <= (x-tx)^2+(y-ty)^2

        a = 2 * (tx - sx)
        b = 2 * (ty - sy)

        c = (
            tx * tx + ty * ty
            - sx * sx - sy * sy
        )

        polygon = clip_halfplane(
            polygon, a, b, c
        )

        if not polygon:
            break

    return polygon


def polygon_area(polygon):
    if len(polygon) < 3:
        return 0.0

    total = 0.0

    for i, p in enumerate(polygon):
        q = polygon[(i + 1) % len(polygon)]

        total += (
            p[0] * q[1]
            - q[0] * p[1]
        )

    return abs(total) / 2


# 四家虚构医院
sites = {
    "A": (20, 24),
    "B": (74, 25),
    "C": (29, 78),
    "D": (77, 72),
}

bounds = (0, 0, 100, 100)

all_positions = list(sites.values())

fig, ax = plt.subplots(figsize=(7, 7))

total_area = 0

for name, site in sites.items():
    region = voronoi_cell(
        site,
        all_positions,
        bounds
    )

    area = polygon_area(region)
    total_area += area

    ax.add_patch(
        Polygon(
            region,
            closed=True,
            alpha=0.3,
            edgecolor="black"
        )
    )

    ax.scatter(*site)
    ax.annotate(
        name,
        (site[0] + 2, site[1] + 2)
    )

    print(f"医院 {name}:区域面积 {area:.2f}")

ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
ax.set_aspect("equal")

ax.set_title("Voronoi Diagram")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.grid(alpha=0.15)

plt.show()

print("全部区域面积之和:", total_area)

assert math.isclose(
    total_area,
    10000,
    abs_tol=1e-6
)
这份代码有一个很值得关注的性质。我们没有先计算全部边界的交点。也没有单独建立三角剖分。每家医院只需要从一个方形区域开始。再逐次与其他医院产生的半平面求交。最终便得到自己的完整裁剪区域。

为什么全部区域面积之和等于10000?

因为研究画布是:100×100100\times100的正方形。面积:1000010000只要站点位置互不相同,距离计算正确,那么这些最近区域会覆盖整个正方形。不同区域的内部不会相互重叠。它们可以在边界上共享一些点,但边界的面积为零。因此:∑iAi=10000\boxed{\sum_i A_i=10000}这个关系可以作为一项简单的程序自检。不过它不是充分的正确性证明。即使某份错误分区的面积加起来刚好也是10000,也不能保证其每一处边界都正确。因此,正式测试时仍然需要检查距离归属条件、退化情况和数值精度。

这份教学算法需要多少计算量?

假设有:nn个站点。对于每个站点,我们要与其他大约:n−1n-1个站点比较。每次比较,都需要裁剪当前多边形。在一个区域逐渐由多个半平面限定时,其边数最多可以随约束数量线性增长。因此,这种直接实现的朴素最坏情况工作量可以达到:O(n3)\boxed{O(n^3)}这一界限描述的是对每个站点独立执行半平面裁剪的简单策略。它并不是沃罗诺伊图这个问题的最佳复杂度。专业的平面沃罗诺伊算法可以通过扫描线或分治等技术,在:O(nlog⁡n)\boxed{O(n\log n)}时间内构造完整结构。所以,理解基础算法很重要。但在真实的大型项目里,选择合适的算法库同样重要。

使用 SciPy 快速计算

SciPy 提供了 scipy.spatial.Voronoi,可以直接计算普通点站点的沃罗诺伊结构。
python

import numpy as np
from scipy.spatial import Voronoi

points = np.array([
    [20, 24],
    [74, 25],
    [29, 78],
    [77, 72],
    [49, 49],
])

vor = Voronoi(points)

print("沃罗诺伊顶点:")
print(vor.vertices)

print("相邻站点对:")
print(vor.ridge_points)

print("区域顶点索引:")
print(vor.regions)
这与我们手写的裁剪算法有所不同。SciPy 返回的是沃罗诺伊结构,包括:顶点坐标。区域与顶点的关系。相邻站点对。区域边的信息。当某个区域延伸到无限远时,结构中可能使用 -1 表示无穷远方向。因此,不能简单将所有区域索引都当成有限闭合多边形,直接用于绘图。如果想在城市边界或某个矩形范围里显示它们,往往还需要额外的裁剪操作。[SciPy v1.18.0 Manual]

QGIS:从数学公式进入真正的地理信息系统

QGIS 提供了名为 Voronoi polygons 的几何处理功能,可以从输入点图层生成相应多边形区域。[QGIS Documentation documentation]如果希望在真实 GIS 数据里实验,可以使用 QGIS。它的处理工具包含:Voronoi polygons这项工具能够读取一组点要素,并生成对应的沃罗诺伊多边形图层。在 QGIS 中,它属于矢量几何处理工具,通常可以从几何工具相关入口找到。[QGIS Documentation documentation]不过,如果输入坐标是经纬度:(经度,纬度)(\text{经度},\text{纬度})就必须特别关注坐标参考系统。经纬度不是简单的平面米制坐标。不能在全球范围内,直接把经纬度数值差当成真实地表距离。对于城市尺度的平面距离分析,通常应先采用适合当地范围的投影坐标系统。对于道路旅行时间,则需要道路网络模型。这是将课堂几何推导转化为真实GIS项目时,必须处理的第一批工程问题。

第十一幕:当最近点不再意味着最近医院

现代空间规划通常需要同时考虑几何距离、道路通达性和服务能力。普通沃罗诺伊图是基础模型之一,并非所有现实服务区域的完整答案。现在,我们已经能够画出漂亮的彩色区域。但当真正把它用于城市规划时,还会出现很多新问题。

第一种变化:不是每家医院都一样大

假设A是一所大型综合医院。B只是一家小型诊所。即使某个居民在直线距离上离B更近,也不意味着B能够提供其所需的医疗服务。如果我们希望考虑医院等级、容量或某种优先权,就需要改变模型。一种常见的数学推广叫作加权沃罗诺伊图(Weighted Voronoi Diagram)。但需要注意,“加权沃罗诺伊图”并不是单一的一种模型。不同加权方式,可能产生不同的区域边界。例如,如果使用:πi(x)=∥x−pi∥2−wi\boxed{ \pi_i(x)=\|x-p_i\|^2-w_i }来代表站点 pip_i 的加权距离指标,那么按照最小 πi\pi_i 划分空间,可以得到一种被称为**幂图(Power Diagram)**的结构。因为比较两个站点时,平方距离中的二次项依然能够消去,所以它的边界仍然是直线。对应单元仍然是凸的。但是,如果使用:d(x,pi)−wid(x,p_i)-w_i或者:d(x,pi)si\frac{d(x,p_i)}{s_i}等不同的加权规则,边界形状就可能发生变化。因此,在讨论加权沃罗诺伊图时,必须明确具体采用哪一种距离函数。更重要的是,加权值需要具有合理的现实解释。不能因为一所医院规模更大,就随意给它增加一个数学权重,然后宣称分区已经具有医疗上的最优性。

第二种变化:道路会改变距离

在普通欧几里得距离下,两点之间最短的是直线。但对于汽车而言,真正能够行驶的路线受到道路网络限制。这时,我们可以将地图道路表示为图:G=(V,E)G=(V,E)每条道路对应一条边。边权可以表示距离或预计旅行时间。然后,我们根据道路网络上的最短路径长度,将位置归属于最近的设施。这种划分与前面所讲的最短路径算法密切联系。例如,迪杰斯特拉算法可以帮助计算从多个设施出发到道路节点的最短距离。它与普通点站点沃罗诺伊图在思想上相通,但边界的几何形状不一定是平面的直线。

第三种变化:机器人需要避开障碍物

机器人路径规划中的广义沃罗诺伊结构,可以帮助表示与障碍物边界等距的空间骨架。在特定模型中,它可以用于寻找保持较大障碍物间距的候选路线。在机器人路径规划中,最近点的概念也能够被反过来使用。例如,室内机器人需要穿过一条两侧都有障碍物的通道。如果只追求最短路,路线可能非常贴近墙壁。但如果更关心安全距离,我们可能希望机器人尽量远离障碍物。在适当的模型中,可以研究障碍物边界等距的位置,从而形成一种广义沃罗诺伊图或空间骨架。这些结构有时能够作为机器人路径规划的候选道路网络。它们不保证在所有现实条件下直接给出最佳机器人路径。因为还需要考虑:机器人尺寸。转弯半径。运动学限制。动态障碍物。定位误差。以及路径规划目标。但它展示了沃罗诺伊思想的一种重要变形。普通沃罗诺伊图寻找最近站点区域。某些机器人几何规划则利用等距边界,寻找远离障碍物的空间结构。同一个距离概念,能够从不同方向服务于不同任务。

第四种变化:三维空间里的沃罗诺伊单元

还记得上一章最后提到的三维凸包吗?沃罗诺伊图也能够推广到三维。假设我们拥有若干个三维站点:pi=(xi,yi,zi)p_i=(x_i,y_i,z_i)每个站点对应的区域,包含所有距离它不超过其他站点的空间位置。在欧几里得距离下,这些区域不再是平面多边形。而是三维凸多面体。如果站点形成规则晶格,其单元就与固体物理中的 Wigner–Seitz Cell 有直接联系。如果站点在空间中任意分布,则可能获得复杂的不规则多面体结构。再继续推广到更高维,类似的数学定义仍然成立。但维度越高,几何结构的复杂度也会显著变化。因此,不能直接把二维:O(nlog⁡n)O(n\log n)的构造复杂度,推广到任意维数。同一个几何定义,可以存在于不同维度,但求解它的算法难度并不相同。

尾声:当世界不再属于一个整体,而是被距离重新组织

让我们重新回到1908年。沃罗诺伊正在研究二次型与空间几何。他的论文里没有医院地图。没有移动机器人。也没有可以随意调整坐标的交互界面。他面对的是数学中更加抽象的问题。格点。高维空间。凸多面体。以及不同区域之间的几何关系。但是,他研究的这套结构,最终进入了一个远远超出当时想象的世界。到了二十世纪,地理学家开始使用最近点区域描述观测站的影响范围。物理学家利用相关几何结构研究晶格。德劳内发展了具有空圆性质的三角剖分思想。计算机科学家则进一步研究:怎样从大量点坐标出发,高效构造整个空间分割?1986年,Steven Fortune 的扫描线研究,利用抛物线组成的海滩线,把复杂的几何变化转化成可以处理的事件。而在今天,只要输入几组坐标,我们就可以看到那些漂亮的多边形区域迅速出现。但真正值得记住的,并不是这些多边形有多么漂亮。而是它们来自一个极其简单的规则:每个位置,属于距离它最近的站点。一个规则。无穷多个位置。却能够产生一套有限、精确且具有数学结构的区域划分。这是数学抽象的力量。

从凸包到沃罗诺伊图

上一章,我们用一根想象中的橡皮筋,找出了点集的最外围。我们不需要知道所有内部点的详细位置,就能够描述整个点集的凸包。这一章,我们改变了问题。不再问:哪些点位于最外侧?而是问:空间中的每一个位置,应该归属于哪个点?于是,最外围的整体形状被转换成一张内部区域地图。两项算法虽然研究不同对象,却拥有相同的基础思想。它们都试图将人类的空间直觉,转化为严格的数学判断。凸包依靠:方向。排序。左转与右转。沃罗诺伊图依靠:距离。垂直平分线。半平面交集。而德劳内三角剖分,又把最近区域关系转化为站点之间的三角网络。这让我们看到,计算几何并不是一套彼此孤立的图形算法。它是一种能够不断转换观察角度的数学语言。

最近,并不等于最好

本章还有一项现实启示。假设一位居民站在两家医院之间。沃罗诺伊图可以告诉他,按照直线距离,哪家医院更近。但是,这不意味着它一定更适合他。一家医院可能有更好的医疗设备。另一家医院可能有更短的排队时间。道路、交通、服务容量,也可能改变真正的到达成本。因此:数学模型可以准确回答它被定义用来回答的问题,却不会自动回答所有现实问题。这与前面第二篇的优化章节,形成了很好的呼应。单纯形法可以寻找给定约束下的最优计划。但如果遗漏重要约束,结果仍然可能不适合现实。匈牙利算法能够找到最小成本分配。但成本最低,不代表参与者愿意接受。稳定匹配能够排除某些阻挡对。却不代表每个人都获得第一志愿。同样,沃罗诺伊图能够给出最近站点。却不能自动判断哪一家设施能够提供最好的服务。真正成熟的算法使用者,需要同时理解数学保证与模型边界。

计算机终于学会了一种新的空间语言

回顾整章,我们可以把沃罗诺伊图的数学思想总结成三个层次。
图42-9:从距离到空间结构
第一层:比较距离某个位置究竟距离哪个指定点最近?∥x−pi∥≤∥x−pj∥\|x-p_i\|\le\|x-p_j\|

第二层:形成凸区域将每一个距离关系转化为半平面,再取交集。Vi=⋂j≠iHijV_i=\bigcap_{j\ne i}H_{ij}

第三层:获得全局结构区域形成沃罗诺伊图,相邻站点关系又与德劳内三角剖分互相联系。
从一个距离比较,到一条垂直平分线。从一条垂直平分线,到一个凸多边形。从一个凸多边形,到覆盖整个空间的分区网络。这是一条非常美丽的数学道路。而计算机之所以能够理解空间,并不是因为它真正拥有人的视觉直觉。而是因为数学家找到了那些可以用数字表达的空间规律。当距离变成边界,边界形成区域,区域建立邻接关系,机器便开始拥有了理解空间结构的能力。

历史档案:从1850年到1987年的研究接力

本章的关键历史资料如下。
年份研究者重要贡献
1644年René Descartes在自然哲学中使用具有类似空间镶嵌特征的图示,但尚非现代严格定义
1850年Peter G. L. Dirichlet在二次型研究中使用与最近格点区域密切相关的划分
1854—1855年John Snow研究伦敦霍乱与水泵关系,后来的地图包含以步行距离划定的最近水泵区域边界
1908年Georgy Voronoi系统研究与二次型和高维几何有关的区域结构
1911年前后Alfred H. Thiessen将类似区域划分用于气象、水文观测的空间估计
1934年Boris Delaunay发表空球研究,发展与沃罗诺伊结构密切关联的三角剖分
1986—1987年Steven Fortune提出具有 O(nlog⁡n)O(n\log n) 时间界的沃罗诺伊扫描线算法
主要文献:本章以虚构的医院服务区域作为教学主线;它不代表沃罗诺伊本人研究过医院规划。所有站点坐标、区域变化、几何实验和代码均为现代教学设计。人物生平及论文发表信息有独立史料支持,历史上不同学科对类似结构的独立研究没有被编造成彼此直接合作的故事。
下一章预告 · 第43章

《让一条直线扫过城市:平面扫描算法的诞生》

1979年,两位计算机科学家正在研究平面上大量线段之间的相交关系。假设一座城市有几千条道路。其中有些道路相交,有些道路平行,有些道路则完全没有关系。如果我们希望找出全部交点,最直接的办法,是将每两条线段都拿出来检查。但是,如果线段数量达到十万条,需要检查的线段对数量就可能达到数十亿。有没有办法,不再反复检查那些距离很远、根本没有机会相交的线段?数学家发现,只需要想象一条竖直直线,从地图最左侧缓缓扫向最右侧。在每一个时刻,我们只关注当前与扫描线相交的几条线段,以及它们之间的上下顺序。而真正重要的,是线段端点与交点这些事件。下一章,我们将认识 Jon Bentley 与 Thomas Ottmann,追踪1979年的经典研究《Algorithms for Reporting and Counting Geometric Intersections》,并通过事件队列与平衡搜索树,理解如何高效发现大量几何对象之间的交点。[数字对象标识符]不是检查所有可能的关系,而是让空间按照事件顺序,逐渐揭示那些真正需要计算的关系。
——《算法的故事》第二季 · 第42章 完

本章配图