找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 178|回复: 0

计算几何笔记

[复制链接]

1

主题

0

回帖

35

积分

管理员

积分
35
发表于 2024-3-16 09:08:26 | 显示全部楼层 |阅读模式
  1. 向量
  2. 常规操作
  3. struct Vector {
  4.     double x, y;
  5.     Vector(double x = 0, double y = 0) : x(x), y(y) {};
  6.     Vector operator + (const Vector &A) const {
  7.         return Vector(x + A.x, y + A.y);
  8.     }//向量的加法
  9.     Vector operator - (const Vector &A) const {
  10.         return Vector(x - A.x, y - A.y);
  11.     }//减法
  12.     Vector operator * (const double &A) const {
  13.         return Vector(x * A, y * A);
  14.     }//数乘
  15.     Vector operator / (const double &A) const {
  16.         return Vector(x / A, y / A);
  17.     }//数除
  18.     bool operator == (const Vector &A) const  {
  19.         return dcmp(x - A.x) == 0 && dcmp(y - A.y) == 0;
  20.     }//相等
  21. };
  22. 复制
  23. 向量的极角
  24. 极角:这里指从$x$轴旋转到向量方向的弧度
  25. double PolarAngle(Vector A) {
  26.     return atan2(A.y, A.x);
  27. }//向量的极角
  28. 复制
  29. 向量的旋转
  30. 若向量$(x, y)$旋转角度为$a$,则旋转后的向量为$(xcosa - ysina, y cosa + xsina)$
  31. 证明:
  32. 设旋转之前的向量的极角为$t$,半径为$r$
  33. 那么
  34. $$x = rcost$$
  35. $$y = rsint$$
  36. 旋转时候的向量为
  37. $$x' = rcos(t + a) = r(costcosa - sintsina) = xcosa - ysina$$
  38. $$y' = rsin(t + a) = r(sintcosa + costsina) = ycosa + xsina$$
  39. Vector rotate(Vector &A, double a) {
  40.     return A = Vector(A.x * cos(a) - A.y * sin(a), A.x * sin(a) + A.y * cos(a));
  41. }//向量旋转,a为弧度
  42. 复制
  43. 向量的点积
  44. $a \cdot b = |a||b|cos<a,b>$
  45. 两向量的点积得到的是标量,即一个向量的模长乘另一个向量在该向量上正投影的数量
  46. double Dot(Vector A, Vector B) {
  47.     return A.x * B.x +  A.y * B.y;
  48. }//两向量点积
  49. 复制
  50. 向量的叉积
  51. $a \times b = |a||b| sin<a,b>$
  52. 两向量叉积得到的是向量,在二维平面中得到的是三维空间中与这两个向量垂直的向量
  53. 在平面中,向量$v$和$w$的叉积等于$v$和$w$组成的三角形的有向面积的两倍
  54. 记$cross(v,w)$表示两向量的叉积,若$cross(v,w) > 0 $则说明$w$在$v$的左侧,否则$w$在$v$的右侧
  55. double Cross(Vector A, Vector B) {
  56.     return A.x * B.y - A.y * B.x;
  57. }//两向量叉积
  58. 复制
  59. 计算三角形面积
  60. 直接利用叉积的定义
  61. double Area(Point A, Point B, Point C) {
  62.     return fabs(Cross(B - A, C - A) / 2);
  63. }//计算三角形的面积
  64. 复制
  65. 计算向量的长度
  66. 直接利用点积的定义
  67. double Length(Vector A) {
  68.     return sqrt(Dot(A, A));
  69. }//计算向量的长度
  70. 复制
  71. 计算向量的夹角
  72. 同样直接利用点积的定义
  73. double Angle(Vector A, Vector B) {
  74.     return acos(Dot(A, B) / Length(A) / Length(B));
  75. }//计算向量的夹角
  76. 复制
  77. 线段
  78. 判断两直线的相对位置
  79. 判断$P采用1P采用0$与$P采用1P采用2$的相对位置关系,可以转化为判断$P采用1P采用0$与$P采用2P采用0$叉积的正负性
  80. int Direction(Vector P1, Vector P2, Vector P0) {
  81.     int opt = Cross(P1 - P0, P2 - P0);
  82.     return dcmp(opt);
  83. }//判断P1-P0,P1-P2的相对位置关系,-1为逆时针,1为顺时针(P1P0顺时针旋转到P1P2),0为共线
  84. 复制
  85. 判断两直线的交点
  86. 尼玛看不懂
  87. Point GetLineIntersection(Point P, Vector V, Point Q, Vector W) {
  88.     Vector u = P - Q;
  89.     double t = Cross(W, u) / Cross(V, W);
  90.     return P + V * t;
  91. }//判断两直线(P + tv,Q + tW)的交点(看不懂直接上y = kx + b吧)
  92. 复制
  93. 计算点到直线的距离
  94. 利用叉积算出他们围城的平行四边形的面积,再除以底,高即为距离
  95. double DistanceToLine(Point P, Point A, Point B) {
  96.     Vector v1 = B - A, v2 = P - A;
  97.     return fabs(Cross(v1, v2)) / Length(v1);
  98. }//计算点P到直线AB的距离(平行四边形面积 / 底)
  99. 复制
  100. 计算点到线段的距离
  101. 这个要分三种情况讨论
  102. double DistanceToSegment(Point P, Point A, Point B) {
  103.     if(A == B) return Length(P - A);
  104.     if(dcmp(Dot(P - A, B - A)) < 0) return Length(P - A);
  105.     if(dcmp(Dot(P - B, A - B)) < 0) return Length(P - B);
  106.     return DistanceToLine(P, A, B);
  107. }//计算点P到线段AB的距离
  108. 复制
  109. 多边形
  110. 计算多边形的有向面积
  111. 将$n$边形拆成三角形
  112. double PolygonAread(Point *P, int N) {
  113.     double area = 0;
  114.     for(int i = 1; i <= N - 1; i++)
  115.         area += Cross(P[i] - P[0], P[i + 1] - P[0]);
  116.     return area / 2;
  117. }//计算多边形的有向面积
  118. 复制
  119. 判断点是否在多边形内部
  120. 基本思想:从点$P$向右做一条射线,判断从无限远处到点$P$,射线穿过了几条边
  121. 有两种需要特判的情况
  122. 1.射线与某条边重合,该边不统计入答案
  123. 2.射线与端点重合
  124. 此时,我们钦定边是由编号小的连向编号大的
  125. 若边从上到下穿过了射线,包含终点不包含起点
  126. 若边从下到上穿过了射线,包含起点不包含重点
  127. int isPointInPolygon(Point P, Point Poly[], int N) {
  128.     int wn = 0, k, d1, d2;
  129.     for(int i = 0; i < N; i++) {
  130.         if(!dcmp(DistanceToSegment(P, Poly[i], Poly[(i + 1) % N]))) return -1;
  131.     //点在线段的边界上
  132.         k = dcmp(Cross(Poly[(i + 1) % N] - Poly[i], P - Poly[i]));
  133.         d1 = dcmp(Poly[i].y - P.y);
  134.         d2 = dcmp(Poly[(i + 1) % N].y - P.y);
  135.         if(k > 0 && d1 <= 0 && d2 > 0) wn++;//点在左,下上穿
  136.         if(k > 0 && d2 <= 0 && d1 > 0) wn++;//点在右,上下穿
  137.         return wn & 1; // 1:内 2:外   
  138.     }   
  139. }//判断点是否在多边形内部
  140. 复制
  141. 对踵点
  142. 定义:若点对$(a, b)$均为多边形上的点且存在过$a$点的切线与过$b$点的切线平行,则成$(a, b)$为多边形上的对踵点
  143. 计算方法:
  144. 设$p采用{ymin}$表示$y$最小的点,$q采用{ymax}$表示$y$最大的点,显然它们是一对对踵点
  145. 接下来以相同的角速度逆时针旋转两条射线,当其中的一条穿过多边形的下一个端点$p采用{next}$时,用$p采用{next}$作为新的端点,同时与$q采用{pre}$构成新的对踵点。
  146. 在这个算法中,我们快速的找出两条射线究竟是哪条先穿过下一个端点,我们可以用叉积来优化这一过程。
  147. 求凸多边形的直径
  148. 定义:凸多边形的直径为多边形的上最远的点对的距离
  149. 很显然,直径一定是在对踵点处取得,直接枚举对踵点即可
  150. double RotatingCaliper采用diameter(Point Poly[], int N) {
  151.     int p = 0, q = N - 1, fl;
  152.     double ret = 0;
  153.     for(int i = 0; i < N; i++) {
  154.         if(Poly[i].y > Poly[q].y) q = i;
  155.         if(Poly[i].y < Poly[p].y) p = i;
  156.     }
  157.     for(int i = 0; i < N * 3; i++) {
  158.         ret = max(ret, Length(Poly[p % N] - Poly[q % N]));
  159.         fl = dcmp(Cross(Poly[(p + 1) % N] - Poly[p % N], Poly[q % N] - Poly[(q + 1) % N]));
  160.         if(!fl) {
  161.             ret = max(ret, Length(Poly[p % N] - Poly[(q + 1) % N]));
  162.             ret = max(ret, Length(Poly[q % N] - Poly[(p + 1) % N]));
  163.             p++, q++;
  164.         } else {
  165.             if(fl > 0) p++;
  166.             else q++;
  167.         }
  168.     }
  169. }//计算多边形直径
  170. 复制
  171. 凸多边形的宽度
  172. 凸多边形最小面积外接矩形
  173. 凸包-Andrew算法
  174. 首先按照$x$为第一关键字,$y$为第二关键字从小到大排序,并删除重复的点
  175. 用栈维护凸包内的点
  176. 1、把$p采用1, p采用2$放入栈中
  177. 2、若$p采用{i{(i > 3)}}$在直线$p采用{i - 1}, p采用{i - 2}$的右侧,则不断的弹出栈顶,直到该点在直线左侧
  178. 3、此时我们已经得到了下凸包,那么反过来从$p采用n$再做一次即可得到下凸包
  179. 题目链接
  180. // luogu-judger-enable-o2
  181. #include<cstdio>
  182. #include<cmath>
  183. #include<algorithm>
  184. using namespace std;
  185. const int eps = 1e-10;
  186. int dcmp(double x) {
  187.     if(fabs(x) < eps) return 0;
  188.     return x < 0 ? -1 : 1;
  189. }
  190. #define Point Vector
  191. struct Vector {
  192.     double x, y;
  193.     Vector(double x = 0, double y = 0) : x(x), y(y) {};
  194.     bool operator < (const Vector &rhs) const {
  195.         return dcmp(x - rhs.x) == 0 ? y < rhs.y : x < rhs.x;
  196.     }
  197.     Vector operator - (const Vector &rhs) const {
  198.         return Vector(x - rhs.x, y - rhs.y);
  199.     }
  200. };
  201. double Cross(Vector A, Vector B) {
  202.     return A.x * B.y - A.y * B.x;
  203. }
  204. double dis(Point a, Point b) {
  205.     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
  206. }
  207. int N;
  208. Point p[10001], q[10001];
  209. int top;
  210. void Push(Point p) {
  211.     while(Cross(q[top] - q[top - 1], p - q[top - 1]) < 0) top--;
  212.     q[++top] = p;
  213. }
  214. void Andrew() {
  215.     q[0] = q[top = 1] = p[1];
  216.     for(int i = 2; i <= N; i++) Push(p[i]);
  217.     for(int i = N - 1; i; --i)  Push(p[i]);
  218. }
  219. int main() {   
  220.     scanf("%d", &N);
  221.     for(int i = 1; i <= N; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
  222.     sort(p + 1, p + N + 1);
  223.     Andrew();
  224.     double ans = 0;
  225.     for(int i = 1; i < top; i++)
  226.         ans += dis(q[i], q[i + 1]);
  227.     printf("%.2lf", ans);
  228.     return 0;
  229. }
  230. 复制
  231. 要做的题
  232. POJ 2187 凸多边形直径
  233. #include<cstdio>
  234. #include<cmath>
  235. using namespace std;
  236. const int eps = 1e-10;
  237. int dcmp(double x) {
  238.     if(fabs(x) < eps) return 0;
  239.     return x < 0 ? -1 : 1;
  240. }
  241. #define Point Vector
  242. struct Vector {
  243.     double x, y;
  244.     Vector(double x = 0, double y = 0) : x(x), y(y) {};
  245.     Vector operator + (const Vector &A) const {
  246.         return Vector(x + A.x, y + A.y);
  247.     }//向量的加法
  248.     Vector operator - (const Vector &A) const {
  249.         return Vector(x - A.x, y - A.y);
  250.     }//减法
  251.     Vector operator * (const double &A) const {
  252.         return Vector(x * A, y * A);
  253.     }//数乘
  254.     Vector operator / (const double &A) const {
  255.         return Vector(x / A, y / A);
  256.     }//数除
  257.     bool operator == (const Vector &A) const  {
  258.         return dcmp(x - A.x) == 0 && dcmp(y - A.y) == 0;
  259.     }//相等
  260. };
  261. double PolarAngle(Vector A) {
  262.     return atan2(A.y, A.x);
  263. }//向量的极角
  264. Vector rotate(Vector &A, double a) {
  265.     return A = Vector(A.x * cos(a) - A.y * sin(a), A.x * sin(a) + A.y * cos(a));
  266. }//向量旋转,a为弧度
  267. double Dot(Vector A, Vector B) {
  268.     return A.x * B.x +  A.y * B.y;
  269. }//两向量点积
  270. double Cross(Vector A, Vector B) {
  271.     return A.x * B.y - A.y * B.x;
  272. }//两向量叉积
  273. double Area(Point A, Point B, Point C) {
  274.     return fabs(Cross(B - A, C - A) / 2);
  275. }//计算三角形的面积
  276. double Length(Vector A) {
  277.     return sqrt(Dot(A, A));
  278. }//计算向量的长度
  279. double Angle(Vector A, Vector B) {
  280.     return acos(Dot(A, B) / Length(A) / Length(B));
  281. }//计算向量的夹角
  282. int Direction(Vector P1, Vector P2, Vector P0) {
  283.     int opt = Cross(P1 - P0, P2 - P0);
  284.     return dcmp(opt);
  285. }//判断P1-P0,P1-P2的相对位置关系,-1为逆时针,1为顺时针(P1P0顺时针旋转到P1P2),0为共线
  286. Point GetLineIntersection(Point P, Vector V, Point Q, Vector W) {
  287.     Vector u = P - Q;
  288.     double t = Cross(W, u) / Cross(V, W);
  289.     return P + V * t;
  290. }//判断两直线(P + tv,Q + tW)的交点(看不懂直接上y = kx + b吧)
  291. double DistanceToLine(Point P, Point A, Point B) {
  292.     Vector v1 = B - A, v2 = P - A;
  293.     return fabs(Cross(v1, v2)) / Length(v1);
  294. }//计算点P到直线AB的距离(平行四边形面积 / 底)
  295. double DistanceToSegment(Point P, Point A, Point B) {
  296.     if(A == B) return Length(P - A);
  297.     if(dcmp(Dot(P - A, B - A)) < 0) return Length(P - A);
  298.     if(dcmp(Dot(P - B, A - B)) < 0) return Length(P - B);
  299.     return DistanceToLine(P, A, B);
  300. }//计算点P到线段AB的距离
  301. double PolygonAread(Point *P, int N) {
  302.     double area = 0;
  303.     for(int i = 1; i <= N - 1; i++)
  304.         area += Cross(P[i] - P[0], P[i + 1] - P[0]);
  305.     return area / 2;
  306. }//计算多边形的有向面积
  307. int isPointInPolygon(Point P, Point Poly[], int N) {
  308.     int wn = 0, k, d1, d2;
  309.     for(int i = 0; i < N; i++) {
  310.         if(!dcmp(DistanceToSegment(P, Poly[i], Poly[(i + 1) % N]))) return -1;
  311.     //点在线段的边界上
  312.         k = dcmp(Cross(Poly[(i + 1) % N] - Poly[i], P - Poly[i]));
  313.         d1 = dcmp(Poly[i].y - P.y);
  314.         d2 = dcmp(Poly[(i + 1) % N].y - P.y);
  315.         if(k > 0 && d1 <= 0 && d2 > 0) wn++;//点在左,下上穿
  316.         if(k > 0 && d2 <= 0 && d1 > 0) wn++;//点在右,上下穿
  317.         return wn & 1; // 1:内 2:外   
  318.     }   
  319. }//判断点是否在多边形内部
  320. int main() {   
  321.         
  322.     return 0;
  323. }
  324. https://cloud.tencent.com/developer/article/1172724?areaId=106001
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|膜结构网

GMT+8, 2025-1-1 18:21 , Processed in 0.156290 second(s), 23 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表