●UVA 10674 Tangents

时间:2023-03-09 07:49:11
●UVA 10674 Tangents

题链:

https://vjudge.net/problem/UVA-10674

题解:

计算几何,求两个圆的公切线。

《算法竞赛入门经典——训练指南》P266,讲得很清楚的。

大致是分为6种情况——内含,重合,内切,相交,外切,相离这六个情况去处理,

找到共通点,便于代码编写。

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const double eps=1e-8;
const double Pi=acos(-1);
int sign(double x){
if(fabs(x)<=eps) return 0;
return x<0?-1:1;
}
struct Point{
double x,y;
Point(double _x=0,double _y=0):x(_x),y(_y){}
void Read(){scanf("%lf%lf",&x,&y);}
};
struct Circle{
Point o; double r;
Point GP(double a){//Get_Point
return Point(o.x+r*cos(a),o.y+r*sin(a));
}
}C1,C2;
struct Intersect{
Point P[2];
bool operator <(const Intersect &rtm) const{
return sign(P[0].x-rtm.P[0].x)<0||(sign(P[0].x-rtm.P[0].x)==0&&sign(P[0].y-rtm.P[0].y)<0);
}
}ANS[7];
typedef Point Vector;
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Point A,Point B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator * (Point A,double p){return Vector(A.x*p,A.y*p);}
double operator ^ (Vector A,Vector B){return A.x*B.y-A.y*B.x;}
double operator * (Vector A,Vector B){return A.x*B.x+A.y*B.y;}
double GPA(Vector A){//Get_Polar_Angle
return atan2(A.y,A.x);
}
double GL(Vector A){//Get_Length
return sqrt(A*A);
}
int GCCI(Circle A,Circle B){//Get_Circle_Circle_Intersection
int cnt=0,a=0,b=1;
if(A.r<B.r) swap(A,B),swap(a,b);
Vector u=B.o-A.o;
double d=GL(u),rdec=A.r-B.r,radd=A.r+B.r;
if(sign(d-rdec)<0) return 0; //内含
if(sign(d)==0&&A.r==B.r) return -1; //重合,无线多
double base=GPA(u);
if(sign(d-rdec)==0){ //内切
ANS[++cnt].P[a]=A.GP(base); ANS[cnt].P[b]=B.GP(base);
return cnt;
}
double da=acos((A.r-B.r)/d); //2条外公切线
ANS[++cnt].P[a]=A.GP(base+da); ANS[cnt].P[b]=B.GP(base+da);
ANS[++cnt].P[a]=A.GP(base-da); ANS[cnt].P[b]=B.GP(base-da);
if(sign(d-radd)==0){ //1条内公切线
ANS[++cnt].P[a]=A.GP(base); ANS[cnt].P[b]=B.GP(base+Pi);
}
else if(sign(d-radd)>0){ //2条内公切线
da=acos((A.r+B.r)/d);
ANS[++cnt].P[a]=A.GP(base+da); ANS[cnt].P[b]=B.GP(base+da+Pi);
ANS[++cnt].P[a]=A.GP(base-da); ANS[cnt].P[b]=B.GP(base-da+Pi);
}
return cnt;
}
int main(){
int cnt;
while(1){
C1.o.Read(); scanf("%lf",&C1.r);
C2.o.Read(); scanf("%lf",&C2.r);
if(!C1.o.x&&!C1.o.y&&!C1.r&&!C2.o.x&&!C2.o.y&&!C2.r) break;
cnt=GCCI(C1,C2);
printf("%d\n",cnt);
if(cnt<=0) continue;
sort(ANS+1,ANS+cnt+1);
for(int i=1;i<=cnt;i++){
printf("%.5lf %.5lf %.5lf %.5lf %.5lf\n",ANS[i].P[0].x,ANS[i].P[0].y,ANS[i].P[1].x,ANS[i].P[1].y,GL(ANS[i].P[1]-ANS[i].P[0]));
} }
return 0;
}