二维计算几何模板整理


分类: ACMICPC 130人阅读 评论(0) 收藏 举报
  1. /***********三分法求函数极值*************/
  2. void solve()
  3. {
  4. double L, R, m, mm, mv, mmv;
  5. while (L + eps < R)
  6. {
  7. m = (L + R) / 2;
  8. mm = (m + R) / 2;
  9. mv = calc(m);
  10. mmv = calc(mm);
  11. if (mv <= mmv) R = mm; //三分法求最大值时改为mv>=mmv
  12. else L = m;
  13. }
  14. }
  15. /*************基础***********/
  16. int dcmp(double x) {
  17. if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;
  18. }
  19. struct Point {
  20. double x, y;
  21. Point(double x=0, double y=0):x(x),y(y) { }
  22. };
  23. typedef Point Vector;
  24. Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }
  25. Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y-B.y); }
  26. Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
  27. Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); }
  28. bool operator < (const Point& a, const Point& b) {
  29. return a.x < b.x || (a.x == b.x && a.y < b.y);
  30. }
  31. bool operator == (const Point& a, const Point &b) {
  32. return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
  33. }
  34. double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }
  35. double Length(Vector A) { return sqrt(Dot(A, A)); }
  36. double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }
  37. double angle(Vector v) { return atan2(v.y, v.x); }
  38. double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }
  39. Vector vecunit(Vector x){ return x / Length(x);} //单位向量
  40. Vector Normal(Vector x) { return Point(-x.y, x.x) / Length(x);} //垂直法向量
  41. Vector Rotate(Vector A, double rad) {
  42. return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
  43. }
  44. double Area2(const Point A, const Point B, const Point C) { return Length(Cross(B-A, C-A)); }
  45. /****************直线与线段**************/
  46. //求直线p+tv和q+tw的交点 Cross(v, w) == 0无交点
  47. Point GetLineIntersection(Point p, Vector v, Point q, Vector w)
  48. {
  49. Vector u = p-q;
  50. double t = Cross(w, u) / Cross(v, w);
  51. return p + v*t;
  52. }
  53. //点p在直线ab的投影
  54. Point GetLineProjection(Point P, Point A, Point B) {
  55. Vector v = B-A;
  56. return A+v*(Dot(v, P-A) / Dot(v, v));
  57. }
  58. //点到直线距离
  59. double DistanceToLine(Point P, Point A, Point B) {
  60. Vector v1 = B - A, v2 = P - A;
  61. return fabs(Cross(v1, v2)) / Length(v1); // 如果不取绝对值,得到的是有向距离
  62. }
  63. //点在p线段上
  64. bool OnSegment(Point p, Point a1, Point a2) {
  65. return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0;
  66. }
  67. // 过两点p1, p2的直线一般方程ax+by+c=0
  68. // (x2-x1)(y-y1) = (y2-y1)(x-x1)
  69. void getLineGeneralEquation(const Point& p1, const Point& p2, double& a, double& b, double &c) {
  70. a = p2.y-p1.y;
  71. b = p1.x-p2.x;
  72. c = -a*p1.x - b*p1.y;
  73. }
  74. //点到线段距离
  75. double DistanceToSegment(Point p, Point a, Point b)
  76. {
  77. if(a == b) return Length(p-a);
  78. Vector v1 = b-a, v2 = p-a, v3 = p-b;
  79. if(dcmp(Dot(v1, v2)) < 0) return Length(v2);
  80. else if(dcmp(Dot(v1, v3)) > 0) return Length(v3);
  81. else return fabs(Cross(v1, v2)) / Length(v1);
  82. }
  83. //两线段最近距离
  84. double dis_pair_seg(Point p1, Point p2, Point p3, Point p4)
  85. {
  86. return min(min(DistanceToSegment(p1, p3, p4), DistanceToSegment(p2, p3, p4)),
  87. min(DistanceToSegment(p3, p1, p2), DistanceToSegment(p4, p1, p2)));
  88. }
  89. //线段相交判定
  90. bool SegmentItersection(Point a1, Point a2, Point b1, Point b2)
  91. {
  92. double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1),
  93. c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
  94. return dcmp(c1)*dcmp(c2) < 0 && dcmp(c3)*dcmp(c4) < 0;
  95. }
  96. // 有向直线。它的左边就是对应的半平面
  97. struct Line {
  98. Point P; // 直线上任意一点
  99. Vector v; // 方向向量
  100. double ang; // 极角,即从x正半轴旋转到向量v所需要的角(弧度)
  101. Line() {}
  102. Line(Point P, Vector v):P(P),v(v){ ang = atan2(v.y, v.x); }
  103. bool operator < (const Line& L) const {
  104. return ang < L.ang;
  105. }
  106. };
  107. //两直线交点
  108. Point GetLineIntersection(Line a, Line b) {
  109. return GetLineIntersection(a.p, a.v, b.p, b.v);
  110. }
  111. // 点p在有向直线L的左边(线上不算)
  112. bool OnLeft(const Line& L, const Point& p) {
  113. return Cross(L.v, p-L.P) > 0;
  114. }
  115. // 二直线交点,假定交点惟一存在
  116. Point GetLineIntersection(const Line& a, const Line& b) {
  117. Vector u = a.P-b.P;
  118. double t = Cross(b.v, u) / Cross(a.v, b.v);
  119. return a.P+a.v*t;
  120. }
  121. // 半平面交主过程
  122. vector<Point> HalfplaneIntersection(vector<Line> L) {
  123. int n = L.size();
  124. sort(L.begin(), L.end()); // 按极角排序
  125. int first, last; // 双端队列的第一个元素和最后一个元素的下标
  126. vector<Point> p(n); // p[i]为q[i]和q[i+1]的交点
  127. vector<Line> q(n); // 双端队列
  128. vector<Point> ans; // 结果
  129. q[first=last=0] = L[0]; // 双端队列初始化为只有一个半平面L[0]
  130. for(int i = 1; i < n; i++) {
  131. while(first < last && !OnLeft(L[i], p[last-1])) last--;
  132. while(first < last && !OnLeft(L[i], p[first])) first++;
  133. q[++last] = L[i];
  134. if(fabs(Cross(q[last].v, q[last-1].v)) < eps) { // 两向量平行且同向,取内侧的一个
  135. last--;
  136. if(OnLeft(q[last], L[i].P)) q[last] = L[i];
  137. }
  138. if(first < last) p[last-1] = GetLineIntersection(q[last-1], q[last]);
  139. }
  140. while(first < last && !OnLeft(q[first], p[last-1])) last--; // 删除无用平面
  141. if(last - first <= 1) return ans; // 空集
  142. p[last] = GetLineIntersection(q[last], q[first]); // 计算首尾两个半平面的交点
  143. // 从deque复制到输出中
  144. for(int i = first; i <= last; i++) ans.push_back(p[i]);
  145. return ans;
  146. }
  147. /***********多边形**************/
  148. //多边形有向面积
  149. double PolygonArea(vector<Point> p) {
  150. int n = p.size();
  151. double area = 0;
  152. for(int i = 1; i < n-1; i++)
  153. area += Cross(p[i]-p[0], p[i+1]-p[0]);
  154. return area/2;
  155. }
  156. // 点集凸包
  157. // 如果不希望在凸包的边上有输入点,把两个 <= 改成 <
  158. // 注意:输入点集会被修改
  159. vector<Point> ConvexHull(vector<Point>& p) {
  160. // 预处理,删除重复点
  161. sort(p.begin(), p.end());
  162. p.erase(unique(p.begin(), p.end()), p.end());
  163. int n = p.size();
  164. int m = 0;
  165. vector<Point> ch(n+1);
  166. for(int i = 0; i < n; i++) {
  167. while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
  168. ch[m++] = p[i];
  169. }
  170. int k = m;
  171. for(int i = n-2; i >= 0; i--) {
  172. while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) <= 0) m--;
  173. ch[m++] = p[i];
  174. }
  175. if(n > 1) m--;
  176. ch.resize(m);
  177. return ch;
  178. }
  179. // 凸包直径返回 点集直径的平方
  180. int diameter2(vector<Point>& points) {
  181. vector<Point> p = ConvexHull(points);
  182. int n = p.size();
  183. if(n == 1) return 0;
  184. if(n == 2) return Dist2(p[0], p[1]);
  185. p.push_back(p[0]); // 免得取模
  186. int ans = 0;
  187. for(int u = 0, v = 1; u < n; u++) {
  188. // 一条直线贴住边p[u]-p[u+1]
  189. for(;;) {
  190. int diff = Cross(p[u+1]-p[u], p[v+1]-p[v]);
  191. if(diff <= 0) {
  192. ans = max(ans, Dist2(p[u], p[v])); // u和v是对踵点
  193. if(diff == 0) ans = max(ans, Dist2(p[u], p[v+1])); // diff == 0时u和v+1也是对踵点
  194. break;
  195. }
  196. v = (v + 1) % n;
  197. }
  198. }
  199. return ans;
  200. }
  201. //两凸包最近距离
  202. double RC_Distance(Point *ch1, Point *ch2, int n, int m)
  203. {
  204. int q=0, p=0;
  205. REP(i, n) if(ch1[i].y-ch1[p].y < -eps) p=i;
  206. REP(i, m) if(ch2[i].y-ch2[q].y > eps) q=i;
  207. ch1[n]=ch1[0]; ch2[m]=ch2[0];
  208. double tmp, ans=1e100;
  209. REP(i, n)
  210. {
  211. while((tmp = Cross(ch1[p+1]-ch1[p], ch2[q+1]-ch1[p]) - Cross(ch1[p+1]-ch1[p], ch2[q]- ch1[p])) > eps)
  212. q=(q+1)%m;
  213. if(tmp < -eps) ans = min(ans,DistanceToSegment(ch2[q],ch1[p],ch1[p+1]));
  214. else ans = min(ans,dis_pair_seg(ch1[p],ch1[p+1],ch2[q],ch2[q+1]));
  215. p=(p+1)%n;
  216. }
  217. return ans;
  218. }
  219. //凸包最大内接三角形
  220. double RC_Triangle(Point* res,int n)// 凸包最大内接三角形
  221. {
  222. if(n<3) return 0;
  223. double ans=0, tmp;
  224. res[n] = res[0];
  225. int j, k;
  226. REP(i, n)
  227. {
  228. j = (i+1)%n;
  229. k = (j+1)%n;
  230. while((j != k) && (k != i))
  231. {
  232. while(Cross(res[j] - res[i], res[k+1] - res[i]) > Cross(res[j] - res[i], res[k] - res[i])) k= (k+1)%n;
  233. tmp = Cross(res[j] - res[i], res[k] - res[i]);if(tmp > ans) ans = tmp;
  234. j = (j+1)%n;
  235. }
  236. }
  237. return ans;
  238. }
  239. //模拟退火求费马点 保存在ptres中
  240. double fermat_point(Point *pt, int n, Point& ptres)
  241. {
  242. Point u, v;
  243. double step = 0.0, curlen, explen, minlen;
  244. int i, j, k, idx;
  245. bool flag;
  246. u.x = u.y = v.x = v.y = 0.0;
  247. REP(i, n)
  248. {
  249. step += fabs(pt[i].x) + fabs(pt[i].y);
  250. u.x += pt[i].x;
  251. u.y += pt[i].y;
  252. }
  253. u.x /= n;
  254. u.y /= n;
  255. flag = 0;
  256. while(step > eps)
  257. {
  258. for(k = 0; k < 10; step /= 2, ++k)
  259. for(i = -1; i <= 1; ++i)
  260. for(j = -1; j <= 1; ++j)
  261. {
  262. v.x = u.x + step*i;
  263. v.y = u.y + step*j;
  264. curlen = explen = 0.0;
  265. REP(idx, n)
  266. {
  267. curlen += dist(u, pt[idx]);
  268. explen += dist(v, pt[idx]);
  269. }
  270. if(curlen > explen)
  271. {
  272. u = v;
  273. minlen = explen;
  274. flag = 1;
  275. }
  276. }
  277. }
  278. ptres = u;
  279. return flag ? minlen : curlen;
  280. }
  281. //最近点对
  282. bool cmpxy(const Point& a, const Point& b)
  283. {
  284. if(a.x != b.x)
  285. return a.x < b.x;
  286. return a.y < b.y;
  287. }
  288. bool cmpy(const int& a, const int& b)
  289. {
  290. return point[a].y < point[b].y;
  291. }
  292. double Closest_Pair(int left, int right)
  293. {
  294. double d = INF;
  295. if(left==right)
  296. return d;
  297. if(left + 1 == right)
  298. return dis(left, right);
  299. int mid = (left+right)>>1;
  300. double d1 = Closest_Pair(left,mid);
  301. double d2 = Closest_Pair(mid+1,right);
  302. d = min(d1,d2);
  303. int i,j,k=0;
  304. //分离出宽度为d的区间
  305. for(i = left; i <= right; i++)
  306. {
  307. if(fabs(point[mid].x-point[i].x) <= d)
  308. tmpt[k++] = i;
  309. }
  310. sort(tmpt,tmpt+k,cmpy);
  311. //线性扫描
  312. for(i = 0; i < k; i++)
  313. {
  314. for(j = i+1; j < k && point[tmpt[j]].y-point[tmpt[i]].y<d; j++)
  315. {
  316. double d3 = dis(tmpt[i],tmpt[j]);
  317. if(d > d3)
  318. d = d3;
  319. }
  320. }
  321. return d;
  322. }
  323. /************圆************/
  324. struct Circle
  325. {
  326. Point c;
  327. double r;
  328. Circle(){}
  329. Circle(Point c, double r):c(c), r(r){}
  330. Point point(double a) //根据圆心角求点坐标
  331. {
  332. return Point(c.x+cos(a)*r, c.y+sin(a)*r);
  333. }
  334. };
  335. //直线与圆交点 返回个数
  336. int getLineCircleIntersection(Line L, Circle C, double& t1, double& t2, vector<Point>& sol){
  337. double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y;
  338. double e = a*a + c*c, f = 2*(a*b + c*d), g = b*b + d*d - C.r*C.r;
  339. double delta = f*f - 4*e*g; // 判别式
  340. if(dcmp(delta) < 0) return 0; // 相离
  341. if(dcmp(delta) == 0) { // 相切
  342. t1 = t2 = -f / (2 * e); sol.push_back(L.point(t1));
  343. return 1;
  344. }
  345. // 相交
  346. t1 = (-f - sqrt(delta)) / (2 * e); sol.push_back(L.point(t1));
  347. t2 = (-f + sqrt(delta)) / (2 * e); sol.push_back(L.point(t2));
  348. return 2;
  349. }
  350. //两圆交点 返回个数
  351. int getCircleCircleIntersection(Circle C1, Circle C2, vector<Point>& sol) {
  352. double d = Length(C1.c - C2.c);
  353. if(dcmp(d) == 0) {
  354. if(dcmp(C1.r - C2.r) == 0) return -1; // 重合,无穷多交点
  355. return 0;
  356. }
  357. if(dcmp(C1.r + C2.r - d) < 0) return 0;
  358. if(dcmp(fabs(C1.r-C2.r) - d) > 0) return 0;
  359. double a = angle(C2.c - C1.c);
  360. double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d));
  361. Point p1 = C1.point(a-da), p2 = C1.point(a+da);
  362. sol.push_back(p1);
  363. if(p1 == p2) return 1;
  364. sol.push_back(p2);
  365. return 2;
  366. }
  367. //三角形外接圆
  368. Circle CircumscribedCircle(Point p1, Point p2, Point p3) {
  369. double Bx = p2.x-p1.x, By = p2.y-p1.y;
  370. double Cx = p3.x-p1.x, Cy = p3.y-p1.y;
  371. double D = 2*(Bx*Cy-By*Cx);
  372. double cx = (Cy*(Bx*Bx+By*By) - By*(Cx*Cx+Cy*Cy))/D + p1.x;
  373. double cy = (Bx*(Cx*Cx+Cy*Cy) - Cx*(Bx*Bx+By*By))/D + p1.y;
  374. Point p = Point(cx, cy);
  375. return Circle(p, Length(p1-p));
  376. }
  377. //三角形内切圆
  378. Circle InscribedCircle(Point p1, Point p2, Point p3) {
  379. double a = Length(p2-p3);
  380. double b = Length(p3-p1);
  381. double c = Length(p1-p2);
  382. Point p = (p1*a+p2*b+p3*c)/(a+b+c);
  383. return Circle(p, DistanceToLine(p, p1, p2));
  384. }
  385. // 过点p到圆C的切线。v[i]是第i条切线的向量。返回切线条数
  386. int getTangents(Point p, Circle C, Vector* v) {
  387. Vector u = C.c - p;
  388. double dist = Length(u);
  389. if(dist < C.r) return 0;
  390. else if(dcmp(dist - C.r) == 0) { // p在圆上,只有一条切线
  391. v[0] = Rotate(u, PI/2);
  392. return 1;
  393. } else {
  394. double ang = asin(C.r / dist);
  395. v[0] = Rotate(u, -ang);
  396. v[1] = Rotate(u, +ang);
  397. return 2;
  398. }
  399. }
  400. //所有经过点p 半径为r 且与直线L相切的圆心
  401. vector<Point> CircleThroughPointTangentToLineGivenRadius(Point p, Line L, double r) {
  402. vector<Point> ans;
  403. double t1, t2;
  404. getLineCircleIntersection(L.move(-r), Circle(p, r), t1, t2, ans);
  405. getLineCircleIntersection(L.move(r), Circle(p, r), t1, t2, ans);
  406. return ans;
  407. }
  408. //半径为r 与a b两直线相切的圆心
  409. vector<Point> CircleTangentToLinesGivenRadius(Line a, Line b, double r) {
  410. vector<Point> ans;
  411. Line L1 = a.move(-r), L2 = a.move(r);
  412. Line L3 = b.move(-r), L4 = b.move(r);
  413. ans.push_back(GetLineIntersection(L1, L3));
  414. ans.push_back(GetLineIntersection(L1, L4));
  415. ans.push_back(GetLineIntersection(L2, L3));
  416. ans.push_back(GetLineIntersection(L2, L4));
  417. return ans;
  418. }
  419. //与两圆相切 半径为r的所有圆心
  420. vector<Point> CircleTangentToTwoDisjointCirclesWithRadius(Circle c1, Circle c2, double r) {
  421. vector<Point> ans;
  422. Vector v = c2.c - c1.c;
  423. double dist = Length(v);
  424. int d = dcmp(dist - c1.r -c2.r - r*2);
  425. if(d > 0) return ans;
  426. getCircleCircleIntersection(Circle(c1.c, c1.r+r), Circle(c2.c, c2.r+r), ans);
  427. return ans;
  428. }
  429. //多边形与圆相交面积
  430. Point GetIntersection(Line a, Line b) //线段交点
  431. {
  432. Vector u = a.p-b.p;
  433. double t = Cross(b.v, u) / Cross(a.v, b.v);
  434. return a.p + a.v*t;
  435. }
  436. bool OnSegment(Point p, Point a1, Point a2)
  437. {
  438. return dcmp(Cross(a1-p, a2-p)) == 0 && dcmp(Dot(a1-p, a2-p)) < 0;
  439. }
  440. bool InCircle(Point x, Circle c) { return dcmp(sqr(c.r) - sqr(Length(c.c - x))) >= 0;}
  441. bool OnCircle(Point x, Circle c) { return dcmp(sqr(c.r) - sqr(Length(c.c - x))) == 0;}
  442. //线段与圆的交点
  443. int getSegCircleIntersection(Line L, Circle C, Point* sol)
  444. {
  445. Vector nor = normal(L.v);
  446. Line pl = Line(C.c, nor);
  447. Point ip = GetIntersection(pl, L);
  448. double dis = Length(ip - C.c);
  449. if (dcmp(dis - C.r) > 0) return 0;
  450. Point dxy = vecunit(L.v) * sqrt(sqr(C.r) - sqr(dis));
  451. int ret = 0;
  452. sol[ret] = ip + dxy;
  453. if (OnSegment(sol[ret], L.p, L.point(1))) ret++;
  454. sol[ret] = ip - dxy;
  455. if (OnSegment(sol[ret], L.p, L.point(1))) ret++;
  456. return ret;
  457. }
  458. double SegCircleArea(Circle C, Point a, Point b) //线段切割圆
  459. {
  460. double a1 = angle(a - C.c);
  461. double a2 = angle(b - C.c);
  462. double da = fabs(a1 - a2);
  463. if (da > PI) da = PI * 2.0 - da;
  464. return dcmp(Cross(b - C.c, a - C.c)) * da * sqr(C.r) / 2.0;
  465. }
  466. double PolyCiclrArea(Circle C, Point *p, int n)//多边形与圆相交面积
  467. {
  468. double ret = 0.0;
  469. Point sol[2];
  470. p[n] = p[0];
  471. REP(i, n)
  472. {
  473. double t1, t2;
  474. int cnt = getSegCircleIntersection(Line(p[i], p[i+1]-p[i]), C, sol);
  475. if (cnt == 0)
  476. {
  477. if (!InCircle(p[i], C) || !InCircle(p[i+1], C)) ret += SegCircleArea(C, p[i], p[i+1]);
  478. else ret += Cross(p[i+1] - C.c, p[i] - C.c) / 2.0;
  479. }
  480. if (cnt == 1)
  481. {
  482. if (InCircle(p[i], C) && !InCircle(p[i+1], C)) ret += Cross(sol[0] - C.c, p[i] - C.c) / 2.0, ret += SegCircleArea(C, sol[0], p[i+1]);
  483. else ret += SegCircleArea(C, p[i], sol[0]), ret += Cross(p[i+1] - C.c, sol[0] - C.c) / 2.0;
  484. }
  485. if (cnt == 2)
  486. {
  487. if ((p[i] < p[i + 1]) ^ (sol[0] < sol[1])) swap(sol[0], sol[1]);
  488. ret += SegCircleArea(C, p[i], sol[0]);
  489. ret += Cross(sol[1] - C.c, sol[0] - C.c) / 2.0;
  490. ret += SegCircleArea(C, sol[1], p[i+1]);
  491. }
  492. }
  493. return fabs(ret);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值