计算几何模板整理

整理计算几何模板,以及一些题目

 

Update 1:基础函数,点,向量的运算

Update 2:凸包,旋转卡壳

基础的函数定义

1 const double eps = 1e-8;
2 int dcmp(double x) {
3   if (fabs(x) < eps) return 0;
4   else return x > 0 ? 1:-1;
5 }
dcmp

 

基于点和向量的运算

  1 struct Point {
  2   double x, y;
  3   Point(double _x, double _y):x(_x),y(_y){}
  4   Point():x(0.0),y(0.0){}
  5 };
  6 typedef Point Vec;
  7 
  8 void showPoint(Point A) {
  9   printf("(%.6f, %.6f)\n", A.x, A.y);
 10 }
 11 const Vec operator + (Vec A, Vec B) {
 12   return Vec(A.x+B.x, A.y+B.y);
 13 }
 14 const Vec operator - (Vec A, Vec B) {
 15   return Vec(A.x-B.x, A.y-B.y);
 16 }
 17 const double operator * (Vec A, Vec B) {
 18   return A.x*B.x + A.y*B.y;
 19 }
 20 // A*B = |A|*|B|*sin(theta)
 21 // theta为 A,B 向量的夹角
 22 // 如果 A 在 B 的顺时针方向180度内,则theta取正值
 23 // 向量叉乘
 24 // 返回值为正时,表示 A 在 B 的右侧180度内
 25 // 返回值的绝对值等于以A,B向量为邻边的平行四边型的面积
 26 const double operator ^ (Vec A, Vec B) {
 27   return A.x*B.y - A.y*B.x;
 28 }
 29 
 30 double Lenth(Vec &v) {
 31     return sqrt(v*v);
 32 }
 33 
 34 
 35 // 将点 A 绕 p 逆时针旋转 theta 角度(弧度制)
 36 // 1.平移坐标
 37 // 2.旋转
 38 // 3.平移坐标
 39 Vec rotate(point A, point p, double theta) {
 40     A = A-p;
 41     point ret = point(A.x*cos(theta)-A.y*sin(theta), A.x*sin(theta)+A.y*cos(theta)) + p;
 42     return ret;
 43 }
 44 
 45 
 46 // 计算C到AB的距离
 47 // isSeg = 1 : AB为线段
 48 // isSeg = 0 : AB为直线
 49 double linePointDist(Point A, Point B, Point C, bool isSeg) {
 50   double dist = ((B-A)^(C-A)) / sqrt((B-A)*(B-A));
 51   if (isSeg) {
 52     double dot1 = (C-B)*(B-A);
 53     if (dot1 > 0) return sqrt((B-C)*(B-C));
 54     double dot2 = (C-A)*(A-B);
 55     if (dot2 > 0) return sqrt((A-C)*(A-C));
 56   }
 57   return fabs(dist);
 58 }
 59 
 60 // 判断线段的两个端点是否在直线的两侧
 61 bool lineCrossSeg(Point p1, Point p2, Point ls, Point le)
 62 {
 63   Vec ver = ls-le, v1 = p1-ls, v2 = p2-ls;
 64   return dcmp((ver^v1)*(ver^v2)) <= 0;
 65 }
 66 
 67 // 判断点是否在线段上
 68 // 叉积为 0 表示共线
 69 bool pointOnSeg(point s1, point s2, point p, bool includeEnd)
 70 {
 71   if ((s1 == p || s2 == p) && !includeEnd) return false;
 72   s2 = s2-s1;
 73   p = p-s1;
 74   return (s2^p)==0 && (s2*p)>=0;
 75 
 76   double minx = min(s1.x, s2.x);
 77   double maxx = max(s1.x, s2.x);
 78   double miny = min(s1.y, s2.y);
 79   double maxy = max(s1.y, s2.y);
 80 
 81   if ((s1 == p || s2 == p) && !includeEnd) return false;
 82   if (p.x-minx>=0 
 83       && maxx-p.x>=0 
 84       && p.y-miny>=0 
 85       && maxy-p.y>=0
 86       && ((s2-s1)^(p-s1)) == 0)
 87     return true;
 88   else
 89     return false;
 90 }
 91 
 92 
 93 // 判断两条线段是否相交
 94 // 两次跨立试验
 95 typedef pair<Point, Point> seg;
 96 bool segCrossSeg(seg a, seg b, bool includeEnd)
 97 {
 98   Vec ver = b.X-b.Y, v1 = a.X-b.X, v2 = a.Y-b.X;
 99   int tmp1 = dcmp((ver^v1)*(ver^v2));
100   ver = a.X-a.Y, v1 = b.X-a.X, v2 = b.Y-a.X;
101   int tmp2 = dcmp((ver^v1)*(ver^v2));
102   if (includeEnd)
103     return tmp1 <= 0 && tmp2 <= 0;
104   else
105     return tmp1 < 0 && tmp2 < 0;
106 }
107 
108 double areaPoly(vector<Point> &P) {
109   double area = 0.0;
110   for (int i = 1, n = P.size(); i+1 < n; i++) {
111     area += (P[i+1]-P[0])^(P[i]-P[0]);
112   }
113   return area / 2.0;
114 }
Points

 

