File indexing completed on 2024-04-21 03:51:20
0001 /* 0002 SPDX-FileCopyrightText: 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "collisionsolver.h" 0008 #include "rigidbody.h" 0009 #include "particle.h" 0010 0011 #include <algorithm> 0012 0013 #define EIGEN_USE_NEW_STDVECTOR 0014 #include <Eigen/StdVector> 0015 0016 namespace StepCore { 0017 0018 // XXX: units for toleranceAbs and localError 0019 STEPCORE_META_OBJECT(CollisionSolver, QT_TRANSLATE_NOOP("ObjectClass", "CollisionSolver"), "CollisionSolver", MetaObject::ABSTRACT, STEPCORE_SUPER_CLASS(Object), 0020 STEPCORE_PROPERTY_RW(double, toleranceAbs, QT_TRANSLATE_NOOP("PropertyName", "toleranceAbs"), STEPCORE_UNITS_1, QT_TRANSLATE_NOOP("PropertyDescription", "Allowed absolute tolerance"), toleranceAbs, setToleranceAbs) 0021 STEPCORE_PROPERTY_R_D(double, localError, QT_TRANSLATE_NOOP("PropertyName", "localError"), STEPCORE_UNITS_1, QT_TRANSLATE_NOOP("PropertyDescription", "Maximal local error during last step"), localError)) 0022 0023 STEPCORE_META_OBJECT(GJKCollisionSolver, QT_TRANSLATE_NOOP("ObjectClass", "GJKCollisionSolver"), "GJKCollisionSolver", 0, 0024 STEPCORE_SUPER_CLASS(CollisionSolver),) 0025 0026 int GJKCollisionSolver::checkPolygonPolygon(Contact* contact) 0027 { 0028 BasePolygon* polygon0 = static_cast<BasePolygon*>(contact->body0); 0029 BasePolygon* polygon1 = static_cast<BasePolygon*>(contact->body1); 0030 0031 if(polygon0->vertexes().empty() || polygon1->vertexes().empty()) { 0032 return contact->state = Contact::Unknown; 0033 } 0034 0035 // Algorithm description can be found in 0036 // "A Fast and Robust GJK Implementation for 0037 // Collision Detection of Convex Objects" 0038 // by Gino van den Bergen 0039 0040 Vector2dList vertexes[2]; 0041 vertexes[0].reserve(polygon0->vertexes().size()); 0042 vertexes[1].reserve(polygon1->vertexes().size()); 0043 0044 const Vector2dList::const_iterator p0_it_end = polygon0->vertexes().end(); 0045 for(Vector2dList::const_iterator it0 = polygon0->vertexes().begin(); 0046 it0 != p0_it_end; ++it0) { 0047 vertexes[0].push_back(polygon0->pointLocalToWorld(*it0)); 0048 } 0049 0050 const Vector2dList::const_iterator p1_it_end = polygon1->vertexes().end(); 0051 for(Vector2dList::const_iterator it1 = polygon1->vertexes().begin(); 0052 it1 != p1_it_end; ++it1) { 0053 vertexes[1].push_back(polygon1->pointLocalToWorld(*it1)); 0054 } 0055 0056 int wsize; 0057 Vector2d w[3]; // Vertexes of current simplex 0058 Vector2d v; // Closest point of current simplex 0059 Vector2d s; // New support vertex in direction v 0060 0061 Vector2d vv[2]; // Closest points on the first and second objects 0062 int wi[2][3]; // Indexes of vertexes corresponding to w 0063 int si[2] = {0, 0}; // Indexes of vertexes corresponding to s 0064 0065 wsize = 1; 0066 // Start with arbitrary vertex (TODO: cache the whole w simplex) 0067 if(contact->state >= Contact::Separating && contact->state < Contact::Intersected) { 0068 wi[0][0] = contact->_w1[0]; 0069 wi[1][0] = contact->_w1[1]; 0070 } else { 0071 wi[0][0] = 0; 0072 wi[1][0] = 0; 0073 } 0074 vv[0] = vertexes[0][wi[0][0]]; 0075 vv[1] = vertexes[1][wi[1][0]]; 0076 w[0] = v = vv[1] - vv[0]; 0077 0078 bool intersects = false; 0079 unsigned int iteration = 0; 0080 for(;; ++iteration) { 0081 //STEPCORE_ASSERT_NOABORT( iteration < vertexes[0].size()*vertexes[1].size() ); 0082 0083 double smin = v.squaredNorm(); 0084 0085 // Check for penetration (part 1) 0086 // If we are closer to the origin then given tolerance 0087 // we should stop just now to avoid computational errors later 0088 if(smin < _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance for penetration ? 0089 intersects = true; 0090 break; 0091 } 0092 0093 // Find support vertex in direction v 0094 // TODO: coherence optimization 0095 bool sfound = false; 0096 unsigned int vertex0_size = vertexes[0].size(); 0097 unsigned int vertex1_size = vertexes[1].size(); 0098 0099 for(unsigned int i0=0; i0<vertex0_size; ++i0) { 0100 for(unsigned int i1=0; i1<vertex1_size; ++i1) { 0101 Vector2d sn = vertexes[1][i1] - vertexes[0][i0]; 0102 double scurr = sn.dot(v); 0103 if(smin - scurr > _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance ? 0104 smin = scurr; 0105 s = sn; 0106 si[0] = i0; 0107 si[1] = i1; 0108 sfound = true; 0109 } 0110 } 0111 } 0112 0113 // If no support vertex have been found than we are at minimum 0114 if(!sfound) { 0115 if(wsize == 0) { // we have guessed right point 0116 w[0] = v; 0117 wi[0][0] = 0; 0118 wi[1][0] = 0; 0119 wsize = 1; 0120 } 0121 break; 0122 } 0123 0124 // Check for penetration (part 2) 0125 if(wsize == 2) { 0126 // objects are penetrating if origin lies inside the simplex 0127 // XXX: are there faster method to test it ? 0128 Vector2d w02 = w[0] - s; 0129 Vector2d w12 = w[1] - s; 0130 double det = w02[0]*w12[1] - w02[1]*w12[0]; 0131 double det0 = -s[0]*w12[1] + s[1]*w12[0]; 0132 double det1 = -w02[0]* s[1] + w02[1]* s[0]; 0133 if(det0/det > 0 && det1/det > 0) { // XXX: tolerance 0134 w[wsize] = s; 0135 wi[0][wsize] = si[0]; 0136 wi[1][wsize] = si[1]; 0137 ++wsize; 0138 v.setZero(); 0139 intersects = true; 0140 break; 0141 } 0142 } 0143 0144 // Find v = dist(conv(w+s)) 0145 double lambda = 0; 0146 int ii = -1; 0147 for(int i=0; i<wsize; ++i) { 0148 double lambda0 = - (w[i]-s).dot(s) / (w[i]-s).squaredNorm(); 0149 if(lambda0 > 0) { 0150 Vector2d vn = s*(1-lambda0) + w[i]*lambda0; 0151 if(vn.squaredNorm() < v.squaredNorm()) { 0152 v = vn; ii = i; 0153 lambda = lambda0; 0154 } 0155 } 0156 } 0157 0158 if(ii >= 0) { // Closest simplex is line 0159 vv[0] = vertexes[0][si[0]]*(1-lambda) + vertexes[0][wi[0][ii]]*lambda; 0160 vv[1] = vertexes[1][si[1]]*(1-lambda) + vertexes[1][wi[1][ii]]*lambda; 0161 if(wsize == 2) { 0162 w[1-ii] = s; 0163 wi[0][1-ii] = si[0]; 0164 wi[1][1-ii] = si[1]; 0165 } else { 0166 w[wsize] = s; 0167 wi[0][wsize] = si[0]; 0168 wi[1][wsize] = si[1]; 0169 ++wsize; 0170 } 0171 } else { // Closest simplex is vertex 0172 STEPCORE_ASSERT_NOABORT(iteration == 0 || s.squaredNorm() < v.squaredNorm()); 0173 0174 v = w[0] = s; 0175 vv[0] = vertexes[0][si[0]]; 0176 vv[1] = vertexes[1][si[1]]; 0177 wi[0][0] = si[0]; 0178 wi[1][0] = si[1]; 0179 wsize = 1; 0180 } 0181 } 0182 0183 if(intersects) { 0184 /* 0185 qDebug("penetration detected"); 0186 qDebug("iteration = %d", iteration); 0187 qDebug("simplexes:"); 0188 qDebug(" 1: 2:"); 0189 for(int i=0; i<wsize; ++i) { 0190 qDebug(" %d %d", wi[0][i], wi[1][i]); 0191 } 0192 */ 0193 contact->distance = 0; 0194 contact->normal.setZero(); 0195 contact->pointsCount = 0; 0196 return contact->state = Contact::Intersected; 0197 } 0198 0199 /* 0200 qDebug("distance = %f", v.norm()); 0201 Vector2d v1 = v / v.norm(); 0202 qDebug("normal = (%f,%f)", v1[0], v1[1]); 0203 qDebug("iteration = %d", iteration); 0204 qDebug("simplexes:"); 0205 qDebug(" 1: 2:"); 0206 for(int i=0; i<wsize; ++i) { 0207 qDebug(" %d %d", wi[0][i], wi[1][i]); 0208 } 0209 qDebug("contact points:"); 0210 qDebug(" (%f,%f) (%f,%f)", vv[0][0], vv[0][1], vv[1][0], vv[1][1]); 0211 */ 0212 0213 double vnorm = v.norm(); 0214 contact->distance = vnorm; 0215 contact->normal = v/vnorm; 0216 contact->pointsCount = 0; 0217 contact->state = Contact::Separated; 0218 0219 contact->_w1[0] = wi[0][0]; 0220 contact->_w1[1] = wi[1][0]; 0221 0222 if(vnorm > _toleranceAbs) return contact->state; 0223 0224 // If the objects are close enough we need to find contact manifold 0225 // We are going to find simplexes (lines) that are 'most parallel' 0226 // to contact plane and look for contact manifold among them. It 0227 // works for almost all cases when adjacent polygon edges are 0228 // not parallel 0229 Vector2d vunit = v / vnorm; 0230 Vector2d wm[2][2]; 0231 0232 for(int i=0; i<2; ++i) { 0233 wm[i][0] = vertexes[i][ wi[i][0] ]; 0234 0235 if(wsize < 2 || wi[i][0] == wi[i][1]) { // vertex contact 0236 // Check two adjacent edges 0237 int ai1 = wi[i][0] - 1; if(ai1 < 0) ai1 = vertexes[i].size()-1; 0238 Vector2d av1 = vertexes[i][ai1]; 0239 Vector2d dv1 = wm[i][0] - av1; 0240 double dist1 = dv1.dot(vunit) * (i==0 ? 1 : -1); 0241 double angle1 = dist1 / dv1.norm(); 0242 0243 int ai2 = wi[i][0] + 1; if(ai2 >= (int) vertexes[i].size()) ai2 = 0; 0244 Vector2d av2 = vertexes[i][ai2]; 0245 Vector2d dv2 = wm[i][0] - av2; 0246 double dist2 = dv2.dot(vunit) * (i==0 ? 1 : -1); 0247 double angle2 = dist2 / dv2.norm(); 0248 0249 if(angle1 <= angle2 && dist1 < (_toleranceAbs-vnorm)/2) { 0250 wm[i][1] = av1; 0251 } else if(angle2 <= angle1 && dist2 < (_toleranceAbs-vnorm)/2) { 0252 wm[i][1] = av2; 0253 } else { 0254 wm[i][1] = wm[i][0]; contact->pointsCount = 1; 0255 break; 0256 } 0257 } else { // edge contact 0258 wm[i][1] = vertexes[i][ wi[i][1] ]; 0259 } 0260 } 0261 0262 // Find intersection of two lines 0263 if(contact->pointsCount != 1) { 0264 Vector2d vunit_o(-vunit[1], vunit[0]); 0265 double wm_o[2][2]; 0266 0267 for(int i=0; i<2; ++i) { 0268 wm_o[i][0] = wm[i][0].dot(vunit_o); 0269 wm_o[i][1] = wm[i][1].dot(vunit_o); 0270 0271 if(wm_o[i][0] > wm_o[i][1]) { 0272 std::swap(wm_o[i][0], wm_o[i][1]); 0273 std::swap(wm[i][0], wm[i][1]); 0274 } 0275 } 0276 0277 if(wm_o[0][0] > wm_o[1][0]) contact->points[0] = wm[0][0]; 0278 else contact->points[0] = wm[1][0]; 0279 0280 if(wm_o[0][1] < wm_o[1][1]) contact->points[1] = wm[0][1]; 0281 else contact->points[1] = wm[1][1]; 0282 0283 // TODO: interpolate to midpoint 0284 if((contact->points[1] - contact->points[0]).norm() > _toleranceAbs) { 0285 /* 0286 for(int i=0; i<2; ++i) { 0287 qDebug("contact%d: (%f,%f)", i, contact->points[i][0], contact->points[i][1]); 0288 } 0289 */ 0290 contact->pointsCount = 2; 0291 } 0292 /* 0293 contact->vrel[0] = (polygon1->velocityWorld(contact->points[0]) - 0294 polygon0->velocityWorld(contact->points[0])).dot(contact->normal); 0295 contact->vrel[1] = (polygon1->velocityWorld(contact->points[1]) - 0296 polygon0->velocityWorld(contact->points[1])).dot(contact->normal); 0297 if(contact->vrel[0] < 0 || contact->vrel[1] < 0) 0298 return contact->state = Contact::Colliding; 0299 else if(contact->vrel[0] < _toleranceAbs || contact->vrel[1] < _toleranceAbs) // XXX: tolerance 0300 return contact->state = Colliding::Contacted; 0301 return contact->state = Contact::Separating; 0302 } 0303 */ 0304 } 0305 0306 if(contact->pointsCount != 2) { 0307 contact->pointsCount = 1; 0308 contact->points[0] = vv[0]; // TODO: interpolate vv[0] and vv[1] 0309 //qDebug("contact is one point: (%f %f) (%f %f)", vv[0][0], vv[0][1], vv[1][0], vv[1][1]); 0310 } 0311 0312 int pCount = contact->pointsCount; 0313 for(int i=0; i<pCount; ++i) { 0314 contact->vrel[i] = (polygon1->velocityWorld(contact->points[i]) - 0315 polygon0->velocityWorld(contact->points[i])).dot(contact->normal); 0316 0317 if(contact->vrel[i] < 0) 0318 contact->pointsState[i] = Contact::Colliding; 0319 else if(contact->vrel[i] < _toleranceAbs) // XXX: tolerance 0320 contact->pointsState[i] = Contact::Contacted; 0321 else contact->pointsState[i] = Contact::Separating; 0322 0323 if(contact->pointsState[i] > contact->state) 0324 contact->state = contact->pointsState[i]; 0325 } 0326 0327 contact->normalDerivative.setZero(); //XXX 0328 return contact->state; 0329 } 0330 0331 int GJKCollisionSolver::checkPolygonDisk(Contact* contact) 0332 { 0333 BasePolygon* polygon0 = static_cast<BasePolygon*>(contact->body0); 0334 Disk* disk1 = static_cast<Disk*>(contact->body1); 0335 0336 if(polygon0->vertexes().empty()) { 0337 return contact->state = Contact::Unknown; 0338 } 0339 0340 // Simplier version of checkPolygonPolygon algorithm 0341 0342 Vector2dList vertexes; 0343 vertexes.reserve(polygon0->vertexes().size()); 0344 0345 const Vector2dList::const_iterator p0_it_end = polygon0->vertexes().end(); 0346 for(Vector2dList::const_iterator it0 = polygon0->vertexes().begin(); 0347 it0 != p0_it_end; ++it0) { 0348 vertexes.push_back(polygon0->pointLocalToWorld(*it0)); 0349 } 0350 0351 int wsize; 0352 Vector2d w[3]; // Vertexes of current simplex 0353 Vector2d v; // Closest point of current simplex 0354 Vector2d s; // New support vertex in direction v 0355 0356 Vector2d vv; // Closest points on the polygon 0357 int wi[3]; // Indexes of vertexes corresponding to w 0358 int si = 0; // Indexes of vertexes corresponding to s 0359 0360 // Start with arbitrary vertex (TODO: cache the whole w simplex) 0361 wsize = 1; 0362 if(contact->state >= Contact::Separating && contact->state < Contact::Intersected) { 0363 wi[0] = contact->_w1[0]; 0364 } else { 0365 wi[0] = 0; 0366 } 0367 vv = vertexes[wi[0]]; 0368 w[0] = v = disk1->position() - vv; 0369 0370 bool intersects = false; 0371 unsigned int iteration = 0; 0372 for(;; ++iteration) { 0373 //STEPCORE_ASSERT_NOABORT( iteration < vertexes.size()*vertexes.size() ); 0374 0375 double smin = v.squaredNorm(); 0376 0377 // Check for penetration (part 1) 0378 // If we are closer to the origin then given tolerance 0379 // we should stop just now to avoid computational errors later 0380 if(std::sqrt(smin) - disk1->radius() < _toleranceAbs*1e-2) { // XXX: separate tolerance for penetration ? 0381 intersects = true; 0382 break; 0383 } 0384 0385 // Find support vertex in direction v 0386 // TODO: coherence optimization 0387 bool sfound = false; 0388 unsigned int vertex_size = vertexes.size(); 0389 0390 for(unsigned int i0=0; i0<vertex_size; ++i0) { 0391 Vector2d sn = disk1->position() - vertexes[i0]; 0392 double scurr = sn.dot(v); 0393 if(smin - scurr > _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance ? 0394 smin = scurr; 0395 s = sn; 0396 si = i0; 0397 sfound = true; 0398 } 0399 } 0400 0401 // If no support vertex have been found than we are at minimum 0402 if(!sfound) { 0403 if(wsize == 0) { // we have guessed right point 0404 w[0] = v; 0405 wi[0] = 0; 0406 wsize = 1; 0407 } 0408 break; 0409 } 0410 0411 // Check for penetration (part 2) 0412 if(wsize == 2) { 0413 // objects are penetrating if origin lies inside the simplex 0414 // XXX: are there faster method to test it ? 0415 Vector2d w02 = w[0] - s; 0416 Vector2d w12 = w[1] - s; 0417 Vector2d s0 = s - s.normalized() * disk1->radius(); 0418 double det = w02[0]*w12[1] - w02[1]*w12[0]; 0419 double det0 = -s0[0]*w12[1] + s0[1]*w12[0]; 0420 double det1 = -w02[0]* s0[1] + w02[1]* s0[0]; 0421 if(det0/det > 0 && det1/det > 0) { // XXX: tolerance 0422 w[wsize] = s; 0423 wi[wsize] = si; 0424 ++wsize; 0425 v.setZero(); 0426 intersects = true; 0427 break; 0428 } 0429 } 0430 0431 // Find v = dist(conv(w+s)) 0432 double lambda = 0; 0433 int ii = -1; 0434 for(int i=0; i<wsize; ++i) { 0435 double lambda0 = - (w[i]-s).dot(s) / (w[i]-s).squaredNorm(); 0436 if(lambda0 > 0) { 0437 Vector2d vn = s*(1-lambda0) + w[i]*lambda0; 0438 if(vn.squaredNorm() < v.squaredNorm()) { 0439 v = vn; ii = i; 0440 lambda = lambda0; 0441 } 0442 } 0443 } 0444 0445 if(ii >= 0) { // Closest simplex is line 0446 vv = vertexes[si]*(1-lambda) + vertexes[wi[ii]]*lambda; 0447 if(wsize == 2) { 0448 w[1-ii] = s; 0449 wi[1-ii] = si; 0450 } else { 0451 w[wsize] = s; 0452 wi[wsize] = si; 0453 ++wsize; 0454 } 0455 } else { // Closest simplex is vertex 0456 STEPCORE_ASSERT_NOABORT(iteration == 0 || s.squaredNorm() < v.squaredNorm()); 0457 0458 v = w[0] = s; 0459 vv = vertexes[si]; 0460 wi[0] = si; 0461 wsize = 1; 0462 } 0463 } 0464 0465 if(intersects) { 0466 /*qDebug("penetration detected"); 0467 qDebug("iteration = %d", iteration); 0468 qDebug("simplexes:"); 0469 qDebug(" 1: 2:"); 0470 for(int i=0; i<wsize; ++i) { 0471 qDebug(" %d %d", wi[i], wi[i]); 0472 }*/ 0473 contact->distance = 0; 0474 contact->normal.setZero(); 0475 contact->pointsCount = 0; 0476 return contact->state = Contact::Intersected; 0477 } 0478 0479 /* 0480 qDebug("distance = %f", v.norm()); 0481 Vector2d v1 = v / v.norm(); 0482 qDebug("normal = (%f,%f)", v1[0], v1[1]); 0483 qDebug("iteration = %d", iteration); 0484 qDebug("simplexes:"); 0485 qDebug(" 1: 2:"); 0486 for(int i=0; i<wsize; ++i) { 0487 qDebug(" %d %d", wi[i], wi[i]); 0488 } 0489 qDebug("contact points:"); 0490 qDebug(" (%f,%f) (%f,%f)", vv[0], vv[1], vv[0], vv[1]); 0491 */ 0492 0493 double vnorm = v.norm(); 0494 contact->distance = vnorm - disk1->radius(); 0495 contact->normal = v/vnorm; 0496 0497 contact->_w1[0] = wi[0]; 0498 0499 if(contact->distance > _toleranceAbs) { 0500 contact->pointsCount = 0; 0501 contact->state = Contact::Separated; 0502 return contact->state; 0503 }/* else if(contact->distance < _toleranceAbs*1e-2) { 0504 contact->state = Contact::Intersected; 0505 return contact->state; 0506 }*/ 0507 0508 contact->pointsCount = 1; 0509 contact->points[0] = disk1->position() - contact->normal * disk1->radius(); 0510 contact->vrel[0] = (disk1->velocity() - 0511 polygon0->velocityWorld(contact->points[0])).dot(contact->normal); 0512 0513 if(contact->vrel[0] < 0) 0514 contact->pointsState[0] = Contact::Colliding; 0515 else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance 0516 contact->pointsState[0] = Contact::Contacted; 0517 else contact->pointsState[0] = Contact::Separating; 0518 0519 contact->normalDerivative.setZero(); //XXX 0520 contact->state = contact->pointsState[0]; 0521 return contact->state; 0522 } 0523 0524 int GJKCollisionSolver::checkPolygonParticle(Contact* contact) 0525 { 0526 BasePolygon* polygon0 = static_cast<BasePolygon*>(contact->body0); 0527 Particle* particle1 = static_cast<Particle*>(contact->body1); 0528 0529 if(polygon0->vertexes().empty()) { 0530 return contact->state = Contact::Unknown; 0531 } 0532 0533 // Simplier version of checkPolygonPolygon algorithm 0534 0535 Vector2dList vertexes; 0536 vertexes.reserve(polygon0->vertexes().size()); 0537 0538 const Vector2dList::const_iterator p0_it_end = polygon0->vertexes().end(); 0539 for(Vector2dList::const_iterator it0 = polygon0->vertexes().begin(); 0540 it0 != p0_it_end; ++it0) { 0541 vertexes.push_back(polygon0->pointLocalToWorld(*it0)); 0542 } 0543 0544 int wsize; 0545 Vector2d w[3]; // Vertexes of current simplex 0546 Vector2d v; // Closest point of current simplex 0547 Vector2d s; // New support vertex in direction v 0548 0549 Vector2d vv; // Closest points on the polygon 0550 int wi[3]; // Indexes of vertexes corresponding to w 0551 int si = 0; // Indexes of vertexes corresponding to s 0552 0553 // Start with arbitrary vertex (TODO: cache the whole w simplex) 0554 wsize = 1; 0555 if(contact->state >= Contact::Separating && contact->state < Contact::Intersected) { 0556 wi[0] = contact->_w1[0]; 0557 } else { 0558 wi[0] = 0; 0559 } 0560 vv = vertexes[wi[0]]; 0561 w[0] = v = particle1->position() - vv; 0562 0563 bool intersects = false; 0564 unsigned int iteration = 0; 0565 for(;; ++iteration) { 0566 //STEPCORE_ASSERT_NOABORT( iteration < vertexes[0].size()*vertexes[1].size() ); 0567 0568 double smin = v.squaredNorm(); 0569 0570 // Check for penetration (part 1) 0571 // If we are closer to the origin then given tolerance 0572 // we should stop just now to avoid computational errors later 0573 if(smin < _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance for penetration ? 0574 intersects = true; 0575 break; 0576 } 0577 0578 // Find support vertex in direction v 0579 // TODO: coherence optimization 0580 bool sfound = false; 0581 unsigned int vertex_size = vertexes.size(); 0582 0583 for(unsigned int i0=0; i0<vertex_size; ++i0) { 0584 Vector2d sn = particle1->position() - vertexes[i0]; 0585 double scurr = sn.dot(v); 0586 if(smin - scurr > _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance ? 0587 smin = scurr; 0588 s = sn; 0589 si = i0; 0590 sfound = true; 0591 } 0592 } 0593 0594 // If no support vertex have been found than we are at minimum 0595 if(!sfound) { 0596 if(wsize == 0) { // we have guessed right point 0597 w[0] = v; 0598 wi[0] = 0; 0599 wsize = 1; 0600 } 0601 break; 0602 } 0603 0604 // Check for penetration (part 2) 0605 if(wsize == 2) { 0606 // objects are penetrating if origin lies inside the simplex 0607 // XXX: are there faster method to test it ? 0608 Vector2d w02 = w[0] - s; 0609 Vector2d w12 = w[1] - s; 0610 double det = w02[0]*w12[1] - w02[1]*w12[0]; 0611 double det0 = -s[0]*w12[1] + s[1]*w12[0]; 0612 double det1 = -w02[0]* s[1] + w02[1]* s[0]; 0613 if(det0/det > 0 && det1/det > 0) { // XXX: tolerance 0614 w[wsize] = s; 0615 wi[wsize] = si; 0616 ++wsize; 0617 v.setZero(); 0618 intersects = true; 0619 break; 0620 } 0621 } 0622 0623 // Find v = dist(conv(w+s)) 0624 double lambda = 0; 0625 int ii = -1; 0626 for(int i=0; i<wsize; ++i) { 0627 double lambda0 = - (w[i]-s).dot(s) / (w[i]-s).squaredNorm(); 0628 if(lambda0 > 0) { 0629 Vector2d vn = s*(1-lambda0) + w[i]*lambda0; 0630 if(vn.squaredNorm() < v.squaredNorm()) { 0631 v = vn; ii = i; 0632 lambda = lambda0; 0633 } 0634 } 0635 } 0636 0637 if(ii >= 0) { // Closest simplex is line 0638 vv = vertexes[si]*(1-lambda) + vertexes[wi[ii]]*lambda; 0639 if(wsize == 2) { 0640 w[1-ii] = s; 0641 wi[1-ii] = si; 0642 } else { 0643 w[wsize] = s; 0644 wi[wsize] = si; 0645 ++wsize; 0646 } 0647 } else { // Closest simplex is vertex 0648 STEPCORE_ASSERT_NOABORT(iteration == 0 || s.squaredNorm() < v.squaredNorm()); 0649 0650 v = w[0] = s; 0651 vv = vertexes[si]; 0652 wi[0] = si; 0653 wsize = 1; 0654 } 0655 } 0656 0657 if(intersects) { 0658 /* 0659 qDebug("penetration detected"); 0660 qDebug("iteration = %d", iteration); 0661 qDebug("simplexes:"); 0662 qDebug(" 1: 2:"); 0663 for(int i=0; i<wsize; ++i) { 0664 qDebug(" %d %d", wi[0][i], wi[1][i]); 0665 } 0666 */ 0667 contact->distance = 0; 0668 contact->normal.setZero(); 0669 contact->pointsCount = 0; 0670 return contact->state = Contact::Intersected; 0671 } 0672 0673 /* 0674 qDebug("distance = %f", v.norm()); 0675 Vector2d v1 = v / v.norm(); 0676 qDebug("normal = (%f,%f)", v1[0], v1[1]); 0677 qDebug("iteration = %d", iteration); 0678 qDebug("simplexes:"); 0679 qDebug(" 1: 2:"); 0680 for(int i=0; i<wsize; ++i) { 0681 qDebug(" %d %d", wi[0][i], wi[1][i]); 0682 } 0683 qDebug("contact points:"); 0684 qDebug(" (%f,%f) (%f,%f)", vv[0][0], vv[0][1], vv[1][0], vv[1][1]); 0685 */ 0686 0687 double vnorm = v.norm(); 0688 contact->distance = vnorm; 0689 contact->normal = v/vnorm; 0690 0691 contact->_w1[0] = wi[0]; 0692 0693 if(vnorm > _toleranceAbs) { 0694 contact->pointsCount = 0; 0695 contact->state = Contact::Separated; 0696 return contact->state; 0697 } 0698 0699 contact->pointsCount = 1; 0700 contact->points[0] = particle1->position(); 0701 contact->vrel[0] = (particle1->velocity() - 0702 polygon0->velocityWorld(contact->points[0])).dot(contact->normal); 0703 0704 if(contact->vrel[0] < 0) 0705 contact->pointsState[0] = Contact::Colliding; 0706 else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance 0707 contact->pointsState[0] = Contact::Contacted; 0708 else contact->pointsState[0] = Contact::Separating; 0709 0710 contact->state = contact->pointsState[0]; 0711 return contact->state; 0712 } 0713 0714 int GJKCollisionSolver::checkDiskDisk(Contact* contact) 0715 { 0716 Disk* disk0 = static_cast<Disk*>(contact->body0); 0717 Disk* disk1 = static_cast<Disk*>(contact->body1); 0718 0719 Vector2d r = disk1->position() - disk0->position(); 0720 double rd = disk1->radius() + disk0->radius(); 0721 double rn = r.norm(); 0722 contact->normal = r/rn; 0723 contact->distance = rn - rd; 0724 0725 if(contact->distance > _toleranceAbs) { 0726 contact->state = Contact::Separated; 0727 return contact->state; 0728 } else if(contact->distance < 0) { 0729 contact->state = Contact::Intersected; 0730 return contact->state; 0731 } 0732 0733 contact->pointsCount = 1; 0734 contact->points[0] = disk0->position() + contact->normal * disk0->radius(); 0735 0736 Vector2d v = disk1->velocity() - disk0->velocity(); 0737 contact->vrel[0] = v.dot(contact->normal); 0738 contact->normalDerivative = v / rn - (v.dot(r)/rn/rn/rn) * r; 0739 0740 if(contact->vrel[0] < 0) 0741 contact->pointsState[0] = Contact::Colliding; 0742 else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance 0743 contact->pointsState[0] = Contact::Contacted; 0744 else contact->pointsState[0] = Contact::Separating; 0745 0746 contact->normalDerivative.setZero(); //XXX 0747 contact->state = contact->pointsState[0]; 0748 return contact->state; 0749 } 0750 0751 int GJKCollisionSolver::checkDiskParticle(Contact* contact) 0752 { 0753 Disk* disk0 = static_cast<Disk*>(contact->body0); 0754 Particle* particle1 = static_cast<Particle*>(contact->body1); 0755 0756 Vector2d r = particle1->position() - disk0->position(); 0757 double rd = disk0->radius(); 0758 double rn = r.norm(); 0759 contact->normal = r/rn; 0760 contact->distance = rn - rd; 0761 0762 if(contact->distance > _toleranceAbs) { 0763 contact->state = Contact::Separated; 0764 return contact->state; 0765 } else if(contact->distance < _toleranceAbs*1e-2) { 0766 contact->state = Contact::Intersected; 0767 return contact->state; 0768 } 0769 0770 contact->pointsCount = 1; 0771 contact->points[0] = disk0->position() + contact->normal * disk0->radius(); 0772 0773 Vector2d v = particle1->velocity() - disk0->velocity(); 0774 contact->vrel[0] = v.dot(contact->normal); 0775 contact->normalDerivative = v / rn - (v.dot(r)/rn/rn/rn) * r; 0776 0777 if(contact->vrel[0] < 0) 0778 contact->pointsState[0] = Contact::Colliding; 0779 else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance 0780 contact->pointsState[0] = Contact::Contacted; 0781 else contact->pointsState[0] = Contact::Separating; 0782 0783 contact->state = contact->pointsState[0]; 0784 return contact->state; 0785 } 0786 0787 0788 /* 0789 int GJKCollisionSolver::checkContact(Contact* contact) 0790 { 0791 0792 if(contact->type == Contact::UnknownType) { 0793 if(contact->body0->metaObject()->inherits<BasePolygon>()) { 0794 if(contact->body1->metaObject()->inherits<BasePolygon>()) contact->type = Contact::PolygonPolygonType; 0795 else if(contact->body1->metaObject()->inherits<Particle>()) contact->type = Contact::PolygonParticleType; 0796 } else if(contact->body0->metaObject()->inherits<Particle>()) { 0797 if(contact->body1->metaObject()->inherits<BasePolygon>()) { 0798 std::swap(contact->body0, contact->body1); 0799 contact->type = Contact::PolygonParticleType; 0800 } 0801 } 0802 contact->state = Contact::Unknown; 0803 } 0804 0805 if(contact->type == Contact::PolygonPolygonType) return checkPolygonPolygon(contact); 0806 else if(contact->type == Contact::PolygonParticleType) return checkPolygonParticle(contact); 0807 return contact->state = Contact::Unknown; 0808 }*/ 0809 0810 inline int GJKCollisionSolver::checkContact(Contact* contact) 0811 { 0812 if(contact->type == Contact::PolygonPolygonType) checkPolygonPolygon(contact); 0813 else if(contact->type == Contact::PolygonDiskType) checkPolygonDisk(contact); 0814 else if(contact->type == Contact::PolygonParticleType) checkPolygonParticle(contact); 0815 else if(contact->type == Contact::DiskDiskType) checkDiskDisk(contact); 0816 else if(contact->type == Contact::DiskParticleType) checkDiskParticle(contact); 0817 else contact->state = Contact::Unknown; 0818 return contact->state; 0819 } 0820 0821 int GJKCollisionSolver::checkContacts(BodyList& bodies, bool collisions, int* retCount) 0822 { 0823 int state = Contact::Unknown; 0824 int count = 0; 0825 0826 checkCache(bodies); 0827 0828 // Detect and classify contacts... 0829 // ... and count contact joints 0830 const ContactValueList::iterator end = _contacts.end(); 0831 for(ContactValueList::iterator it = _contacts.begin(); it != end; ++it) { 0832 Contact& contact = *it; 0833 0834 checkContact(&contact); 0835 0836 if(contact.state > state) state = contact.state; 0837 if( (it->state == Contact::Contacted) || (collisions && it->state == Contact::Colliding) ) 0838 count += it->pointsCount; 0839 } 0840 if (retCount) *retCount = count; 0841 return state; 0842 } 0843 0844 void GJKCollisionSolver::getContactsInfo(ConstraintsInfo& info, bool collisions) 0845 { 0846 const ContactValueList::iterator end = _contacts.end(); 0847 0848 int i = info.constraintsCount-1; 0849 // Add contact joints 0850 for(ContactValueList::iterator it = _contacts.begin(); it != end; ++it) { 0851 Contact& contact = *it; 0852 if(contact.state == Contact::Contacted) { 0853 //qDebug("** resting contact, points: %d", contact.pointsCount); 0854 for(int p=0; p<contact.pointsCount; ++p) { 0855 // XXX: check signs ! 0856 // XXX: rotation and friction ! 0857 /*info.value[i0] = contact.normal[0] * contact.distance; 0858 info.value[i1] = contact.normal[1] * contact.distance; 0859 info.derivative[i0] = contact.normal[0] * contact.vrel[0]; 0860 info.derivative[i1] = contact.normal[1] * contact.vrel[0];*/ 0861 /*info.value[i] = contact.distance; 0862 info.derivative[i] = contact.vrel[p];*/ 0863 ++i; 0864 info.jacobian.coeffRef(i, contact.body0->variablesOffset() + RigidBody::PositionOffset) = -contact.normal[0]; 0865 info.jacobian.coeffRef(i, contact.body0->variablesOffset() + RigidBody::PositionOffset+1) = -contact.normal[1]; 0866 info.jacobian.coeffRef(i, contact.body1->variablesOffset() + RigidBody::PositionOffset) = contact.normal[0]; 0867 info.jacobian.coeffRef(i, contact.body1->variablesOffset() + RigidBody::PositionOffset+1) = contact.normal[1]; 0868 0869 if(!collisions) { 0870 info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() + 0871 RigidBody::PositionOffset) = ( -contact.normalDerivative[0]); 0872 info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() + 0873 RigidBody::PositionOffset+1) = ( -contact.normalDerivative[1]); 0874 info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() + 0875 RigidBody::PositionOffset) = ( contact.normalDerivative[0]); 0876 info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() + 0877 RigidBody::PositionOffset+1) = ( contact.normalDerivative[1]); 0878 } 0879 0880 if(contact.body0->metaObject()->inherits<RigidBody>()) { 0881 Vector2d r = static_cast<RigidBody*>(contact.body0)->position() - contact.points[p]; 0882 Vector2d v = static_cast<RigidBody*>(contact.body0)->velocity(); 0883 double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0]; 0884 double rd = v[0]*contact.normal[1] - v[1]*contact.normal[0] + 0885 r[0]*contact.normalDerivative[1] - r[1]*contact.normalDerivative[0]; 0886 info.jacobian.coeffRef(i, contact.body0->variablesOffset() + 0887 RigidBody::AngleOffset) = ( +rn); 0888 if(!collisions) 0889 info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() + 0890 RigidBody::AngleOffset) = ( +rd); 0891 } 0892 0893 if(contact.body1->metaObject()->inherits<RigidBody>()) { 0894 Vector2d r = static_cast<RigidBody*>(contact.body1)->position() - contact.points[p]; 0895 Vector2d v = static_cast<RigidBody*>(contact.body1)->velocity(); 0896 double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0]; 0897 double rd = v[0]*contact.normal[1] - v[1]*contact.normal[0] + 0898 r[0]*contact.normalDerivative[1] - r[1]*contact.normalDerivative[0]; 0899 info.jacobian.coeffRef(i, contact.body1->variablesOffset() + RigidBody::AngleOffset) = -rn; 0900 if(!collisions) 0901 info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() + RigidBody::AngleOffset) = -rd; 0902 } 0903 info.forceMin[i] = 0; 0904 } 0905 0906 } else if(collisions && contact.state == Contact::Colliding) { 0907 //qDebug("** collision, points: %d", contact.pointsCount); 0908 for(int p = 0; p<contact.pointsCount; ++p) { 0909 ++i; 0910 info.jacobian.coeffRef(i, contact.body0->variablesOffset() + 0911 RigidBody::PositionOffset) = ( -contact.normal[0]); 0912 info.jacobian.coeffRef(i, contact.body0->variablesOffset() + 0913 RigidBody::PositionOffset+1) = ( -contact.normal[1]); 0914 info.jacobian.coeffRef(i, contact.body1->variablesOffset() + 0915 RigidBody::PositionOffset) = ( contact.normal[0]); 0916 info.jacobian.coeffRef(i, contact.body1->variablesOffset() + 0917 RigidBody::PositionOffset+1) = ( contact.normal[1]); 0918 0919 // jacobianDerivative is special in this case: it is not really 0920 // a derivative, but rather just an expression that should be in 0921 // constraint equation 0922 info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() + 0923 RigidBody::PositionOffset) = ( -2*contact.normal[0]); 0924 info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() + 0925 RigidBody::PositionOffset+1) = ( -2*contact.normal[1]); 0926 info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() + 0927 RigidBody::PositionOffset) = ( 2*contact.normal[0]); 0928 info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() + 0929 RigidBody::PositionOffset+1) = ( 2*contact.normal[1]); 0930 0931 if(contact.body0->metaObject()->inherits<RigidBody>()) { 0932 Vector2d r = static_cast<RigidBody*>(contact.body0)->position() - contact.points[p]; 0933 double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0]; 0934 info.jacobian.coeffRef(i, contact.body0->variablesOffset() + 0935 RigidBody::AngleOffset) = ( +rn); 0936 info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() + 0937 RigidBody::AngleOffset) = ( +2*rn); 0938 } 0939 0940 if(contact.body1->metaObject()->inherits<RigidBody>()) { 0941 Vector2d r = static_cast<RigidBody*>(contact.body1)->position() - contact.points[p]; 0942 double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0]; 0943 info.jacobian.coeffRef(i, contact.body1->variablesOffset() + 0944 RigidBody::AngleOffset) = ( -rn); 0945 info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() + 0946 RigidBody::AngleOffset) = ( -2*rn); 0947 } 0948 0949 info.forceMin[i] = 0; 0950 info.collisionFlag = true; 0951 } 0952 } 0953 } 0954 } 0955 0956 int GJKCollisionSolver::solvePolygonPolygon(Contact* contact) 0957 { 0958 RigidBody* body0 = static_cast<RigidBody*>(contact->body0); 0959 RigidBody* body1 = static_cast<RigidBody*>(contact->body1); 0960 0961 if(contact->pointsCount == 2 && 0962 contact->pointsState[0] == Contact::Colliding && 0963 contact->pointsState[1] == Contact::Colliding) { 0964 qDebug("*********** Two-point collisions are still buggy!"); 0965 } 0966 0967 // calculate impulse 0968 double b = 1; // coefficient of bounceness 0969 0970 int pointNum = (contact->pointsState[0] == Contact::Colliding ? 0 : 1); 0971 0972 double vrel = contact->vrel[pointNum]; 0973 STEPCORE_ASSERT_NOABORT( vrel < 0 ); 0974 0975 Vector2d r0 = contact->points[pointNum] - body0->position(); 0976 Vector2d r1 = contact->points[pointNum] - body1->position(); 0977 0978 double r0n = r0[0]*contact->normal[1] - r0[1]*contact->normal[0]; 0979 double r1n = r1[0]*contact->normal[1] - r1[1]*contact->normal[0]; 0980 0981 double term0 = (Vector2d( -r0n*r0[1], r0n*r0[0] )).dot(contact->normal) / body0->inertia(); 0982 double term1 = (Vector2d( -r1n*r1[1], r1n*r1[0] )).dot(contact->normal) / body1->inertia(); 0983 0984 double term2 = 1/body0->mass() + 1/body1->mass(); 0985 0986 /* 0987 qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1], 0988 body1->velocity()[0], body1->velocity()[1]); 0989 qDebug("body0=%p, body1=%p", body0, body1); 0990 qDebug("vrel=%f", vrel); 0991 qDebug("normal=(%f,%f)", contact->normal[0], contact->normal[1]); 0992 */ 0993 Vector2d j = contact->normal * ( -(1+b)*vrel / (term0 + term1 + term2) ); 0994 //qDebug("mass0=%f mass1=%f j=(%f,%f)", body0->mass(), body1->mass(), j[0], j[1]); 0995 body0->setVelocity(body0->velocity() - j / body0->mass()); 0996 body1->setVelocity(body1->velocity() + j / body1->mass()); 0997 body0->setAngularVelocity(body0->angularVelocity() - j.norm() * r0n / body0->inertia()); 0998 body1->setAngularVelocity(body1->angularVelocity() + j.norm() * r1n / body1->inertia()); 0999 1000 /* 1001 double vrel1 = (body1->velocityWorld(contact->points[pointNum]) - 1002 body0->velocityWorld(contact->points[pointNum])).dot(contact->normal); 1003 STEPCORE_ASSERT_NOABORT(vrel1 >= 0); 1004 qDebug("vrel1 = %f", vrel1); 1005 qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1], 1006 body1->velocity()[0], body1->velocity()[1]); 1007 qDebug(" "); 1008 */ 1009 contact->pointsState[pointNum] = Contact::Separating; 1010 contact->state = Contact::Separating; // XXX 1011 return 2;//CollisionDetected; 1012 } 1013 1014 int GJKCollisionSolver::solvePolygonDisk(Contact* contact) 1015 { 1016 RigidBody* body0 = static_cast<RigidBody*>(contact->body0); 1017 Disk* body1 = static_cast<Disk*>(contact->body1); 1018 1019 STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 ); 1020 1021 // calculate impulse 1022 double b = 1; // coefficient of bounceness 1023 1024 double vrel = contact->vrel[0]; 1025 STEPCORE_ASSERT_NOABORT( vrel < 0 ); 1026 1027 Vector2d r0 = contact->points[0] - body0->position(); 1028 double r0n = r0[0]*contact->normal[1] - r0[1]*contact->normal[0]; 1029 double term0 = (Vector2d( -r0n*r0[1], r0n*r0[0])).dot(contact->normal) / body0->inertia(); 1030 1031 double term2 = 1/body0->mass() + 1/body1->mass(); 1032 1033 /* 1034 qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1], 1035 body1->velocity()[0], body1->velocity()[1]); 1036 qDebug("body0=%p, body1=%p", body0, body1); 1037 qDebug("vrel=%f", vrel); 1038 qDebug("normal=(%f,%f)", contact->normal[0], contact->normal[1]); 1039 */ 1040 Vector2d j = contact->normal * ( -(1+b)*vrel / (term0 + term2) ); 1041 //qDebug("mass0=%f mass1=%f j=(%f,%f)", body0->mass(), body1->mass(), j[0], j[1]); 1042 body0->setVelocity(body0->velocity() - j / body0->mass()); 1043 body1->setVelocity(body1->velocity() + j / body1->mass()); 1044 body0->setAngularVelocity(body0->angularVelocity() - j.norm() * r0n / body0->inertia()); 1045 1046 /* 1047 double vrel1 = (body1->velocity() - 1048 body0->velocityWorld(contact->points[0])).dot(contact->normal); 1049 STEPCORE_ASSERT_NOABORT(vrel1 >= 0); 1050 qDebug("vrel1 = %f", vrel1); 1051 qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1], 1052 body1->velocity()[0], body1->velocity()[1]); 1053 qDebug(" "); 1054 */ 1055 contact->pointsState[0] = Contact::Separating; 1056 contact->state = Contact::Separating; // XXX 1057 return 2;//CollisionDetected; 1058 } 1059 1060 int GJKCollisionSolver::solvePolygonParticle(Contact* contact) 1061 { 1062 RigidBody* body0 = static_cast<RigidBody*>(contact->body0); 1063 Particle* body1 = static_cast<Particle*>(contact->body1); 1064 1065 STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 ); 1066 1067 // calculate impulse 1068 double b = 1; // coefficient of bounceness 1069 1070 double vrel = contact->vrel[0]; 1071 STEPCORE_ASSERT_NOABORT( vrel < 0 ); 1072 1073 Vector2d r0 = contact->points[0] - body0->position(); 1074 double r0n = r0[0]*contact->normal[1] - r0[1]*contact->normal[0]; 1075 double term0 = (Vector2d( -r0n*r0[1], r0n*r0[0])).dot(contact->normal) / body0->inertia(); 1076 1077 double term2 = 1/body0->mass() + 1/body1->mass(); 1078 1079 /* 1080 qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1], 1081 body1->velocity()[0], body1->velocity()[1]); 1082 qDebug("body0=%p, body1=%p", body0, body1); 1083 qDebug("vrel=%f", vrel); 1084 qDebug("normal=(%f,%f)", contact->normal[0], contact->normal[1]); 1085 */ 1086 Vector2d j = contact->normal * ( -(1+b)*vrel / (term0 + term2) ); 1087 //qDebug("mass0=%f mass1=%f j=(%f,%f)", body0->mass(), body1->mass(), j[0], j[1]); 1088 body0->setVelocity(body0->velocity() - j / body0->mass()); 1089 body1->setVelocity(body1->velocity() + j / body1->mass()); 1090 body0->setAngularVelocity(body0->angularVelocity() - j.norm() * r0n / body0->inertia()); 1091 1092 /* 1093 double vrel1 = (body1->velocity() - 1094 body0->velocityWorld(contact->points[0])).dot(contact->normal); 1095 STEPCORE_ASSERT_NOABORT(vrel1 >= 0); 1096 qDebug("vrel1 = %f", vrel1); 1097 qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1], 1098 body1->velocity()[0], body1->velocity()[1]); 1099 qDebug(" "); 1100 */ 1101 contact->pointsState[0] = Contact::Separating; 1102 contact->state = Contact::Separating; // XXX 1103 return 2;//CollisionDetected; 1104 } 1105 1106 int GJKCollisionSolver::solveDiskDisk(Contact* contact) 1107 { 1108 Disk* disk0 = static_cast<Disk*>(contact->body0); 1109 Disk* disk1 = static_cast<Disk*>(contact->body1); 1110 1111 STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 ); 1112 1113 // calculate impulse 1114 double b = 1; // coefficient of bounceness 1115 double vrel = contact->vrel[0]; 1116 STEPCORE_ASSERT_NOABORT( vrel < 0 ); 1117 1118 Vector2d j = contact->normal * ( -(1+b)*vrel / (1/disk0->mass() + 1/disk1->mass()) ); 1119 disk0->setVelocity(disk0->velocity() - j / disk0->mass()); 1120 disk1->setVelocity(disk1->velocity() + j / disk1->mass()); 1121 1122 contact->pointsState[0] = Contact::Separating; 1123 contact->state = Contact::Separating; // XXX 1124 return 2;//CollisionDetected; 1125 } 1126 1127 int GJKCollisionSolver::solveDiskParticle(Contact* contact) 1128 { 1129 Disk* disk0 = static_cast<Disk*>(contact->body0); 1130 Particle* particle1 = static_cast<Particle*>(contact->body1); 1131 1132 STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 ); 1133 1134 // calculate impulse 1135 double b = 1; // coefficient of bounceness 1136 double vrel = contact->vrel[0]; 1137 STEPCORE_ASSERT_NOABORT( vrel < 0 ); 1138 1139 Vector2d j = contact->normal * ( -(1+b)*vrel / (1/disk0->mass() + 1/particle1->mass()) ); 1140 disk0->setVelocity(disk0->velocity() - j / disk0->mass()); 1141 particle1->setVelocity(particle1->velocity() + j / particle1->mass()); 1142 1143 contact->pointsState[0] = Contact::Separating; 1144 contact->state = Contact::Separating; // XXX 1145 return 2;//CollisionDetected; 1146 } 1147 1148 int GJKCollisionSolver::solveCollisions(BodyList& bodies) 1149 { 1150 int ret = 0; 1151 1152 // Detect and classify contacts 1153 ret = checkContacts(bodies); 1154 STEPCORE_ASSERT_NOABORT(ret != Contact::Intersected); 1155 1156 // Solve collisions 1157 1158 const ContactValueList::iterator end = _contacts.end(); 1159 for(ContactValueList::iterator it = _contacts.begin(); it != end; ++it) { 1160 Contact& contact = *it; 1161 1162 if(contact.state != Contact::Colliding) continue; 1163 1164 if(contact.type == Contact::PolygonPolygonType) ret = solvePolygonPolygon(&contact); 1165 else if(contact.type == Contact::PolygonDiskType) ret = solvePolygonDisk(&contact); 1166 else if(contact.type == Contact::PolygonParticleType) ret = solvePolygonParticle(&contact); 1167 else if(contact.type == Contact::DiskDiskType) ret = solveDiskDisk(&contact); 1168 else if(contact.type == Contact::DiskParticleType) ret = solveDiskParticle(&contact); 1169 else { STEPCORE_ASSERT_NOABORT(0); } 1170 1171 } 1172 1173 return 0; 1174 } 1175 1176 #if 0 1177 int GJKCollisionSolver::solveConstraints(BodyList& /*bodies*/) 1178 { 1179 1180 return 0; 1181 } 1182 #endif 1183 1184 void GJKCollisionSolver::checkCache(BodyList& bodies) 1185 { 1186 if(!_contactsIsValid) { 1187 _contacts.clear(); 1188 1189 BodyList::const_iterator end = bodies.end(); 1190 for(BodyList::const_iterator i0 = bodies.begin(); i0 != end; ++i0) { 1191 for(BodyList::const_iterator i1 = i0+1; i1 != end; ++i1) { 1192 addContact(*i0, *i1); 1193 } 1194 } 1195 1196 _contactsIsValid = true; 1197 } 1198 } 1199 1200 void GJKCollisionSolver::bodyAdded(BodyList& bodies, Body* body) 1201 { 1202 if(!_contactsIsValid) return; 1203 1204 BodyList::const_iterator end = bodies.end(); 1205 for(BodyList::const_iterator i1 = bodies.begin(); i1 != end; ++i1) 1206 addContact(body, *i1); 1207 } 1208 1209 void GJKCollisionSolver::bodyRemoved(BodyList&, Body* body) 1210 { 1211 if(!_contactsIsValid) return; 1212 1213 for(;;) { 1214 const ContactValueList::iterator end = _contacts.end(); 1215 ContactValueList::iterator it = _contacts.begin(); 1216 for(; it != end; ++it) 1217 if((*it).body0 == body || (*it).body1 == body) break; 1218 if(it != end) _contacts.erase(it); 1219 else break; 1220 } 1221 } 1222 1223 void GJKCollisionSolver::addContact(Body* body0, Body* body1) 1224 { 1225 int type = Contact::UnknownType; 1226 1227 if(body1->metaObject()->inherits<BasePolygon>() && 1228 !body0->metaObject()->inherits<BasePolygon>()) { 1229 std::swap(body0, body1); 1230 } 1231 1232 if(body0->metaObject()->inherits<BasePolygon>()) { 1233 if(body1->metaObject()->inherits<BasePolygon>()) type = Contact::PolygonPolygonType; 1234 else if(body1->metaObject()->inherits<Disk>()) type = Contact::PolygonDiskType; 1235 else if(body1->metaObject()->inherits<Particle>()) type = Contact::PolygonParticleType; 1236 } else { 1237 1238 if(body1->metaObject()->inherits<Disk>() && 1239 !body0->metaObject()->inherits<Disk>()) { 1240 std::swap(body0, body1); 1241 } 1242 1243 if(body0->metaObject()->inherits<Disk>()) { 1244 if(body1->metaObject()->inherits<Disk>()) type = Contact::DiskDiskType; 1245 else if(body1->metaObject()->inherits<Particle>()) type = Contact::DiskParticleType; 1246 } 1247 1248 } 1249 1250 if(type != Contact::UnknownType) { 1251 Contact contact; 1252 contact.type = type; 1253 contact.body0 = body0; 1254 contact.body1 = body1; 1255 contact.state = Contact::Unknown; 1256 _contacts.push_back(contact); 1257 } 1258 } 1259 1260 void GJKCollisionSolver::resetCaches() 1261 { 1262 _contactsIsValid = false; 1263 } 1264 1265 } // namespace StepCore 1266