1 /*UVA 10969计算几何
2 这道题和LA2572相似,但相对简单些。
3 思路:求圆间的交点,顺序枚举出圆上的圆弧,中点判断是否被覆盖。
4 */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <math.h>
9 #include <ctype.h>
10 #include <string>
11 #include <iostream>
12 #include <sstream>
13 #include <vector>
14 #include <queue>
15 #include <stack>
16 #include <map>
17 #include <list>
18 #include <set>
19 #include <algorithm>
20 #define INF 0x3f3f3f3f
21 #define eps 1e-7
22 #define eps2 1e-3
23 using namespace std;
24
25 struct Point
26 {
27 double x,y;
28 Point() {}
29 Point(double xx,double yy)
30 {
31 x=xx;
32 y=yy;
33 }
34 };
35 struct Circle
36 {
37 Point O;
38 double r;
39 Circle() {}
40 Circle(Point O1,double r1)
41 {
42 O=O1;
43 r=r1;
44 }
45 Point point(double a)
46 {
47 return Point(O.x+cos(a)*r,O.y+sin(a)*r);
48 }
49 };
50 typedef Point Vector;
51
52 bool operator==(Point A,Point B)
53 {
54 if ((fabs(A.x-B.x)<1e-10) && (fabs(A.y-B.y)<1e-10)) return true;
55 else return false;
56 }
57 Vector operator-(Point A,Point B)//表示A指向B
58 {
59 return Vector(A.x-B.x,A.y-B.y);
60 }
61 Vector operator*(Vector A,double k)
62 {
63 return Vector(A.x*k,A.y*k);
64 }
65 Vector operator+(Point A,Point B)//表示A指向B
66 {
67 return Vector(B.x+A.x,B.y+A.y);
68 }
69 double Dot(Vector A,Vector B)
70 {
71 return A.x*B.x+A.y*B.y;
72 }
73 double Length(Vector A)
74 {
75 return sqrt(Dot(A,A));
76 }
77 double Cross(Vector A,Vector B)
78 {
79 return A.x*B.y-A.y*B.x;
80 }
81 int dcmp(double x)
82 {
83 if(fabs(x)<1e-10) return 0;
84 else if(x>0) return 1;
85 else return -1;
86 }
87 double angle(Vector v)
88 {
89 return atan2(v.y,v.x);
90 }
91 double normal(double rad)
92 {
93 return rad-2*M_PI*floor(rad/(2*M_PI));
94 }
95
96 Point GetMid(double a,double b,double r,double x,double y)//圆上两点,获得中点的坐标
97 {
98 double arf=(b+a)/2;
99 double xx=r*cos(arf)+x;
100 double xy=r*sin(arf)+y;
101 Point P=Point(xx,xy);
102 return P;
103 }
104 bool PInCircle(Point P,Circle C)//判断点在圆内
105 {
106 double dis=Length(P-C.O);
107 if (dis-C.r>1e-6) return false;
108 else return true;
109 }
110 void getcircleinter(Point c1,double r1,Point c2,double r2,vector<double>& rad)
111 {
112 double d=Length(c1-c2);
113 if(dcmp(d)==0) return;
114 if(dcmp(r1+r2-d)<0) return;
115 if(dcmp(fabs(r1-r2)-d)>0) return;
116 double a=angle(c2-c1);
117 double da=acos((r1*r1+d*d-r2*r2)/(2*r1*d));
118 rad.push_back(normal(a+da));
119 rad.push_back(normal(a-da));
120 }
121
122 int n;
123 Circle CC[110];//圆
124 vector<double> Arf[110];//圆心角
125
126 int cas;
127 int main()
128 {
129 cin>>cas;
130 while(cas--)
131 {
132 double ans=0.0;
133 cin>>n;
134 for(int i=1; i<=n; i++)//读取信息
135 {
136 double x,y,r;
137 cin>>r>>x>>y;
138 CC[i]=Circle(Point(x,y),r);
139 }
140 for(int i=1; i<=n; i++) {Arf[i].clear();Arf[i].push_back(0);Arf[i].push_back(2*M_PI);}
141
142 for(int i=1; i<=n; i++)//获得圆上的交点的角度
143 for(int j=1; j<=n; j++)
144 getcircleinter(CC[i].O,CC[i].r,CC[j].O,CC[j].r,Arf[i]);
145
146 for(int i=1; i<=n; i++) //枚举n个圆上的圆弧
147 {
148 int k=Arf[i].size();
149 sort(Arf[i].begin(),Arf[i].end());
150
151 for(int j=0; j<k-1; j++) //枚举每条弧
152 {
153 Point Mid=GetMid(Arf[i][j],Arf[i][j+1],CC[i].r,CC[i].O.x,CC[i].O.y);
154
155 bool ok=true;//表示这条圆弧可见
156 for(int l=i+1; l<=n; l++) //判断中点是否可见
157 if (PInCircle(Mid,CC[l])) ok=false;
158
159 if(ok) ans+=(Arf[i][j+1]-Arf[i][j])*CC[i].r;
160 }
161 }
162
163 printf("%.3lf\n",(ans));//放缩回来
164 }
165 return 0;
166 }