#include<cstdio>
#include<vector>
#include<complex>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

typedef complex<double> Point;

const double EPS=1e-9;
const double PI=acos(-1);

class Line:public vector<Point>{
public:
	Line(const Point &a,const Point &b){ push_back(a), push_back(b); }
};

class Segment:public Line{
public:
	Segment(const Point &a,const Point &b):Line(a,b){}
};

class Circle{
public:
	Point c;
	double r;
	Circle(){}
	Circle(const Point &C,double R):c(C),r(R){}
};

inline double dot(const Point &a,const Point &b){
	return a.real()*b.real()+a.imag()*b.imag();
}

inline double cross(const Point &a,const Point &b){
	return a.real()*b.imag()-a.imag()*b.real();
}

inline void calc_abc(const Line &l,double &a,double &b,double &c){
	a=l[0].imag()-l[1].imag();
	b=l[1].real()-l[0].real();
	c=cross(l[0],l[1]);
}

Point PerpFoot(const Point &p,const Line &l){
	double a,b,c;
	calc_abc(l,a,b,c);
	Point v(a,b);
	return p-(dot(p,v)+c)*v/norm(v);
}

bool cover(const Segment &s,const Point &p){
	return dot(s[0]-p,s[1]-p)<EPS;
}

bool cover(const Circle &c,const Point &p){
	return abs(p-c.c)<c.r+EPS;
}

bool cover(const Circle &c1,const Circle &c2){
	return abs(c1.c-c2.c)+c2.r<c1.r+EPS;
}

int intersect(const Circle &c,const Line &l,Point &p,Point &q){
	Point m=PerpFoot(c.c,l);
	double d2=norm(c.c-m);
	if(c.r*c.r+EPS<d2) return 0;
	else if(abs(c.r*c.r-d2)<EPS){
		p=q=m;
		return 1;
	}
	else{
		Point v;
		double n0=norm(l[0]-m),n1=norm(l[1]-m);
		if(n0<n1) v=l[1]-m, n0=n1;
		else      v=l[0]-m;
		v*=sqrt((c.r*c.r-d2)/n0);
		p=m+v, q=m-v;
		return 2;
	}
}

int intersect(const Circle &c,const Segment &s,Point &p,Point &q){
	Point pp,qq;
	int n=intersect(c,Line(s),pp,qq);
	if(n==0) return 0;
	else if(n==1){
		if(cover(s,pp)){
			p=q=pp;
			return 1;
		}
		return 0;
	}
	else{
		bool bp=cover(s,pp),bq=cover(s,qq);
		if(bp&&bq){
			p=pp, q=qq;
			return 2;
		}
		if(bp||bq){
			p=q=(bp?pp:qq);
			return 1;
		}
		return 0;
	}
}

int intersect(const Circle &c1,const Circle &c2,Point &p,Point &q){
	double d2=norm(c1.c-c2.c);
	if(d2<EPS && abs(c1.r-c2.r)<EPS) return -1; // c1==c2
	if((c1.r+c2.r)*(c1.r+c2.r)+EPS<d2 || d2+EPS<(c1.r-c2.r)*(c1.r-c2.r)) return 0;

	double d=sqrt(d2);
	if(abs(c1.r+c2.r-d)<EPS){
		intersect(c1,Segment(c1.c,c2.c),p,q);
		return 1;
	}

	double a=(c1.r*c1.r-c2.r*c2.r+d2)/(2*d);
	double h=sqrt(c1.r*c1.r-a*a);
	p=q=c1.c+a/d*(c2.c-c1.c);
	Point tmp=h*(c2.c-c1.c)/d;
	p+=tmp*Point(0,-1);
	q+=tmp*Point(0,+1);
	return 2;
}

Point c_cmp;
bool cmp_arg(const Point &p,const Point &q){ return arg(p-c_cmp)<arg(q-c_cmp); }

int main(){
	for(int n;scanf("%d",&n),n;){
		Circle C[100];
		rep(i,n){
			double x,y; scanf("%lf%lf%lf",&x,&y,&C[i].r);
			C[i].c=Point(x,y);
		}

		vector<Point> P[100];
		rep(j,n) rep(i,j) {
			Point p,q;
			if(intersect(C[i],C[j],p,q)==2){
				P[i].push_back(p); P[i].push_back(q);
				P[j].push_back(p); P[j].push_back(q);
			}
		}

		double ans=0;
		rep(i,n){
			bool cov=false;
			rep(j,n) if(j!=i && cover(C[j],C[i])) cov=true;
			if(cov) continue;

			int m=P[i].size();
			c_cmp=C[i].c;
			sort(P[i].begin(),P[i].end(),cmp_arg);

			if(m==0) ans+=2*PI*C[i].r;

			rep(j,m){
				const Point &a=P[i][j],&b=P[i][(j+1)%m];
				double theta=arg(b-C[i].c)-arg(a-C[i].c);
				if(theta<0) theta+=2*PI;
				Point c=C[i].c+(a-C[i].c)*exp(Point(0,theta/2));

				bool ok=true;
				rep(k,n) if(k!=i && cover(C[k],c)) ok=false;
				if(ok) ans+=C[i].r*theta;
			}
		}

		printf("%.9f\n",ans);
	}

	return 0;
}

Measured memory_bytes: 0