兩個圓的切線與切點
阿新 • • 發佈:2021-09-15
兩個圓的切線與切點
https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_G
int sgn(double x) { if(fabs(x)<eps)return 0; return x<0?-1:1; } struct Point { //定義點和基本運算 double x,y; double ang; Point() {} Point(double x,double y):x(x),y(y) {} Point operator + (Point B) { return Point(x+B.x,y+B.y); } Point operator - (Point B) { return Point(x-B.x,y-B.y); } Point operator * (double k) { return Point(x*k,y*k); //長度增大k倍 } Point operator / (double k) { return Point(x/k,y/k); //長度縮小k倍 } bool operator == (Point B) { return sgn(x-B.x)==0 && sgn(y-B.y)==0; } double operator ^(Point B) { return x*B.y-y*B.x; } double distance(Point p) { return hypot(x-p.x,y-p.y); } }; typedef Point Vector; double Cross(Vector A,Vector B) { return A.x*B.y - A.y*B.x; //叉積 } struct Line { Point p1,p2;//線上的兩個點 Line() {} Line(Point p1,Point p2):p1(p1),p2(p2) {} }; struct Circle { Point c;//圓心 double r;//半徑 Circle() {} Circle(Point c,double r):c(c),r(r) {} Circle(double x,double y,double _r) { c=Point(x,y); r = _r; } Point point(double ang) { //圓上與圓心極座標為ang的點----------------- return Point(c.x+cos(ang)*r,c.y+sin(ang)*r); } }; //0,-1:沒有切線 a[]是c1上的切點,b[]是c2 int getTangents(Circle A, Circle B, Point *a, Point *b) { int cnt = 0; //存切點用 if(sgn(A.r - B.r) < 0) { swap(A, B); swap(a, b); } double d = sqrt((A.c.x - B.c.x) * (A.c.x - B.c.x) + (A.c.y - B.c.y) * (A.c.y - B.c.y)); //圓心距 double rdiff = A.r - B.r; //兩圓半徑差 double rsum = A.r + B.r; //兩圓半徑和 if(sgn(d - rdiff) < 0) return 0; //1.內含 double base = atan2(B.c.y - A.c.y, B.c.x - A.c.x); //向量AB的極角 if(sgn(d) == 0) return -1; //2.重合 if(sgn(d - rdiff) == 0) { //3.內切 a[cnt] = b[cnt] = A.point(base); cnt++; return 1; } double ang = acos((A.r - B.r) / d); a[cnt] = A.point(base + ang); b[cnt] = B.point(base + ang); cnt++; //4.相交(外切、外離的外公切線也在此求出) a[cnt] = A.point(base - ang); b[cnt] = B.point(base - ang); cnt++; //兩條外公切線的切點 if(sgn(d - rsum) == 0) { //5.外切 a[cnt] = b[cnt] = A.point(base); cnt++; } else if(sgn(d - rsum) > 0) { //6.外離 double ang = acos((A.r + B.r) / d); a[cnt] = A.point(base + ang); b[cnt] = B.point(PI + base + ang); cnt++; a[cnt] = A.point(base - ang); b[cnt] = B.point(PI + base - ang); cnt++; } return cnt; } bool cmp(Point a,Point b) { if(sgn(a.x-b.x)!=0)return a.x < b.x; else if(sgn(a.x-b.x)==0)return a.y < b.y; } void work() { Circle a,b; scanf("%lf%lf%lf",&a.c.x,&a.c.y,&a.r); scanf("%lf%lf%lf",&b.c.x,&b.c.y,&b.r); Point p1[5],p2[5]; int cnt = getTangents(a,b,p1,p2); // cout << cnt << endl; if(cnt == -1 ||cnt==0)return ; vector<Point>ans; for(int i=0; i<cnt; i++) { ans.push_back(p1[i]); } sort(ans.begin(),ans.end(),cmp); for(int i=0; i<cnt; i++) { printf("%.10f %.10f\n",ans[i].x,ans[i].y); } }