Bentley-Ottmann线段求交算法
因为很喜欢我的伪代码所以备份一下
条件
- 全部都是直线段
- 没有重合的线段
- 线段端点不重合
- 没有三条及以上线段在同一点相交
基本算法思路
- 事件点优先队列Q
将所有线段的端点作为事件点,分为起点和终点,按x坐标排序,若x坐标相同则按y坐标排序。使用一个红黑树存储点指针。 - 扫描线状态活动集S
使用一个平衡二叉搜索树来维护当前扫描线与线段,按线段在扫描线上的y坐标排序。每当扫描线经过一个事件点时,更新树的状态。由于
std::set底层不支持动态更新key值,所以自己实现了平衡搜索树。 - 处理事件点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28//处理事件点伪代码
while(Q非空)
{
弹出事件点p;
switch(p的类型)
{
case 起点:
p的关联线段l插入到S;
if(l的上邻居与l相交)
计算交点并插入Q;
if(l的下邻居与l相交)
计算交点并插入Q;
break;
case 终点:
if(l的上邻居与l的下邻居相交)
计算交点并插入Q;
l从S中删除;
break;
case 交点:
交点关联的两条线段为l1和l2;
交换l1和l2在S中的位置;//设定交换后l1在上,l2在下
if(l1的上邻居与l1相交)
计算交点并插入Q;
if(l2的下邻居与l2相交)
计算交点并插入Q;
break;
}
} - 拆分线段
记录每个线段对应的事件点指针。如果数量大于2,将线段删除并拆分成多个线段,重新插入到原链表中。
剩下的是付费内容()