00001 #ifndef OPENTISSUE_COLLISION_COLLISION_BOX_BOX_H
00002 #define OPENTISSUE_COLLISION_COLLISION_BOX_BOX_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/math_coordsys.h>
00013 #include <OpenTissue/core/math/math_constants.h>
00014
00015 #include <OpenTissue/core/math/math_precision.h>
00016 #include <OpenTissue/core/geometry/geometry_compute_closest_points_line_line.h>
00017 #include <OpenTissue/collision/intersect/intersect_rect_quad.h>
00018
00019 namespace OpenTissue
00020 {
00021 namespace collision
00022 {
00023
00052 template<typename real_type,typename vector3_type,typename matrix3x3_type>
00053 unsigned int box_box(
00054 vector3_type p_a
00055 , matrix3x3_type R_a
00056 , vector3_type const & a
00057 , vector3_type p_b
00058 , matrix3x3_type R_b
00059 , vector3_type const & b
00060 , real_type const & envelope
00061 , vector3_type * p
00062 , vector3_type & n
00063 , real_type * distances
00064 )
00065 {
00066 using std::sqrt;
00067 using std::fabs;
00068 typedef CoordSys<real_type> coordsys_type;
00069 typedef typename coordsys_type::quaternion_type quaternion_type;
00070 assert(p);
00071 assert(distances);
00072
00073
00074
00075 quaternion_type Q_a = R_a;
00076 quaternion_type Q_b = R_b;
00077 coordsys_type BtoA = model_update(p_b,Q_b,p_a,Q_a);
00078
00079 vector3_type p_ba = BtoA.T();
00080 matrix3x3_type R_ba = BtoA.Q();
00081
00082
00083
00084 vector3_type i_ba,j_ba,k_ba;
00085 i_ba(0) = R_ba(0,0); i_ba(1) = R_ba(1,0); i_ba(2) = R_ba(2,0);
00086 j_ba(0) = R_ba(0,1); j_ba(1) = R_ba(1,1); j_ba(2) = R_ba(2,1);
00087 k_ba(0) = R_ba(0,2); k_ba(1) = R_ba(1,2); k_ba(2) = R_ba(2,2);
00088
00089 vector3_type A[3];
00090 A[0](0) = R_a(0,0); A[0](1) = R_a(1,0); A[0](2) = R_a(2,0);
00091 A[1](0) = R_a(0,1); A[1](1) = R_a(1,1); A[1](2) = R_a(2,1);
00092 A[2](0) = R_a(0,2); A[2](1) = R_a(1,2); A[2](2) = R_a(2,2);
00093
00094 vector3_type B[3];
00095 B[0](0) = R_b(0,0); B[0](1) = R_b(1,0); B[0](2) = R_b(2,0);
00096 B[1](0) = R_b(0,1); B[1](1) = R_b(1,1); B[1](2) = R_b(2,1);
00097 B[2](0) = R_b(0,2); B[2](1) = R_b(1,2); B[2](2) = R_b(2,2);
00098
00099
00100
00101
00102 real_type eps = boost::numeric_cast<real_type>(1e-15);
00103 real_type Q00 = fabs(R_ba(0,0))+eps;
00104 real_type Q01 = fabs(R_ba(0,1))+eps;
00105 real_type Q02 = fabs(R_ba(0,2))+eps;
00106 real_type Q10 = fabs(R_ba(1,0))+eps;
00107 real_type Q11 = fabs(R_ba(1,1))+eps;
00108 real_type Q12 = fabs(R_ba(1,2))+eps;
00109 real_type Q20 = fabs(R_ba(2,0))+eps;
00110 real_type Q21 = fabs(R_ba(2,1))+eps;
00111 real_type Q22 = fabs(R_ba(2,2))+eps;
00112
00113
00114
00115
00116 vector3_type normal;
00117
00118
00119
00120
00121 real_type separation = 0;
00122
00123
00124
00125 real_type distance = math::detail::lowest<real_type>();
00126
00127
00128
00129 bool flip_normal = false;
00130
00131
00132
00133
00134 unsigned int code = 0;
00135
00136
00137
00138
00139
00140 const real_type fudge_factor = real_type(1.05);
00141
00142
00143 real_type length = 0;
00144
00145
00146
00147 #define TST(expr1,expr2,norm,axis_code) \
00148 separation = fabs(expr1) - (expr2); \
00149 if (separation > 0) return 0; \
00150 if (separation > distance) { \
00151 distance = separation; \
00152 normal = norm; \
00153 flip_normal = ((expr1) < 0); \
00154 code = (axis_code); \
00155 }
00156 TST( p_ba(0), a(0) + b(0)*Q00 + b(1)*Q10 + b(2)*Q20, A[0], 1);
00157 TST( p_ba(1), a(1) + b(0)*Q01 + b(1)*Q11 + b(2)*Q21, A[1], 2);
00158 TST( p_ba(2), a(2) + b(0)*Q02 + b(1)*Q12 + b(2)*Q22, A[2], 3);
00159 TST( p_ba(0)*R_ba(0,0) + p_ba(1)*R_ba(1,0) + p_ba(2)*R_ba(2,0), b(0) + a(0)*Q00 + a(1)*Q10 + a(2)*Q20, B[0], 4);
00160 TST( p_ba(0)*R_ba(0,1) + p_ba(1)*R_ba(1,1) + p_ba(2)*R_ba(2,1), b(1) + a(0)*Q01 + a(1)*Q11 + a(2)*Q21, B[1], 5);
00161 TST( p_ba(0)*R_ba(0,2) + p_ba(1)*R_ba(1,2) + p_ba(2)*R_ba(2,2), b(2) + a(0)*Q02 + a(1)*Q12 + a(2)*Q22, B[2], 6);
00162 #undef TST
00163
00164
00165
00166 #define TST(expr1,expr2,nx,ny,nz,axis_code) \
00167 separation = fabs(expr1) - (expr2); \
00168 if (separation > 0) return 0; \
00169 length = sqrt ((nx)*(nx) + (ny)*(ny) + (nz)*(nz)); \
00170 if (length > 0) { \
00171 separation /= length; \
00172 if (separation*fudge_factor > distance) { \
00173 distance = separation; \
00174 normal(0) = (nx)/length; normal(1) = (ny)/length; normal(2) = (nz)/length; \
00175 flip_normal = ((expr1) < 0); \
00176 code = (axis_code); \
00177 } \
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190 real_type zero = real_type(0);
00191 TST( p_ba(2)*R_ba(1,0) - p_ba(1)*R_ba(2,0), a(1)*Q20 + a(2)*Q10 + b(1)*Q02 + b(2)*Q01, zero, -i_ba(2), i_ba(1), 7);
00192 TST( p_ba(2)*R_ba(1,1) - p_ba(1)*R_ba(2,1), a(1)*Q21 + a(2)*Q11 + b(2)*Q00 + b(0)*Q02, zero, -j_ba(2), j_ba(1), 8);
00193 TST( p_ba(2)*R_ba(1,2) - p_ba(1)*R_ba(2,2), a(1)*Q22 + a(2)*Q12 + b(0)*Q01 + b(1)*Q00, zero, -k_ba(2), k_ba(1), 9);
00194 TST( p_ba(0)*R_ba(2,0) - p_ba(2)*R_ba(0,0), a(2)*Q00 + a(0)*Q20 + b(1)*Q12 + b(2)*Q11, i_ba(2), zero, -i_ba(0), 10);
00195 TST( p_ba(0)*R_ba(2,1) - p_ba(2)*R_ba(0,1), a(2)*Q01 + a(0)*Q21 + b(2)*Q10 + b(0)*Q12, j_ba(2), zero, -j_ba(0), 11);
00196 TST( p_ba(0)*R_ba(2,2) - p_ba(2)*R_ba(0,2), a(2)*Q02 + a(0)*Q22 + b(0)*Q11 + b(1)*Q10, k_ba(2), zero, -k_ba(0), 12);
00197 TST( p_ba(1)*R_ba(0,0) - p_ba(0)*R_ba(1,0), a(0)*Q10 + a(1)*Q00 + b(1)*Q22 + b(2)*Q21, -i_ba(1), i_ba(0), zero, 13);
00198 TST( p_ba(1)*R_ba(0,1) - p_ba(0)*R_ba(1,1), a(0)*Q11 + a(1)*Q01 + b(2)*Q20 + b(0)*Q22, -j_ba(1), j_ba(0), zero, 14);
00199 TST( p_ba(1)*R_ba(0,2) - p_ba(0)*R_ba(1,2), a(0)*Q12 + a(1)*Q02 + b(0)*Q21 + b(1)*Q20, -k_ba(1), k_ba(0), zero, 15);
00200 #undef TST
00201
00202 if (!code)
00203 return 0;
00204
00205 if(flip_normal)
00206 normal = - normal;
00207
00208
00209 if(code>6)
00210 {
00211
00212 n = R_a * normal;
00213
00214
00215 for(int i=0;i<3;++i)
00216 if(n*A[i] > 0) p_a += a(i)*A[i]; else p_a -= a(i)*A[i];
00217
00218 for(int i=0;i<3;++i)
00219 if(n*B[i] < 0) p_b += b(i)*B[i]; else p_b -= b(i)*B[i];
00220
00221 int columnA = ((code)-7)/3;
00222 int columnB = ((code)-7)%3;
00223
00224
00225
00226
00227 real_type s,t;
00228 OpenTissue::geometry::compute_closest_points_line_line(p_a, A[columnA], p_b, B[columnB], s, t);
00229
00230
00231 p_a += A[columnA]*s;
00232 p_b += B[columnB]*t;
00233
00234 p[0] = (p_a + p_b)*.5;
00235 distances[0] = distance;
00236 return 1;
00237 }
00238 n = normal;
00239
00240
00241
00242
00243
00244
00245
00246 vector3_type * R_r,* R_i;
00247 vector3_type ext_r,ext_i;
00248 vector3_type p_r,p_i;
00249
00250 if (code <= 3)
00251 {
00252
00253 R_r = A;
00254 R_i = B;
00255 p_r = p_a;
00256 p_i = p_b;
00257 ext_r = a;
00258 ext_i = b;
00259 }
00260 else
00261 {
00262
00263 R_r = B;
00264 R_i = A;
00265 p_r = p_b;
00266 p_i = p_a;
00267 ext_r = b;
00268 ext_i = a;
00269 }
00270
00271
00272
00273
00274
00275
00276
00277 vector3_type n_r_wcs,n_r,abs_n_r;
00278 if (code <= 3)
00279 {
00280 n_r_wcs = normal;
00281
00282 }
00283 else
00284 {
00285 n_r_wcs = -normal;
00286 }
00287
00288
00289
00290
00291
00292 n_r(0) = R_i[0] * n_r_wcs;
00293 n_r(1) = R_i[1] * n_r_wcs;
00294 n_r(2) = R_i[2] * n_r_wcs;
00295
00296 abs_n_r = fabs (n_r);
00297
00298
00299
00300 int a1,a2,a3;
00301 if (abs_n_r(1) > abs_n_r(0))
00302 {
00303 if (abs_n_r(1) > abs_n_r(2))
00304 {
00305 a1 = 2;
00306 a2 = 0;
00307 a3 = 1;
00308 }
00309 else
00310 {
00311 a1 = 0;
00312 a2 = 1;
00313 a3 = 2;
00314 }
00315 }
00316 else
00317 {
00318 if (abs_n_r(0) > abs_n_r(2))
00319 {
00320 a1 = 1;
00321 a2 = 2;
00322 a3 = 0;
00323 }
00324 else
00325 {
00326 a1 = 0;
00327 a2 = 1;
00328 a3 = 2;
00329 }
00330 }
00331
00332
00333 vector3_type center_i_wcs;
00334 if (n_r(a3) < 0)
00335 {
00336 center_i_wcs = p_i + ext_i(a3) * R_i[a3];
00337 }
00338 else
00339 {
00340 center_i_wcs = p_i - ext_i(a3) * R_i[a3];
00341 }
00342
00343 vector3_type center_ir = center_i_wcs - p_r;
00344
00345 int code1,code2,code3;
00346 if (code <= 3)
00347 code3 = code-1;
00348 else
00349 code3 = code-4;
00350 if (code3==0)
00351 {
00352 code1 = 1;
00353 code2 = 2;
00354 }
00355 else if (code3==1)
00356 {
00357 code1 = 2;
00358 code2 = 0;
00359 }
00360 else
00361 {
00362 code1 = 0;
00363 code2 = 1;
00364 }
00365
00366
00367 real_type quad[8];
00368
00369
00370
00371 real_type c1 = R_r[code1] * center_ir;
00372 real_type c2 = R_r[code2] * center_ir;
00373
00374
00375
00376
00377
00378
00379 real_type m11 = R_r[code1] * R_i[a1];
00380 real_type m12 = R_r[code1] * R_i[a2];
00381 real_type m21 = R_r[code2] * R_i[a1];
00382 real_type m22 = R_r[code2] * R_i[a2];
00383 {
00384 real_type k1 = m11 * ext_i(a1);
00385 real_type k2 = m21 * ext_i(a1);
00386 real_type k3 = m12 * ext_i(a2);
00387 real_type k4 = m22 * ext_i(a2);
00388 quad[0] = c1 - k1 - k3;
00389 quad[1] = c2 - k2 - k4;
00390 quad[2] = c1 - k1 + k3;
00391 quad[3] = c2 - k2 + k4;
00392 quad[4] = c1 + k1 + k3;
00393 quad[5] = c2 + k2 + k4;
00394 quad[6] = c1 + k1 - k3;
00395 quad[7] = c2 + k2 - k4;
00396 }
00397
00398 real_type rect[2];
00399 rect[0] = ext_r(code1);
00400 rect[1] = ext_r(code2);
00401
00402 real_type ret[16];
00403 int detected = OpenTissue::intersect::rect_quad(rect,quad,ret);
00404 if(detected<1)
00405 return 0;
00406 assert(detected<=8);
00407
00408
00409 real_type det1 = real_type(1.)/(m11*m22 - m12*m21);
00410 m11 *= det1;
00411 m12 *= det1;
00412 m21 *= det1;
00413 m22 *= det1;
00414 int cnt = 0;
00415 for (int j=0; j < detected; ++j)
00416 {
00417 real_type k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2);
00418 real_type k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2);
00419
00420 vector3_type point = center_ir + k1*R_i[a1] + k2*R_i[a2];
00421
00422 real_type depth = n_r_wcs*point - ext_r(code3);
00423 if(depth<envelope)
00424 {
00425 p[cnt] = point + p_r;
00426 distances[cnt] = depth;
00427 ++cnt;
00428 }
00429 }
00430 return cnt;
00431 }
00432
00433 }
00434
00435 }
00436
00437
00438 #endif