计算几何(圆相关模板) - 2D Geometry 110 in 1! - UVA 12304
题意:
共 有 6 个 问 题 : 共有6个问题: 共有6个问题:
① 、 给 定 不 共 线 的 三 个 点 坐 标 , 输 出 外 接 圆 的 圆 心 和 半 径 。 ①、给定不共线的三个点坐标,输出外接圆的圆心和半径。 ①、给定不共线的三个点坐标,输出外接圆的圆心和半径。
②
、
给
定
不
共
线
的
三
个
点
坐
标
,
输
出
内
切
圆
的
圆
心
和
半
径
。
②、给定不共线的三个点坐标,输出内切圆的圆心和半径。
②、给定不共线的三个点坐标,输出内切圆的圆心和半径。
③
、
给
定
圆
C
的
圆
心
坐
标
和
半
径
r
,
输
出
过
定
点
P
的
圆
C
的
切
线
的
倾
角
。
③、给定圆C的圆心坐标和半径r,输出过定点P的圆C的切线的倾角。
③、给定圆C的圆心坐标和半径r,输出过定点P的圆C的切线的倾角。
④
、
给
定
一
个
定
点
P
,
直
线
A
B
,
输
出
过
点
P
且
与
A
B
相
切
的
圆
的
圆
心
坐
标
。
④、给定一个定点P,直线AB,输出过点P且与AB相切的圆的圆心坐标。
④、给定一个定点P,直线AB,输出过点P且与AB相切的圆的圆心坐标。
⑤
、
给
出
四
个
顶
点
A
,
B
,
C
,
D
的
坐
标
和
常
数
r
,
直
线
A
B
与
C
D
相
交
,
计
算
A
B
与
C
D
的
半
径
为
r
公
切
圆
的
圆
心
。
⑤、给出四个顶点A,B,C,D的坐标和常数r,直线AB与CD相交,计算AB与CD的半径为r公切圆的圆心。
⑤、给出四个顶点A,B,C,D的坐标和常数r,直线AB与CD相交,计算AB与CD的半径为r公切圆的圆心。
⑥ 、 给 定 两 个 不 相 交 的 圆 C 1 和 C 2 , 输 出 这 两 个 圆 公 切 圆 的 圆 心 。 ⑥、给定两个不相交的圆C_1和C_2,输出这两个圆公切圆的圆心。 ⑥、给定两个不相交的圆C1和C2,输出这两个圆公切圆的圆心。
Sample Input
CircumscribedCircle 0 0 20 1 8 17
InscribedCircle 0 0 20 1 8 17
TangentLineThroughPoint 200 200 100 40 150
TangentLineThroughPoint 200 200 100 200 100
TangentLineThroughPoint 200 200 100 270 210
CircleThroughAPointAndTangentToALineWithRadius 100 200 75 190 185 65 100
CircleThroughAPointAndTangentToALineWithRadius 75 190 75 190 185 65 100
CircleThroughAPointAndTangentToALineWithRadius 100 300 100 100 200 100 100
CircleThroughAPointAndTangentToALineWithRadius 100 300 100 100 200 100 99
CircleTangentToTwoLinesWithRadius 50 80 320 190 85 190 125 40 30
CircleTangentToTwoDisjointCirclesWithRadius 120 200 50 210 150 30 25
CircleTangentToTwoDisjointCirclesWithRadius 100 100 80 300 250 70 50
Sample Output
(9.734940,5.801205,11.332389)
(9.113006,6.107686,5.644984)
[53.977231,160.730818]
[0.000000]
[]
[(112.047575,299.271627),(199.997744,199.328253)]
[(-0.071352,123.937211),(150.071352,256.062789)]
[(100.000000,200.000000)]
[]
[(72.231286,121.451368),(87.815122,63.011983),(128.242785,144.270867),(143.826621,85.831483)]
[(157.131525,134.836744),(194.943947,202.899105)]
[(204.000000,178.000000)]
分析:
圆 相 关 问 题 的 一 些 模 板 测 试 。 圆相关问题的一些模板测试。 圆相关问题的一些模板测试。
思路参照:UVA - 12304 2D Geometry 110 in 1!
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const double eps=1e-10;
const double pi=acos(-1.0);
struct Point
{
double x,y;
Point(double x=0,double y=0) : x(x), y(y) {}
};
int dcmp(double x)
{
if(fabs(x)<eps) return 0;
else return x<0 ? -1 : 1;
}
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 * (Vector A,double p) { return Vector(A.x*p,A.y*p); }
Vector operator / (Vector A,double p) { return Vector(A.x/p,A.y/p); }
bool operator < (const Point &a,const Point &b)
{
return a.x<b.x || (!dcmp(a.x-b.x) && a.y<b.y);
}
bool operator == (const Point &a, const Point &b)
{
return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;
}
double Dot(Vector A,Vector B) { return A.x*B.x + A.y*B.y; }
double Length(Vector A) { return sqrt(Dot(A,A)); }
double Angle(Vector A, Vector B) { return acos(Dot(A,B) / Length(A) / Length(B)); }
double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }
double angle(Vector v) { return atan2(v.y,v.x); }
double angtox(Vector v)
{
double ang=angle(v);
if(dcmp(ang)<0) ang+=pi;
if(dcmp(ang-pi)>=0) ang-=pi;
return ang;
}
double dis2(Point A,Point B) { return (A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y); }
double dis(Point A,Point B) { return sqrt(dis2(A,B)); }
Vector Rotate(Vector A, double rad)
{
return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A)
{
double L=Length(A);
return Vector(-A.y/L,A.x/L);
}
struct Line
{
Point v, p;
Vector dir;
double ang;
Line() { }
Line(Point v, Point p):v(v), p(p){ dir=p-v; ang=atan2(dir.y,dir.x); }
bool operator < (const Line& L) const
{
return ang < L.ang;
}
Point point(double t)
{
return v + dir*t;
}
};
Point GetLineIntersection(Point P,Vector v,Point Q,Vector w)
{
Vector u=P-Q;
double t=Cross(w,u)/Cross(v,w);
return P+v*t;
}
Point GetLineIntersection(Line L1, Line L2)
{
return GetLineIntersection(L1.v,L1.dir,L2.v,L2.dir);
}
double DistanceToLine(Point P,Point A,Point B)
{
Vector v1=B-A, v2=P-A;
return fabs(Cross(v1,v2))/Length(v1);
}
double DistanceToLine(Point P,Line L)
{
return DistanceToLine(P,L.v,L.p);
}
Point GetLineProjection(Point P,Point A,Point B)
{
Vector v=B-A;
return A+v*(Dot(v,P-A)/Dot(v,v));
}
Point GetLineProjection(Point P,Line L)
{
return GetLineProjection(P,L.v,L.p);
}
struct Circle
{
Point c;
double r;
Circle(Point c=Point(0,0), double r=0):c(c), r(r) {}
Point point(double a)
{
return Point(c.x + cos(a)*r, c.y + sin(a)*r);
}
};
Circle Excenter(Point a, Point b, Point c)
{
double a1 = b.x - a.x;
double b1 = b.y - a.y;
double c1 = (a1*a1 + b1*b1)/2;
double a2 = c.x - a.x;
double b2 = c.y - a.y;
double c2 = (a2*a2 + b2*b2)/2;
double d = a1*b2 - a2*b1;
Point O = Point(a.x + (c1*b2 - c2*b1)/d, a.y + (a1*c2 - a2*c1)/d);
double r=dis(O,a);
return Circle(O,r);
}
Circle getNqc(Point a, Point b, Point c)
{
double C = dis(a, b);
double B = dis(a, c);
double A = dis(b, c);
Circle cir;
cir.c.x = (A*a.x + B*b.x + C*c.x) / (A + B + C);
cir.c.y = (A*a.y + B*b.y + C*c.y) / (A + B + C);
cir.r = sqrt((A + B - C)*(A - B + C)*(-A + B + C) / (A + B + C)) / 2;
return cir;
}
int getTangents(Point p,Circle C,Vector *v)
{
Vector u=C.c-p;
double dist=Length(u);
if(dcmp(dist-C.r)<0) return 0;
else if(dcmp(dist-C.r)==0) //p在圆上
{
v[0]=Rotate(u,pi/2);
return 1;
}
else
{
double ang=asin(C.r/dist);
v[0]=Rotate(u,-ang);
v[1]=Rotate(u,ang);
return 2;
}
}
int getLineCircleIntersection(Line a, Circle b, vector<Point>& res)
{
double h = DistanceToLine(b.c, a);
if (dcmp(b.r-h) < 0) return 0;
Point c = GetLineProjection(b.c, a);
if (!dcmp(h-b.r))
{
res.push_back(c);
return 1;
}
double w = sqrt(b.r * b.r - h * h);
res.push_back(c + a.dir/Length(a.dir) * w); //直线L的单位向量
res.push_back(c - a.dir/Length(a.dir) * w);
sort(res.begin(), res.end());
return 2;
}
vector<Point> Circle_Through_A_Point_And_Tangent_To_A_Line_With_Radius(Point a, Line b, double r)
{
vector<Point> res;
Vector c = Normal(b.dir);
Circle k(a, r);
Point p=b.v+c*r, q=b.v-c*r;
Line L1=Line(p, p+b.dir), L2=Line(q, q+b.dir);
getLineCircleIntersection(L1, k, res);
getLineCircleIntersection(L2, k, res);
sort(res.begin(), res.end());
return res;
}
vector<Point> Circle_Tangent_To_Two_Lines_With_Radius(Line L1,Line L2,double r)
{
vector<Point> res;
Vector n1 = Normal(L1.dir), n2 = Normal(L2.dir);
Point p1=L1.v+n1*r, p2=L1.v-n1*r, q1=L2.v+n2*r, q2=L2.v-n2*r;
Line L3(p1,p1+L1.dir), L4(p2,p2+L1.dir), L5(q1,q1+L2.dir), L6(q2,q2+L2.dir);
Point O[5];
O[1]=GetLineIntersection(L3,L5), O[2]=GetLineIntersection(L3,L6),
O[3]=GetLineIntersection(L4,L5), O[4]=GetLineIntersection(L4,L6);
for(int i=1;i<=4;i++) res.push_back(O[i]);
sort(res.begin(),res.end());
return res;
}
int getCircleCircleIntersection(Circle C1,Circle C2,vector<Point> &sol)
{
double d=Length(C1.c-C2.c);
if(dcmp(d)==0)
{
if(dcmp(C1.r-C2.r)==0) return -1;
return 0;
}
if(dcmp(C1.r+C2.r-d)<0) return 0;
if(dcmp(fabs(C1.r-C2.r)-d)>0) return 0;
double a=angle(C2.c-C1.c);
double da=acos((C1.r*C1.r + d*d - C2.r*C2.r)/(2*C1.r*d));
Point p1=C1.point(a-da), p2=C1.point(a+da);
sol.push_back(p1);
if(p1==p2) return 1;
sol.push_back(p2);
return 2;
}
void print(vector<Point> &res)
{
int num=res.size();
printf("[");
for(int i=0;i<num-1;i++) printf("(%lf,%lf),",res[i].x,res[i].y);
if(num>0) printf("(%lf,%lf)",res[num-1].x,res[num-1].y);
printf("]\n");
}
Point V[10];
char str[100];
int main()
{
while(~scanf("%s",str))
{
if(strcmp(str,"CircumscribedCircle")==0)
{
for(int i=0;i<3;i++) scanf("%lf%lf",&V[i].x,&V[i].y);
Circle C=Excenter(V[0],V[1],V[2]);
printf("(%lf,%lf,%lf)\n",C.c.x,C.c.y,C.r);
}
else if(strcmp(str,"InscribedCircle")==0)
{
for(int i=0;i<3;i++) scanf("%lf%lf",&V[i].x,&V[i].y);
Circle C=getNqc(V[0],V[1],V[2]);
printf("(%lf,%lf,%lf)\n",C.c.x,C.c.y,C.r);
}
else if(strcmp(str,"TangentLineThroughPoint")==0)
{
Circle C;
Point P;
scanf("%lf%lf%lf",&C.c.x,&C.c.y,&C.r);
scanf("%lf%lf",&P.x,&P.y);
Vector L[5];
int num=getTangents(P,C,L);
for(int i=0;i<num;i++) L[i]=angtox(L[i])/pi*180;
sort(L,L+num);
printf("[");
for(int i=0;i<num-1;i++) printf("%lf,",L[i]);
if(num>0) printf("%lf",L[num-1]);
printf("]\n");
}
else if(strcmp(str,"CircleThroughAPointAndTangentToALineWithRadius")==0)
{
double r;
for(int i=0;i<3;i++) scanf("%lf%lf",&V[i].x,&V[i].y);
scanf("%lf",&r);
vector<Point> res;
res=Circle_Through_A_Point_And_Tangent_To_A_Line_With_Radius(V[0],Line(V[1],V[2]),r);
sort(res.begin(),res.end());
print(res);
}
else if(strcmp(str,"CircleTangentToTwoLinesWithRadius")==0)
{
for(int i=0;i<4;i++) scanf("%lf%lf",&V[i].x,&V[i].y);
double r; scanf("%lf",&r);
Line L1(V[0],V[1]), L2(V[2],V[3]);
vector<Point> res;
res=Circle_Tangent_To_Two_Lines_With_Radius(L1,L2,r);
sort(res.begin(),res.end());
print(res);
}
else if(strcmp(str,"CircleTangentToTwoDisjointCirclesWithRadius")==0)
{
double r1,r2,r;
Point O1,O2;
scanf("%lf%lf%lf",&O1.x,&O1.y,&r1);
scanf("%lf%lf%lf",&O2.x,&O2.y,&r2);
scanf("%lf",&r);
Circle C1(O1,r1+r), C2(O2,r2+r);
vector<Point> res;
getCircleCircleIntersection(C1,C2,res);
sort(res.begin(),res.end());
print(res);
}
}
return 0;
}