00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052 #include <list>
00053
00054 #include <archon/math/vector.H>
00055
00056 namespace Archon
00057 {
00058 using namespace std;
00059
00060 namespace Utilities
00061 {
00062 template<int N>
00063 class MinimalBoundingBall
00064 {
00065 public:
00066
00067 typedef Math::BasicVector<double, N> Point;
00068 typedef typename list<Point>::iterator It;
00069 typedef typename list<Point>::const_iterator Cit;
00070
00071 class Basis
00072 {
00073 private:
00074
00075 int m, s;
00076 double q0[N];
00077
00078 double z[N+1];
00079 double f[N+1];
00080 double v[N+1][N];
00081 double a[N+1][N];
00082
00083 double c[N+1][N];
00084 double sqr_r[N+1];
00085
00086 double *current_c;
00087 double current_sqr_r;
00088
00089 double sqr(double r) const { return r*r; }
00090
00091 public:
00092 Basis();
00093
00094
00095 const double *center() const;
00096 double squared_radius() const;
00097 int size() const;
00098 int support_size() const;
00099 double excess(const Point &) const;
00100
00101
00102 void reset();
00103 bool push(const Point &);
00104 void pop();
00105
00106
00107 double slack() const;
00108 };
00109
00110 private:
00111
00112 list<Point> L;
00113 Basis B;
00114 It support_end;
00115
00116
00117 void mtf_mb(It k);
00118 void pivot_mb(It k);
00119 void move_to_front(It j);
00120 double max_excess(It t, It i, It &pivot) const;
00121 double abs(double r) const { return r>0 ? r : -r; }
00122 double sqr(double r) const { return r*r; }
00123
00124 public:
00125
00126 MinimalBoundingBall() {}
00127 void check_in(const Point &);
00128 void build(bool pivoting = true);
00129
00130
00131 Point center() const;
00132 double squared_radius() const;
00133 int nr_points() const;
00134 Cit points_begin() const;
00135 Cit points_end() const;
00136 int nr_support_points() const;
00137 Cit support_points_begin() const;
00138 Cit support_points_end() const;
00139
00140
00141 double accuracy(double &slack) const;
00142 bool is_valid(double tolerance = 1e-15) const;
00143 };
00144
00145
00146
00147 template <int N>
00148 void MinimalBoundingBall<N>::check_in(const Point &p)
00149 {
00150 L.push_back(p);
00151 }
00152
00153 template<int N>
00154 void MinimalBoundingBall<N>::build(bool pivoting)
00155 {
00156 B.reset();
00157 support_end = L.begin();
00158 if(pivoting) pivot_mb(L.end());
00159 else mtf_mb(L.end());
00160 }
00161
00162 template<int N>
00163 void MinimalBoundingBall<N>::mtf_mb(It i)
00164 {
00165 support_end = L.begin();
00166 if((B.size())==N+1) return;
00167 for(It k=L.begin(); k!=i;)
00168 {
00169 It j=k++;
00170 if(B.excess(*j) > 0)
00171 {
00172 if(B.push(*j))
00173 {
00174 mtf_mb (j);
00175 B.pop();
00176 move_to_front(j);
00177 }
00178 }
00179 }
00180 }
00181
00182 template<int N>
00183 void MinimalBoundingBall<N>::move_to_front(It j)
00184 {
00185 if(support_end == j) support_end++;
00186 L.splice(L.begin(), L, j);
00187 }
00188
00189 template<int N>
00190 void MinimalBoundingBall<N>::pivot_mb(It i)
00191 {
00192 It t = ++L.begin();
00193 mtf_mb(t);
00194 double max_e, old_sqr_r = 0;
00195 do
00196 {
00197 It pivot;
00198 max_e = max_excess(t, i, pivot);
00199 if(max_e > 0)
00200 {
00201 t = support_end;
00202 if(t==pivot) ++t;
00203 old_sqr_r = B.squared_radius();
00204 B.push(*pivot);
00205 mtf_mb(support_end);
00206 B.pop();
00207 move_to_front(pivot);
00208 }
00209 }
00210 while(max_e > 0 && B.squared_radius() > old_sqr_r);
00211 }
00212
00213 template<int N>
00214 double MinimalBoundingBall<N>::max_excess(It t, It i, It &pivot) const
00215 {
00216 const double *c = B.center(), sqr_r = B.squared_radius();
00217 double e, max_e = 0;
00218 for(It k=t; k!=i; ++k)
00219 {
00220 const Point &p = *k;
00221 e = -sqr_r;
00222 for(int j=0; j<N; ++j) e += sqr(p[j]-c[j]);
00223 if(e > max_e)
00224 {
00225 max_e = e;
00226 pivot = k;
00227 }
00228 }
00229 return max_e;
00230 }
00231
00232 template<int N>
00233 typename MinimalBoundingBall<N>::Point MinimalBoundingBall<N>::center() const
00234 {
00235 return Point(B.center());
00236 }
00237
00238 template<int N>
00239 double MinimalBoundingBall<N>::squared_radius() const
00240 {
00241 return B.squared_radius();
00242 }
00243
00244 template<int N>
00245 int MinimalBoundingBall<N>::nr_points() const
00246 {
00247 return L.size();
00248 }
00249
00250 template<int N>
00251 typename MinimalBoundingBall<N>::Cit MinimalBoundingBall<N>::points_begin() const
00252 {
00253 return L.begin();
00254 }
00255
00256 template<int N>
00257 typename MinimalBoundingBall<N>::Cit MinimalBoundingBall<N>::points_end() const
00258 {
00259 return L.end();
00260 }
00261
00262 template<int N>
00263 int MinimalBoundingBall<N>::nr_support_points() const
00264 {
00265 return B.support_size();
00266 }
00267
00268 template<int N>
00269 typename MinimalBoundingBall<N>::Cit MinimalBoundingBall<N>::support_points_begin() const
00270 {
00271 return L.begin();
00272 }
00273
00274 template<int N>
00275 typename MinimalBoundingBall<N>::Cit MinimalBoundingBall<N>::support_points_end() const
00276 {
00277 return support_end;
00278 }
00279
00280 template<int N>
00281 double MinimalBoundingBall<N>::accuracy(double &slack) const
00282 {
00283 double e, max_e = 0;
00284 int n_supp=0;
00285 Cit i;
00286 for(i=L.begin(); i!=support_end; ++i,++n_supp)
00287 if((e = abs(B.excess(*i))) > max_e)
00288 max_e = e;
00289
00290
00291 assert(n_supp == nr_support_points());
00292
00293 for(i=support_end; i!=L.end(); ++i)
00294 if((e = B.excess(*i)) > max_e)
00295 max_e = e;
00296
00297 slack = B.slack();
00298 return max_e/squared_radius();
00299 }
00300
00301 template<int N>
00302 bool MinimalBoundingBall<N>::is_valid(double tolerance) const
00303 {
00304 double slack;
00305 return accuracy(slack) < tolerance && slack == 0;
00306 }
00307
00308
00309
00310
00311 template<int N>
00312 const double *MinimalBoundingBall<N>::Basis::center() const
00313 {
00314 return current_c;
00315 }
00316
00317 template<int N>
00318 double MinimalBoundingBall<N>::Basis::squared_radius() const
00319 {
00320 return current_sqr_r;
00321 }
00322
00323 template<int N>
00324 int MinimalBoundingBall<N>::Basis::size() const
00325 {
00326 return m;
00327 }
00328
00329 template<int N>
00330 int MinimalBoundingBall<N>::Basis::support_size() const
00331 {
00332 return s;
00333 }
00334
00335 template<int N>
00336 double MinimalBoundingBall<N>::Basis::excess(const Point &p) const
00337 {
00338 double e = -current_sqr_r;
00339 for(int k=0; k<N; ++k) e += sqr(p[k]-current_c[k]);
00340 return e;
00341 }
00342
00343 template<int N>
00344 void MinimalBoundingBall<N>::Basis::reset()
00345 {
00346 m = s = 0;
00347
00348 for(int j=0; j<N; ++j) c[0][j]=0;
00349 current_c = c[0];
00350 current_sqr_r = -1;
00351 }
00352
00353 template<int N>
00354 MinimalBoundingBall<N>::Basis::Basis()
00355 {
00356 reset();
00357 }
00358
00359 template<int N>
00360 void MinimalBoundingBall<N>::Basis::pop()
00361 {
00362 --m;
00363 }
00364
00365 template<int N>
00366 bool MinimalBoundingBall<N>::Basis::push(const Point &p)
00367 {
00368 int i, j;
00369 double eps = 1e-32;
00370 if(m==0)
00371 {
00372 for(i=0; i<N; ++i) q0[i] = p[i];
00373 for(i=0; i<N; ++i) c[0][i] = q0[i];
00374 sqr_r[0] = 0;
00375 }
00376 else
00377 {
00378
00379 for(i=0; i<N; ++i) v[m][i] = p[i]-q0[i];
00380
00381
00382 for(i=1; i<m; ++i)
00383 {
00384 a[m][i] = 0;
00385 for(j=0; j<N; ++j) a[m][i] += v[i][j] * v[m][j];
00386 a[m][i]*=(2/z[i]);
00387 }
00388
00389
00390 for(i=1; i<m; ++i)
00391 for(j=0; j<N; ++j)
00392 v[m][j] -= a[m][i]*v[i][j];
00393
00394
00395 z[m]=0;
00396 for(j=0; j<N; ++j) z[m] += sqr(v[m][j]);
00397 z[m]*=2;
00398
00399
00400 if(z[m]<eps*current_sqr_r) return false;
00401
00402
00403 double e = -sqr_r[m-1];
00404 for(i=0; i<N; ++i) e += sqr(p[i]-c[m-1][i]);
00405 f[m]=e/z[m];
00406
00407 for(i=0; i<N; ++i) c[m][i] = c[m-1][i]+f[m]*v[m][i];
00408 sqr_r[m] = sqr_r[m-1] + e*f[m]/2;
00409 }
00410 current_c = c[m];
00411 current_sqr_r = sqr_r[m];
00412 s = ++m;
00413 return true;
00414 }
00415
00416 template<int N>
00417 double MinimalBoundingBall<N>::Basis::slack() const
00418 {
00419 double l[N+1], min_l=0;
00420 l[0] = 1;
00421 for(int i=s-1; i>0; --i)
00422 {
00423 l[i] = f[i];
00424 for(int k=s-1; k>i; --k) l[i]-=a[k][i]*l[k];
00425 if(l[i] < min_l) min_l = l[i];
00426 l[0] -= l[i];
00427 }
00428 if(l[0] < min_l) min_l = l[0];
00429 return min_l < 0 ? -min_l : 0;
00430 }
00431 }
00432 }