各种点线与圆的关系。
1、三角形外接圆:求各边中垂线交点;
2、三角形内切圆:定比分点构造等腰三角形求角平分线,求两角平分线交点;
3、定点到圆切线:点到圆心斜率加减切线夹角,处理结果的表示范围;
4、切直线、过定点的圆:点在线上是两个对称的圆,否则圆在点线确定的双曲线上,利用双曲线性质构造直角梯形,然后利用向量与定比分点求;
5、与两相交直线相切的圆:分别将直线朝不同方向平移半径距离求交点;
6、两相离圆的公共外切圆:三圆心连线构成三角形,所求圆心做三角形的高,余弦定理+定比分点求出各项数据。
特殊情况进行特判求值。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<math.h> 5 #include<algorithm> 6 using namespace std; 7 const double eps = 1e-10; 8 const double pi = acos(-1.0); 9 char buf[100]; 10 char task[6][100] = { 11 "CircumscribedCircle", 12 "InscribedCircle", 13 "TangentLineThroughPoint", 14 "CircleThroughAPointAndTangentToALineWithRadius", 15 "CircleTangentToTwoLinesWithRadius", 16 "CircleTangentToTwoDisjointCirclesWithRadius" 17 }; 18 inline double Sqr(double x) 19 {return x * x;} 20 inline int dcmp(double x) 21 { 22 if(x > eps) return 1; 23 return x < -eps ? -1 : 0; 24 } 25 inline double pz(double x) 26 {return dcmp(x) ? x : 0;} 27 struct Point 28 { 29 double x, y; 30 Point(){x = y = 0;} 31 Point(double a, double b) 32 {x = a, y = b;} 33 Point operator-(const Point &b)const 34 {return Point(x - b.x, y - b.y);} 35 Point operator+(const Point &b)const 36 {return Point(x + b.x, y + b.y);} 37 Point operator-() 38 {return Point(-x, -y);} 39 Point operator*(const double &b)const 40 {return Point(x * b, y * b);} 41 double dot(const Point &b)const 42 {return x * b.x + y * b.y;} 43 double cross(const Point &b, const Point &c)const 44 {return (b.x - x) * (c.y - y) - (c.x - x) * (b.y - y);} 45 double Dis(const Point &b)const 46 {return sqrt((*this - b).dot(*this - b));} 47 bool operator<(const Point &b)const 48 { 49 if(!dcmp(x - b.x)) return y < b.y; 50 return x < b.x; 51 } 52 bool operator>(const Point &b)const 53 {return b < *this;} 54 }; 55 inline double min(double a, double b) 56 {return a < b ? a : b;} 57 inline double max(double a, double b) 58 {return a > b ? a : b;} 59 inline Point min(Point a, Point b) 60 {return a < b ? a : b;} 61 inline Point max(Point a, Point b) 62 {return a > b ? a : b;} 63 Point CrossPoint(Point a, Point b, Point c, Point d) 64 { 65 double u = a.cross(b, c), v = b.cross(a, d); 66 return Point((c.x * v + d.x * u) / (u + v), (c.y * v + d.y * u) / (u + v)); 67 } 68 int Task(char *s) 69 { 70 for(int i = 0; i < 6; ++ i) 71 if(!strcmp(s, task[i])) return i; 72 } 73 74 void CC() //外接圆 75 { 76 Point a, b, c, ab, ac, r; 77 scanf("%lf%lf%lf%lf%lf%lf", &a.x, &a.y, &b.x, &b.y, &c.x, &c.y); 78 ab = (a + b) * 0.5, ac = (a + c) * 0.5; 79 r = CrossPoint(ab, Point(ab.x + a.y - b.y, ab.y + b.x - a.x), 80 ac, Point(ac.x + a.y - c.y, ac.y + c.x - a.x)); 81 printf("(%.6f,%.6f,%.6f)\n", 82 eps + pz(r.x), eps + pz(r.y), eps + pz(r.Dis(a))); 83 } 84 void IC() //内切圆 85 { 86 Point a, b, c, apf, bpf, r; 87 scanf("%lf%lf%lf%lf%lf%lf", &a.x, &a.y, &b.x, &b.y, &c.x, &c.y); 88 double la = b.Dis(c), lb = a.Dis(c), lc = a.Dis(b), p = (la + lb + lc) * 0.5; 89 apf = (c + a + (b - a) * (lb / lc)) * 0.5; 90 bpf = (c + b + (a - b) * (la / lc)) * 0.5; 91 r = CrossPoint(a, apf, b, bpf); 92 printf("(%.6f,%.6f,%.6f)\n", eps + pz(r.x), eps + pz(r.y), 93 eps + pz(sqrt(p * (p - la) * (p - lb) * (p - lc)) * 2 / (la + lb + lc))); 94 } 95 double ManageDeg(double x) 96 { 97 while(x < -eps) x += pi; 98 while(x > pi - eps) x -= pi; 99 return x; 100 } 101 void TLTP() //点到圆切线 102 { 103 Point a, r; 104 double R, ang, ang1, ang2; 105 scanf("%lf%lf%lf%lf%lf", &r.x, &r.y, &R, &a.x, &a.y); 106 ang = atan2(r.y - a.y, r.x - a.x); 107 switch(dcmp(a.Dis(r) - R)) 108 { 109 case 0: 110 printf("[%.6f]\n", eps + pz(ManageDeg(ang + pi * 0.5) / pi * 180)); 111 break; 112 case 1: 113 ang1 = ManageDeg(ang + asin(R / a.Dis(r))) / pi * 180; 114 ang2 = ManageDeg(ang - asin(R / a.Dis(r))) / pi * 180; 115 printf("[%.6f,%.6f]\n", eps + pz(min(ang1, ang2)), 116 eps + pz(max(ang1, ang2))); 117 break; 118 default: 119 printf("[]\n"); 120 } 121 } 122 void CTAPATTAWR()//切直线且经定点、半径定值的圆 123 { 124 Point p, a, b, pcl, pcz, r1, r2, xl; 125 double R, rcp; 126 scanf("%lf%lf%lf%lf%lf%lf%lf", &p.x, &p.y, &a.x, &a.y, &b.x, &b.y, &R); 127 pcl = Point(p.x + a.y - b.y, p.y + b.x - a.x);//pcl-p 垂线向量 128 pcz = CrossPoint(p, pcl, a, b);//垂足 129 if(!dcmp(p.cross(a, b))) 130 { 131 r1 = p + (pcl - p) * (R / p.Dis(pcl)); 132 r2 = p - (pcl - p) * (R / p.Dis(pcl)); 133 printf("[(%.6f,%.6f),", eps + pz(min(r1, r2).x), eps + pz(min(r1, r2).y)); 134 printf("(%.6f,%.6f)]\n", eps + pz(max(r1, r2).x), eps + pz(max(r1, r2).y)); 135 } 136 else if(!dcmp(R - p.Dis(pcz) * 0.5)) 137 { 138 r1 = (p + pcz) * 0.5; 139 printf("[(%.6f,%.6f)]\n", eps + pz(r1.x), eps + pz(r1.y)); 140 } 141 else if(dcmp(R - p.Dis(pcz) * 0.5) > 0)//利用双曲线性质,构造直角梯形求解。 142 { 143 rcp = sqrt(R * R - Sqr(R - p.Dis(pcz)));//直角梯形的高。。。 144 r1 = pcz + (a - b) * (rcp / (a.Dis(b))) + (p - pcz) * (R / p.Dis(pcz)); 145 r2 = pcz - (a - b) * (rcp / (a.Dis(b))) + (p - pcz) * (R / p.Dis(pcz)); 146 printf("[(%.6f,%.6f),", eps + pz(min(r1, r2).x), eps + pz(min(r1, r2).y)); 147 printf("(%.6f,%.6f)]\n", eps + pz(max(r1, r2).x), eps + pz(max(r1, r2).y)); 148 } 149 else printf("[]\n"); 150 151 } 152 void CTTTLWR()//与两相交直线相切的圆 153 { 154 Point a, b, c, d, A, B, C, D, jd, xl1, xl2, r[4]; 155 double R, R_, ang, l1, l2; 156 scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf", 157 &a.x, &a.y, &b.x, &b.y, &c.x, &c.y, &d.x, &d.y, &R); 158 xl1 = Point(a.y - b.y, b.x - a.x); xl1 = xl1 * (R / sqrt(xl1.dot(xl1))); 159 xl2 = Point(c.y - d.y, d.x - c.x); xl2 = xl2 * (R / sqrt(xl2.dot(xl2))); 160 r[0] = CrossPoint(a + xl1, b + xl1, c + xl2, d + xl2); 161 r[1] = CrossPoint(a + xl1, b + xl1, c - xl2, d - xl2); 162 r[2] = CrossPoint(a - xl1, b - xl1, c + xl2, d + xl2); 163 r[3] = CrossPoint(a - xl1, b - xl1, c - xl2, d - xl2); 164 sort(r, r + 4); 165 printf("["); 166 for(int i = 0; i < 4; ++ i) 167 { 168 if(i)printf(","); 169 printf("(%.6f,%.6f)", eps + pz(r[i].x), eps + pz(r[i].y)); 170 } 171 printf("]\n"); 172 } 173 void CTTTDCWR()//两相离圆的公共外切圆 174 { 175 Point r1, r2, r[2], zd, xl; 176 double R1, R2, R, len; 177 scanf("%lf%lf%lf%lf%lf%lf%lf", &r1.x, &r1.y, &R1, &r2.x, &r2.y, &R2, &R); 178 if(!dcmp(R + R1 + R + R2 - r1.Dis(r2))) 179 { 180 r[0] = r1 + (r2 - r1) * ((R + R1) / (R + R1 + R + R2)); 181 printf("[(%.6f,%.6f)]\n", eps + pz(r[0].x), eps + pz(r[0].y)); 182 } 183 else if(dcmp(R + R1 + R + R2 - r1.Dis(r2)) > 0) 184 { 185 zd = r1 + (r2 - r1) * (((R + R1) * (Sqr(R + R1) + Sqr(r1.Dis(r2)) - Sqr(R + R2)) * 186 0.5 / (R + R1) / r1.Dis(r2)) / r1.Dis(r2));//对称圆心的中点 187 len = sqrt(Sqr(R + R1) - Sqr(zd.Dis(r1)));//zd到所求圆心距离 188 xl = Point(r1.y - r2.y, r2.x - r1.x);//zd到所求圆心的向量 189 r[0] = zd + xl * (len / sqrt(xl.dot(xl))); 190 r[1] = zd - xl * (len / sqrt(xl.dot(xl))); 191 sort(r, r + 2); 192 printf("[(%.6f,%.6f),(%.6f,%.6f)]\n", 193 eps + pz(r[0].x), eps + pz(r[0].y), eps + pz(r[1].x), eps + pz(r[1].y)); 194 } 195 else printf("[]\n"); 196 } 197 int main() 198 { 199 while(scanf("%s", buf) != EOF) 200 { 201 switch(Task(buf)) 202 { 203 case 0: CC();break; 204 case 1: IC();break; 205 case 2: TLTP();break; 206 case 3: CTAPATTAWR();break; 207 case 4: CTTTLWR();break; 208 case 5: CTTTDCWR();break; 209 } 210 } 211 return 0; 212 }