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
00037 #include "fcl/BVH/BV_fitter.h"
00038 #include "fcl/BVH/BVH_utility.h"
00039 #include <limits>
00040
00041 namespace fcl
00042 {
00043
00044
00045 static const double kIOS_RATIO = 1.5;
00046 static const double invSinA = 2;
00047 static const double invCosA = 2.0 / sqrt(3.0);
00048 static const double sinA = 0.5;
00049 static const double cosA = sqrt(3.0) / 2.0;
00050
00051 static inline void axisFromEigen(Vec3f eigenV[3], Matrix3f::U eigenS[3], Vec3f axis[3])
00052 {
00053 int min, mid, max;
00054 if(eigenS[0] > eigenS[1]) { max = 0; min = 1; }
00055 else { min = 0; max = 1; }
00056 if(eigenS[2] < eigenS[min]) { mid = min; min = 2; }
00057 else if(eigenS[2] > eigenS[max]) { mid = max; max = 2; }
00058 else { mid = 2; }
00059
00060 axis[0].setValue(eigenV[0][max], eigenV[1][max], eigenV[2][max]);
00061 axis[1].setValue(eigenV[0][mid], eigenV[1][mid], eigenV[2][mid]);
00062 axis[2].setValue(eigenV[1][max]*eigenV[2][mid] - eigenV[1][mid]*eigenV[2][max],
00063 eigenV[0][mid]*eigenV[2][max] - eigenV[0][max]*eigenV[2][mid],
00064 eigenV[0][max]*eigenV[1][mid] - eigenV[0][mid]*eigenV[1][max]);
00065 }
00066
00067 namespace OBB_fit_functions
00068 {
00069
00070 void fit1(Vec3f* ps, OBB& bv)
00071 {
00072 bv.To = ps[0];
00073 bv.axis[0].setValue(1, 0, 0);
00074 bv.axis[1].setValue(0, 1, 0);
00075 bv.axis[2].setValue(0, 0, 1);
00076 bv.extent.setValue(0);
00077 }
00078
00079 void fit2(Vec3f* ps, OBB& bv)
00080 {
00081 const Vec3f& p1 = ps[0];
00082 const Vec3f& p2 = ps[1];
00083 Vec3f p1p2 = p1 - p2;
00084 FCL_REAL len_p1p2 = p1p2.length();
00085 p1p2.normalize();
00086
00087 bv.axis[0] = p1p2;
00088 generateCoordinateSystem(bv.axis[0], bv.axis[1], bv.axis[2]);
00089
00090 bv.extent.setValue(len_p1p2 * 0.5, 0, 0);
00091 bv.To.setValue(0.5 * (p1[0] + p2[0]),
00092 0.5 * (p1[1] + p2[1]),
00093 0.5 * (p1[2] + p2[2]));
00094 }
00095
00096 void fit3(Vec3f* ps, OBB& bv)
00097 {
00098 const Vec3f& p1 = ps[0];
00099 const Vec3f& p2 = ps[1];
00100 const Vec3f& p3 = ps[2];
00101 Vec3f e[3];
00102 e[0] = p1 - p2;
00103 e[1] = p2 - p3;
00104 e[2] = p3 - p1;
00105 FCL_REAL len[3];
00106 len[0] = e[0].sqrLength();
00107 len[1] = e[1].sqrLength();
00108 len[2] = e[2].sqrLength();
00109
00110 int imax = 0;
00111 if(len[1] > len[0]) imax = 1;
00112 if(len[2] > len[imax]) imax = 2;
00113
00114 Vec3f& u = bv.axis[0];
00115 Vec3f& v = bv.axis[1];
00116 Vec3f& w = bv.axis[2];
00117
00118 w = e[0].cross(e[1]);
00119 w.normalize();
00120 u = e[imax];
00121 u.normalize();
00122 v = w.cross(u);
00123
00124 getExtentAndCenter(ps, NULL, NULL, NULL, 3, bv.axis, bv.To, bv.extent);
00125 }
00126
00127 void fit6(Vec3f* ps, OBB& bv)
00128 {
00129 OBB bv1, bv2;
00130 fit3(ps, bv1);
00131 fit3(ps + 3, bv2);
00132 bv = bv1 + bv2;
00133 }
00134
00135
00136 void fitn(Vec3f* ps, int n, OBB& bv)
00137 {
00138 Matrix3f M;
00139 Vec3f E[3];
00140 Matrix3f::U s[3] = {0, 0, 0};
00141
00142 getCovariance(ps, NULL, NULL, NULL, n, M);
00143 eigen(M, s, E);
00144 axisFromEigen(E, s, bv.axis);
00145
00146
00147 getExtentAndCenter(ps, NULL, NULL, NULL, n, bv.axis, bv.To, bv.extent);
00148 }
00149
00150 }
00151
00152
00153 namespace RSS_fit_functions
00154 {
00155 void fit1(Vec3f* ps, RSS& bv)
00156 {
00157 bv.Tr = ps[0];
00158 bv.axis[0].setValue(1, 0, 0);
00159 bv.axis[1].setValue(0, 1, 0);
00160 bv.axis[2].setValue(0, 0, 1);
00161 bv.l[0] = 0;
00162 bv.l[1] = 0;
00163 bv.r = 0;
00164 }
00165
00166 void fit2(Vec3f* ps, RSS& bv)
00167 {
00168 const Vec3f& p1 = ps[0];
00169 const Vec3f& p2 = ps[1];
00170 Vec3f p1p2 = p1 - p2;
00171 FCL_REAL len_p1p2 = p1p2.length();
00172 p1p2.normalize();
00173
00174 bv.axis[0] = p1p2;
00175 generateCoordinateSystem(bv.axis[0], bv.axis[1], bv.axis[2]);
00176 bv.l[0] = len_p1p2;
00177 bv.l[1] = 0;
00178
00179 bv.Tr = p2;
00180 bv.r = 0;
00181 }
00182
00183 void fit3(Vec3f* ps, RSS& bv)
00184 {
00185 const Vec3f& p1 = ps[0];
00186 const Vec3f& p2 = ps[1];
00187 const Vec3f& p3 = ps[2];
00188 Vec3f e[3];
00189 e[0] = p1 - p2;
00190 e[1] = p2 - p3;
00191 e[2] = p3 - p1;
00192 FCL_REAL len[3];
00193 len[0] = e[0].sqrLength();
00194 len[1] = e[1].sqrLength();
00195 len[2] = e[2].sqrLength();
00196
00197 int imax = 0;
00198 if(len[1] > len[0]) imax = 1;
00199 if(len[2] > len[imax]) imax = 2;
00200
00201 Vec3f& u = bv.axis[0];
00202 Vec3f& v = bv.axis[1];
00203 Vec3f& w = bv.axis[2];
00204
00205 w = e[0].cross(e[1]);
00206 w.normalize();
00207 u = e[imax];
00208 u.normalize();
00209 v = w.cross(u);
00210
00211 getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, 3, bv.axis, bv.Tr, bv.l, bv.r);
00212 }
00213
00214 void fit6(Vec3f* ps, RSS& bv)
00215 {
00216 RSS bv1, bv2;
00217 fit3(ps, bv1);
00218 fit3(ps + 3, bv2);
00219 bv = bv1 + bv2;
00220 }
00221
00222 void fitn(Vec3f* ps, int n, RSS& bv)
00223 {
00224 Matrix3f M;
00225 Vec3f E[3];
00226 Matrix3f::U s[3] = {0, 0, 0};
00227
00228 getCovariance(ps, NULL, NULL, NULL, n, M);
00229 eigen(M, s, E);
00230 axisFromEigen(E, s, bv.axis);
00231
00232
00233 getRadiusAndOriginAndRectangleSize(ps, NULL, NULL, NULL, n, bv.axis, bv.Tr, bv.l, bv.r);
00234 }
00235
00236 }
00237
00238 namespace kIOS_fit_functions
00239 {
00240
00241 void fit1(Vec3f* ps, kIOS& bv)
00242 {
00243 bv.num_spheres = 1;
00244 bv.spheres[0].o = ps[0];
00245 bv.spheres[0].r = 0;
00246
00247 bv.obb.axis[0].setValue(1, 0, 0);
00248 bv.obb.axis[1].setValue(0, 1, 0);
00249 bv.obb.axis[2].setValue(0, 0, 1);
00250 bv.obb.extent.setValue(0);
00251 bv.obb.To = ps[0];
00252 }
00253
00254 void fit2(Vec3f* ps, kIOS& bv)
00255 {
00256 bv.num_spheres = 5;
00257
00258 const Vec3f& p1 = ps[0];
00259 const Vec3f& p2 = ps[1];
00260 Vec3f p1p2 = p1 - p2;
00261 FCL_REAL len_p1p2 = p1p2.length();
00262 p1p2.normalize();
00263
00264 Vec3f* axis = bv.obb.axis;
00265 axis[0] = p1p2;
00266 generateCoordinateSystem(axis[0], axis[1], axis[2]);
00267
00268 FCL_REAL r0 = len_p1p2 * 0.5;
00269 bv.obb.extent.setValue(r0, 0, 0);
00270 bv.obb.To = (p1 + p2) * 0.5;
00271
00272 bv.spheres[0].o = bv.obb.To;
00273 bv.spheres[0].r = r0;
00274
00275 FCL_REAL r1 = r0 * invSinA;
00276 FCL_REAL r1cosA = r1 * cosA;
00277 bv.spheres[1].r = r1;
00278 bv.spheres[2].r = r1;
00279 Vec3f delta = axis[1] * r1cosA;
00280 bv.spheres[1].o = bv.spheres[0].o - delta;
00281 bv.spheres[2].o = bv.spheres[0].o + delta;
00282
00283 bv.spheres[3].r = r1;
00284 bv.spheres[4].r = r1;
00285 delta = axis[2] * r1cosA;
00286 bv.spheres[3].o = bv.spheres[0].o - delta;
00287 bv.spheres[4].o = bv.spheres[0].o + delta;
00288 }
00289
00290 void fit3(Vec3f* ps, kIOS& bv)
00291 {
00292 bv.num_spheres = 3;
00293
00294 const Vec3f& p1 = ps[0];
00295 const Vec3f& p2 = ps[1];
00296 const Vec3f& p3 = ps[2];
00297 Vec3f e[3];
00298 e[0] = p1 - p2;
00299 e[1] = p2 - p3;
00300 e[2] = p3 - p1;
00301 FCL_REAL len[3];
00302 len[0] = e[0].sqrLength();
00303 len[1] = e[1].sqrLength();
00304 len[2] = e[2].sqrLength();
00305
00306 int imax = 0;
00307 if(len[1] > len[0]) imax = 1;
00308 if(len[2] > len[imax]) imax = 2;
00309
00310 Vec3f& u = bv.obb.axis[0];
00311 Vec3f& v = bv.obb.axis[1];
00312 Vec3f& w = bv.obb.axis[2];
00313
00314 w = e[0].cross(e[1]);
00315 w.normalize();
00316 u = e[imax];
00317 u.normalize();
00318 v = w.cross(u);
00319
00320 getExtentAndCenter(ps, NULL, NULL, NULL, 3, bv.obb.axis, bv.obb.To, bv.obb.extent);
00321
00322
00323 FCL_REAL r0;
00324 Vec3f center;
00325 circumCircleComputation(p1, p2, p3, center, r0);
00326
00327 bv.spheres[0].o = center;
00328 bv.spheres[0].r = r0;
00329
00330 FCL_REAL r1 = r0 * invSinA;
00331 Vec3f delta = bv.obb.axis[2] * (r1 * cosA);
00332
00333 bv.spheres[1].r = r1;
00334 bv.spheres[1].o = center - delta;
00335 bv.spheres[2].r = r1;
00336 bv.spheres[2].o = center + delta;
00337 }
00338
00339 void fitn(Vec3f* ps, int n, kIOS& bv)
00340 {
00341 Matrix3f M;
00342 Vec3f E[3];
00343 Matrix3f::U s[3] = {0, 0, 0};
00344
00345 getCovariance(ps, NULL, NULL, NULL, n, M);
00346 eigen(M, s, E);
00347
00348 Vec3f* axis = bv.obb.axis;
00349 axisFromEigen(E, s, axis);
00350
00351 getExtentAndCenter(ps, NULL, NULL, NULL, n, axis, bv.obb.To, bv.obb.extent);
00352
00353
00354 const Vec3f& center = bv.obb.To;
00355 const Vec3f& extent = bv.obb.extent;
00356 FCL_REAL r0 = maximumDistance(ps, NULL, NULL, NULL, n, center);
00357
00358
00359 if(extent[0] > kIOS_RATIO * extent[2])
00360 {
00361 if(extent[0] > kIOS_RATIO * extent[1]) bv.num_spheres = 5;
00362 else bv.num_spheres = 3;
00363 }
00364 else bv.num_spheres = 1;
00365
00366
00367 bv.spheres[0].o = center;
00368 bv.spheres[0].r = r0;
00369
00370 if(bv.num_spheres >= 3)
00371 {
00372 FCL_REAL r10 = sqrt(r0 * r0 - extent[2] * extent[2]) * invSinA;
00373 Vec3f delta = axis[2] * (r10 * cosA - extent[2]);
00374 bv.spheres[1].o = center - delta;
00375 bv.spheres[2].o = center + delta;
00376
00377 FCL_REAL r11 = 0, r12 = 0;
00378 r11 = maximumDistance(ps, NULL, NULL, NULL, n, bv.spheres[1].o);
00379 r12 = maximumDistance(ps, NULL, NULL, NULL, n, bv.spheres[2].o);
00380 bv.spheres[1].o += axis[2] * (-r10 + r11);
00381 bv.spheres[2].o += axis[2] * (r10 - r12);
00382
00383 bv.spheres[1].r = r10;
00384 bv.spheres[2].r = r10;
00385 }
00386
00387 if(bv.num_spheres >= 5)
00388 {
00389 FCL_REAL r10 = bv.spheres[1].r;
00390 Vec3f delta = axis[1] * (sqrt(r10 * r10 - extent[0] * extent[0] - extent[2] * extent[2]) - extent[1]);
00391 bv.spheres[3].o = bv.spheres[0].o - delta;
00392 bv.spheres[4].o = bv.spheres[0].o + delta;
00393
00394 FCL_REAL r21 = 0, r22 = 0;
00395 r21 = maximumDistance(ps, NULL, NULL, NULL, n, bv.spheres[3].o);
00396 r22 = maximumDistance(ps, NULL, NULL, NULL, n, bv.spheres[4].o);
00397
00398 bv.spheres[3].o += axis[1] * (-r10 + r21);
00399 bv.spheres[4].o += axis[1] * (r10 - r22);
00400
00401 bv.spheres[3].r = r10;
00402 bv.spheres[4].r = r10;
00403 }
00404 }
00405
00406 }
00407
00408 namespace OBBRSS_fit_functions
00409 {
00410 void fit1(Vec3f* ps, OBBRSS& bv)
00411 {
00412 OBB_fit_functions::fit1(ps, bv.obb);
00413 RSS_fit_functions::fit1(ps, bv.rss);
00414 }
00415
00416 void fit2(Vec3f* ps, OBBRSS& bv)
00417 {
00418 OBB_fit_functions::fit2(ps, bv.obb);
00419 RSS_fit_functions::fit2(ps, bv.rss);
00420 }
00421
00422 void fit3(Vec3f* ps, OBBRSS& bv)
00423 {
00424 OBB_fit_functions::fit3(ps, bv.obb);
00425 RSS_fit_functions::fit3(ps, bv.rss);
00426 }
00427
00428 void fitn(Vec3f* ps, int n, OBBRSS& bv)
00429 {
00430 OBB_fit_functions::fitn(ps, n, bv.obb);
00431 RSS_fit_functions::fitn(ps, n, bv.rss);
00432 }
00433
00434 }
00435
00436
00437
00438 template<>
00439 void fit(Vec3f* ps, int n, OBB& bv)
00440 {
00441 switch(n)
00442 {
00443 case 1:
00444 OBB_fit_functions::fit1(ps, bv);
00445 break;
00446 case 2:
00447 OBB_fit_functions::fit2(ps, bv);
00448 break;
00449 case 3:
00450 OBB_fit_functions::fit3(ps, bv);
00451 break;
00452 case 6:
00453 OBB_fit_functions::fit6(ps, bv);
00454 break;
00455 default:
00456 OBB_fit_functions::fitn(ps, n, bv);
00457 }
00458 }
00459
00460
00461 template<>
00462 void fit(Vec3f* ps, int n, RSS& bv)
00463 {
00464 switch(n)
00465 {
00466 case 1:
00467 RSS_fit_functions::fit1(ps, bv);
00468 break;
00469 case 2:
00470 RSS_fit_functions::fit2(ps, bv);
00471 break;
00472 case 3:
00473 RSS_fit_functions::fit3(ps, bv);
00474 break;
00475 default:
00476 RSS_fit_functions::fitn(ps, n, bv);
00477 }
00478 }
00479
00480 template<>
00481 void fit(Vec3f* ps, int n, kIOS& bv)
00482 {
00483 switch(n)
00484 {
00485 case 1:
00486 kIOS_fit_functions::fit1(ps, bv);
00487 break;
00488 case 2:
00489 kIOS_fit_functions::fit2(ps, bv);
00490 break;
00491 case 3:
00492 kIOS_fit_functions::fit3(ps, bv);
00493 break;
00494 default:
00495 kIOS_fit_functions::fitn(ps, n, bv);
00496 }
00497 }
00498
00499 template<>
00500 void fit(Vec3f* ps, int n, OBBRSS& bv)
00501 {
00502 switch(n)
00503 {
00504 case 1:
00505 OBBRSS_fit_functions::fit1(ps, bv);
00506 break;
00507 case 2:
00508 OBBRSS_fit_functions::fit2(ps, bv);
00509 break;
00510 case 3:
00511 OBBRSS_fit_functions::fit3(ps, bv);
00512 break;
00513 default:
00514 OBBRSS_fit_functions::fitn(ps, n, bv);
00515 }
00516 }
00517
00518
00519 OBB BVFitter<OBB>::fit(unsigned int* primitive_indices, int num_primitives)
00520 {
00521 OBB bv;
00522
00523 Matrix3f M;
00524 Vec3f E[3];
00525 Matrix3f::U s[3];
00526
00527 getCovariance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, M);
00528 eigen(M, s, E);
00529
00530 axisFromEigen(E, s, bv.axis);
00531
00532
00533 getExtentAndCenter(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.axis, bv.To, bv.extent);
00534
00535 return bv;
00536 }
00537
00538 OBBRSS BVFitter<OBBRSS>::fit(unsigned int* primitive_indices, int num_primitives)
00539 {
00540 OBBRSS bv;
00541 Matrix3f M;
00542 Vec3f E[3];
00543 Matrix3f::U s[3];
00544
00545 getCovariance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, M);
00546 eigen(M, s, E);
00547
00548 axisFromEigen(E, s, bv.obb.axis);
00549 bv.rss.axis[0] = bv.obb.axis[0];
00550 bv.rss.axis[1] = bv.obb.axis[1];
00551 bv.rss.axis[2] = bv.obb.axis[2];
00552
00553 getExtentAndCenter(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.obb.axis, bv.obb.To, bv.obb.extent);
00554
00555 Vec3f origin;
00556 FCL_REAL l[2];
00557 FCL_REAL r;
00558 getRadiusAndOriginAndRectangleSize(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.rss.axis, origin, l, r);
00559
00560 bv.rss.Tr = origin;
00561 bv.rss.l[0] = l[0];
00562 bv.rss.l[1] = l[1];
00563 bv.rss.r = r;
00564
00565 return bv;
00566 }
00567
00568 RSS BVFitter<RSS>::fit(unsigned int* primitive_indices, int num_primitives)
00569 {
00570 RSS bv;
00571
00572 Matrix3f M;
00573 Vec3f E[3];
00574 Matrix3f::U s[3];
00575 getCovariance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, M);
00576 eigen(M, s, E);
00577 axisFromEigen(E, s, bv.axis);
00578
00579
00580
00581 Vec3f origin;
00582 FCL_REAL l[2];
00583 FCL_REAL r;
00584 getRadiusAndOriginAndRectangleSize(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.axis, origin, l, r);
00585
00586 bv.Tr = origin;
00587 bv.l[0] = l[0];
00588 bv.l[1] = l[1];
00589 bv.r = r;
00590
00591
00592 return bv;
00593 }
00594
00595
00596 kIOS BVFitter<kIOS>::fit(unsigned int* primitive_indices, int num_primitives)
00597 {
00598 kIOS bv;
00599
00600 Matrix3f M;
00601 Vec3f E[3];
00602 Matrix3f::U s[3];
00603
00604 getCovariance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, M);
00605 eigen(M, s, E);
00606
00607 Vec3f* axis = bv.obb.axis;
00608 axisFromEigen(E, s, axis);
00609
00610
00611 getExtentAndCenter(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, axis, bv.obb.To, bv.obb.extent);
00612
00613 const Vec3f& center = bv.obb.To;
00614 const Vec3f& extent = bv.obb.extent;
00615 FCL_REAL r0 = maximumDistance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, center);
00616
00617
00618 if(extent[0] > kIOS_RATIO * extent[2])
00619 {
00620 if(extent[0] > kIOS_RATIO * extent[1]) bv.num_spheres = 5;
00621 else bv.num_spheres = 3;
00622 }
00623 else bv.num_spheres = 1;
00624
00625 bv.spheres[0].o = center;
00626 bv.spheres[0].r = r0;
00627
00628 if(bv.num_spheres >= 3)
00629 {
00630 FCL_REAL r10 = sqrt(r0 * r0 - extent[2] * extent[2]) * invSinA;
00631 Vec3f delta = axis[2] * (r10 * cosA - extent[2]);
00632 bv.spheres[1].o = center - delta;
00633 bv.spheres[2].o = center + delta;
00634
00635 FCL_REAL r11 = maximumDistance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.spheres[1].o);
00636 FCL_REAL r12 = maximumDistance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.spheres[2].o);
00637
00638 bv.spheres[1].o += axis[2] * (-r10 + r11);
00639 bv.spheres[2].o += axis[2] * (r10 - r12);
00640
00641 bv.spheres[1].r = r10;
00642 bv.spheres[2].r = r10;
00643 }
00644
00645 if(bv.num_spheres >= 5)
00646 {
00647 FCL_REAL r10 = bv.spheres[1].r;
00648 Vec3f delta = axis[1] * (sqrt(r10 * r10 - extent[0] * extent[0] - extent[2] * extent[2]) - extent[1]);
00649 bv.spheres[3].o = bv.spheres[0].o - delta;
00650 bv.spheres[4].o = bv.spheres[0].o + delta;
00651
00652 FCL_REAL r21 = 0, r22 = 0;
00653 r21 = maximumDistance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.spheres[3].o);
00654 r22 = maximumDistance(vertices, prev_vertices, tri_indices, primitive_indices, num_primitives, bv.spheres[4].o);
00655
00656 bv.spheres[3].o += axis[1] * (-r10 + r21);
00657 bv.spheres[4].o += axis[1] * (r10 - r22);
00658
00659 bv.spheres[3].r = r10;
00660 bv.spheres[4].r = r10;
00661 }
00662
00663 return bv;
00664 }
00665
00666
00667 }