计算几何图形算法经典问题学习整理

几何算法经典问题


一、几何基础问题

1. 判断两条线段是否相交

  • 考点:向量叉积,跨立实验,快速排斥
  • 推荐实现方法
    • 使用 cross(p1, p2, q1)cross(p1, p2, q2) 判断是否在同侧(跨立实验)
    • 边界处理:是否共线、点在线段上
步骤:
1.快速排斥:先检查两条线段的包围盒是否重叠,符合if表示不重叠
判断条件:if(max(x1, x2) < min(x3,x4) || max(x3, x4) < min(x1, x2) || max(y1, y2) < min(y3, y4) || max(y3, y4) < min(y1, y2)
包围盒空间上就错开了,那线段更不可能相交

2.跨立实验:把线段2的两个端点看成顶点1和顶点2,判断两顶点在线段1的哪一测
计算cross(p1, p2, q1)cross(p1, p2, q2)
两者结果相乘,位于同侧为正,分居两侧为负 

关键点:先排除明显不可能相交的情况,以及利用叉积判断顶点在左侧还是右侧

2. 判断点是否在多边形内

  • 方法
    • 射线法(ray casting)
    • 奇偶规则判断穿过边的次数
  • 注意:边界点、共线点的特殊处理
从点向右发射水平射线,统计与多边形交点的个数(奇数在内,偶数在外)
多边形是顶点有序的,每条边由​​相邻两个顶点​​定义

步骤:
1.遍历每条边
for(int i = 0, j = n - 1; i < n; j = i++)
i从0出发,j表示i的前一个顶点,ij组成一条边, j = i++理解为j=i,然后再i++,即前进一条边

2.检查顶点是否在两端点
if ((p.x == a.x && p.y == a.y) || (p.x == b.x && p.y == b.y))

3.排除水平边和无效y范围
if((a.y > p.y) == (b.y > p.y))
有交点得点p位于a点和b点的中间区域

4.因为是水平向右的射线,实际是计算a和b之间的插值
交点的y是肯定的,即p的y值,所以插值计算x值
x = a.x + (p.y - a.y) * (b.x - a.x) / (b.y - a.y);
if(x > p.x) inside = !inside;
如果插值的x在p点右边,即交点,则切换一次内外状态

关键:关键点在于先得排除不存在交点的情况。计算交点坐标关键点在于确定y值是固定的,便可以转化为插值算x值的问题。

3. 凸包计算

  • 算法
    • Graham 扫描法(极角排序)
  • 输入:平面上一组点
  • 输出:构成凸包的顶点顺序列表
方法一:经典Graham算法
步骤:
1.选定一个基准点(y值最小点)
2.以逆时针方向,对其他顶点做极角排序(以基准点x轴正方向为0度)
极角排序用到atan2(y - y0, x - x0)计算,atan2的计算是基于atan的分段逻辑
3.建立栈,第一个点(基准)和第二个点入栈,遍历顶点。
4.计算叉乘,判断右转出栈,左转入栈

方法二:
步骤:
1.对所有顶点根据x值排序,得到p1,p2...pn
2.划分为上凸包和下凸包
3.对于上凸包:p1和p2入upper栈,遍历顶点入栈,取末尾三个点找右拐,非右拐则删去倒数第二个顶点(三个点的中间那个)
4.对于下凸包:pn和pn-1入lower栈,遍历顶点入栈,取末尾三个点找右拐,非右拐则删去倒数第二个顶点
5.合并upper和lower(删去重复的p首尾顶点)

关键:先排序完才能遍历,以及利用叉积判断右拐

4. 判断一个有序点集的方向(顺时针 or 逆时针)

  • 方法Shoelace 公式求有向面积
    对于三角形:
    S = 1 2 ∣ x 1 y 1 1 x 2 y 2 1 x 3 y 3 1 ∣ S = \frac{1}{2}\left|\begin{array}{ccc} x_{1} & y_{1} & 1 \\ x_{2} & y_{2} & 1 \\ x_{3} & y_{3} & 1 \end{array}\right| S=21 x1x2x3y1y2y3111
    二维向量叉积的模等于两向量张成的平行四边形面积,三角形面积则除以2。那三角形面积即二分之一的向量叉积,然后写成行列式即上式。
    对于多边形:
    S t o t a l = 1 2 ∑ i = 0 n − 1 ( x i y i + 1 − x i + 1 y i ) S_{total} = \frac{1}{2}\sum_{i=0}^{n-1}(x_iy_{i+1}- x_{i+1}y_{i}) Stotal=

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值