基于直线的运算(直线方程 : Ax+By=C)

 1 struct Line {
 2   // Ax + By = C
 3   double A, B, C;
 4   Line(double _A, double _B, double _C):A(_A),B(_B),C(_C){}
 5   Line():A(0.0),B(0.0),C(0.0){}
 6 };
 7 
 8 Line getLineFromPoints(Point p1, Point p2) {
 9   double A = p2.y-p1.y;
10   double B = p1.x-p2.x;
11   double C = A*p1.x + B*p1.y;
12   return Line(A,B,C);
13 }
14 
15 // int = 0 无交点
16 // int = 1 一个交点
17 // int = 2 两直线重合
18 pair<Point, int> intersectPoint(Line l1, Line l2) {
19   double det = l1.A*l2.B - l2.A*l1.B;
20   if (dcmp(det) == 0) {
21     // 两直线平行 重合
22     if (dcmp(l1.A*l2.C - l2.A*l1.C) == 0 &&
23         dcmp(l1.B*l2.C - l2.B*l1.C) == 0)
24     return make_pair(Point(), 2);
25     else
26       return make_pair(Point(), 0);
27   }
28   else {
29     double x = (l2.B*l1.C - l1.B*l2.C) / det;
30     double y = (l1.A*l2.C - l2.A*l1.C) / det;
31     return make_pair(Point(x,y), 1);
32   }
33 }
Lines

 

凸包模板(白书)

 1 bool cmpxy(point a, point b)
 2 {
 3   if (a.x == b.x) return a.y < b.y;
 4   return a.x < b.x;
 5 }
 6 // 包含边上的点就将 <= 改为 <
 7 int convexHull(Point *p, int n)
 8 {
 9   sort(p, p + n, cmpxy);
10   int top = 0;
11   for (int i = 0; i < n; i++)
12   {
13     while(top>1 && ((p[s[top-1]]-p[s[top-2]])^(p[i]-p[s[top-2]])) <= 0) top--;
14     s[top++] = i;
15   }
16   int k = top;
17   for (int i=n-2;i>=0;i--)
18   {
19     while(top>k && ((p[s[top-1]]-p[s[top-2]])^(p[i]-p[s[top-2]])) <= 0) top--;
20     s[top++] = i;
21   }
22   if (n > 1) top--;
23   return top;
24 }
convexHull

 

旋转卡壳

 1 // s 为保存有序的凸包点的下标的栈
 2 // 此处的凸包点为顺时针的顺序
 3 int rotatingCaliper(Point *p, int top)
 4 {
 5   int q = 1;
 6   int ans = 0;
 7   s[top] = 0;
 8   for (int i = 0; i < top; i++)
 9   {
10     while( ((p[s[i+1]]-p[s[i]])^(p[s[q+1]]-p[s[i]])) > 
11            ((p[s[i+1]]-p[s[i]])^(p[s[q]]  -p[s[i]])) )
12       q = (q+1)%top;
13     ans = max(ans, (p[s[i]]-p[s[q]])*(p[s[i]]-p[s[q]]));
14     // 处理两条边平行的情况
15     ans = max(ans, (p[s[i+1]]-p[s[q+1]])*(p[s[i+1]]-p[s[q+1]]));
16   }
17   return ans;
18 }
rotatingCaliper

 

posted @ 2016-09-08 22:50  poore  阅读(277)  评论(0编辑  收藏  举报