weeping的私人模板,需要的话就拿去用吧(虽然可能会有小错,如果有请提醒我)
这是现在日常用的模板
2017.10.11 update:
把白书上的半平面交模板换成别的了,原来的那个好像有问题,一直wa。
把求三角形外心的模板改了精度更高的模板。
2017.10.08 update:
原来的模板太啰嗦,今天全部重新简化了,但同时保留以前模板。
2017.09.04 update:
1.发现射线法判断点在多边形内部的代码有误,已修正
2017.08.06 update:
1.卷包裹法求凸包
2.三角形和圆的相关模板
3.O(logn)判断点在凸包内
现在模板:
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 6 7 using namespace std; 8 const double PI = acos(-1.0); 9 const double eps = 1e-10; 10 11 /****************常用函数***************/ 12 //判断ta与tb的大小关系 13 int sgn( double ta, double tb) 14 { 15 if(fabs(ta-tb)<eps)return 0; 16 if(ta<tb) return -1; 17 return 1; 18 } 19 20 //点 21 class Point 22 { 23 public: 24 25 double x, y; 26 27 Point(){} 28 Point( double tx, double ty){ x = tx, y = ty;} 29 30 bool operator < (const Point &_se) const 31 { 32 return x<_se.x || (x==_se.x && y<_se.y); 33 } 34 friend Point operator + (const Point &_st,const Point &_se) 35 { 36 return Point(_st.x + _se.x, _st.y + _se.y); 37 } 38 friend Point operator - (const Point &_st,const Point &_se) 39 { 40 return Point(_st.x - _se.x, _st.y - _se.y); 41 } 42 //点位置相同(double类型) 43 bool operator == (const Point &_off)const 44 { 45 return sgn(x, _off.x) == 0 && sgn(y, _off.y) == 0; 46 } 47 48 }; 49 50 /****************常用函数***************/ 51 //点乘 52 double dot(const Point &po,const Point &ps,const Point &pe) 53 { 54 return (ps.x - po.x) * (pe.x - po.x) + (ps.y - po.y) * (pe.y - po.y); 55 } 56 //叉乘 57 double xmult(const Point &po,const Point &ps,const Point &pe) 58 { 59 return (ps.x - po.x) * (pe.y - po.y) - (pe.x - po.x) * (ps.y - po.y); 60 } 61 //两点间距离的平方 62 double getdis2(const Point &st,const Point &se) 63 { 64 return (st.x - se.x) * (st.x - se.x) + (st.y - se.y) * (st.y - se.y); 65 } 66 //两点间距离 67 double getdis(const Point &st,const Point &se) 68 { 69 return sqrt((st.x - se.x) * (st.x - se.x) + (st.y - se.y) * (st.y - se.y)); 70 } 71 72 //两点表示的向量 73 class Line 74 { 75 public: 76 77 Point s, e;//两点表示,起点[s],终点[e] 78 double a, b, c;//一般式,ax+by+c=0 79 double angle;//向量的角度,[-pi,pi] 80 81 Line(){} 82 Line( Point ts, Point te):s(ts),e(te){}//get_angle();} 83 Line(double _a,double _b,double _c):a(_a),b(_b),c(_c){} 84 85 //排序用 86 bool operator < (const Line &ta)const 87 { 88 return angle<ta.angle; 89 } 90 //向量与向量的叉乘 91 friend double operator / ( const Line &_st, const Line &_se) 92 { 93 return (_st.e.x - _st.s.x) * (_se.e.y - _se.s.y) - (_st.e.y - _st.s.y) * (_se.e.x - _se.s.x); 94 } 95 //向量间的点乘 96 friend double operator *( const Line &_st, const Line &_se) 97 { 98 return (_st.e.x - _st.s.x) * (_se.e.x - _se.s.x) - (_st.e.y - _st.s.y) * (_se.e.y - _se.s.y); 99 } 100 //从两点表示转换为一般表示 101 //a=y2-y1,b=x1-x2,c=x2*y1-x1*y2 102 bool pton() 103 { 104 a = e.y - s.y; 105 b = s.x - e.x; 106 c = e.x * s.y - e.y * s.x; 107 return true; 108 } 109 //半平面交用 110 //点在向量左边(右边的小于号改成大于号即可,在对应直线上则加上=号) 111 friend bool operator < (const Point &_Off, const Line &_Ori) 112 { 113 return (_Ori.e.y - _Ori.s.y) * (_Off.x - _Ori.s.x) 114 < (_Off.y - _Ori.s.y) * (_Ori.e.x - _Ori.s.x); 115 } 116 //求直线或向量的角度 117 double get_angle( bool isVector = true) 118 { 119 angle = atan2( e.y - s.y, e.x - s.x); 120 if(!isVector && angle < 0) 121 angle += PI; 122 return angle; 123 } 124 125 //点在线段或直线上 1:点在直线上 2点在s,e所在矩形内 126 bool has(const Point &_Off, bool isSegment = false) const 127 { 128 bool ff = sgn( xmult( s, e, _Off), 0) == 0; 129 if( !isSegment) return ff; 130 return ff 131 && sgn(_Off.x - min(s.x, e.x), 0) >= 0 && sgn(_Off.x - max(s.x, e.x), 0) <= 0 132 && sgn(_Off.y - min(s.y, e.y), 0) >= 0 && sgn(_Off.y - max(s.y, e.y), 0) <= 0; 133 } 134 135 //点到直线/线段的距离 136 double dis(const Point &_Off, bool isSegment = false) 137 { 138 ///化为一般式 139 pton(); 140 //到直线垂足的距离 141 double td = (a * _Off.x + b * _Off.y + c) / sqrt(a * a + b * b); 142 //如果是线段判断垂足 143 if(isSegment) 144 { 145 double xp = (b * b * _Off.x - a * b * _Off.y - a * c) / ( a * a + b * b); 146 double yp = (-a * b * _Off.x + a * a * _Off.y - b * c) / (a * a + b * b); 147 double xb = max(s.x, e.x); 148 double yb = max(s.y, e.y); 149 double xs = s.x + e.x - xb; 150 double ys = s.y + e.y - yb; 151 if(xp > xb + eps || xp < xs - eps || yp > yb + eps || yp < ys - eps) 152 td = min( getdis(_Off,s), getdis(_Off,e)); 153 } 154 return fabs(td); 155 } 156 157 //关于直线对称的点 158 Point mirror(const Point &_Off) 159 { 160 ///注意先转为一般式 161 Point ret; 162 double d = a * a + b * b; 163 ret.x = (b * b * _Off.x - a * a * _Off.x - 2 * a * b * _Off.y - 2 * a * c) / d; 164 ret.y = (a * a * _Off.y - b * b * _Off.y - 2 * a * b * _Off.x - 2 * b * c) / d; 165 return ret; 166 } 167 //计算两点的中垂线 168 static Line ppline(const Point &_a,const Point &_b) 169 { 170 Line ret; 171 ret.s.x = (_a.x + _b.x) / 2; 172 ret.s.y = (_a.y + _b.y) / 2; 173 //一般式 174 ret.a = _b.x - _a.x; 175 ret.b = _b.y - _a.y; 176 ret.c = (_a.y - _b.y) * ret.s.y + (_a.x - _b.x) * ret.s.x; 177 //两点式 178 if(fabs(ret.a) > eps) 179 { 180 ret.e.y = 0.0; 181 ret.e.x = - ret.c / ret.a; 182 if(ret.e == ret. s) 183 { 184 ret.e.y = 1e10; 185 ret.e.x = - (ret.c - ret.b * ret.e.y) / ret.a; 186 } 187 } 188 else 189 { 190 ret.e.x = 0.0; 191 ret.e.y = - ret.c / ret.b; 192 if(ret.e == ret. s) 193 { 194 ret.e.x = 1e10; 195 ret.e.y = - (ret.c - ret.a * ret.e.x) / ret.b; 196 } 197 } 198 return ret; 199 } 200 201 //------------直线和直线(向量)------------- 202 //向量向左边平移t的距离 203 Line& moveLine( double t) 204 { 205 Point of; 206 of = Point( -( e.y - s.y), e.x - s.x); 207 double dis = sqrt( of.x * of.x + of.y * of.y); 208 of.x= of.x * t / dis, of.y = of.y * t / dis; 209 s = s + of, e = e + of; 210 return *this; 211 } 212 //直线重合 213 static bool equal(const Line &_st,const Line &_se) 214 { 215 return _st.has( _se.e) && _se.has( _st.s); 216 } 217 //直线平行 218 static bool parallel(const Line &_st,const Line &_se) 219 { 220 return sgn( _st / _se, 0) == 0; 221 } 222 //两直线(线段)交点 223 //返回-1代表平行,0代表重合,1代表相交 224 static bool crossLPt(const Line &_st,const Line &_se, Point &ret) 225 { 226 if(parallel(_st,_se)) 227 { 228 if(Line::equal(_st,_se)) return 0; 229 return -1; 230 } 231 ret = _st.s; 232 double t = ( Line(_st.s,_se.s) / _se) / ( _st / _se); 233 ret.x += (_st.e.x - _st.s.x) * t; 234 ret.y += (_st.e.y - _st.s.y) * t; 235 return 1; 236 } 237 //------------线段和直线(向量)---------- 238 //直线和线段相交 239 //参数:直线[_st],线段[_se] 240 friend bool crossSL( Line &_st, Line &_se) 241 { 242 return sgn( xmult( _st.s, _se.s, _st.e) * xmult( _st.s, _st.e, _se.e), 0) >= 0; 243 } 244 245 //判断线段是否相交(注意添加eps) 246 static bool isCrossSS( const Line &_st, const Line &_se) 247 { 248 //1.快速排斥试验判断以两条线段为对角线的两个矩形是否相交 249 //2.跨立试验(等于0时端点重合) 250 return 251 max(_st.s.x, _st.e.x) >= min(_se.s.x, _se.e.x) && 252 max(_se.s.x, _se.e.x) >= min(_st.s.x, _st.e.x) && 253 max(_st.s.y, _st.e.y) >= min(_se.s.y, _se.e.y) && 254 max(_se.s.y, _se.e.y) >= min(_st.s.y, _st.e.y) && 255 sgn( xmult( _se.s, _st.s, _se.e) * xmult( _se.s, _se.e, _st.s), 0) >= 0 && 256 sgn( xmult( _st.s, _se.s, _st.e) * xmult( _st.s, _st.e, _se.s), 0) >= 0; 257 } 258 }; 259 260 //寻找凸包的graham 扫描法所需的排序函数 261 Point gsort; 262 bool gcmp( const Point &ta, const Point &tb)/// 选取与最后一条确定边夹角最小的点,即余弦值最大者 263 { 264 double tmp = xmult( gsort, ta, tb); 265 if( fabs( tmp) < eps) 266 return getdis( gsort, ta) < getdis( gsort, tb); 267 else if( tmp > 0) 268 return 1; 269 return 0; 270 } 271 272 class Polygon 273 { 274 public: 275 const static int maxpn = 5e4+7; 276 Point pt[maxpn];//点(顺时针或逆时针) 277 Line dq[maxpn]; //求半平面交打开注释 278 int n;//点的个数 279 280 281 //求多边形面积,多边形内点必须顺时针或逆时针 282 double area() 283 { 284 double ans = 0.0; 285 for(int i = 0; i < n; i ++) 286 { 287 int nt = (i + 1) % n; 288 ans += pt[i].x * pt[nt].y - pt[nt].x * pt[i].y; 289 } 290 return fabs( ans / 2.0); 291 } 292 //求多边形重心,多边形内点必须顺时针或逆时针 293 Point gravity() 294 { 295 Point ans; 296 ans.x = ans.y = 0.0; 297 double area = 0.0; 298 for(int i = 0; i < n; i ++) 299 { 300 int nt = (i + 1) % n; 301 double tp = pt[i].x * pt[nt].y - pt[nt].x * pt[i].y; 302 area += tp; 303 ans.x += tp * (pt[i].x + pt[nt].x); 304 ans.y += tp * (pt[i].y + pt[nt].y); 305 } 306 ans.x /= 3 * area; 307 ans.y /= 3 * area; 308 return ans; 309 } 310 //判断点是否在任意多边形内[射线法],O(n) 311 bool ahas( Point &_Off) 312 { 313 int ret = 0; 314 double infv = 1e20;//坐标系最大范围 315 Line l = Line( _Off, Point( -infv ,_Off.y)); 316 for(int i = 0; i < n; i ++) 317 { 318 Line ln = Line( pt[i], pt[(i + 1) % n]); 319 if(fabs(ln.s.y - ln.e.y) > eps) 320 { 321 Point tp = (ln.s.y > ln.e.y)? ln.s: ln.e; 322 if( ( fabs( tp.y - _Off.y) < eps && tp.x < _Off.x + eps) || Line::isCrossSS( ln, l)) 323 ret++; 324 } 325 else if( Line::isCrossSS( ln, l)) 326 ret++; 327 } 328 return ret&1; 329 } 330 331 //判断任意点是否在凸包内,O(logn) 332 bool bhas( Point & p) 333 { 334 if( n < 3) 335 return false; 336 if( xmult( pt[0], p, pt[1]) > eps) 337 return false; 338 if( xmult( pt[0], p, pt[n-1]) < -eps) 339 return false; 340 int l = 2,r = n-1; 341 int line = -1; 342 while( l <= r) 343 { 344 int mid = ( l + r) >> 1; 345 if( xmult( pt[0], p, pt[mid]) >= 0) 346 line = mid,r = mid - 1; 347 else l = mid + 1; 348 } 349 return xmult( pt[line-1], p, pt[line]) <= eps; 350 } 351 352 353 354 //凸多边形被直线分割 355 Polygon split( Line &_Off) 356 { 357 //注意确保多边形能被分割 358 Polygon ret; 359 Point spt[2]; 360 double tp = 0.0, np; 361 bool flag = true; 362 int i, pn = 0, spn = 0; 363 for(i = 0; i < n; i ++) 364 { 365 if(flag) 366 pt[pn ++] = pt[i]; 367 else 368 ret.pt[ret.n ++] = pt[i]; 369 np = xmult( _Off.s, _Off.e, pt[(i + 1) % n]); 370 if(tp * np < -eps) 371 { 372 flag = !flag; 373 Line::crossLPt( _Off, Line(pt[i], pt[(i + 1) % n]), spt[spn++]); 374 } 375 tp = (fabs(np) > eps)?np: tp; 376 } 377 ret.pt[ret.n ++] = spt[0]; 378 ret.pt[ret.n ++] = spt[1]; 379 n = pn; 380 return ret; 381 } 382 383 384 /** 卷包裹法求点集凸包,_p为输入点集,_n为点的数量 **/ 385 void ConvexClosure( Point _p[], int _n) 386 { 387 sort( _p, _p + _n); 388 n = 0; 389 for(int i = 0; i < _n; i++) 390 { 391 while( n > 1 && sgn( xmult( pt[n-2], pt[n-1], _p[i]), 0) <= 0) 392 n--; 393 pt[n++] = _p[i]; 394 } 395 int _key = n; 396 for(int i = _n - 2; i >= 0; i--) 397 { 398 while( n > _key && sgn( xmult( pt[n-2], pt[n-1], _p[i]), 0) <= 0) 399 n--; 400 pt[n++] = _p[i]; 401 } 402 if(n>1) n--;//除去重复的点,该点已是凸包凸包起点 403 } 404 /****** 寻找凸包的graham 扫描法********************/ 405 /****** _p为输入的点集,_n为点的数量****************/ 406 407 void graham( Point _p[], int _n) 408 { 409 int cur=0; 410 for(int i = 1; i < _n; i++) 411 if( sgn( _p[cur].y, _p[i].y) > 0 || ( sgn( _p[cur].y, _p[i].y) == 0 && sgn( _p[cur].x, _p[i].x) > 0) ) 412 cur = i; 413 swap( _p[cur], _p[0]); 414 n = 0, gsort = pt[n++] = _p[0]; 415 if( _n <= 1) return; 416 sort( _p + 1, _p+_n ,gcmp); 417 pt[n++] = _p[1]; 418 for(int i = 2; i < _n; i++) 419 { 420 while(n>1 && sgn( xmult( pt[n-2], pt[n-1], _p[i]), 0) <= 0)// 当凸包退化成直线时需特别注意n 421 n--; 422 pt[n++] = _p[i]; 423 } 424 } 425 //凸包旋转卡壳(注意点必须顺时针或逆时针排列) 426 //返回值凸包直径的平方(最远两点距离的平方) 427 pair<Point,Point> rotating_calipers() 428 { 429 int i = 1 % n; 430 double ret = 0.0; 431 pt[n] = pt[0]; 432 pair<Point,Point>ans=make_pair(pt[0],pt[0]); 433 for(int j = 0; j < n; j ++) 434 { 435 while( fabs( xmult( pt[i+1], pt[j], pt[j + 1])) > fabs( xmult( pt[i], pt[j], pt[j + 1])) + eps) 436 i = (i + 1) % n; 437 //pt[i]和pt[j],pt[i + 1]和pt[j + 1]可能是对踵点 438 if(ret < getdis2(pt[i],pt[j])) ret = getdis2(pt[i],pt[j]), ans = make_pair(pt[i],pt[j]); 439 if(ret < getdis2(pt[i+1],pt[j+1])) ret = getdis(pt[i+1],pt[j+1]), ans = make_pair(pt[i+1],pt[j+1]); 440 } 441 return ans; 442 } 443 444 //凸包旋转卡壳(注意点必须逆时针排列) 445 //返回值两凸包的最短距离 446 double rotating_calipers( Polygon &_Off) 447 { 448 int i = 0; 449 double ret = 1e10;//inf 450 pt[n] = pt[0]; 451 _Off.pt[_Off.n] = _Off.pt[0]; 452 //注意凸包必须逆时针排列且pt[0]是左下角点的位置 453 while( _Off.pt[i + 1].y > _Off.pt[i].y) 454 i = (i + 1) % _Off.n; 455 for(int j = 0; j < n; j ++) 456 { 457 double tp; 458 //逆时针时为 >,顺时针则相反 459 while((tp = xmult(_Off.pt[i + 1],pt[j], pt[j + 1]) - xmult(_Off.pt[i], pt[j], pt[j + 1])) > eps) 460 i = (i + 1) % _Off.n; 461 //(pt[i],pt[i+1])和(_Off.pt[j],_Off.pt[j + 1])可能是最近线段 462 ret = min(ret, Line(pt[j], pt[j + 1]).dis(_Off.pt[i], true)); 463 ret = min(ret, Line(_Off.pt[i], _Off.pt[i + 1]).dis(pt[j + 1], true)); 464 if(tp > -eps)//如果不考虑TLE问题最好不要加这个判断 465 { 466 ret = min(ret, Line(pt[j], pt[j + 1]).dis(_Off.pt[i + 1], true)); 467 ret = min(ret, Line(_Off.pt[i], _Off.pt[i + 1]).dis(pt[j], true)); 468 } 469 } 470 return ret; 471 } 472 473 //-----------半平面交------------- 474 //复杂度:O(nlog2(n)) 475 //获取半平面交的多边形(多边形的核) 476 //参数:向量集合[l],向量数量[ln];(半平面方向在向量左边) 477 //函数运行后如果n[即返回多边形的点数量]为0则不存在半平面交的多边形(不存在区域或区域面积无穷大) 478 int judege( Line &_lx, Line &_ly, Line &_lz) 479 { 480 Point tmp; 481 Line::crossLPt(_lx,_ly,tmp); 482 return sgn(xmult(_lz.s,tmp,_lz.e),0); 483 } 484 int halfPanelCross(Line L[], int ln) 485 { 486 int i, tn, bot, top; 487 for(int i = 0; i < ln; i++) 488 L[i].get_angle(); 489 sort(L, L + ln); 490 //平面在向量左边的筛选 491 for(i = tn = 1; i < ln; i ++) 492 if(fabs(L[i].angle - L[i - 1].angle) > eps) 493 L[tn ++] = L[i]; 494 ln = tn, n = 0, bot = 0, top = 1; 495 dq[0] = L[0], dq[1] = L[1]; 496 for(i = 2; i < ln; i ++) 497 { 498 while(bot < top && judege(dq[top],dq[top-1],L[i]) > 0) 499 top --; 500 while(bot < top && judege(dq[bot],dq[bot+1],L[i]) > 0) 501 bot ++; 502 dq[++ top] = L[i]; 503 } 504 while(bot < top && judege(dq[top],dq[top-1],dq[bot]) > 0) 505 top --; 506 while(bot < top && judege(dq[bot],dq[bot+1],dq[top]) > 0) 507 bot ++; 508 //若半平面交退化为点或线 509 // if(top <= bot + 1) 510 // return 0; 511 dq[++top] = dq[bot]; 512 for(i = bot; i < top; i ++) 513 Line::crossLPt(dq[i],dq[i + 1],pt[n++]); 514 return n; 515 } 516 }; 517 518 519 class Circle 520 { 521 public: 522 Point c;//圆心 523 double r;//半径 524 double db, de;//圆弧度数起点, 圆弧度数终点(逆时针0-360) 525 526 //-------圆--------- 527 528 //判断圆在多边形内 529 bool inside( Polygon &_Off) 530 { 531 if(_Off.ahas(c) == false) 532 return false; 533 for(int i = 0; i < _Off.n; i ++) 534 { 535 Line l = Line(_Off.pt[i], _Off.pt[(i + 1) % _Off.n]); 536 if(l.dis(c, true) < r - eps) 537 return false; 538 } 539 return true; 540 } 541 542 //判断多边形在圆内(线段和折线类似) 543 bool has( Polygon &_Off) 544 { 545 for(int i = 0; i < _Off.n; i ++) 546 if( getdis2(_Off.pt[i],c) > r * r - eps) 547 return false; 548 return true; 549 } 550 551 //-------圆弧------- 552 //圆被其他圆截得的圆弧,参数:圆[_Off] 553 Circle operator-(Circle &_Off) const 554 { 555 //注意圆必须相交,圆心不能重合 556 double d2 = getdis2(c,_Off.c); 557 double d = getdis(c,_Off.c); 558 double ans = acos((d2 + r * r - _Off.r * _Off.r) / (2 * d * r)); 559 Point py = _Off.c - c; 560 double oans = atan2(py.y, py.x); 561 Circle res; 562 res.c = c; 563 res.r = r; 564 res.db = oans + ans; 565 res.de = oans - ans + 2 * PI; 566 return res; 567 } 568 //圆被其他圆截得的圆弧,参数:圆[_Off] 569 Circle operator+(Circle &_Off) const 570 { 571 //注意圆必须相交,圆心不能重合 572 double d2 = getdis2(c,_Off.c); 573 double d = getdis(c,_Off.c); 574 double ans = acos((d2 + r * r - _Off.r * _Off.r) / (2 * d * r)); 575 Point py = _Off.c - c; 576 double oans = atan2(py.y, py.x); 577 Circle res; 578 res.c = c; 579 res.r = r; 580 res.db = oans - ans; 581 res.de = oans + ans; 582 return res; 583 } 584 585 //过圆外一点的两条切线 586 //参数:点[_Off](必须在圆外),返回:两条切线(切线的s点为_Off,e点为切点) 587 pair<Line, Line> tangent( Point &_Off) 588 { 589 double d = getdis(c,_Off); 590 //计算角度偏移的方式 591 double angp = acos(r / d), ango = atan2(_Off.y - c.y, _Off.x - c.x); 592 Point pl = Point(c.x + r * cos(ango + angp), c.y + r * sin(ango + angp)), 593 pr = Point(c.x + r * cos(ango - angp), c.y + r * sin(ango - angp)); 594 return make_pair(Line(_Off, pl), Line(_Off, pr)); 595 } 596 597 //计算直线和圆的两个交点 598 //参数:直线[_Off](两点式),返回两个交点,注意直线必须和圆有两个交点 599 pair<Point, Point> cross(Line _Off) 600 { 601 _Off.pton(); 602 //到直线垂足的距离 603 double td = fabs(_Off.a * c.x + _Off.b * c.y + _Off.c) / sqrt(_Off.a * _Off.a + _Off.b * _Off.b); 604 605 //计算垂足坐标 606 double xp = (_Off.b * _Off.b * c.x - _Off.a * _Off.b * c.y - _Off.a * _Off.c) / ( _Off.a * _Off.a + _Off.b * _Off.b); 607 double yp = (- _Off.a * _Off.b * c.x + _Off.a * _Off.a * c.y - _Off.b * _Off.c) / (_Off.a * _Off.a + _Off.b * _Off.b); 608 609 double ango = atan2(yp - c.y, xp - c.x); 610 double angp = acos(td / r); 611 612 return make_pair(Point(c.x + r * cos(ango + angp), c.y + r * sin(ango + angp)), 613 Point(c.x + r * cos(ango - angp), c.y + r * sin(ango - angp))); 614 } 615 }; 616 617 class triangle 618 { 619 public: 620 Point a, b, c;//顶点 621 triangle(){} 622 triangle(Point a, Point b, Point c): a(a), b(b), c(c){} 623 624 //计算三角形面积 625 double area() 626 { 627 return fabs( xmult(a, b, c)) / 2.0; 628 } 629 630 //计算三角形外心 631 //返回:外接圆圆心 632 Point circumcenter() 633 { 634 double pa = a.x * a.x + a.y * a.y; 635 double pb = b.x * b.x + b.y * b.y; 636 double pc = c.x * c.x + c.y * c.y; 637 double ta = pa * ( b.y - c.y) - pb * ( a.y - c.y) + pc * ( a.y - b.y); 638 double tb = -pa * ( b.x - c.x) + pb * ( a.x - c.x) - pc * ( a.x - b.x); 639 double tc = a.x * ( b.y - c.y) - b.x * ( a.y - c.y) + c.x * ( a.y - b.y); 640 return Point( ta / 2.0 / tc, tb / 2.0 / tc); 641 } 642 643 //计算三角形内心 644 //返回:内接圆圆心 645 Point incenter() 646 { 647 Line u, v; 648 double m, n; 649 u.s = a; 650 m = atan2(b.y - a.y, b.x - a.x); 651 n = atan2(c.y - a.y, c.x - a.x); 652 u.e.x = u.s.x + cos((m + n) / 2); 653 u.e.y = u.s.y + sin((m + n) / 2); 654 v.s = b; 655 m = atan2(a.y - b.y, a.x - b.x); 656 n = atan2(c.y - b.y, c.x - b.x); 657 v.e.x = v.s.x + cos((m + n) / 2); 658 v.e.y = v.s.y + sin((m + n) / 2); 659 Point ret; 660 Line::crossLPt(u,v,ret); 661 return ret; 662 } 663 664 //计算三角形垂心 665 //返回:高的交点 666 Point perpencenter() 667 { 668 Line u,v; 669 u.s = c; 670 u.e.x = u.s.x - a.y + b.y; 671 u.e.y = u.s.y + a.x - b.x; 672 v.s = b; 673 v.e.x = v.s.x - a.y + c.y; 674 v.e.y = v.s.y + a.x - c.x; 675 Point ret; 676 Line::crossLPt(u,v,ret); 677 return ret; 678 } 679 680 //计算三角形重心 681 //返回:重心 682 //到三角形三顶点距离的平方和最小的点 683 //三角形内到三边距离之积最大的点 684 Point barycenter() 685 { 686 Line u,v; 687 u.s.x = (a.x + b.x) / 2; 688 u.s.y = (a.y + b.y) / 2; 689 u.e = c; 690 v.s.x = (a.x + c.x) / 2; 691 v.s.y = (a.y + c.y) / 2; 692 v.e = b; 693 Point ret; 694 Line::crossLPt(u,v,ret); 695 return ret; 696 } 697 698 //计算三角形费马点 699 //返回:到三角形三顶点距离之和最小的点 700 Point fermentPoint() 701 { 702 Point u, v; 703 double step = fabs(a.x) + fabs(a.y) + fabs(b.x) + fabs(b.y) + fabs(c.x) + fabs(c.y); 704 int i, j, k; 705 u.x = (a.x + b.x + c.x) / 3; 706 u.y = (a.y + b.y + c.y) / 3; 707 while (step > eps) 708 { 709 for (k = 0; k < 10; step /= 2, k ++) 710 { 711 for (i = -1; i <= 1; i ++) 712 { 713 for (j =- 1; j <= 1; j ++) 714 { 715 v.x = u.x + step * i; 716 v.y = u.y + step * j; 717 if (getdis(u,a) + getdis(u,b) + getdis(u,c) > getdis(v,a) + getdis(v,b) + getdis(v,c)) 718 u = v; 719 } 720 } 721 } 722 } 723 return u; 724 } 725 }; 726 727 int main(void) 728 { 729 730 return 0; 731 }
以前模板:
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 6 7 using namespace std; 8 const double PI = acos(-1.0); 9 const double eps = 1e-10; 10 //点 11 class Point 12 { 13 public: 14 double x, y; 15 16 Point(){} 17 Point(double x, double y):x(x),y(y){} 18 19 bool operator < (const Point &_se) const 20 { 21 return x<_se.x || (x==_se.x && y<_se.y); 22 } 23 /*******判断ta与tb的大小关系*******/ 24 static int sgn(double ta,double tb) 25 { 26 if(fabs(ta-tb)<eps)return 0; 27 if(ta<tb) return -1; 28 return 1; 29 } 30 static double xmult(const Point &po, const Point &ps, const Point &pe) 31 { 32 return (ps.x - po.x) * (pe.y - po.y) - (pe.x - po.x) * (ps.y - po.y); 33 } 34 friend Point operator + (const Point &_st,const Point &_se) 35 { 36 return Point(_st.x + _se.x, _st.y + _se.y); 37 } 38 friend Point operator - (const Point &_st,const Point &_se) 39 { 40 return Point(_st.x - _se.x, _st.y - _se.y); 41 } 42 //点位置相同(double类型) 43 bool operator == (const Point &_off) const 44 { 45 return Point::sgn(x, _off.x) == 0 && Point::sgn(y, _off.y) == 0; 46 } 47 //点位置不同(double类型) 48 bool operator != (const Point &_Off) const 49 { 50 return ((*this) == _Off) == false; 51 } 52 //两点间距离的平方 53 static double dis2(const Point &_st,const Point &_se) 54 { 55 return (_st.x - _se.x) * (_st.x - _se.x) + (_st.y - _se.y) * (_st.y - _se.y); 56 } 57 //两点间距离 58 static double dis(const Point &_st, const Point &_se) 59 { 60 return sqrt((_st.x - _se.x) * (_st.x - _se.x) + (_st.y - _se.y) * (_st.y - _se.y)); 61 } 62 }; 63 //两点表示的向量 64 class Line 65 { 66 public: 67 Point s, e;//两点表示,起点[s],终点[e] 68 double a, b, c;//一般式,ax+by+c=0 69 double angle;//向量的角度,[-pi,pi] 70 Line(){} 71 Line(const Point &s, const Point &e):s(s),e(e){get_angle(1);} 72 Line(double _a,double _b,double _c):a(_a),b(_b),c(_c){} 73 74 //向量与点的叉乘,参数:点[_Off] 75 //[点相对向量位置判断] 76 double operator /(const Point &_Off) const 77 { 78 return (_Off.y - s.y) * (e.x - s.x) - (_Off.x - s.x) * (e.y - s.y); 79 } 80 //向量与向量的叉乘,参数:向量[_Off] 81 friend double operator /(const Line &_st,const Line &_se) 82 { 83 return (_st.e.x - _st.s.x) * (_se.e.y - _se.s.y) - (_st.e.y - _st.s.y) * (_se.e.x - _se.s.x); 84 } 85 friend double operator *(const Line &_st,const Line &_se) 86 { 87 return (_st.e.x - _st.s.x) * (_se.e.x - _se.s.x) - (_st.e.y - _st.s.y) * (_se.e.y - _se.s.y); 88 } 89 //从两点表示转换为一般表示 90 //a=y2-y1,b=x1-x2,c=x2*y1-x1*y2 91 bool pton() 92 { 93 a = e.y - s.y; 94 b = s.x - e.x; 95 c = e.x * s.y - e.y * s.x; 96 return true; 97 } 98 //求直线或向量的角度 99 double get_angle(bool isVector) 100 { 101 angle=atan2(e.y-s.y,e.x-s.x); 102 if(!isVector && angle<0) 103 angle+=PI; 104 return angle; 105 } 106 107 // 108 bool operator < (const Line &ta)const 109 { 110 return angle<ta.angle; 111 } 112 //-----------点和直线(向量)----------- 113 //点在向量左边(右边的小于号改成大于号即可,在对应直线上则加上=号) 114 //参数:点[_Off],向量[_Ori] 115 friend bool operator<(const Point &_Off, const Line &_Ori) 116 { 117 return (_Ori.e.y - _Ori.s.y) * (_Off.x - _Ori.s.x) 118 < (_Off.y - _Ori.s.y) * (_Ori.e.x - _Ori.s.x); 119 } 120 121 //点在直线上,参数:点[_Off] 122 bool lhas(const Point &_Off) const 123 { 124 return Point::sgn((*this) / _Off, 0) == 0; 125 } 126 //点在线段上,参数:点[_Off] 127 bool shas(const Point &_Off) const 128 { 129 return lhas(_Off) 130 && Point::sgn(_Off.x - min(s.x, e.x), 0) > 0 && Point::sgn(_Off.x - max(s.x, e.x), 0) < 0 131 && Point::sgn(_Off.y - min(s.y, e.y), 0) > 0 && Point::sgn(_Off.y - max(s.y, e.y), 0) < 0; 132 } 133 134 //点到直线/线段的距离 135 //参数: 点[_Off], 是否是线段[isSegment](默认为直线) 136 double dis(const Point &_Off, bool isSegment = false) 137 { 138 ///化为一般式 139 pton(); 140 141 //到直线垂足的距离 142 double td = (a * _Off.x + b * _Off.y + c) / sqrt(a * a + b * b); 143 144 //如果是线段判断垂足 145 if(isSegment) 146 { 147 double xp = (b * b * _Off.x - a * b * _Off.y - a * c) / ( a * a + b * b); 148 double yp = (-a * b * _Off.x + a * a * _Off.y - b * c) / (a * a + b * b); 149 double xb = max(s.x, e.x); 150 double yb = max(s.y, e.y); 151 double xs = s.x + e.x - xb; 152 double ys = s.y + e.y - yb; 153 if(xp > xb + eps || xp < xs - eps || yp > yb + eps || yp < ys - eps) 154 td = min(Point::dis(_Off,s), Point::dis(_Off,e)); 155 } 156 157 return fabs(td); 158 } 159 160 //关于直线对称的点 161 Point mirror(const Point &_Off) const 162 { 163 ///注意先转为一般式 164 Point ret; 165 double d = a * a + b * b; 166 ret.x = (b * b * _Off.x - a * a * _Off.x - 2 * a * b * _Off.y - 2 * a * c) / d; 167 ret.y = (a * a * _Off.y - b * b * _Off.y - 2 * a * b * _Off.x - 2 * b * c) / d; 168 return ret; 169 } 170 //计算两点的中垂线 171 static Line ppline(const Point &_a, const Point &_b) 172 { 173 Line ret; 174 ret.s.x = (_a.x + _b.x) / 2; 175 ret.s.y = (_a.y + _b.y) / 2; 176 //一般式 177 ret.a = _b.x - _a.x; 178 ret.b = _b.y - _a.y; 179 ret.c = (_a.y - _b.y) * ret.s.y + (_a.x - _b.x) * ret.s.x; 180 //两点式 181 if(std::fabs(ret.a) > eps) 182 { 183 ret.e.y = 0.0; 184 ret.e.x = - ret.c / ret.a; 185 if(ret.e == ret. s) 186 { 187 ret.e.y = 1e10; 188 ret.e.x = - (ret.c - ret.b * ret.e.y) / ret.a; 189 } 190 } 191 else 192 { 193 ret.e.x = 0.0; 194 ret.e.y = - ret.c / ret.b; 195 if(ret.e == ret. s) 196 { 197 ret.e.x = 1e10; 198 ret.e.y = - (ret.c - ret.a * ret.e.x) / ret.b; 199 } 200 } 201 return ret; 202 } 203 204 //------------直线和直线(向量)------------- 205 //直线向左边平移t的距离 206 Line& moveLine(double t) 207 { 208 Point of; 209 of=Point(-(e.y-s.y),e.x-s.x); 210 double dis=sqrt(of.x*of.x+of.y*of.y); 211 of.x=of.x*t/dis,of.y=of.y*t/dis; 212 s=s+of,e=e+of; 213 return *this; 214 } 215 //直线重合,参数:直线向量[_st],[_se] 216 static bool equal(const Line &_st, const Line &_se) 217 { 218 return _st.lhas(_se.e) && _se.lhas(_se.s); 219 } 220 //直线平行,参数:直线向量[_st],[_se] 221 static bool parallel(const Line &_st,const Line &_se) 222 { 223 return Point::sgn(_st / _se, 0) == 0; 224 } 225 //两直线(线段)交点,参数:直线向量[_st],[_se],交点 226 //返回-1代表平行,0代表重合,1代表相交 227 static bool crossLPt(const Line &_st,const Line &_se,Point &ret) 228 { 229 if(Line::parallel(_st,_se)) 230 { 231 if(Line::equal(_st,_se)) return 0; 232 return -1; 233 } 234 ret = _st.s; 235 double t = (Line(_st.s,_se.s)/_se)/(_st/_se); 236 ret.x += (_st.e.x - _st.s.x) * t; 237 ret.y += (_st.e.y - _st.s.y) * t; 238 return 1; 239 } 240 //------------线段和直线(向量)---------- 241 //线段和直线交 242 //参数:直线[_st],线段[_se] 243 friend bool crossSL(const Line &_st,const Line &_se) 244 { 245 return Point::sgn((_st / _se.s) * (_st / _se.e) ,0) <= 0; 246 } 247 248 //------------线段和线段(向量)---------- 249 //判断线段是否相交(注意添加eps),参数:线段[_st],线段[_se] 250 static bool isCrossSS(const Line &_st,const Line &_se) 251 { 252 //1.快速排斥试验判断以两条线段为对角线的两个矩形是否相交 253 //2.跨立试验(等于0时端点重合) 254 return 255 max(_st.s.x, _st.e.x) >= min(_se.s.x, _se.e.x) && 256 max(_se.s.x, _se.e.x) >= min(_st.s.x, _st.e.x) && 257 max(_st.s.y, _st.e.y) >= min(_se.s.y, _se.e.y) && 258 max(_se.s.y, _se.e.y) >= min(_st.s.y, _st.e.y) && 259 Point::sgn((_st / Line(_st.s, _se.s)) * (_st / Line(_st.s, _se.e)), 0) <= 0 && 260 Point::sgn((_se / Line(_se.s, _st.s)) * (_se / Line(_se.s, _st.e)), 0) <= 0; 261 } 262 }; 263 264 class Polygon 265 { 266 public: 267 const static int maxpn = 5e4+7; 268 Point pt[maxpn];//点(顺时针或逆时针) 269 int n;//点的个数 270 271 272 //求多边形面积,多边形内点必须顺时针或逆时针 273 double area() const 274 { 275 double ans = 0.0; 276 for(int i = 0; i < n; i ++) 277 { 278 int nt = (i + 1) % n; 279 ans += pt[i].x * pt[nt].y - pt[nt].x * pt[i].y; 280 } 281 return fabs(ans / 2.0); 282 } 283 //求多边形重心,多边形内点必须顺时针或逆时针 284 Point gravity() const 285 { 286 Point ans; 287 ans.x = ans.y = 0.0; 288 double area = 0.0; 289 for(int i = 0; i < n; i ++) 290 { 291 int nt = (i + 1) % n; 292 double tp = pt[i].x * pt[nt].y - pt[nt].x * pt[i].y; 293 area += tp; 294 ans.x += tp * (pt[i].x + pt[nt].x); 295 ans.y += tp * (pt[i].y + pt[nt].y); 296 } 297 ans.x /= 3 * area; 298 ans.y /= 3 * area; 299 return ans; 300 } 301 //判断点在凸多边形内,参数:点[_Off] 302 bool chas(const Point &_Off) const 303 { 304 double tp = 0, np; 305 for(int i = 0; i < n; i ++) 306 { 307 np = Line(pt[i], pt[(i + 1) % n]) / _Off; 308 if(tp * np < -eps) 309 return false; 310 tp = (fabs(np) > eps)?np: tp; 311 } 312 return true; 313 } 314 //判断点是否在任意多边形内[射线法],O(n) 315 bool ahas(const Point &_Off) const 316 { 317 int ret = 0; 318 double infv = 1e20;//坐标系最大范围 319 Line l = Line(_Off, Point( -infv ,_Off.y)); 320 for(int i = 0; i < n; i ++) 321 { 322 Line ln = Line(pt[i], pt[(i + 1) % n]); 323 if(fabs(ln.s.y - ln.e.y) > eps) 324 { 325 Point tp = (ln.s.y > ln.e.y)? ln.s: ln.e; 326 if((fabs(tp.y - _Off.y) < eps && tp.x < _Off.x + eps)||Line::isCrossSS(ln,l)) 327 ret ++; 328 } 329 else if(Line::isCrossSS(ln,l)) 330 ret ++; 331 } 332 return ret&1; 333 } 334 335 //判断任意点是否在凸包内,O(lgn) 336 bool bhas(const Point & p) 337 { 338 if(n<3) 339 return false; 340 if(Point::xmult(pt[0],p,pt[1])>eps) 341 return false; 342 if(Point::xmult(pt[0],p,pt[n-1])<-eps) 343 return false; 344 int l=2,r=n-1; 345 int line=-1; 346 while(l<=r) 347 { 348 int mid=(l+r)>>1; 349 if(Point::xmult(pt[0],p,pt[mid])>=0) 350 line=mid,r=mid-1; 351 else l=mid+1; 352 } 353 return Point::xmult(pt[line-1],p,pt[line])<=eps; 354 } 355 356 357 358 //凸多边形被直线分割,参数:直线[_Off] 359 Polygon split(Line _Off) 360 { 361 //注意确保多边形能被分割 362 Polygon ret; 363 Point spt[2]; 364 double tp = 0.0, np; 365 bool flag = true; 366 int i, pn = 0, spn = 0; 367 for(i = 0; i < n; i ++) 368 { 369 if(flag) 370 pt[pn ++] = pt[i]; 371 else 372 ret.pt[ret.n ++] = pt[i]; 373 np = _Off / pt[(i + 1) % n]; 374 if(tp * np < -eps) 375 { 376 flag = !flag; 377 Line::crossLPt(_Off,Line(pt[i], pt[(i + 1) % n]),spt[spn++]); 378 } 379 tp = (fabs(np) > eps)?np: tp; 380 } 381 ret.pt[ret.n ++] = spt[0]; 382 ret.pt[ret.n ++] = spt[1]; 383 n = pn; 384 return ret; 385 } 386 387 388 /** 卷包裹法求点集凸包,_p为输入点集,_n为点的数量 **/ 389 void ConvexClosure(Point _p[],int _n) 390 { 391 sort(_p,_p+_n); 392 n=0; 393 for(int i=0;i<_n;i++) 394 { 395 while(n>1&&Point::sgn(Line(pt[n-2],pt[n-1])/Line(pt[n-2],_p[i]),0)<=0) 396 n--; 397 pt[n++]=_p[i]; 398 } 399 int _key=n; 400 for(int i=_n-2;i>=0;i--) 401 { 402 while(n>_key&&Point::sgn(Line(pt[n-2],pt[n-1])/Line(pt[n-2],_p[i]),0)<=0) 403 n--; 404 pt[n++]=_p[i]; 405 } 406 if(n>1) n--;//除去重复的点,该点已是凸包凸包起点 407 } 408 // /****** 寻找凸包的graham 扫描法********************/ 409 // /****** _p为输入的点集,_n为点的数量****************/ 410 // /**使用时需把gmp函数放在Polygon类上面L,ine类下面,并且看情况修改pt[0]**/ 411 // bool gcmp(const Point &ta,const Point &tb)/// 选取与最后一条确定边夹角最小的点,即余弦值最大者 412 // { 413 // double tmp=Line(pt[0],ta)/Line(pt[0],tb); 414 // if(Point::sgn(tmp,0)==0) 415 // return Point::dis(pt[0],ta)<Point::dis(pt[0],tb); 416 // else if(tmp>0) 417 // return 1; 418 // return 0; 419 // } 420 // void graham(Point _p[],int _n) 421 // { 422 // int cur=0; 423 // for(int i=1;i<_n;i++) 424 // if(Point::sgn(_p[cur].y,_p[i].y)>0 || (Point::sgn(_p[cur].y,_p[i].y)==0 && Point::sgn(_p[cur].x,_p[i].x)>0)) 425 // cur=i; 426 // swap(_p[cur],_p[0]); 427 // n=0,pt[n++]=_p[0]; 428 // if(_n==1) return; 429 // sort(_p+1,_p+_n,Polygon::gcmp); 430 // pt[n++]=_p[1],pt[n++]=_p[2]; 431 // for(int i=3;i<_n;i++) 432 // { 433 // while(n>1 && Point::sgn(Line(pt[n-2],pt[n-1])/Line(pt[n-2],_p[i]),0)<0)// 当凸包退化成直线时需特别注意n 434 // n--; 435 // pt[n++]=_p[i]; 436 // } 437 // } 438 //凸包旋转卡壳(注意点必须顺时针或逆时针排列) 439 //返回值凸包直径的平方(最远两点距离的平方) 440 double rotating_calipers() 441 { 442 int i = 1; 443 double ret = 0.0; 444 pt[n] = pt[0]; 445 for(int j = 0; j < n; j ++) 446 { 447 while(fabs(Point::xmult(pt[i+1],pt[j], pt[j + 1])) > fabs(Point::xmult(pt[i],pt[j], pt[j + 1])) + eps) 448 i = (i + 1) % n; 449 //pt[i]和pt[j],pt[i + 1]和pt[j + 1]可能是对踵点 450 ret = max(ret, max(Point::dis(pt[i],pt[j]), Point::dis(pt[i + 1],pt[j + 1]))); 451 } 452 return ret; 453 } 454 455 //凸包旋转卡壳(注意点必须逆时针排列) 456 //返回值两凸包的最短距离 457 double rotating_calipers(Polygon &_Off) 458 { 459 int i = 0; 460 double ret = 1e10;//inf 461 pt[n] = pt[0]; 462 _Off.pt[_Off.n] = _Off.pt[0]; 463 //注意凸包必须逆时针排列且pt[0]是左下角点的位置 464 while(_Off.pt[i + 1].y > _Off.pt[i].y) 465 i = (i + 1) % _Off.n; 466 for(int j = 0; j < n; j ++) 467 { 468 double tp; 469 //逆时针时为 >,顺时针则相反 470 while((tp = Point::xmult(_Off.pt[i + 1],pt[j], pt[j + 1]) - Point::xmult(_Off.pt[i], pt[j], pt[j + 1])) > eps) 471 i = (i + 1) % _Off.n; 472 //(pt[i],pt[i+1])和(_Off.pt[j],_Off.pt[j + 1])可能是最近线段 473 ret = min(ret, Line(pt[j], pt[j + 1]).dis(_Off.pt[i], true)); 474 ret = min(ret, Line(_Off.pt[i], _Off.pt[i + 1]).dis(pt[j + 1], true)); 475 if(tp > -eps)//如果不考虑TLE问题最好不要加这个判断 476 { 477 ret = min(ret, Line(pt[j], pt[j + 1]).dis(_Off.pt[i + 1], true)); 478 ret = min(ret, Line(_Off.pt[i], _Off.pt[i + 1]).dis(pt[j], true)); 479 } 480 } 481 return ret; 482 } 483 484 //-----------半平面交------------- 485 //复杂度:O(nlog2(n)) 486 //#include <algorithm> 487 488 //获取半平面交的多边形(多边形的核) 489 //参数:向量集合[l],向量数量[ln];(半平面方向在向量左边) 490 //函数运行后如果n[即返回多边形的点数量]为0则不存在半平面交的多边形(不存在区域或区域面积无穷大) 491 int halfPanelCross(Line *L, int ln) 492 { 493 sort(L,L + ln); //极角排序 494 int first,last; //双端队列的队首和队尾的下标 495 Point *p = new Point[ln]; //p[i]为q[i]和q[i+1]的交点 496 Line *q = new Line[ln]; //双端队列 497 q[first=last=0] = L[0]; //双端队列初始只有一个半平面L[0] 498 for(int i = 1; i < ln; i++) 499 { 500 while(first < last && !(p[last-1] < L[i])) last--; 501 while(first < last && !(p[first] < L[i])) first++; 502 q[++last] = L[i]; 503 if(fabs(q[last]/q[last-1]) < eps) 504 { 505 if(L[i].s < q[--last]) q[last] = L[i]; //两向量平行,取内侧的一个 506 } 507 if(first < last) Line::crossLPt(q[last-1], q[last], p[last-1]); 508 } 509 while(first < last && !(p[last-1] < q[first])) last--; //删除无用平面 510 if(last - first <= 1) return 0; //空集 511 Line::crossLPt(q[last], q[first], p[last]); //计算首尾两个半平面的交点 512 int m=0; 513 for(int i = 1; i <= last; i++) pt[m++] = p[i]; //复制到pt中 514 return m; 515 } 516 }; 517 518 class Circle 519 { 520 public: 521 Point c;//圆心 522 double r;//半径 523 double db, de;//圆弧度数起点, 圆弧度数终点(逆时针0-360) 524 525 //-------圆--------- 526 527 //判断圆在多边形内 528 bool inside(const Polygon &_Off) const 529 { 530 if(_Off.ahas(c) == false) 531 return false; 532 for(int i = 0; i < _Off.n; i ++) 533 { 534 Line l = Line(_Off.pt[i], _Off.pt[(i + 1) % _Off.n]); 535 if(l.dis(c, true) < r - eps) 536 return false; 537 } 538 return true; 539 } 540 541 //判断多边形在圆内(线段和折线类似) 542 bool has(const Polygon &_Off) const 543 { 544 for(int i = 0; i < _Off.n; i ++) 545 if(Point::dis2(_Off.pt[i],c) > r * r - eps) 546 return false; 547 return true; 548 } 549 550 //-------圆弧------- 551 //圆被其他圆截得的圆弧,参数:圆[_Off] 552 Circle operator-(Circle &_Off) const 553 { 554 //注意圆必须相交,圆心不能重合 555 double d2 = Point::dis2(c,_Off.c); 556 double d = Point::dis(c,_Off.c); 557 double ans = acos((d2 + r * r - _Off.r * _Off.r) / (2 * d * r)); 558 Point py = _Off.c - c; 559 double oans = atan2(py.y, py.x); 560 Circle res; 561 res.c = c; 562 res.r = r; 563 res.db = oans + ans; 564 res.de = oans - ans + 2 * PI; 565 return res; 566 } 567 //圆被其他圆截得的圆弧,参数:圆[_Off] 568 Circle operator+(Circle &_Off) const 569 { 570 //注意圆必须相交,圆心不能重合 571 double d2 = Point::dis2(c,_Off.c); 572 double d = Point::dis(c,_Off.c); 573 double ans = acos((d2 + r * r - _Off.r * _Off.r) / (2 * d * r)); 574 Point py = _Off.c - c; 575 double oans = atan2(py.y, py.x); 576 Circle res; 577 res.c = c; 578 res.r = r; 579 res.db = oans - ans; 580 res.de = oans + ans; 581 return res; 582 } 583 584 //过圆外一点的两条切线 585 //参数:点[_Off](必须在圆外),返回:两条切线(切线的s点为_Off,e点为切点) 586 std::pair<Line, Line> tangent(const Point &_Off) const 587 { 588 double d = Point::dis(c,_Off); 589 //计算角度偏移的方式 590 double angp = std::acos(r / d), ango = std::atan2(_Off.y - c.y, _Off.x - c.x); 591 Point pl = Point(c.x + r * std::cos(ango + angp), c.y + r * std::sin(ango + angp)), 592 pr = Point(c.x + r * std::cos(ango - angp), c.y + r * std::sin(ango - angp)); 593 return std::make_pair(Line(_Off, pl), Line(_Off, pr)); 594 } 595 596 //计算直线和圆的两个交点 597 //参数:直线[_Off](两点式),返回两个交点,注意直线必须和圆有两个交点 598 std::pair<Point, Point> cross(Line _Off) const 599 { 600 _Off.pton(); 601 //到直线垂足的距离 602 double td = fabs(_Off.a * c.x + _Off.b * c.y + _Off.c) / sqrt(_Off.a * _Off.a + _Off.b * _Off.b); 603 604 //计算垂足坐标 605 double xp = (_Off.b * _Off.b * c.x - _Off.a * _Off.b * c.y - _Off.a * _Off.c) / ( _Off.a * _Off.a + _Off.b * _Off.b); 606 double yp = (- _Off.a * _Off.b * c.x + _Off.a * _Off.a * c.y - _Off.b * _Off.c) / (_Off.a * _Off.a + _Off.b * _Off.b); 607 608 double ango = std::atan2(yp - c.y, xp - c.x); 609 double angp = std::acos(td / r); 610 611 return std::make_pair(Point(c.x + r * std::cos(ango + angp), c.y + r * std::sin(ango + angp)), 612 Point(c.x + r * std::cos(ango - angp), c.y + r * std::sin(ango - angp))); 613 } 614 }; 615 616 class triangle 617 { 618 public: 619 Point a, b, c;//顶点 620 triangle(){} 621 triangle(Point a, Point b, Point c): a(a), b(b), c(c){} 622 623 //计算三角形面积 624 double area() 625 { 626 return fabs(Point::xmult(a, b, c)) / 2.0; 627 } 628 629 //计算三角形外心 630 //返回:外接圆圆心 631 Point circumcenter() 632 { 633 Line u,v; 634 u.s.x = (a.x + b.x) / 2; 635 u.s.y = (a.y + b.y) / 2; 636 u.e.x = u.s.x - a.y + b.y; 637 u.e.y = u.s.y + a.x - b.x; 638 v.s.x = (a.x + c.x) / 2; 639 v.s.y = (a.y + c.y) / 2; 640 v.e.x = v.s.x - a.y + c.y; 641 v.e.y = v.s.y + a.x - c.x; 642 Point ret; 643 Line::crossLPt(u,v,ret); 644 return ret; 645 } 646 647 //计算三角形内心 648 //返回:内接圆圆心 649 Point incenter() 650 { 651 Line u, v; 652 double m, n; 653 u.s = a; 654 m = atan2(b.y - a.y, b.x - a.x); 655 n = atan2(c.y - a.y, c.x - a.x); 656 u.e.x = u.s.x + cos((m + n) / 2); 657 u.e.y = u.s.y + sin((m + n) / 2); 658 v.s = b; 659 m = atan2(a.y - b.y, a.x - b.x); 660 n = atan2(c.y - b.y, c.x - b.x); 661 v.e.x = v.s.x + cos((m + n) / 2); 662 v.e.y = v.s.y + sin((m + n) / 2); 663 Point ret; 664 Line::crossLPt(u,v,ret); 665 return ret; 666 } 667 668 //计算三角形垂心 669 //返回:高的交点 670 Point perpencenter() 671 { 672 Line u,v; 673 u.s = c; 674 u.e.x = u.s.x - a.y + b.y; 675 u.e.y = u.s.y + a.x - b.x; 676 v.s = b; 677 v.e.x = v.s.x - a.y + c.y; 678 v.e.y = v.s.y + a.x - c.x; 679 Point ret; 680 Line::crossLPt(u,v,ret); 681 return ret; 682 } 683 684 //计算三角形重心 685 //返回:重心 686 //到三角形三顶点距离的平方和最小的点 687 //三角形内到三边距离之积最大的点 688 Point barycenter() 689 { 690 Line u,v; 691 u.s.x = (a.x + b.x) / 2; 692 u.s.y = (a.y + b.y) / 2; 693 u.e = c; 694 v.s.x = (a.x + c.x) / 2; 695 v.s.y = (a.y + c.y) / 2; 696 v.e = b; 697 Point ret; 698 Line::crossLPt(u,v,ret); 699 return ret; 700 } 701 702 //计算三角形费马点 703 //返回:到三角形三顶点距离之和最小的点 704 Point fermentPoint() 705 { 706 Point u, v; 707 double step = fabs(a.x) + fabs(a.y) + fabs(b.x) + fabs(b.y) + fabs(c.x) + fabs(c.y); 708 int i, j, k; 709 u.x = (a.x + b.x + c.x) / 3; 710 u.y = (a.y + b.y + c.y) / 3; 711 while (step > eps) 712 { 713 for (k = 0; k < 10; step /= 2, k ++) 714 { 715 for (i = -1; i <= 1; i ++) 716 { 717 for (j =- 1; j <= 1; j ++) 718 { 719 v.x = u.x + step * i; 720 v.y = u.y + step * j; 721 if (Point::dis(u,a) + Point::dis(u,b) + Point::dis(u,c) > Point::dis(v,a) + Point::dis(v,b) + Point::dis(v,c)) 722 u = v; 723 } 724 } 725 } 726 } 727 return u; 728 } 729 }; 730 731 int main(void) 732 { 733 734 return 0; 735 }