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 #ifndef SOFA_COMPONENT_COLLISION_DISCRETEINTERSECTION_INL
00026 #define SOFA_COMPONENT_COLLISION_DISCRETEINTERSECTION_INL
00027 #include <sofa/helper/system/config.h>
00028 #include <sofa/component/collision/DiscreteIntersection.h>
00029 #include <sofa/core/ObjectFactory.h>
00030 #include <sofa/core/componentmodel/collision/Intersection.inl>
00031
00032 #include <sofa/component/collision/proximity.h>
00033 #include <iostream>
00034 #include <algorithm>
00035
00036
00037 namespace sofa
00038 {
00039
00040 namespace component
00041 {
00042
00043 namespace collision
00044 {
00045
00046 using namespace sofa::defaulttype;
00047 using namespace sofa::core::componentmodel::collision;
00048
00049 template<class Sphere>
00050 bool DiscreteIntersection::testIntersection(Sphere& sph1, Sphere& sph2)
00051 {
00052
00053 typename Sphere::Coord sph1Pos(sph1.center());
00054 typename Sphere::Coord sph2Pos(sph2.center());
00055 typename Sphere::Real radius1 = sph1.r(), radius2 = sph2.r();
00056 typename Sphere::Coord tmp = sph1Pos - sph2Pos;
00057 return (tmp.norm2() < (radius1 + radius2) * (radius1 + radius2));
00058 }
00059
00060 template<class Sphere>
00061 bool DiscreteIntersection::testIntersection( Sphere& sph1, Cube& cube)
00062 {
00063
00064 Vector3 Bmin = cube.minVect();
00065 Vector3 Bmax = cube.maxVect();
00066
00067 Vector3 ctr(sph1.center());
00068
00069 double r2 = sph1.r()*sph1.r();
00070
00071 double dmin = 0;
00072
00073 for ( int i = 0; i<3; i++)
00074 {
00075 if ( ctr[i] < Bmin[i] ) dmin += (ctr[i]-Bmin[i])*(ctr[i]-Bmin[i]);
00076 else if ( ctr[i] > Bmax[i] ) dmin += (ctr[i]-Bmax[i])*(ctr[i]-Bmax[i]);
00077 }
00078
00079 return (dmin <= r2 );
00080 }
00081
00082 template<class Sphere>
00083 bool DiscreteIntersection::testIntersection( Sphere& sph, Triangle& triangle)
00084 {
00085 double EPSILON = 0.00001;
00086
00087 Vector3 p0 = triangle.p1();
00088 Vector3 p1 = triangle.p2();
00089 Vector3 p2 = triangle.p3();
00090
00091
00092 const Vector3 sphCenter(sph.center());
00093
00094 const double r = sph.r();
00095
00096
00097 Vector3 normal = cross( (p1 - p0), (p2 - p0) );
00098 normal.normalize();
00099
00100
00101 double distance = sphCenter*normal - normal*p0;
00102
00103
00104 Vector3 projPoint = sphCenter - normal*distance;
00105
00106
00107 if (distance < 0.0)
00108 distance = -distance;
00109
00110
00111 distance -= r;
00112
00113
00114
00115
00116 if (distance > EPSILON)
00117 {
00118 return false;
00119 }
00120
00121
00122
00123
00124 #define SAMESIDE(ap1,ap2,ap3,ap4) (((cross((ap4-ap3),(ap1-ap3))) * (cross((ap4-ap3),(ap2-ap3)))) >= 0)
00125 if ( (SAMESIDE(projPoint,p0,p1,p2) && SAMESIDE(projPoint,p1,p0,p2) && SAMESIDE(projPoint,p2,p0,p1)))
00126 {
00127 return true;
00128 }
00129 #undef SAMESIDE
00130 return false;
00131 }
00132
00133 template<class Sphere>
00134 bool DiscreteIntersection::testIntersection(Ray& ray1, Sphere& sph2)
00135 {
00136
00137
00138 const Vector3 sph2Pos(sph2.center());
00139
00140 const double radius1 = sph2.r();
00141
00142 const Vector3 ray1Origin(ray1.origin());
00143 const Vector3 ray1Direction(ray1.direction());
00144 const double length2 = ray1.l();
00145 const Vector3 tmp = sph2Pos - ray1Origin;
00146 const double rayPos = tmp*ray1Direction;
00147 const double rayPosInside = std::max(std::min(rayPos,length2),0.0);
00148 const double dist2 = tmp.norm2() - (rayPosInside*rayPosInside);
00149 return (dist2 < (radius1*radius1));
00150 }
00151
00152 template<class Sphere>
00153 int DiscreteIntersection::computeIntersection( Sphere& sph, Triangle& triangle, OutputVector* contacts)
00154 {
00155 double EPSILON = 0.00001;
00156
00157 Vector3 p0 = triangle.p1();
00158 Vector3 p1 = triangle.p2();
00159 Vector3 p2 = triangle.p3();
00160
00161
00162 const Vector3 sphCenter(sph.center());
00163
00164 const double r = sph.r();
00165
00166
00167 Vector3 normal = cross( (p1 - p0), (p2 - p0) );
00168 normal.normalize();
00169
00170
00171 double distance = sphCenter*normal - normal*p0;
00172
00173
00174 Vector3 projPoint = sphCenter - normal*distance;
00175
00176
00177 if (distance < 0.0)
00178 distance = -distance;
00179
00180
00181 distance -= r;
00182
00183
00184
00185
00186 if (distance > EPSILON)
00187 {
00188 return 0;
00189 }
00190
00191
00192
00193
00194 #define SAMESIDE(ap1,ap2,ap3,ap4) (((cross((ap4-ap3),(ap1-ap3))) * (cross((ap4-ap3),(ap2-ap3)))) >= 0)
00195 if ( (SAMESIDE(projPoint,p0,p1,p2) && SAMESIDE(projPoint,p1,p0,p2) && SAMESIDE(projPoint,p2,p0,p1)))
00196 {
00197 contacts->resize(contacts->size()+1);
00198 DetectionOutput *detection = &*(contacts->end()-1);
00199 detection->normal = -normal;
00200 detection->point[1] = projPoint;
00201 detection->point[0] = sph.center() - detection->normal * sph.r();
00202
00203 detection->value = -distance;
00204
00205
00206 detection->elem.first = sph;
00207 detection->elem.second = triangle;
00208 detection->id = sph.getIndex();
00209 return 1;
00210 }
00211 #undef SAMESIDE
00212
00215
00217
00218
00219
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252 return 0;
00253 }
00254
00255
00256 template<class Sphere>
00257 int DiscreteIntersection::computeIntersection(Sphere& sph1, Sphere& sph2, OutputVector* contacts)
00258 {
00259 double r = sph1.r() + sph2.r();
00260 Vector3 dist = sph2.center() - sph1.center();
00261
00262 if (dist.norm2() >= r*r)
00263 return 0;
00264
00265 contacts->resize(contacts->size()+1);
00266 DetectionOutput *detection = &*(contacts->end()-1);
00267 detection->normal = dist;
00268 double distSph1Sph2 = detection->normal.norm();
00269 detection->normal /= distSph1Sph2;
00270 detection->point[0] = sph1.center() + detection->normal * sph1.r();
00271 detection->point[1] = sph2.center() - detection->normal * sph2.r();
00272
00273 detection->value = distSph1Sph2 - r;
00274 detection->elem.first = sph1;
00275 detection->elem.second = sph2;
00276 detection->id = (sph1.getCollisionModel()->getSize() > sph2.getCollisionModel()->getSize()) ? sph1.getIndex() : sph2.getIndex();
00277
00278 return 1;
00279 }
00280
00281 template<class Sphere>
00282 int DiscreteIntersection::computeIntersection(Sphere& , Cube& , OutputVector* )
00283 {
00284
00285 return 0;
00286 }
00287
00288 template<class Sphere>
00289 int DiscreteIntersection::computeIntersection(Ray& ray1, Sphere& sph2, OutputVector* contacts)
00290 {
00291
00292 const Vector3 sph2Pos(sph2.center());
00293
00294 const double radius1 = sph2.r();
00295
00296 const Vector3 ray1Origin(ray1.origin());
00297 const Vector3 ray1Direction(ray1.direction());
00298 const double length2 = ray1.l();
00299 const Vector3 tmp = sph2Pos - ray1Origin;
00300 const double rayPos = tmp*ray1Direction;
00301 const double rayPosInside = std::max(std::min(rayPos,length2),0.0);
00302 const double dist2 = tmp.norm2() - (rayPosInside*rayPosInside);
00303 if (dist2 >= (radius1*radius1))
00304 return 0;
00305
00306 const double dist = sqrt(dist2);
00307
00308 contacts->resize(contacts->size()+1);
00309 DetectionOutput *detection = &*(contacts->end()-1);
00310
00311 detection->point[0] = ray1Origin + ray1Direction*rayPosInside;
00312 detection->normal = sph2Pos - detection->point[0];
00313 detection->normal /= dist;
00314 detection->point[1] = sph2Pos - detection->normal * radius1;
00315 detection->value = dist - radius1;
00316 detection->elem.first = ray1;
00317 detection->elem.second = sph2;
00318 detection->id = ray1.getIndex();
00319
00320 return 1;
00321 }
00322
00323 template<class Sphere>
00324 bool DiscreteIntersection::testIntersection(RigidDistanceGridCollisionElement&, Sphere&)
00325 {
00326 return true;
00327 }
00328
00329 template<class Sphere>
00330 int DiscreteIntersection::computeIntersection(RigidDistanceGridCollisionElement& e1, Sphere& e2, OutputVector* contacts)
00331 {
00332 DistanceGrid* grid1 = e1.getGrid();
00333 bool useXForm = e1.isTransformed();
00334 const Vector3& t1 = e1.getTranslation();
00335 const Matrix3& r1 = e1.getRotation();
00336
00337 const double d0 = e1.getProximity() + e2.getProximity() + this->getContactDistance() + e2.r();
00338 const SReal margin = 0.001f + (SReal)d0;
00339
00340 Vector3 p2 = e2.center();
00341 DistanceGrid::Coord p1;
00342
00343 if (useXForm)
00344 {
00345 p1 = r1.multTranspose(p2-t1);
00346 }
00347 else p1 = p2;
00348
00349 if (!grid1->inBBox( p1, margin )) return 0;
00350 if (!grid1->inGrid( p1 ))
00351 {
00352 std::cerr << "WARNING: margin less than "<<margin<<" in DistanceGrid "<<e1.getCollisionModel()->getName()<<std::endl;
00353 return 0;
00354 }
00355
00356 SReal d = grid1->interp(p1);
00357 if (d >= margin) return 0;
00358
00359 Vector3 grad = grid1->grad(p1);
00360 grad.normalize();
00361
00362
00363
00364 contacts->resize(contacts->size()+1);
00365 DetectionOutput *detection = &*(contacts->end()-1);
00366
00367 detection->point[0] = Vector3(p1) - grad * d;
00368 detection->point[1] = Vector3(p2);
00369 detection->normal = (useXForm) ? r1 * grad : grad;
00370 detection->value = d - d0;
00371 detection->elem.first = e1;
00372 detection->elem.second = e2;
00373 detection->id = e2.getIndex();
00374 return 1;
00375 }
00376
00377 template<class Sphere>
00378 bool DiscreteIntersection::testIntersection(FFDDistanceGridCollisionElement&, Sphere&)
00379 {
00380 return true;
00381 }
00382
00383 template<class Sphere>
00384 int DiscreteIntersection::computeIntersection(FFDDistanceGridCollisionElement& e1, Sphere& e2, OutputVector* contacts)
00385 {
00386
00387 DistanceGrid* grid1 = e1.getGrid();
00388 FFDDistanceGridCollisionModel::DeformedCube& c1 = e1.getCollisionModel()->getDeformCube(e1.getIndex());
00389
00390 const double d0 = e1.getProximity() + e2.getProximity() + getContactDistance() + e2.r();
00391 const SReal margin = 0.001f + (SReal)d0;
00392
00393 c1.updateFaces();
00394 const SReal cubesize = c1.invDP.norm();
00395 Vector3 p2 = e2.center();
00396 DistanceGrid::Coord p1 = p2;
00397
00398
00399 DistanceGrid::Coord b = c1.undeform0(p1);
00400
00401
00402 int iter;
00403 SReal err1 = 1000.0f;
00404 for(iter=0; iter<5; ++iter)
00405 {
00406 DistanceGrid::Coord pdeform = c1.deform(b);
00407 DistanceGrid::Coord diff = p1-pdeform;
00408 SReal err = diff.norm();
00409 if (iter>3)
00410 std::cout << "Iter"<<iter<<": "<<err1<<" -> "<<err<<" b = "<<b<<" diff = "<<diff<<" d = "<<grid1->interp(c1.initpos(b))<<"\n";
00411 SReal berr = err*cubesize; if (berr>0.5f) berr=0.5f;
00412 if (b[0] < -berr || b[0] > 1+berr
00413 || b[1] < -berr || b[1] > 1+berr
00414 || b[2] < -berr || b[2] > 1+berr)
00415 break;
00416 if (err < 0.005f)
00417 {
00418 if (b[0] > 0.001f && b[0] < 0.999f
00419 && b[1] > 0.001f && b[1] < 0.999f
00420 && b[2] > 0.001f && b[2] < 0.999f)
00421 {
00422 DistanceGrid::Coord pinit = c1.initpos(b);
00423 SReal d = grid1->interp(pinit);
00424 if (d < margin)
00425 {
00426 DistanceGrid::Coord grad = grid1->grad(pinit);
00427 grad.normalize();
00428 pinit -= grad*d;
00429 grad = c1.deformDir(c1.baryCoords(pinit),grad);
00430 grad.normalize();
00431
00432 contacts->resize(contacts->size()+1);
00433 DetectionOutput *detection = &*(contacts->end()-1);
00434
00435 detection->point[0] = Vector3(pinit);
00436 detection->point[1] = Vector3(p2);
00437 detection->normal = Vector3(grad);
00438 detection->value = d - d0;
00439 detection->elem.first = e1;
00440 detection->elem.second = e2;
00441 detection->id = e2.getIndex();
00442 return 1;
00443 }
00444 }
00445 break;
00446 }
00447 err1 = err;
00448 SReal d = grid1->interp(c1.initpos(b));
00449 if (d*0.5f - err > margin)
00450 break;
00451
00452
00453 b += c1.undeformDir( b, diff );
00454 }
00455 if (iter == 5)
00456 {
00457 if (b[0] > 0.001f && b[0] < 0.999f
00458 && b[1] > 0.001f && b[1] < 0.999f
00459 && b[2] > 0.001f && b[2] < 0.999f)
00460 std::cerr << "ERROR: FFD-FFD collision failed to converge to undeformed point: p1 = "<<p1<<" b = "<<b<<" c000 = "<<c1.corners[0]<<" c100 = "<<c1.corners[1]<<" c010 = "<<c1.corners[2]<<" c110 = "<<c1.corners[3]<<" c001 = "<<c1.corners[4]<<" c101 = "<<c1.corners[5]<<" c011 = "<<c1.corners[6]<<" c111 = "<<c1.corners[7]<<" pinit = "<<c1.initpos(b)<<" pdeform = "<<c1.deform(b)<<" err = "<<err1<<std::endl;
00461 }
00462
00463 return 0;
00464 }
00465
00466 }
00467
00468 }
00469
00470 }
00471
00472 #endif