-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathminEnclosingBall.cpp
58 lines (58 loc) · 2.14 KB
/
minEnclosingBall.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Pt : { x , y , z }
#define N 202020
int n, nouter; Pt pt[ N ], outer[4], res;
double radius,tmp;
void ball() {
Pt q[3]; double m[3][3], sol[3], L[3], det;
int i,j; res.x = res.y = res.z = radius = 0;
switch ( nouter ) {
case 1: res=outer[0]; break;
case 2: res=(outer[0]+outer[1])/2; radius=norm2(res, outer[0]); break;
case 3:
for (i=0; i<2; ++i) q[i]=outer[i+1]-outer[0];
for (i=0; i<2; ++i) for(j=0; j<2; ++j) m[i][j]=(q[i] * q[j])*2;
for (i=0; i<2; ++i) sol[i]=(q[i] * q[i]);
if (fabs(det=m[0][0]*m[1][1]-m[0][1]*m[1][0])<eps) return;
L[0]=(sol[0]*m[1][1]-sol[1]*m[0][1])/det;
L[1]=(sol[1]*m[0][0]-sol[0]*m[1][0])/det;
res=outer[0]+q[0]*L[0]+q[1]*L[1];
radius=norm2(res, outer[0]);
break;
case 4:
for (i=0; i<3; ++i) q[i]=outer[i+1]-outer[0], sol[i]=(q[i] * q[i]);
for (i=0;i<3;++i) for(j=0;j<3;++j) m[i][j]=(q[i] * q[j])*2;
det= m[0][0]*m[1][1]*m[2][2]
+ m[0][1]*m[1][2]*m[2][0]
+ m[0][2]*m[2][1]*m[1][0]
- m[0][2]*m[1][1]*m[2][0]
- m[0][1]*m[1][0]*m[2][2]
- m[0][0]*m[1][2]*m[2][1];
if ( fabs(det)<eps ) return;
for (j=0; j<3; ++j) {
for (i=0; i<3; ++i) m[i][j]=sol[i];
L[j]=( m[0][0]*m[1][1]*m[2][2]
+ m[0][1]*m[1][2]*m[2][0]
+ m[0][2]*m[2][1]*m[1][0]
- m[0][2]*m[1][1]*m[2][0]
- m[0][1]*m[1][0]*m[2][2]
- m[0][0]*m[1][2]*m[2][1]
) / det;
for (i=0; i<3; ++i) m[i][j]=(q[i] * q[j])*2;
} res=outer[0];
for (i=0; i<3; ++i ) res = res + q[i] * L[i];
radius=norm2(res, outer[0]);
}}
void minball(int n){ ball();
if( nouter < 4 ) for( int i = 0 ; i < n ; i ++ )
if( norm2(res, pt[i]) - radius > eps ){
outer[ nouter ++ ] = pt[ i ]; minball(i); --nouter;
if(i>0){ Pt Tt = pt[i];
memmove(&pt[1], &pt[0], sizeof(Pt)*i); pt[0]=Tt;
}}}
double solve(){
// n points in pt
random_shuffle(pt, pt+n); radius=-1;
for(int i=0;i<n;i++) if(norm2(res,pt[i])-radius>eps)
nouter=1, outer[0]=pt[i], minball(i);
return sqrt(radius);
}