UVa12304(计算几何中圆的基本操作)

Posted alphawa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVa12304(计算几何中圆的基本操作)相关的知识,希望对你有一定的参考价值。

断断续续写了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)
", 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)
", 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("]
");
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("]
");
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("]
");
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("]
");
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(计算几何中圆的基本操作)的主要内容,如果未能解决你的问题,请参考以下文章

做题UVA-12304——平面计算集合六合一

UVA 12304 /// 圆的综合题 圆的模板

UVA12304 2D Geometry 110 in 1!

如何更改 d3 中圆的半径和不透明度?

●UVA 10674 Tangents

计算 UIView 中圆上 Subview 的中心坐标(倒坐标系)