1. 程式人生 > >UVa12304(計算幾何中圓的基本操作)

UVa12304(計算幾何中圓的基本操作)

成功 cross spa intersect code 不難 事情 urn 練習

斷斷續續寫了250多行的模擬,其間被其他事情打擾,總共花了一天才AC吧~

這道題目再次讓我明白,有些事情看起來很難,實際上並沒有我們想象中的那麽難。當然了我主要指的不是這個題的難度……

也是初學計算幾何,然後居然膽大妄為地不用劉汝佳的思路去實現這些個功能,其中有三個功能是我用自己的思路實現的吧(瞎暴力),最後果然也是自己寫的出鍋了。

當一個賊長的模擬題交上去一發WA時,我是欲哭無淚的……這讓我怎麽debug……只好不斷安慰自己要用計算幾何題去練習耐心。

只是沒想到在不斷的固執與冷靜的試探之下,不到一個晚上就成功了,當然了,對拍拍出來的唄……

我的主要錯誤在於在我自己的實現思路裏,旋轉向量時應該順時針還是逆時針是取決於輸入的,而我粗暴地“一視同仁”了。還好後來發現不難改,加個正負1去control就好了~

自己的辣雞代碼貼一貼留著自己看,難得寫這麽長:

技術分享圖片
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 struct Point
  5 {
  6     double x, y;
  7     Point(double a = 0, double b = 0):x(a), y(b){ }
  8 };
  9 typedef Point Vector;
 10 
 11 const double PI = acos(-1.0);
 12 int dcmp(double x)
 13 {
 14     if (fabs(x) < 1e-6
) return 0; 15 else return x < 0 ? -1 : 1; 16 } 17 Vector operator + (const Point &A, const Point &B) { return Vector(A.x + B.x, A.y + B.y); } 18 Vector operator - (const Point &A, const Point &B) { return Vector(A.x - B.x, A.y - B.y); } 19 Vector operator * (const Point &A, double
p) { return Vector(A.x * p, A.y * p); } 20 Vector operator / (const Point &A, double p) { return Vector(A.x / p, A.y / p); } 21 bool operator < (const Point &A, const Point &B) { return dcmp(A.x - B.x) < 0 || (dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) < 0); } 22 bool operator == (const Point &A, const Point &B) { return dcmp(A.x - B.x) == 0 && dcmp(A.y - B.y) == 0; } 23 24 double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; } 25 double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; } 26 double Length(Vector A) { return sqrt(Dot(A, A)); } 27 double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); } 28 Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y / L, A.x / L); } 29 Vector Rotate(Vector A, double rad) { return Vector(A.x * cos(rad) - A.y * sin(rad), A.x * sin(rad) + A.y * cos(rad)); } 30 31 Point Get_Line_Intersect(Point P, Vector v, Point Q, Vector w) 32 { 33 Point u = P - Q; 34 double t = Cross(w, u) / Cross(v, w); 35 return P + v*t; 36 } 37 38 double Distance_to_Line(Point P, Point A, Point B) 39 { 40 Vector v1 = P - A, v2 = B - A; 41 return fabs(Cross(v1, v2) / Length(v2)); 42 } 43 44 struct Circle 45 { 46 Point c; 47 double r; 48 // Circle(Point a = (0, 0), double x = 0):c(a), r(x){} 49 Point point(double seta) { return Point(c.x + cos(seta)*r, c.y + sin(seta)*r); } 50 }; 51 52 struct Line 53 { 54 Point p; 55 Vector v; 56 Line(Point p, Vector v):p(p), v(v) { } 57 58 Point point(double t) { return p + v*t; } 59 Line move(double d) { return Line(p + Normal(v)*d, v); } 60 }; 61 62 double formattedAngle(Vector A) 63 { 64 double a = atan2(A.y, A.x) / PI * 180; 65 if (dcmp(a) < 0) a += 180; 66 if (dcmp(a - 180) >= 0) a -= 180; 67 return a; 68 } 69 70 int getTangents(Point P, Circle C, vector<double> &v) 71 { 72 Vector u = C.c - P; 73 double d = Length(u); 74 75 if (dcmp(d - C.r) < 0) return 0; 76 else if (dcmp(d - C.r) == 0) 77 { 78 v.push_back(formattedAngle(Rotate(u, PI/2))); 79 return 1; 80 } 81 else 82 { 83 double a = asin(C.r / d); 84 v.push_back(formattedAngle(Rotate(u, a))); 85 v.push_back(formattedAngle(Rotate(u, -a))); 86 return 2; 87 } 88 } 89 90 void get_Line_Circle_Intersection(Line L, Circle C, vector<Point> &ans) 91 { 92 double t1, t2; 93 double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y; 94 double e = a*a + c*c, f = 2*(a*b + c*d), g = b*b + d*d - C.r*C.r; 95 double delta = f*f - 4*e*g; 96 97 if (dcmp(delta) < 0) return; 98 else if (dcmp(delta) == 0) 99 { 100 t1 = t2 = -f/2/e; 101 ans.push_back(L.point(t1)); 102 } 103 else 104 { 105 t1 = (-f + sqrt(delta)) / 2 / e; 106 t2 = (-f - sqrt(delta)) / 2 / e; 107 ans.push_back(L.point(t1)), ans.push_back(L.point(t2)); 108 } 109 } 110 111 inline double angle(Vector A) { return atan2(A.y, A.x); } 112 113 int get_Circle_Circle_Intersection(Circle C1, Circle C2, vector<Point> &v) 114 { 115 double d = Length(C1.c - C2.c); 116 if (dcmp(d) == 0) 117 { 118 if (dcmp(C1.r - C2.r) == 0) return -1; 119 return 0; 120 } 121 if (dcmp(C1.r + C2.r - d) < 0) return 0; 122 if (dcmp(fabs(C1.r - C2.r) - d) > 0) return 0; 123 124 double a = angle(C2.c - C1.c); 125 double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d)); 126 Point p1 = C1.point(a - da), p2 = C1.point(a + da); 127 128 v.push_back(p1); 129 if (p1 == p2) return 1; 130 v.push_back(p2); 131 return 2; 132 } 133 134 void CircumscribedCircle() 135 { 136 Point P[3]; 137 for (int i = 0; i < 3; i++) scanf("%lf%lf", &P[i].x, &P[i].y); 138 139 Point c = Get_Line_Intersect((P[0] + P[1])/2, Rotate(P[1] - P[0], PI/2), (P[2] + P[0])/2, Rotate(P[2] - P[0], -PI/2)); 140 141 printf("(%.6lf,%.6lf,%.6lf)\n", c.x, c.y, Length(c - P[0])); 142 } 143 144 void InscribedCircle() 145 { 146 Point P[3]; 147 for (int i = 0; i < 3; i++) scanf("%lf%lf", &P[i].x, &P[i].y); 148 149 Vector v1 = Rotate(P[1] - P[0], (Cross(P[2] - P[0], P[1] - P[0]) > 0 ? -1 : 1) * Angle(P[1]-P[0], P[2]-P[0]) / 2); 150 Vector v2 = Rotate(P[0] - P[1], (Cross(P[2] - P[1], P[0] - P[1]) > 0 ? -1 : 1) * Angle(P[0]-P[1], P[2]-P[1]) / 2); 151 Point c = Get_Line_Intersect(P[0], v1, P[1], v2); 152 153 printf("(%.6lf,%.6lf,%.6lf)\n", c.x, c.y, Distance_to_Line(c, P[0], P[1])); 154 } 155 156 void TangentLineThroughPoint() 157 { 158 Circle C; 159 Point P; 160 vector<double> v; 161 scanf("%lf%lf%lf", &C.c.x, &C.c.y, &C.r); 162 scanf("%lf%lf", &P.x, &P.y); 163 164 printf("["); 165 if (getTangents(P, C, v)) sort(v.begin(), v.end()), printf("%.6lf", v[0]); 166 if (v.size() == 2) printf(",%.6lf", v[1]); 167 printf("]\n"); 168 } 169 170 void CircleThroughAPointAndTangentToALineWithRadius() 171 { 172 Circle P; 173 Point A, B; 174 scanf("%lf%lf%lf%lf%lf%lf%lf", &P.c.x, &P.c.y, &A.x, &A.y, &B.x, &B.y, &P.r); 175 176 Line original(A, B - A); 177 vector<Point> v; 178 get_Line_Circle_Intersection(original.move(P.r), P, v); 179 get_Line_Circle_Intersection(original.move(-P.r), P, v); 180 sort(v.begin(), v.end()); 181 182 printf("["); 183 if (v.size()) printf("(%.6lf,%.6lf)", v[0].x, v[0].y); 184 for (int i = 1; i < v.size(); i++) printf(",(%.6lf,%.6lf)", v[i].x, v[i].y); 185 printf("]\n"); 186 } 187 188 inline Point e_to_go(Vector A, double len) { return A / Length(A) * len; } 189 190 void CircleTangentToTwoLinesWithRadius() 191 { 192 Point A, B, C ,D; 193 double r; 194 scanf("%lf%lf %lf%lf %lf%lf %lf%lf %lf", &A.x, &A.y, &B.x, &B.y, &C.x, &C.y, &D.x, &D.y, &r); 195 196 vector<Point> v; 197 int control = Cross(B - A, D - C) < 0 ? -1 : 1; 198 199 Point P = Get_Line_Intersect(A, B-A, C, D-C); 200 double seta = Angle(B - A, D - C)/2; 201 Vector v1 = Rotate(B - A, control*seta); 202 Vector v2 = Rotate(B - A, -control*(PI/2 - seta)); 203 204 v.push_back(P + e_to_go(v1, r/sin(seta))); 205 v.push_back(P - e_to_go(v1, r/sin(seta))); 206 v.push_back(P + e_to_go(v2, r/cos(seta))); 207 v.push_back(P - e_to_go(v2, r/cos(seta))); 208 sort(v.begin(), v.end()); 209 210 for (int i = 0; i < v.size(); i++) 211 printf("%c(%.6lf,%.6lf)", ",["[i == 0], v[i].x, v[i].y); 212 printf("]\n"); 213 } 214 215 void CircleTangentToTwoDisjointCirclesWithRadius() 216 { 217 Circle C1, C2; 218 double r; 219 scanf("%lf%lf%lf %lf%lf%lf %lf", &C1.c.x, &C1.c.y, &C1.r, &C2.c.x, &C2.c.y, &C2.r, &r); 220 C1.r += r, C2.r += r; 221 vector<Point> v; 222 get_Circle_Circle_Intersection(C1, C2, v); 223 sort(v.begin(), v.end()); 224 225 if (!v.size()) printf("["); 226 for (int i = 0; i < v.size(); i++) 227 printf("%c(%.6lf,%.6lf)", ",["[i == 0], v[i].x, v[i].y); 228 printf("]\n"); 229 } 230 231 int main() 232 { 233 string s; 234 while (cin >> s) 235 { 236 if (s.length() < 19) InscribedCircle(); 237 else 238 { 239 switch(s[18]) 240 { 241 case e: 242 CircumscribedCircle(); break; 243 case P: 244 TangentLineThroughPoint(); break; 245 case t: 246 CircleThroughAPointAndTangentToALineWithRadius(); break; 247 case L: 248 CircleTangentToTwoLinesWithRadius(); break; 249 case D: 250 CircleTangentToTwoDisjointCirclesWithRadius(); break; 251 default : break; 252 } 253 } 254 } 255 return 0; 256 }
View Code

UVa12304(計算幾何中圓的基本操作)