00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef PEEKABOT_GEOM_GEOMETRY_TOOLBOX_HH_INCLUDED
00023 #define PEEKABOT_GEOM_GEOMETRY_TOOLBOX_HH_INCLUDED
00024
00025
00026 #include <cmath>
00027 #include <cassert>
00028 #include <cstddef>
00029 #include <vector>
00030 #include <Eigen/Core>
00031
00032
00033 namespace peekabot
00034 {
00035 namespace geom
00036 {
00037 template<class FwdIt, class VertexType>
00038 void calc_optimal_bounding_sphere(
00039 FwdIt begin, FwdIt end,
00040 VertexType &midp, float &r,
00041 float x_scale_factor,
00042 float y_scale_factor,
00043 float z_scale_factor) throw()
00044 {
00045 float max_sq_dist = 0;
00046 midp = VertexType(0,0,0);
00047
00048 size_t count = 0;
00049
00050 for( FwdIt it = begin; it < end; )
00051 {
00052 ++count;
00053
00054 const VertexType &v1 = *it;
00055 FwdIt next_it = ++it;
00056
00057 for( FwdIt jt = next_it; jt < end; ++jt )
00058 {
00059 VertexType diff = v1 - (*jt);
00060 diff(0) *= x_scale_factor;
00061 diff(1) *= y_scale_factor;
00062 diff(2) *= z_scale_factor;
00063 float sq_dist = diff.dot(diff);
00064
00065 if( sq_dist > max_sq_dist )
00066 {
00067 max_sq_dist = sq_dist;
00068 midp = *jt;
00069 midp(0) *= x_scale_factor;
00070 midp(1) *= y_scale_factor;
00071 midp(2) *= z_scale_factor;
00072 midp += diff/2;
00073 }
00074 }
00075 }
00076
00077
00078 if( count == 1 )
00079 midp = *begin;
00080
00081 r = sqrtf(max_sq_dist)/2;
00082 }
00083
00084
00085 template<typename FwdIt, typename VertexType>
00086 void calc_approx_bounding_sphere_naive(
00087 FwdIt begin, FwdIt end,
00088 VertexType &midp, float &r,
00089 float x_scale_factor,
00090 float y_scale_factor,
00091 float z_scale_factor) throw()
00092 {
00093
00094 if( begin == end )
00095 {
00096 midp = VertexType(0, 0, 0);
00097 r = 0;
00098 return;
00099 }
00100
00101 const VertexType sv(
00102 x_scale_factor, y_scale_factor, z_scale_factor);
00103
00104 midp = VertexType(0, 0, 0);
00105 for( FwdIt it = begin; it < end; ++it )
00106 midp += (*it).cwise() * sv;
00107 midp /= std::distance(begin, end);
00108
00109 float sq_r = 0;
00110 for( FwdIt it = begin; it < end; ++it )
00111 sq_r = std::max(sq_r, ((*it).cwise() * sv - midp).squaredNorm());
00112 r = sqrtf(sq_r);
00113 }
00114
00115
00116 inline void calc_approx_bounding_sphere_naive(
00117 const std::vector<Eigen::Vector3f> &pts,
00118 Eigen::Vector3f &midp, float &r,
00119 float x_scale_factor,
00120 float y_scale_factor,
00121 float z_scale_factor) throw()
00122 {
00123 typedef Eigen::Vector3f VertexType;
00124
00125
00126 if( pts.empty() )
00127 {
00128 midp = VertexType(0, 0, 0);
00129 r = 0;
00130 return;
00131 }
00132
00133 const VertexType sv(
00134 x_scale_factor, y_scale_factor, z_scale_factor);
00135
00136 midp = VertexType(0, 0, 0);
00137 for( std::size_t i = 0; i < pts.size(); ++i )
00138 midp += pts[i].cwise() * sv;
00139 midp /= pts.size();
00140
00141 float sq_r = 0;
00142 for( std::size_t i = 0; i < pts.size(); ++i )
00143 sq_r = std::max(sq_r, (pts[i].cwise() * sv - midp).squaredNorm());
00144 r = sqrtf(sq_r);
00145 }
00146
00147
00148 template<typename FwdIt, typename VertexType>
00149 void calc_approx_bounding_sphere_ritter(
00150 FwdIt begin, FwdIt end,
00151 VertexType &midp, float &r,
00152 float x_scale_factor,
00153 float y_scale_factor,
00154 float z_scale_factor) throw()
00155 {
00156
00157 if( begin == end )
00158 {
00159 midp = VertexType(0,0,0);
00160 r = 0;
00161 return;
00162 }
00163
00164 VertexType min[3], max[3];
00165 for( int i = 0; i < 3; ++i )
00166 min[i] = max[i] = *begin;
00167
00168 FwdIt it = begin;
00169 for( ++it; it < end; ++it )
00170 {
00171 for( int i = 0; i < 3; ++i )
00172 {
00173 if( (*it)(i) < min[i](i) )
00174 min[i] = *it;
00175 else if( (*it)(i) > max[i](i) )
00176 max[i] = *it;
00177 }
00178 }
00179
00180 const VertexType sv(
00181 x_scale_factor, y_scale_factor, z_scale_factor);
00182
00183 midp = VertexType(0, 0, 0);
00184 r = 0;
00185
00186 for( int i = 0; i < 3; ++i )
00187 {
00188 max[i] = max[i].cwise() * sv;
00189 min[i] = min[i].cwise() * sv;
00190
00191 float sq_d = (max[i]-min[i]).squaredNorm();
00192 if( sq_d > r )
00193 {
00194 r = sq_d;
00195 midp = min[i] + (max[i]-min[i])/2;
00196 }
00197 }
00198
00199 r = sqrt(r/4);
00200
00201 for( FwdIt it = begin; it < end; ++it )
00202 {
00203 VertexType diff = (*it).cwise() * sv - midp;
00204 float sq_d = diff.squaredNorm();
00205
00206 if( sq_d > r*r+0.0000000001 )
00207 {
00208 float d = sqrtf(sq_d);
00209 r = (d + r)/2;
00210 midp += (d-r)/d * diff;
00211 }
00212 }
00213 }
00214
00215
00216 inline void calc_approx_bounding_sphere_ritter(
00217 const std::vector<Eigen::Vector3f> &pts,
00218 Eigen::Vector3f &midp, float &r,
00219 float x_scale_factor,
00220 float y_scale_factor,
00221 float z_scale_factor) throw()
00222 {
00223 typedef Eigen::Vector3f VertexType;
00224
00225
00226 if( pts.empty() )
00227 {
00228 midp = VertexType(0,0,0);
00229 r = 0;
00230 return;
00231 }
00232
00233 VertexType min[3], max[3];
00234 for( int i = 0; i < 3; ++i )
00235 min[i] = max[i] = pts[0];
00236
00237 for( std::size_t j = 1; j < pts.size(); ++j )
00238 {
00239 for( int i = 0; i < 3; ++i )
00240 {
00241 if( pts[j](i) < min[i](i) )
00242 min[i] = pts[j];
00243 else if( pts[j](i) > max[i](i) )
00244 max[i] = pts[j];
00245 }
00246 }
00247
00248 const VertexType sv(
00249 x_scale_factor, y_scale_factor, z_scale_factor);
00250
00251 midp = VertexType(0, 0, 0);
00252 r = 0;
00253
00254 for( int i = 0; i < 3; ++i )
00255 {
00256 max[i] = max[i].cwise() * sv;
00257 min[i] = min[i].cwise() * sv;
00258
00259 float sq_d = (max[i]-min[i]).squaredNorm();
00260 if( sq_d > r )
00261 {
00262 r = sq_d;
00263 midp = min[i] + (max[i]-min[i])/2;
00264 }
00265 }
00266
00267 r = sqrt(r/4);
00268
00269 for( std::size_t i = 0; i < pts.size(); ++i )
00270 {
00271 VertexType diff = pts[i].cwise() * sv - midp;
00272 float sq_d = diff.squaredNorm();
00273
00274 if( sq_d > r*r+0.0000000001 )
00275 {
00276 float d = sqrtf(sq_d);
00277 r = (d + r)/2;
00278 midp += (d-r)/d * diff;
00279 }
00280 }
00281 }
00282
00283
00284 template<typename FwdIt, typename VertexType>
00285 void calc_approx_bounding_sphere_aabb_center(
00286 FwdIt begin, FwdIt end,
00287 VertexType &midp, float &r,
00288 float x_scale_factor,
00289 float y_scale_factor,
00290 float z_scale_factor) throw()
00291 {
00292
00293 if( begin == end )
00294 {
00295 midp = VertexType(0, 0, 0);
00296 r = 0;
00297 return;
00298 }
00299
00300 Eigen::Vector3f min(
00301 std::numeric_limits<float>::max(),
00302 std::numeric_limits<float>::max(),
00303 std::numeric_limits<float>::max());
00304
00305 Eigen::Vector3f max(
00306 -std::numeric_limits<float>::max(),
00307 -std::numeric_limits<float>::max(),
00308 -std::numeric_limits<float>::max());
00309
00310 for( FwdIt it = begin; it < end; ++it )
00311 {
00312 for( std::size_t i = 0; i < 3; ++i )
00313 {
00314 min(i) = std::min(min(i), (*it)(i));
00315 max(i) = std::max(max(i), (*it)(i));
00316 }
00317 }
00318
00319 const VertexType sv(
00320 x_scale_factor, y_scale_factor, z_scale_factor);
00321
00322 min = min.cwise() * sv;
00323 max = max.cwise() * sv;
00324 midp = min/2 + max/2;
00325
00326 float sq_r = 0;
00327 for( FwdIt it = begin; it < end; ++it )
00328 sq_r = std::max(sq_r, ((*it).cwise() * sv - midp).squaredNorm());
00329 r = sqrtf(sq_r);
00330 }
00331
00332
00333 inline void calc_approx_bounding_sphere_aabb_center(
00334 const std::vector<Eigen::Vector3f> &pts,
00335 Eigen::Vector3f &midp, float &r,
00336 float x_scale_factor,
00337 float y_scale_factor,
00338 float z_scale_factor) throw()
00339 {
00340
00341 if( pts.empty() )
00342 {
00343 midp = Eigen::Vector3f(0, 0, 0);
00344 r = 0;
00345 return;
00346 }
00347
00348 Eigen::Vector3f min(
00349 std::numeric_limits<float>::max(),
00350 std::numeric_limits<float>::max(),
00351 std::numeric_limits<float>::max());
00352
00353 Eigen::Vector3f max(
00354 -std::numeric_limits<float>::max(),
00355 -std::numeric_limits<float>::max(),
00356 -std::numeric_limits<float>::max());
00357
00358 for( std::size_t j = 0; j < pts.size(); ++j )
00359 {
00360 for( std::size_t i = 0; i < 3; ++i )
00361 {
00362 min(i) = std::min(min(i), pts[j](i));
00363 max(i) = std::max(max(i), pts[j](i));
00364 }
00365 }
00366
00367 const Eigen::Vector3f sv(
00368 x_scale_factor, y_scale_factor, z_scale_factor);
00369
00370 min = min.cwise() * sv;
00371 max = max.cwise() * sv;
00372 midp = min/2 + max/2;
00373
00374 float sq_r = 0;
00375 for( std::size_t i = 0; i < pts.size(); ++i )
00376 sq_r = std::max(sq_r, (pts[i].cwise() * sv - midp).squaredNorm());
00377 r = sqrtf(sq_r);
00378 }
00379
00380
00381 template<typename FwdIt, typename VertexType>
00382 void calc_approx_bounding_sphere(
00383 FwdIt begin, FwdIt end,
00384 VertexType &midp, float &r,
00385 float x_scale_factor,
00386 float y_scale_factor,
00387 float z_scale_factor) throw()
00388 {
00389 calc_approx_bounding_sphere_aabb_center(
00390 begin, end, midp, r,
00391 x_scale_factor, y_scale_factor, z_scale_factor);
00392 }
00393
00394
00395 inline void calc_approx_bounding_sphere(
00396 const std::vector<Eigen::Vector3f> &pts,
00397 Eigen::Vector3f &midp, float &r,
00398 float x_scale_factor,
00399 float y_scale_factor,
00400 float z_scale_factor) throw()
00401 {
00402 calc_approx_bounding_sphere_aabb_center(
00403 pts, midp, r,
00404 x_scale_factor, y_scale_factor, z_scale_factor);
00405 }
00406
00407
00408
00409 inline bool extend_bounding_sphere(
00410 const std::vector<Eigen::Vector3f> &pts,
00411 Eigen::Vector3f &midp, float &r,
00412 float bail_out_thr) throw()
00413 {
00414 const float old_r = r;
00415
00416 for( std::size_t i = 0; i < pts.size(); ++i )
00417 {
00418 Eigen::Vector3f diff = pts[i] - midp;
00419 float sq_d = diff.squaredNorm();
00420
00421 if( sq_d > r*r+0.0000000001 )
00422 {
00423 float d = sqrtf(sq_d);
00424 r = (d + r)/2;
00425 midp += (d-r)/d * diff;
00426
00427 if( r > bail_out_thr*old_r )
00428 {
00429
00430 return true;
00431 }
00432 }
00433 }
00434
00435 return false;
00436 }
00437 }
00438 }
00439
00440
00441 #endif // PEEKABOT_GEOM_GEOMETRY_TOOLBOX_HH_INCLUDED