这只是一个非常简短的概述。有相当多的
源代码本身的附加文档。
稳健细分的目标
镶嵌算法本质上是一种二维算法。我们
最初将所有数据投影到一个平面中;我们的目标是稳健地
镶嵌投影数据。相同的拓扑镶嵌是
然后应用于输入数据。
从拓扑上讲,输出应该始终是镶嵌。如果
输入甚至稍微不平面,那么一些三角形会
从某些角度看,一定是背对着的,但目标
就是尽量减少这种影响。
该算法需要一些清理输入数据的能力
以及其自身计算中的数值误差。一种方法
这是为了指定上面定义的容差,并清理
行扫描过程中的输入和输出。至少,
该算法必须处理重合顶点,顶点与
边和重合边。
算法的阶段
- 求多边形法线 N。
- 将顶点数据投影到平面上。它不需要垂直于法线,例如。我们可以投影到飞机上
垂直于与 N 的点积为的坐标轴
最大。
- 使用线扫描算法,将平面划分为 x 单调区域。任何垂直线与 x 单调区域相交
最多一个间隔。
- 对 x 单调区域进行三角测量。
- 将三角形组合成条形和扇形。
寻找法线向量
求多边形法线的常用方法是计算有符号面积
当多边形沿三个坐标轴投影时。我们
不能这样做,因为轮廓可以有零面积而不是
退化(例如领结)。
我们为顶点数据拟合一个平面,忽略它们是如何连接的
成轮廓。理想情况下,这将是最小二乘拟合;然而对于
我们的目的正常的准确性并不重要。相反,我们
找到三个相距很远的顶点,并计算法线
到它们形成的三角形。顶点的选择使得
三角形的面积至少是任何三角形的最大面积的 1/sqrt(3) 倍
使用输入顶点形成的三角形。
轮廓确实会影响法线的方向;计算后
正常情况下,我们检查有符号轮廓区域的总和是
非负数,必要时反转正态。
投影顶点
我们将顶点投影到垂直于三个顶点之一的平面上
坐标轴。这通过删除
原始输入数据和数据之间的转换步骤
由算法处理。投影还压缩了输入
数据;投影后顶点之间的二维距离可能更小
比原来的二维距离。但是通过选择坐标
与法线的点积最大的轴,压缩
系数最多为 1/sqrt(3)。
即使法线的准确度并不重要(因为
无论如何,我们都垂直于坐标轴投影),
计算的鲁棒性很重要。例如,如果有许多顶点几乎沿着一条直线,而一个顶点 V
它与线很好分开,然后我们的正常计算
应该涉及V,否则结果将是垃圾。
垂直于多边形法线投影的优点是
计算出的交点将尽可能接近
他们的理想地点。要获得此行为,请定义 TRUE_PROJECT。
线扫
共有三种数据结构:网格、事件队列和
边缘字典。
网格是一种“四边形”数据结构,它记录了网络的拓扑结构
当前分解;有关详细信息,请参阅包含文件“mesh.h”。
事件队列只保存所有顶点(原始的和计算的)
个),组织起来,以便我们可以快速提取顶点
最小 x 坐标(以及其中具有最小 y 坐标的那个)。
边字典描述了当前扫过的交点
与多边形的区域对齐。这只是一个排序
与扫描线相交的边,按其当前顺序排序
路口。对于每一对边,我们存储一些关于
它们之间的单调区域——这些被称为“活动区域”
(因为它们被当前扫描线穿过)。
基本算法是从左到右扫一扫,处理每一个
顶点。网格的处理部分(扫描线左侧)是
平面分解。当我们穿过每个顶点时,我们更新网格
和边缘字典,然后我们检查任何新的相邻对
边看它们是否相交。
一个顶点可以有任意数量的边。有很多边的顶点可以
当顶点被合并并且交点被创建时被创建
计算。对于未处理的顶点(扫描线的右侧),这些
边缘在顶点周围没有特定的顺序;用于加工
顶点,拓扑排序应该匹配几何
订购。
顶点处理分为两个阶段:首先我们处理的是
向左边缘(所有这些边缘当前都在边缘
字典)。这涉及:
- 从字典中删除左行边;
- 如有必要,重新链接网格,以便事件顶点周围的这些边的顺序与字典中的顺序相匹配;
- 根据
他们的绕组编号。
当没有左走边,并且事件顶点在一个
“内部”区域,我们需要添加一条边(将区域分割成
单调件)。为此,我们只需将事件顶点连接到
包含的上边缘或下边缘的最右端左端点
地区。
然后我们处理向右的边缘。这涉及:
- 在边缘字典中插入边缘;
- 计算任何新创建的活动区域的绕组数。我们可以使用每条边的绕组增量计算这个
我们在浏览字典时会越过它。
- 如有必要,重新链接网格,以便事件顶点周围的这些边的顺序与字典中的顺序相匹配;
- 检查任何新相邻的边是否相交和/或合并。
如果没有右向边,我们需要再次添加一个来分割
将包含区域分成单调块。在我们的例子中,它是最
方便将边缘添加到任何一个的最左端点
包含边缘;但是我们可能需要稍后更改它(请参阅
代码了解详情)。
不变量
这些是在扫描期间保持的最重要的不变量。
我们定义了一个函数 VertLeq(v1,v2),它定义了
顶点穿过扫描线,以及一个函数 EdgeLeq(e1,e2; loc)
它表示在扫描事件位置“loc”处 e1 是否低于 e2。
此功能仅在扫描事件位置定义,该位置位于
在 {e1,e2} 的最右端和最左端之间
{e1,e2} 的端点。
边缘字典的不变量。
扫描的不变量。
- 如果顶点有任何向左的边,那么在处理顶点时这些边必须在边字典中。
- 如果一条边被标记为“fixUpperEdge”(它是由 ConnectRightVertex 引入的临时边),那么它是唯一的右向
来自其关联顶点的边。 (这表示这些边缘存在
仅在必要时。)
稳健性
算法鲁棒性的关键是保持
上面的不变量,尤其是边缘的正确排序
字典。我们通过以下方式实现这一目标:
编写数值计算以获得最大精度,而不是
超过最大速度。
对边缘的结果完全不做任何假设
交集计算——对于足够退化的输入,
计算出的位置并不比随机数好多少。
当数值错误违反不变量时,恢复它们
通过在必要时进行拓扑更改(即重新链接
网状结构)。
三角剖分和分组
我们在进行任何三角测量之前完成线扫描。这是
因为即使在一个单调区域完成之后,还有更多
由于进一步的顶点合并,其顶点数据发生变化。
在对所有单调区域进行三角剖分后,我们要将
三角形成扇形和条形。我们使用贪婪的方法来做到这一点。
三角剖分本身并未优化以减少
原语;我们只是试图得到一个合理的分解
计算三角剖分。