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