计算几何模板
正如不知何方大佬所言,计算几何精妙之处,就是不用解析几何的方法去做
为了方便查找,防止自己迷路,我把函数名都写成了拼音
绝对不是因为我英语不好!!!
基本数据结构
点和向量:
- 点和向量都可以用一个坐标$(x,y)$来表示.
- 故向量$Vector$可以写为
1
typedef struct point vec;
完整定义如下
1 | typedef struct point vec; //向量vec |
直线和线段:
- 直线和线段都可以用两个点的坐标来表示
- 故线段$Segment$可以写为
1
typedef struct Line Segment;
完整定义如下
1 | typedef struct Line Segment; //线段Segment |
圆:
- 圆的表示有一个点圆心,以及其半径组成
完整定义如下
1 | struct cirles { |
基本函数以及常量
1 | const double pi = acos(-1.0); |
AOJ相关习题
CGL_1_A:Projection
求一个点在向量$\overrightarrow{ab}$上的投影坐标
设点$c$,投影在$\overrightarrow{ab}$上为$c’$,则$c’$的坐标就是:$cos<\overrightarrow{ac},\overrightarrow{ab}>\times |\overrightarrow{ac}|+a$
1 | point touying(Line l, point c) //c投影在直线ab上的位置 |
CGL_1_B:Reflection
求一个点$c$关于向量$\overrightarrow{ab}$的对称点$c’’$
先求出$c$在$ab$上的投影,那么$c’’=2\times \overrightarrow{cc’}+c$
1 | point fanshe(Line l, point c) //求c关于直线ab的对称点c' |
CGL_1_C:Counter-Clockwise
就是..根据图中的判断就是了
1 | void Counter_Clockwise(point p,point p1,point p2) |
CGL_2_A:Parallel/Orthogonal
先判平行,再用点积判垂直
1 | bool pingxing(vec a,vec b) |
CGL_2_B:Intersection
线段相交要考虑蛮多的,首先,先按照x后y从小到大排一下.
最简单的情况,$ab$穿过$cd$,那么必定有交点.
第二种,$a$在$cd$上或者$b$在$cd$上
第三种,共线时,$a$在$cd$之间或$b$在$cd$之间.
处理好以上问题,就解决了
1 | bool bijiao3(vec a, vec b, vec c) |
CGL_2_C:Cross Point
给你两个必定相交的线段,求交点
1 | point xianduan_jiaodian(Segment l1,Segment l2)//两线段交点 |
CGL_2_D:Distance
- 给定两个不相交线段,求两个线段最近距离
- 很明显,最近距离就是两个端点到另一个线段的距离.
- 那么两遍点到线段距离就出来了.
- 点到线段距离有三种
- 第一种是点在线段正上方,则距离为过点向线段作垂线
- 第二种是点在左侧,就是左端点和该点连线
- 第三种同第二种,不过在右侧
1 | double dian_dao_xianduan(Segment l, point c) //点到线段的距离 |
CGL_3_A:Area
计算多边形面积的方法蛮多的.
最暴力的当属以原点和多边形临近两点构成三角形,然后计算三角形的有向面积.
多边形内外符号不同,最后留下的就是多边形面积,然后fabs一下就完事了.这个地方建议”脑洞大开”或者拿纸画画.
不过要是会三角剖分的话,把多边形按顶点分割成一堆三角形,然后求面积也阔以.
1 | double duobianxingmianji(int n) //多边形面积 |
CGL_3_B:Is-Convex
问所给的多边形是不是凸的.
题目给的方法是计算内角和.
嘛,感觉好麻烦的亚子.
还不如暴力求个凸包,看看所给的多边形的点数是不是和凸包点数相同来的快.
1 | void Andrew(int& tail) //求凸包 |
CGL_3_C:Polygon-Point Containment
就,判断点和多边形的位置关系.
看网上都是角度和或者射线法.
结果就让我找到一个看起来很$nb$的象限角度法?
不用考虑角度的精度问题,还不用像射线法考虑多??
1 | bool zaibianshang(point& t,int n) //点在多边形边上否 |
CGL_4_A:Convex Hull
就是…求凸包
这里有个蛋疼的地方,要求是先排y再排x
1 | void Andrew(int& tail) |
CGL_4_B:Diameter of a Convex Polygon
找到凸包距离最远的一对点.
就是旋转卡壳嘛.$O(n)$复杂度嘛.
1 | double tubao_zhijing(int tail) //求出凸包直径 |
CGL_4_C:Convex Cut
用一条直线切割凸包,输出得到图形的坐标.
就是逆时针找交点,按照直线的方向,$\overrightarrow{p_1p_2}$,先放入靠近$p_2$的点,然后按照叉积,向左旋转的放入点.
1 | int zhixian_xianduan_xiangjiao(Line l1, Segment l2) //直线与线段是否有交点 |
CGL_5_A:Closest Pair
在空间内找到最近的点对
分治,建议到洛谷上搜索”平面最近点对(加强版)”
1 | double solve(int l, int r) |
CGL_6_A:Segment Intersections: Manhattan Geometry
扫描线算法,例题可在洛谷上搜索”扫描线”
求平面$n$条线段的交点个数.
有空单开一章来整理这个算法.
1 | struct SegTree { |
CGL_7_A:Intersection
求圆的切线个数
1 | int yuan_yuan_xiangjiao(cirles a, cirles b) //询问圆和圆的切线个数 |
CGL_7_D:Cross Points of a Circle and a Line
求圆和直线的交点.
建议阅读”挑战程序设计竞赛2”
1 | pair<point, point> zhixian_yuan_jiaodian(Line l, cirles a) //求直线与圆交点 |
CGL_7_E:Cross Points of Circles
求两个圆交点
建议阅读”挑战程序设计竞赛2”
1 | pair<vec, vec> yuan_yuan_jiaodian(cirles a, cirles b) //求圆和圆的交点 |
CGL_7_F:Tangent to a Circle
过一个点做圆的切线
根据半径和圆心到点的距离求出夹角,旋转角度,得到交点
1 | pair<point, point> guodian_yuan_qiedian(cirles a, point p) //过一点做圆的切线求切点 |
CGL_7_G:Common Tangent
求两个圆的公切线
根据圆和圆的位置进行判断
1 | int yuanyuan_gongqiexian(cirles a, cirles b, point* u, point* v) //求圆和圆公切线以及切线个数 |
CGL_7_H:Intersection of a Circle and a Polygon
求多边形和圆相交的面积
将多边形的边的顶点与圆心连接行成三角形.
那么面积便是三角形在圆内的有向面积.
对每个三角形在圆内进行判断来计算.
1 | point zhixian_zhixian_jiaodian(Line l1, Line l2) //两直线交点 |
其他相关
辛普森法则
证明待补
1 | double fun(double x)//原积分函数 |
最小圆覆盖
1 | point zhixian_zhixian_jiaodian(Line l1, Line l2) //两直线交点 |