• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeedu API Reference
  • KDE Home
  • Contact Us
 

step/stepcore

  • sources
  • kde-4.12
  • kdeedu
  • step
  • stepcore
collisionsolver.cc
Go to the documentation of this file.
1 /* This file is part of StepCore library.
2  Copyright (C) 2007 Vladimir Kuznetsov <ks.vladimir@gmail.com>
3 
4  StepCore library is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  StepCore library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with StepCore; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include "collisionsolver.h"
20 #include "rigidbody.h"
21 #include "particle.h"
22 
23 #include <algorithm>
24 #include <QtGlobal>
25 
26 #define EIGEN_USE_NEW_STDVECTOR
27 #include <Eigen/StdVector>
28 
29 namespace StepCore {
30 
31 // XXX: units for toleranceAbs and localError
32 STEPCORE_META_OBJECT(CollisionSolver, QT_TRANSLATE_NOOP("ObjectClass", "CollisionSolver"), "CollisionSolver", MetaObject::ABSTRACT, STEPCORE_SUPER_CLASS(Object),
33  STEPCORE_PROPERTY_RW(double, toleranceAbs, QT_TRANSLATE_NOOP("PropertyName", "toleranceAbs"), STEPCORE_UNITS_1, QT_TR_NOOP("Allowed absolute tolerance"), toleranceAbs, setToleranceAbs)
34  STEPCORE_PROPERTY_R_D(double, localError, QT_TRANSLATE_NOOP("PropertyName", "localError"), STEPCORE_UNITS_1, QT_TR_NOOP("Maximal local error during last step"), localError))
35 
36 STEPCORE_META_OBJECT(GJKCollisionSolver, QT_TRANSLATE_NOOP("ObjectClass", "GJKCollisionSolver"), "GJKCollisionSolver", 0,
37  STEPCORE_SUPER_CLASS(CollisionSolver),)
38 
39 int GJKCollisionSolver::checkPolygonPolygon(Contact* contact)
40 {
41  BasePolygon* polygon0 = static_cast<BasePolygon*>(contact->body0);
42  BasePolygon* polygon1 = static_cast<BasePolygon*>(contact->body1);
43 
44  if(polygon0->vertexes().empty() || polygon1->vertexes().empty()) {
45  return contact->state = Contact::Unknown;
46  }
47 
48  // Algorithm description can be found in
49  // "A Fast and Robust GJK Implementation for
50  // Collision Detection of Convex Objects"
51  // by Gino van den Bergen
52 
53  Vector2dList vertexes[2];
54  vertexes[0].reserve(polygon0->vertexes().size());
55  vertexes[1].reserve(polygon1->vertexes().size());
56 
57  const Vector2dList::const_iterator p0_it_end = polygon0->vertexes().end();
58  for(Vector2dList::const_iterator it0 = polygon0->vertexes().begin();
59  it0 != p0_it_end; ++it0) {
60  vertexes[0].push_back(polygon0->pointLocalToWorld(*it0));
61  }
62 
63  const Vector2dList::const_iterator p1_it_end = polygon1->vertexes().end();
64  for(Vector2dList::const_iterator it1 = polygon1->vertexes().begin();
65  it1 != p1_it_end; ++it1) {
66  vertexes[1].push_back(polygon1->pointLocalToWorld(*it1));
67  }
68 
69  int wsize;
70  Vector2d w[3]; // Vertexes of current simplex
71  Vector2d v; // Closest point of current simplex
72  Vector2d s; // New support vertex in direction v
73 
74  Vector2d vv[2]; // Closest points on the first and second objects
75  int wi[2][3]; // Indexes of vertexes corresponding to w
76  int si[2] = {0, 0}; // Indexes of vertexes corresponding to s
77 
78  wsize = 1;
79  // Start with arbitrary vertex (TODO: cache the whole w simplex)
80  if(contact->state >= Contact::Separating && contact->state < Contact::Intersected) {
81  wi[0][0] = contact->_w1[0];
82  wi[1][0] = contact->_w1[1];
83  } else {
84  wi[0][0] = 0;
85  wi[1][0] = 0;
86  }
87  vv[0] = vertexes[0][wi[0][0]];
88  vv[1] = vertexes[1][wi[1][0]];
89  w[0] = v = vv[1] - vv[0];
90 
91  bool intersects = false;
92  unsigned int iteration = 0;
93  for(;; ++iteration) {
94  //STEPCORE_ASSERT_NOABORT( iteration < vertexes[0].size()*vertexes[1].size() );
95 
96  double smin = v.squaredNorm();
97 
98  // Check for penetration (part 1)
99  // If we are closer to the origin then given tolerance
100  // we should stop just now to avoid computational errors later
101  if(smin < _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance for penetration ?
102  intersects = true;
103  break;
104  }
105 
106  // Find support vertex in direction v
107  // TODO: coherence optimization
108  bool sfound = false;
109  unsigned int vertex0_size = vertexes[0].size();
110  unsigned int vertex1_size = vertexes[1].size();
111 
112  for(unsigned int i0=0; i0<vertex0_size; ++i0) {
113  for(unsigned int i1=0; i1<vertex1_size; ++i1) {
114  Vector2d sn = vertexes[1][i1] - vertexes[0][i0];
115  double scurr = v.dot(sn);
116  if(smin - scurr > _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance ?
117  smin = scurr;
118  s = sn;
119  si[0] = i0;
120  si[1] = i1;
121  sfound = true;
122  }
123  }
124  }
125 
126  // If no support vertex have been found than we are at minimum
127  if(!sfound) {
128  if(wsize == 0) { // we have guessed right point
129  w[0] = v;
130  wi[0][0] = 0;
131  wi[1][0] = 0;
132  wsize = 1;
133  }
134  break;
135  }
136 
137  // Check for penetration (part 2)
138  if(wsize == 2) {
139  // objects are penetrating if origin lies inside the simplex
140  // XXX: are there faster method to test it ?
141  Vector2d w02 = w[0] - s;
142  Vector2d w12 = w[1] - s;
143  double det = w02[0]*w12[1] - w02[1]*w12[0];
144  double det0 = -s[0]*w12[1] + s[1]*w12[0];
145  double det1 = -w02[0]* s[1] + w02[1]* s[0];
146  if(det0/det > 0 && det1/det > 0) { // XXX: tolerance
147  w[wsize] = s;
148  wi[0][wsize] = si[0];
149  wi[1][wsize] = si[1];
150  ++wsize;
151  v.setZero();
152  intersects = true;
153  break;
154  }
155  }
156 
157  // Find v = dist(conv(w+s))
158  double lambda = 0;
159  int ii = -1;
160  for(int i=0; i<wsize; ++i) {
161  double lambda0 = - s.dot(w[i]-s) / (w[i]-s).squaredNorm();
162  if(lambda0 > 0) {
163  Vector2d vn = s*(1-lambda0) + w[i]*lambda0;
164  if(vn.squaredNorm() < v.squaredNorm()) {
165  v = vn; ii = i;
166  lambda = lambda0;
167  }
168  }
169  }
170 
171  if(ii >= 0) { // Closest simplex is line
172  vv[0] = vertexes[0][si[0]]*(1-lambda) + vertexes[0][wi[0][ii]]*lambda;
173  vv[1] = vertexes[1][si[1]]*(1-lambda) + vertexes[1][wi[1][ii]]*lambda;
174  if(wsize == 2) {
175  w[1-ii] = s;
176  wi[0][1-ii] = si[0];
177  wi[1][1-ii] = si[1];
178  } else {
179  w[wsize] = s;
180  wi[0][wsize] = si[0];
181  wi[1][wsize] = si[1];
182  ++wsize;
183  }
184  } else { // Closest simplex is vertex
185  STEPCORE_ASSERT_NOABORT(iteration == 0 || s.squaredNorm() < v.squaredNorm());
186 
187  v = w[0] = s;
188  vv[0] = vertexes[0][si[0]];
189  vv[1] = vertexes[1][si[1]];
190  wi[0][0] = si[0];
191  wi[1][0] = si[1];
192  wsize = 1;
193  }
194  }
195 
196  if(intersects) {
197  /*
198  qDebug("penetration detected");
199  qDebug("iteration = %d", iteration);
200  qDebug("simplexes:");
201  qDebug(" 1: 2:");
202  for(int i=0; i<wsize; ++i) {
203  qDebug(" %d %d", wi[0][i], wi[1][i]);
204  }
205  */
206  contact->distance = 0;
207  contact->normal.setZero();
208  contact->pointsCount = 0;
209  return contact->state = Contact::Intersected;
210  }
211 
212  /*
213  qDebug("distance = %f", v.norm());
214  Vector2d v1 = v / v.norm();
215  qDebug("normal = (%f,%f)", v1[0], v1[1]);
216  qDebug("iteration = %d", iteration);
217  qDebug("simplexes:");
218  qDebug(" 1: 2:");
219  for(int i=0; i<wsize; ++i) {
220  qDebug(" %d %d", wi[0][i], wi[1][i]);
221  }
222  qDebug("contact points:");
223  qDebug(" (%f,%f) (%f,%f)", vv[0][0], vv[0][1], vv[1][0], vv[1][1]);
224  */
225 
226  double vnorm = v.norm();
227  contact->distance = vnorm;
228  contact->normal = v/vnorm;
229  contact->pointsCount = 0;
230  contact->state = Contact::Separated;
231 
232  contact->_w1[0] = wi[0][0];
233  contact->_w1[1] = wi[1][0];
234 
235  if(vnorm > _toleranceAbs) return contact->state;
236 
237  // If the objects are close enough we need to find contact manifold
238  // We are going to find simplexes (lines) that are 'most parallel'
239  // to contact plane and look for contact manifold among them. It
240  // works for almost all cases when adjacent polygon edges are
241  // not parallel
242  Vector2d vunit = v / vnorm;
243  Vector2d wm[2][2];
244 
245  for(int i=0; i<2; ++i) {
246  wm[i][0] = vertexes[i][ wi[i][0] ];
247 
248  if(wsize < 2 || wi[i][0] == wi[i][1]) { // vertex contact
249  // Check two adjacent edges
250  int ai1 = wi[i][0] - 1; if(ai1 < 0) ai1 = vertexes[i].size()-1;
251  Vector2d av1 = vertexes[i][ai1];
252  Vector2d dv1 = wm[i][0] - av1;
253  double dist1 = vunit.dot( dv1 ) * (i==0 ? 1 : -1);
254  double angle1 = dist1 / dv1.norm();
255 
256  int ai2 = wi[i][0] + 1; if(ai2 >= (int) vertexes[i].size()) ai2 = 0;
257  Vector2d av2 = vertexes[i][ai2];
258  Vector2d dv2 = wm[i][0] - av2;
259  double dist2 = vunit.dot( dv2 ) * (i==0 ? 1 : -1);
260  double angle2 = dist2 / dv2.norm();
261 
262  if(angle1 <= angle2 && dist1 < (_toleranceAbs-vnorm)/2) {
263  wm[i][1] = av1;
264  } else if(angle2 <= angle1 && dist2 < (_toleranceAbs-vnorm)/2) {
265  wm[i][1] = av2;
266  } else {
267  wm[i][1] = wm[i][0]; contact->pointsCount = 1;
268  break;
269  }
270  } else { // edge contact
271  wm[i][1] = vertexes[i][ wi[i][1] ];
272  }
273  }
274 
275  // Find intersection of two lines
276  if(contact->pointsCount != 1) {
277  Vector2d vunit_o(-vunit[1], vunit[0]);
278  double wm_o[2][2];
279 
280  for(int i=0; i<2; ++i) {
281  wm_o[i][0] = vunit_o.dot(wm[i][0]);
282  wm_o[i][1] = vunit_o.dot(wm[i][1]);
283 
284  if(wm_o[i][0] > wm_o[i][1]) {
285  std::swap(wm_o[i][0], wm_o[i][1]);
286  std::swap(wm[i][0], wm[i][1]);
287  }
288  }
289 
290  if(wm_o[0][0] > wm_o[1][0]) contact->points[0] = wm[0][0];
291  else contact->points[0] = wm[1][0];
292 
293  if(wm_o[0][1] < wm_o[1][1]) contact->points[1] = wm[0][1];
294  else contact->points[1] = wm[1][1];
295 
296  // TODO: interpolate to midpoint
297  if((contact->points[1] - contact->points[0]).norm() > _toleranceAbs) {
298  /*
299  for(int i=0; i<2; ++i) {
300  qDebug("contact%d: (%f,%f)", i, contact->points[i][0], contact->points[i][1]);
301  }
302  */
303  contact->pointsCount = 2;
304  }
305  /*
306  contact->vrel[0] = contact->normal.dot(
307  polygon1->velocityWorld(contact->points[0]) -
308  polygon0->velocityWorld(contact->points[0]));
309  contact->vrel[1] = contact->normal.dot(
310  polygon1->velocityWorld(contact->points[1]) -
311  polygon0->velocityWorld(contact->points[1]));
312  if(contact->vrel[0] < 0 || contact->vrel[1] < 0)
313  return contact->state = Contact::Colliding;
314  else if(contact->vrel[0] < _toleranceAbs || contact->vrel[1] < _toleranceAbs) // XXX: tolerance
315  return contact->state = Colliding::Contacted;
316  return contact->state = Contact::Separating;
317  }
318  */
319  }
320 
321  if(contact->pointsCount != 2) {
322  contact->pointsCount = 1;
323  contact->points[0] = vv[0]; // TODO: interpolate vv[0] and vv[1]
324  //qDebug("contact is one point: (%f %f) (%f %f)", vv[0][0], vv[0][1], vv[1][0], vv[1][1]);
325  }
326 
327  int pCount = contact->pointsCount;
328  for(int i=0; i<pCount; ++i) {
329  contact->vrel[i] = contact->normal.dot(
330  polygon1->velocityWorld(contact->points[i]) -
331  polygon0->velocityWorld(contact->points[i]));
332 
333  if(contact->vrel[i] < 0)
334  contact->pointsState[i] = Contact::Colliding;
335  else if(contact->vrel[i] < _toleranceAbs) // XXX: tolerance
336  contact->pointsState[i] = Contact::Contacted;
337  else contact->pointsState[i] = Contact::Separating;
338 
339  if(contact->pointsState[i] > contact->state)
340  contact->state = contact->pointsState[i];
341  }
342 
343  contact->normalDerivative.setZero(); //XXX
344  return contact->state;
345 }
346 
347 int GJKCollisionSolver::checkPolygonDisk(Contact* contact)
348 {
349  BasePolygon* polygon0 = static_cast<BasePolygon*>(contact->body0);
350  Disk* disk1 = static_cast<Disk*>(contact->body1);
351 
352  if(polygon0->vertexes().empty()) {
353  return contact->state = Contact::Unknown;
354  }
355 
356  // Simplier version of checkPolygonPolygon algorithm
357 
358  Vector2dList vertexes;
359  vertexes.reserve(polygon0->vertexes().size());
360 
361  const Vector2dList::const_iterator p0_it_end = polygon0->vertexes().end();
362  for(Vector2dList::const_iterator it0 = polygon0->vertexes().begin();
363  it0 != p0_it_end; ++it0) {
364  vertexes.push_back(polygon0->pointLocalToWorld(*it0));
365  }
366 
367  int wsize;
368  Vector2d w[3]; // Vertexes of current simplex
369  Vector2d v; // Closest point of current simplex
370  Vector2d s; // New support vertex in direction v
371 
372  Vector2d vv; // Closest points on the polygon
373  int wi[3]; // Indexes of vertexes corresponding to w
374  int si = 0; // Indexes of vertexes corresponding to s
375 
376  // Start with arbitrary vertex (TODO: cache the whole w simplex)
377  wsize = 1;
378  if(contact->state >= Contact::Separating && contact->state < Contact::Intersected) {
379  wi[0] = contact->_w1[0];
380  } else {
381  wi[0] = 0;
382  }
383  vv = vertexes[wi[0]];
384  w[0] = v = disk1->position() - vv;
385 
386  bool intersects = false;
387  unsigned int iteration = 0;
388  for(;; ++iteration) {
389  //STEPCORE_ASSERT_NOABORT( iteration < vertexes.size()*vertexes.size() );
390 
391  double smin = v.squaredNorm();
392 
393  // Check for penetration (part 1)
394  // If we are closer to the origin then given tolerance
395  // we should stop just now to avoid computational errors later
396  if(std::sqrt(smin) - disk1->radius() < _toleranceAbs*1e-2) { // XXX: separate tolerance for penetration ?
397  intersects = true;
398  break;
399  }
400 
401  // Find support vertex in direction v
402  // TODO: coherence optimization
403  bool sfound = false;
404  unsigned int vertex_size = vertexes.size();
405 
406  for(unsigned int i0=0; i0<vertex_size; ++i0) {
407  Vector2d sn = disk1->position() - vertexes[i0];
408  double scurr = v.dot(sn);
409  if(smin - scurr > _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance ?
410  smin = scurr;
411  s = sn;
412  si = i0;
413  sfound = true;
414  }
415  }
416 
417  // If no support vertex have been found than we are at minimum
418  if(!sfound) {
419  if(wsize == 0) { // we have guessed right point
420  w[0] = v;
421  wi[0] = 0;
422  wsize = 1;
423  }
424  break;
425  }
426 
427  // Check for penetration (part 2)
428  if(wsize == 2) {
429  // objects are penetrating if origin lies inside the simplex
430  // XXX: are there faster method to test it ?
431  Vector2d w02 = w[0] - s;
432  Vector2d w12 = w[1] - s;
433  Vector2d s0 = s - s.normalized() * disk1->radius();
434  double det = w02[0]*w12[1] - w02[1]*w12[0];
435  double det0 = -s0[0]*w12[1] + s0[1]*w12[0];
436  double det1 = -w02[0]* s0[1] + w02[1]* s0[0];
437  if(det0/det > 0 && det1/det > 0) { // XXX: tolerance
438  w[wsize] = s;
439  wi[wsize] = si;
440  ++wsize;
441  v.setZero();
442  intersects = true;
443  break;
444  }
445  }
446 
447  // Find v = dist(conv(w+s))
448  double lambda = 0;
449  int ii = -1;
450  for(int i=0; i<wsize; ++i) {
451  double lambda0 = - s.dot(w[i]-s) / (w[i]-s).squaredNorm();
452  if(lambda0 > 0) {
453  Vector2d vn = s*(1-lambda0) + w[i]*lambda0;
454  if(vn.squaredNorm() < v.squaredNorm()) {
455  v = vn; ii = i;
456  lambda = lambda0;
457  }
458  }
459  }
460 
461  if(ii >= 0) { // Closest simplex is line
462  vv = vertexes[si]*(1-lambda) + vertexes[wi[ii]]*lambda;
463  if(wsize == 2) {
464  w[1-ii] = s;
465  wi[1-ii] = si;
466  } else {
467  w[wsize] = s;
468  wi[wsize] = si;
469  ++wsize;
470  }
471  } else { // Closest simplex is vertex
472  STEPCORE_ASSERT_NOABORT(iteration == 0 || s.squaredNorm() < v.squaredNorm());
473 
474  v = w[0] = s;
475  vv = vertexes[si];
476  wi[0] = si;
477  wsize = 1;
478  }
479  }
480 
481  if(intersects) {
482  /*qDebug("penetration detected");
483  qDebug("iteration = %d", iteration);
484  qDebug("simplexes:");
485  qDebug(" 1: 2:");
486  for(int i=0; i<wsize; ++i) {
487  qDebug(" %d %d", wi[i], wi[i]);
488  }*/
489  contact->distance = 0;
490  contact->normal.setZero();
491  contact->pointsCount = 0;
492  return contact->state = Contact::Intersected;
493  }
494 
495  /*
496  qDebug("distance = %f", v.norm());
497  Vector2d v1 = v / v.norm();
498  qDebug("normal = (%f,%f)", v1[0], v1[1]);
499  qDebug("iteration = %d", iteration);
500  qDebug("simplexes:");
501  qDebug(" 1: 2:");
502  for(int i=0; i<wsize; ++i) {
503  qDebug(" %d %d", wi[i], wi[i]);
504  }
505  qDebug("contact points:");
506  qDebug(" (%f,%f) (%f,%f)", vv[0], vv[1], vv[0], vv[1]);
507  */
508 
509  double vnorm = v.norm();
510  contact->distance = vnorm - disk1->radius();
511  contact->normal = v/vnorm;
512 
513  contact->_w1[0] = wi[0];
514 
515  if(contact->distance > _toleranceAbs) {
516  contact->pointsCount = 0;
517  contact->state = Contact::Separated;
518  return contact->state;
519  }/* else if(contact->distance < _toleranceAbs*1e-2) {
520  contact->state = Contact::Intersected;
521  return contact->state;
522  }*/
523 
524  contact->pointsCount = 1;
525  contact->points[0] = disk1->position() - contact->normal * disk1->radius();
526  contact->vrel[0] = contact->normal.dot(
527  disk1->velocity() -
528  polygon0->velocityWorld(contact->points[0]));
529 
530  if(contact->vrel[0] < 0)
531  contact->pointsState[0] = Contact::Colliding;
532  else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance
533  contact->pointsState[0] = Contact::Contacted;
534  else contact->pointsState[0] = Contact::Separating;
535 
536  contact->normalDerivative.setZero(); //XXX
537  contact->state = contact->pointsState[0];
538  return contact->state;
539 }
540 
541 int GJKCollisionSolver::checkPolygonParticle(Contact* contact)
542 {
543  BasePolygon* polygon0 = static_cast<BasePolygon*>(contact->body0);
544  Particle* particle1 = static_cast<Particle*>(contact->body1);
545 
546  if(polygon0->vertexes().empty()) {
547  return contact->state = Contact::Unknown;
548  }
549 
550  // Simplier version of checkPolygonPolygon algorithm
551 
552  Vector2dList vertexes;
553  vertexes.reserve(polygon0->vertexes().size());
554 
555  const Vector2dList::const_iterator p0_it_end = polygon0->vertexes().end();
556  for(Vector2dList::const_iterator it0 = polygon0->vertexes().begin();
557  it0 != p0_it_end; ++it0) {
558  vertexes.push_back(polygon0->pointLocalToWorld(*it0));
559  }
560 
561  int wsize;
562  Vector2d w[3]; // Vertexes of current simplex
563  Vector2d v; // Closest point of current simplex
564  Vector2d s; // New support vertex in direction v
565 
566  Vector2d vv; // Closest points on the polygon
567  int wi[3]; // Indexes of vertexes corresponding to w
568  int si = 0; // Indexes of vertexes corresponding to s
569 
570  // Start with arbitrary vertex (TODO: cache the whole w simplex)
571  wsize = 1;
572  if(contact->state >= Contact::Separating && contact->state < Contact::Intersected) {
573  wi[0] = contact->_w1[0];
574  } else {
575  wi[0] = 0;
576  }
577  vv = vertexes[wi[0]];
578  w[0] = v = particle1->position() - vv;
579 
580  bool intersects = false;
581  unsigned int iteration = 0;
582  for(;; ++iteration) {
583  //STEPCORE_ASSERT_NOABORT( iteration < vertexes[0].size()*vertexes[1].size() );
584 
585  double smin = v.squaredNorm();
586 
587  // Check for penetration (part 1)
588  // If we are closer to the origin then given tolerance
589  // we should stop just now to avoid computational errors later
590  if(smin < _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance for penetration ?
591  intersects = true;
592  break;
593  }
594 
595  // Find support vertex in direction v
596  // TODO: coherence optimization
597  bool sfound = false;
598  unsigned int vertex_size = vertexes.size();
599 
600  for(unsigned int i0=0; i0<vertex_size; ++i0) {
601  Vector2d sn = particle1->position() - vertexes[i0];
602  double scurr = v.dot(sn);
603  if(smin - scurr > _toleranceAbs*_toleranceAbs*1e-4) { // XXX: separate tolerance ?
604  smin = scurr;
605  s = sn;
606  si = i0;
607  sfound = true;
608  }
609  }
610 
611  // If no support vertex have been found than we are at minimum
612  if(!sfound) {
613  if(wsize == 0) { // we have guessed right point
614  w[0] = v;
615  wi[0] = 0;
616  wsize = 1;
617  }
618  break;
619  }
620 
621  // Check for penetration (part 2)
622  if(wsize == 2) {
623  // objects are penetrating if origin lies inside the simplex
624  // XXX: are there faster method to test it ?
625  Vector2d w02 = w[0] - s;
626  Vector2d w12 = w[1] - s;
627  double det = w02[0]*w12[1] - w02[1]*w12[0];
628  double det0 = -s[0]*w12[1] + s[1]*w12[0];
629  double det1 = -w02[0]* s[1] + w02[1]* s[0];
630  if(det0/det > 0 && det1/det > 0) { // XXX: tolerance
631  w[wsize] = s;
632  wi[wsize] = si;
633  ++wsize;
634  v.setZero();
635  intersects = true;
636  break;
637  }
638  }
639 
640  // Find v = dist(conv(w+s))
641  double lambda = 0;
642  int ii = -1;
643  for(int i=0; i<wsize; ++i) {
644  double lambda0 = - s.dot(w[i]-s) / (w[i]-s).squaredNorm();
645  if(lambda0 > 0) {
646  Vector2d vn = s*(1-lambda0) + w[i]*lambda0;
647  if(vn.squaredNorm() < v.squaredNorm()) {
648  v = vn; ii = i;
649  lambda = lambda0;
650  }
651  }
652  }
653 
654  if(ii >= 0) { // Closest simplex is line
655  vv = vertexes[si]*(1-lambda) + vertexes[wi[ii]]*lambda;
656  if(wsize == 2) {
657  w[1-ii] = s;
658  wi[1-ii] = si;
659  } else {
660  w[wsize] = s;
661  wi[wsize] = si;
662  ++wsize;
663  }
664  } else { // Closest simplex is vertex
665  STEPCORE_ASSERT_NOABORT(iteration == 0 || s.squaredNorm() < v.squaredNorm());
666 
667  v = w[0] = s;
668  vv = vertexes[si];
669  wi[0] = si;
670  wsize = 1;
671  }
672  }
673 
674  if(intersects) {
675  /*
676  qDebug("penetration detected");
677  qDebug("iteration = %d", iteration);
678  qDebug("simplexes:");
679  qDebug(" 1: 2:");
680  for(int i=0; i<wsize; ++i) {
681  qDebug(" %d %d", wi[0][i], wi[1][i]);
682  }
683  */
684  contact->distance = 0;
685  contact->normal.setZero();
686  contact->pointsCount = 0;
687  return contact->state = Contact::Intersected;
688  }
689 
690  /*
691  qDebug("distance = %f", v.norm());
692  Vector2d v1 = v / v.norm();
693  qDebug("normal = (%f,%f)", v1[0], v1[1]);
694  qDebug("iteration = %d", iteration);
695  qDebug("simplexes:");
696  qDebug(" 1: 2:");
697  for(int i=0; i<wsize; ++i) {
698  qDebug(" %d %d", wi[0][i], wi[1][i]);
699  }
700  qDebug("contact points:");
701  qDebug(" (%f,%f) (%f,%f)", vv[0][0], vv[0][1], vv[1][0], vv[1][1]);
702  */
703 
704  double vnorm = v.norm();
705  contact->distance = vnorm;
706  contact->normal = v/vnorm;
707 
708  contact->_w1[0] = wi[0];
709 
710  if(vnorm > _toleranceAbs) {
711  contact->pointsCount = 0;
712  contact->state = Contact::Separated;
713  return contact->state;
714  }
715 
716  contact->pointsCount = 1;
717  contact->points[0] = particle1->position();
718  contact->vrel[0] = contact->normal.dot(
719  particle1->velocity() -
720  polygon0->velocityWorld(contact->points[0]));
721 
722  if(contact->vrel[0] < 0)
723  contact->pointsState[0] = Contact::Colliding;
724  else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance
725  contact->pointsState[0] = Contact::Contacted;
726  else contact->pointsState[0] = Contact::Separating;
727 
728  contact->state = contact->pointsState[0];
729  return contact->state;
730 }
731 
732 int GJKCollisionSolver::checkDiskDisk(Contact* contact)
733 {
734  Disk* disk0 = static_cast<Disk*>(contact->body0);
735  Disk* disk1 = static_cast<Disk*>(contact->body1);
736 
737  Vector2d r = disk1->position() - disk0->position();
738  double rd = disk1->radius() + disk0->radius();
739  double rn = r.norm();
740  contact->normal = r/rn;
741  contact->distance = rn - rd;
742 
743  if(contact->distance > _toleranceAbs) {
744  contact->state = Contact::Separated;
745  return contact->state;
746  } else if(contact->distance < 0) {
747  contact->state = Contact::Intersected;
748  return contact->state;
749  }
750 
751  contact->pointsCount = 1;
752  contact->points[0] = disk0->position() + contact->normal * disk0->radius();
753 
754  Vector2d v = disk1->velocity() - disk0->velocity();
755  contact->vrel[0] = contact->normal.dot(v);
756  contact->normalDerivative = v / rn - (r.dot(v)/rn/rn/rn) * r;
757 
758  if(contact->vrel[0] < 0)
759  contact->pointsState[0] = Contact::Colliding;
760  else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance
761  contact->pointsState[0] = Contact::Contacted;
762  else contact->pointsState[0] = Contact::Separating;
763 
764  contact->normalDerivative.setZero(); //XXX
765  contact->state = contact->pointsState[0];
766  return contact->state;
767 }
768 
769 int GJKCollisionSolver::checkDiskParticle(Contact* contact)
770 {
771  Disk* disk0 = static_cast<Disk*>(contact->body0);
772  Particle* particle1 = static_cast<Particle*>(contact->body1);
773 
774  Vector2d r = particle1->position() - disk0->position();
775  double rd = disk0->radius();
776  double rn = r.norm();
777  contact->normal = r/rn;
778  contact->distance = rn - rd;
779 
780  if(contact->distance > _toleranceAbs) {
781  contact->state = Contact::Separated;
782  return contact->state;
783  } else if(contact->distance < _toleranceAbs*1e-2) {
784  contact->state = Contact::Intersected;
785  return contact->state;
786  }
787 
788  contact->pointsCount = 1;
789  contact->points[0] = disk0->position() + contact->normal * disk0->radius();
790 
791  Vector2d v = particle1->velocity() - disk0->velocity();
792  contact->vrel[0] = contact->normal.dot(v);
793  contact->normalDerivative = v / rn - (r.dot(v)/rn/rn/rn) * r;
794 
795  if(contact->vrel[0] < 0)
796  contact->pointsState[0] = Contact::Colliding;
797  else if(contact->vrel[0] < _toleranceAbs) // XXX: tolerance
798  contact->pointsState[0] = Contact::Contacted;
799  else contact->pointsState[0] = Contact::Separating;
800 
801  contact->state = contact->pointsState[0];
802  return contact->state;
803 }
804 
805 
806 /*
807 int GJKCollisionSolver::checkContact(Contact* contact)
808 {
809 
810  if(contact->type == Contact::UnknownType) {
811  if(contact->body0->metaObject()->inherits<BasePolygon>()) {
812  if(contact->body1->metaObject()->inherits<BasePolygon>()) contact->type = Contact::PolygonPolygonType;
813  else if(contact->body1->metaObject()->inherits<Particle>()) contact->type = Contact::PolygonParticleType;
814  } else if(contact->body0->metaObject()->inherits<Particle>()) {
815  if(contact->body1->metaObject()->inherits<BasePolygon>()) {
816  std::swap(contact->body0, contact->body1);
817  contact->type = Contact::PolygonParticleType;
818  }
819  }
820  contact->state = Contact::Unknown;
821  }
822 
823  if(contact->type == Contact::PolygonPolygonType) return checkPolygonPolygon(contact);
824  else if(contact->type == Contact::PolygonParticleType) return checkPolygonParticle(contact);
825  return contact->state = Contact::Unknown;
826 }*/
827 
828 inline int GJKCollisionSolver::checkContact(Contact* contact)
829 {
830  if(contact->type == Contact::PolygonPolygonType) checkPolygonPolygon(contact);
831  else if(contact->type == Contact::PolygonDiskType) checkPolygonDisk(contact);
832  else if(contact->type == Contact::PolygonParticleType) checkPolygonParticle(contact);
833  else if(contact->type == Contact::DiskDiskType) checkDiskDisk(contact);
834  else if(contact->type == Contact::DiskParticleType) checkDiskParticle(contact);
835  else contact->state = Contact::Unknown;
836  return contact->state;
837 }
838 
839 int GJKCollisionSolver::checkContacts(BodyList& bodies, bool collisions, int* retCount)
840 {
841  int state = Contact::Unknown;
842  int count = 0;
843 
844  checkCache(bodies);
845 
846  // Detect and classify contacts...
847  // ... and count contact joints
848  const ContactValueList::iterator end = _contacts.end();
849  for(ContactValueList::iterator it = _contacts.begin(); it != end; ++it) {
850  Contact& contact = *it;
851 
852  checkContact(&contact);
853 
854  if(contact.state > state) state = contact.state;
855  if( (it->state == Contact::Contacted) || (collisions && it->state == Contact::Colliding) )
856  count += it->pointsCount;
857  }
858  if (retCount) *retCount = count;
859  return state;
860 }
861 
862 void GJKCollisionSolver::getContactsInfo(ConstraintsInfo& info, bool collisions)
863 {
864  const ContactValueList::iterator end = _contacts.end();
865 
866  int i = info.constraintsCount-1;
867  // Add contact joints
868  for(ContactValueList::iterator it = _contacts.begin(); it != end; ++it) {
869  Contact& contact = *it;
870  if(contact.state == Contact::Contacted) {
871  //qDebug("** resting contact, points: %d", contact.pointsCount);
872  for(int p=0; p<contact.pointsCount; ++p) {
873  // XXX: check signs !
874  // XXX: rotation and friction !
875  /*info.value[i0] = contact.normal[0] * contact.distance;
876  info.value[i1] = contact.normal[1] * contact.distance;
877  info.derivative[i0] = contact.normal[0] * contact.vrel[0];
878  info.derivative[i1] = contact.normal[1] * contact.vrel[0];*/
879  /*info.value[i] = contact.distance;
880  info.derivative[i] = contact.vrel[p];*/
881  ++i;
882  info.jacobian.coeffRef(i, contact.body0->variablesOffset() + RigidBody::PositionOffset) = -contact.normal[0];
883  info.jacobian.coeffRef(i, contact.body0->variablesOffset() + RigidBody::PositionOffset+1) = -contact.normal[1];
884  info.jacobian.coeffRef(i, contact.body1->variablesOffset() + RigidBody::PositionOffset) = contact.normal[0];
885  info.jacobian.coeffRef(i, contact.body1->variablesOffset() + RigidBody::PositionOffset+1) = contact.normal[1];
886 
887  if(!collisions) {
888  info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() +
889  RigidBody::PositionOffset) = ( -contact.normalDerivative[0]);
890  info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() +
891  RigidBody::PositionOffset+1) = ( -contact.normalDerivative[1]);
892  info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() +
893  RigidBody::PositionOffset) = ( contact.normalDerivative[0]);
894  info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() +
895  RigidBody::PositionOffset+1) = ( contact.normalDerivative[1]);
896  }
897 
898  if(contact.body0->metaObject()->inherits<RigidBody>()) {
899  Vector2d r = static_cast<RigidBody*>(contact.body0)->position() - contact.points[p];
900  Vector2d v = static_cast<RigidBody*>(contact.body0)->velocity();
901  double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0];
902  double rd = v[0]*contact.normal[1] - v[1]*contact.normal[0] +
903  r[0]*contact.normalDerivative[1] - r[1]*contact.normalDerivative[0];
904  info.jacobian.coeffRef(i, contact.body0->variablesOffset() +
905  RigidBody::AngleOffset) = ( +rn);
906  if(!collisions)
907  info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() +
908  RigidBody::AngleOffset) = ( +rd);
909  }
910 
911  if(contact.body1->metaObject()->inherits<RigidBody>()) {
912  Vector2d r = static_cast<RigidBody*>(contact.body1)->position() - contact.points[p];
913  Vector2d v = static_cast<RigidBody*>(contact.body1)->velocity();
914  double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0];
915  double rd = v[0]*contact.normal[1] - v[1]*contact.normal[0] +
916  r[0]*contact.normalDerivative[1] - r[1]*contact.normalDerivative[0];
917  info.jacobian.coeffRef(i, contact.body1->variablesOffset() + RigidBody::AngleOffset) = -rn;
918  if(!collisions)
919  info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() + RigidBody::AngleOffset) = -rd;
920  }
921  info.forceMin[i] = 0;
922  }
923 
924  } else if(collisions && contact.state == Contact::Colliding) {
925  //qDebug("** collision, points: %d", contact.pointsCount);
926  for(int p = 0; p<contact.pointsCount; ++p) {
927  ++i;
928  info.jacobian.coeffRef(i, contact.body0->variablesOffset() +
929  RigidBody::PositionOffset) = ( -contact.normal[0]);
930  info.jacobian.coeffRef(i, contact.body0->variablesOffset() +
931  RigidBody::PositionOffset+1) = ( -contact.normal[1]);
932  info.jacobian.coeffRef(i, contact.body1->variablesOffset() +
933  RigidBody::PositionOffset) = ( contact.normal[0]);
934  info.jacobian.coeffRef(i, contact.body1->variablesOffset() +
935  RigidBody::PositionOffset+1) = ( contact.normal[1]);
936 
937  // jacobianDerivative is special in this case: it is not really
938  // a derivative, but rather just an expression that should be in
939  // constraint equation
940  info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() +
941  RigidBody::PositionOffset) = ( -2*contact.normal[0]);
942  info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() +
943  RigidBody::PositionOffset+1) = ( -2*contact.normal[1]);
944  info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() +
945  RigidBody::PositionOffset) = ( 2*contact.normal[0]);
946  info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() +
947  RigidBody::PositionOffset+1) = ( 2*contact.normal[1]);
948 
949  if(contact.body0->metaObject()->inherits<RigidBody>()) {
950  Vector2d r = static_cast<RigidBody*>(contact.body0)->position() - contact.points[p];
951  double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0];
952  info.jacobian.coeffRef(i, contact.body0->variablesOffset() +
953  RigidBody::AngleOffset) = ( +rn);
954  info.jacobianDerivative.coeffRef(i, contact.body0->variablesOffset() +
955  RigidBody::AngleOffset) = ( +2*rn);
956  }
957 
958  if(contact.body1->metaObject()->inherits<RigidBody>()) {
959  Vector2d r = static_cast<RigidBody*>(contact.body1)->position() - contact.points[p];
960  double rn = r[0]*contact.normal[1] - r[1]*contact.normal[0];
961  info.jacobian.coeffRef(i, contact.body1->variablesOffset() +
962  RigidBody::AngleOffset) = ( -rn);
963  info.jacobianDerivative.coeffRef(i, contact.body1->variablesOffset() +
964  RigidBody::AngleOffset) = ( -2*rn);
965  }
966 
967  info.forceMin[i] = 0;
968  info.collisionFlag = true;
969  }
970  }
971  }
972 }
973 
974 int GJKCollisionSolver::solvePolygonPolygon(Contact* contact)
975 {
976  RigidBody* body0 = static_cast<RigidBody*>(contact->body0);
977  RigidBody* body1 = static_cast<RigidBody*>(contact->body1);
978 
979  if(contact->pointsCount == 2 &&
980  contact->pointsState[0] == Contact::Colliding &&
981  contact->pointsState[1] == Contact::Colliding) {
982  qDebug("*********** Two-point collisions are still buggy!");
983  }
984 
985  // calculate impulse
986  double b = 1; // coefficient of bounceness
987 
988  int pointNum = (contact->pointsState[0] == Contact::Colliding ? 0 : 1);
989 
990  double vrel = contact->vrel[pointNum];
991  STEPCORE_ASSERT_NOABORT( vrel < 0 );
992 
993  Vector2d r0 = contact->points[pointNum] - body0->position();
994  Vector2d r1 = contact->points[pointNum] - body1->position();
995 
996  double r0n = r0[0]*contact->normal[1] - r0[1]*contact->normal[0];
997  double r1n = r1[0]*contact->normal[1] - r1[1]*contact->normal[0];
998 
999  double term0 = contact->normal.dot(
1000  Vector2d( -r0n*r0[1], r0n*r0[0] )) / body0->inertia();
1001  double term1 = contact->normal.dot(
1002  Vector2d( -r1n*r1[1], r1n*r1[0] )) / body1->inertia();
1003 
1004  double term2 = 1/body0->mass() + 1/body1->mass();
1005 
1006  /*
1007  qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1],
1008  body1->velocity()[0], body1->velocity()[1]);
1009  qDebug("body0=%p, body1=%p", body0, body1);
1010  qDebug("vrel=%f", vrel);
1011  qDebug("normal=(%f,%f)", contact->normal[0], contact->normal[1]);
1012  */
1013  Vector2d j = contact->normal * ( -(1+b)*vrel / (term0 + term1 + term2) );
1014  //qDebug("mass0=%f mass1=%f j=(%f,%f)", body0->mass(), body1->mass(), j[0], j[1]);
1015  body0->setVelocity(body0->velocity() - j / body0->mass());
1016  body1->setVelocity(body1->velocity() + j / body1->mass());
1017  body0->setAngularVelocity(body0->angularVelocity() - j.norm() * r0n / body0->inertia());
1018  body1->setAngularVelocity(body1->angularVelocity() + j.norm() * r1n / body1->inertia());
1019 
1020  /*
1021  double vrel1 = contact->normal.dot(
1022  body1->velocityWorld(contact->points[pointNum]) -
1023  body0->velocityWorld(contact->points[pointNum]));
1024  STEPCORE_ASSERT_NOABORT(vrel1 >= 0);
1025  qDebug("vrel1 = %f", vrel1);
1026  qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1],
1027  body1->velocity()[0], body1->velocity()[1]);
1028  qDebug(" ");
1029  */
1030  contact->pointsState[pointNum] = Contact::Separating;
1031  contact->state = Contact::Separating; // XXX
1032  return 2;//CollisionDetected;
1033 }
1034 
1035 int GJKCollisionSolver::solvePolygonDisk(Contact* contact)
1036 {
1037  RigidBody* body0 = static_cast<RigidBody*>(contact->body0);
1038  Disk* body1 = static_cast<Disk*>(contact->body1);
1039 
1040  STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 );
1041 
1042  // calculate impulse
1043  double b = 1; // coefficient of bounceness
1044 
1045  double vrel = contact->vrel[0];
1046  STEPCORE_ASSERT_NOABORT( vrel < 0 );
1047 
1048  Vector2d r0 = contact->points[0] - body0->position();
1049  double r0n = r0[0]*contact->normal[1] - r0[1]*contact->normal[0];
1050  double term0 = contact->normal.dot(
1051  Vector2d( -r0n*r0[1], r0n*r0[0] )) / body0->inertia();
1052 
1053  double term2 = 1/body0->mass() + 1/body1->mass();
1054 
1055  /*
1056  qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1],
1057  body1->velocity()[0], body1->velocity()[1]);
1058  qDebug("body0=%p, body1=%p", body0, body1);
1059  qDebug("vrel=%f", vrel);
1060  qDebug("normal=(%f,%f)", contact->normal[0], contact->normal[1]);
1061  */
1062  Vector2d j = contact->normal * ( -(1+b)*vrel / (term0 + term2) );
1063  //qDebug("mass0=%f mass1=%f j=(%f,%f)", body0->mass(), body1->mass(), j[0], j[1]);
1064  body0->setVelocity(body0->velocity() - j / body0->mass());
1065  body1->setVelocity(body1->velocity() + j / body1->mass());
1066  body0->setAngularVelocity(body0->angularVelocity() - j.norm() * r0n / body0->inertia());
1067 
1068  /*
1069  double vrel1 = contact->normal.dot(
1070  body1->velocity() -
1071  body0->velocityWorld(contact->points[0]));
1072  STEPCORE_ASSERT_NOABORT(vrel1 >= 0);
1073  qDebug("vrel1 = %f", vrel1);
1074  qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1],
1075  body1->velocity()[0], body1->velocity()[1]);
1076  qDebug(" ");
1077  */
1078  contact->pointsState[0] = Contact::Separating;
1079  contact->state = Contact::Separating; // XXX
1080  return 2;//CollisionDetected;
1081 }
1082 
1083 int GJKCollisionSolver::solvePolygonParticle(Contact* contact)
1084 {
1085  RigidBody* body0 = static_cast<RigidBody*>(contact->body0);
1086  Particle* body1 = static_cast<Particle*>(contact->body1);
1087 
1088  STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 );
1089 
1090  // calculate impulse
1091  double b = 1; // coefficient of bounceness
1092 
1093  double vrel = contact->vrel[0];
1094  STEPCORE_ASSERT_NOABORT( vrel < 0 );
1095 
1096  Vector2d r0 = contact->points[0] - body0->position();
1097  double r0n = r0[0]*contact->normal[1] - r0[1]*contact->normal[0];
1098  double term0 = contact->normal.dot(
1099  Vector2d( -r0n*r0[1], r0n*r0[0] )) / body0->inertia();
1100 
1101  double term2 = 1/body0->mass() + 1/body1->mass();
1102 
1103  /*
1104  qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1],
1105  body1->velocity()[0], body1->velocity()[1]);
1106  qDebug("body0=%p, body1=%p", body0, body1);
1107  qDebug("vrel=%f", vrel);
1108  qDebug("normal=(%f,%f)", contact->normal[0], contact->normal[1]);
1109  */
1110  Vector2d j = contact->normal * ( -(1+b)*vrel / (term0 + term2) );
1111  //qDebug("mass0=%f mass1=%f j=(%f,%f)", body0->mass(), body1->mass(), j[0], j[1]);
1112  body0->setVelocity(body0->velocity() - j / body0->mass());
1113  body1->setVelocity(body1->velocity() + j / body1->mass());
1114  body0->setAngularVelocity(body0->angularVelocity() - j.norm() * r0n / body0->inertia());
1115 
1116  /*
1117  double vrel1 = contact->normal.dot(
1118  body1->velocity() -
1119  body0->velocityWorld(contact->points[0]));
1120  STEPCORE_ASSERT_NOABORT(vrel1 >= 0);
1121  qDebug("vrel1 = %f", vrel1);
1122  qDebug("vel0=(%f,%f) vel1=(%f,%f)", body0->velocity()[0], body0->velocity()[1],
1123  body1->velocity()[0], body1->velocity()[1]);
1124  qDebug(" ");
1125  */
1126  contact->pointsState[0] = Contact::Separating;
1127  contact->state = Contact::Separating; // XXX
1128  return 2;//CollisionDetected;
1129 }
1130 
1131 int GJKCollisionSolver::solveDiskDisk(Contact* contact)
1132 {
1133  Disk* disk0 = static_cast<Disk*>(contact->body0);
1134  Disk* disk1 = static_cast<Disk*>(contact->body1);
1135 
1136  STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 );
1137 
1138  // calculate impulse
1139  double b = 1; // coefficient of bounceness
1140  double vrel = contact->vrel[0];
1141  STEPCORE_ASSERT_NOABORT( vrel < 0 );
1142 
1143  Vector2d j = contact->normal * ( -(1+b)*vrel / (1/disk0->mass() + 1/disk1->mass()) );
1144  disk0->setVelocity(disk0->velocity() - j / disk0->mass());
1145  disk1->setVelocity(disk1->velocity() + j / disk1->mass());
1146 
1147  contact->pointsState[0] = Contact::Separating;
1148  contact->state = Contact::Separating; // XXX
1149  return 2;//CollisionDetected;
1150 }
1151 
1152 int GJKCollisionSolver::solveDiskParticle(Contact* contact)
1153 {
1154  Disk* disk0 = static_cast<Disk*>(contact->body0);
1155  Particle* particle1 = static_cast<Particle*>(contact->body1);
1156 
1157  STEPCORE_ASSERT_NOABORT( contact->pointsCount == 1 );
1158 
1159  // calculate impulse
1160  double b = 1; // coefficient of bounceness
1161  double vrel = contact->vrel[0];
1162  STEPCORE_ASSERT_NOABORT( vrel < 0 );
1163 
1164  Vector2d j = contact->normal * ( -(1+b)*vrel / (1/disk0->mass() + 1/particle1->mass()) );
1165  disk0->setVelocity(disk0->velocity() - j / disk0->mass());
1166  particle1->setVelocity(particle1->velocity() + j / particle1->mass());
1167 
1168  contact->pointsState[0] = Contact::Separating;
1169  contact->state = Contact::Separating; // XXX
1170  return 2;//CollisionDetected;
1171 }
1172 
1173 int GJKCollisionSolver::solveCollisions(BodyList& bodies)
1174 {
1175  int ret = 0;
1176 
1177  // Detect and classify contacts
1178  ret = checkContacts(bodies);
1179  STEPCORE_ASSERT_NOABORT(ret != Contact::Intersected);
1180 
1181  // Solve collisions
1182 
1183  const ContactValueList::iterator end = _contacts.end();
1184  for(ContactValueList::iterator it = _contacts.begin(); it != end; ++it) {
1185  Contact& contact = *it;
1186 
1187  if(contact.state != Contact::Colliding) continue;
1188 
1189  if(contact.type == Contact::PolygonPolygonType) ret = solvePolygonPolygon(&contact);
1190  else if(contact.type == Contact::PolygonDiskType) ret = solvePolygonDisk(&contact);
1191  else if(contact.type == Contact::PolygonParticleType) ret = solvePolygonParticle(&contact);
1192  else if(contact.type == Contact::DiskDiskType) ret = solveDiskDisk(&contact);
1193  else if(contact.type == Contact::DiskParticleType) ret = solveDiskParticle(&contact);
1194  else { STEPCORE_ASSERT_NOABORT(0); }
1195 
1196  }
1197 
1198  return 0;
1199 }
1200 
1201 #if 0
1202 int GJKCollisionSolver::solveConstraints(BodyList& /*bodies*/)
1203 {
1204 
1205  return 0;
1206 }
1207 #endif
1208 
1209 void GJKCollisionSolver::checkCache(BodyList& bodies)
1210 {
1211  if(!_contactsIsValid) {
1212  _contacts.clear();
1213 
1214  BodyList::const_iterator end = bodies.end();
1215  for(BodyList::const_iterator i0 = bodies.begin(); i0 != end; ++i0) {
1216  for(BodyList::const_iterator i1 = i0+1; i1 != end; ++i1) {
1217  addContact(*i0, *i1);
1218  }
1219  }
1220 
1221  _contactsIsValid = true;
1222  }
1223 }
1224 
1225 void GJKCollisionSolver::bodyAdded(BodyList& bodies, Body* body)
1226 {
1227  if(!_contactsIsValid) return;
1228 
1229  BodyList::const_iterator end = bodies.end();
1230  for(BodyList::const_iterator i1 = bodies.begin(); i1 != end; ++i1)
1231  addContact(body, *i1);
1232 }
1233 
1234 void GJKCollisionSolver::bodyRemoved(BodyList&, Body* body)
1235 {
1236  if(!_contactsIsValid) return;
1237 
1238  for(;;) {
1239  const ContactValueList::iterator end = _contacts.end();
1240  ContactValueList::iterator it = _contacts.begin();
1241  for(; it != end; ++it)
1242  if((*it).body0 == body || (*it).body1 == body) break;
1243  if(it != end) _contacts.erase(it);
1244  else break;
1245  }
1246 }
1247 
1248 void GJKCollisionSolver::addContact(Body* body0, Body* body1)
1249 {
1250  int type = Contact::UnknownType;
1251 
1252  if(body1->metaObject()->inherits<BasePolygon>() &&
1253  !body0->metaObject()->inherits<BasePolygon>()) {
1254  std::swap(body0, body1);
1255  }
1256 
1257  if(body0->metaObject()->inherits<BasePolygon>()) {
1258  if(body1->metaObject()->inherits<BasePolygon>()) type = Contact::PolygonPolygonType;
1259  else if(body1->metaObject()->inherits<Disk>()) type = Contact::PolygonDiskType;
1260  else if(body1->metaObject()->inherits<Particle>()) type = Contact::PolygonParticleType;
1261  } else {
1262 
1263  if(body1->metaObject()->inherits<Disk>() &&
1264  !body0->metaObject()->inherits<Disk>()) {
1265  std::swap(body0, body1);
1266  }
1267 
1268  if(body0->metaObject()->inherits<Disk>()) {
1269  if(body1->metaObject()->inherits<Disk>()) type = Contact::DiskDiskType;
1270  else if(body1->metaObject()->inherits<Particle>()) type = Contact::DiskParticleType;
1271  }
1272 
1273  }
1274 
1275  if(type != Contact::UnknownType) {
1276  Contact contact;
1277  contact.type = type;
1278  contact.body0 = body0;
1279  contact.body1 = body1;
1280  contact.state = Contact::Unknown;
1281  _contacts.push_back(contact);
1282  }
1283 }
1284 
1285 void GJKCollisionSolver::resetCaches()
1286 {
1287  _contactsIsValid = false;
1288 }
1289 
1290 } // namespace StepCore
1291 
StepCore::Particle::mass
double mass() const
Get mass of the particle.
Definition: particle.h:138
StepCore::ConstraintsInfo::jacobianDerivative
DynSparseRowMatrix jacobianDerivative
Time-derivative of constraintsJacobian.
Definition: world.h:226
rigidbody.h
RigidBody class.
StepCore::Particle::setVelocity
void setVelocity(const Vector2d &velocity)
Set velocity of the particle.
Definition: particle.h:124
StepCore::GJKCollisionSolver::solveCollisions
int solveCollisions(BodyList &bodies)
Solve the collisions between bodies.
Definition: collisionsolver.cc:1173
StepCore::Contact::body0
Body * body0
Body0.
Definition: collisionsolver.h:64
StepCore::Contact::PolygonDiskType
Definition: collisionsolver.h:58
StepCore::Body
Interface for bodies.
Definition: world.h:138
StepCore::Contact::state
int state
Contact state (maximum of pointsState if pointsCount > 0)
Definition: collisionsolver.h:66
StepCore::BasePolygon::vertexes
const Vector2dList & vertexes() const
Get vertex list (constant)
Definition: rigidbody.h:319
StepCore::RigidBody::velocityWorld
Vector2d velocityWorld(const Vector2d &worldPoint) const
Get velocity of given (world) point on the body.
Definition: rigidbody.cc:189
StepCore::Contact
Description of contact between two bodies.
Definition: collisionsolver.h:43
StepCore::RigidBody::AngleOffset
Offset of body angle in variables array.
Definition: rigidbody.h:151
STEPCORE_ASSERT_NOABORT
#define STEPCORE_ASSERT_NOABORT(expr)
Definition: util.h:58
StepCore::RigidBody::PositionOffset
Offset of body position in variables array.
Definition: rigidbody.h:150
StepCore::GJKCollisionSolver::resetCaches
void resetCaches()
Reset internal caches of collision information.
Definition: collisionsolver.cc:1285
StepCore::GJKCollisionSolver::bodyAdded
void bodyAdded(BodyList &bodies, Body *body)
Definition: collisionsolver.cc:1225
StepCore::GJKCollisionSolver::solvePolygonParticle
int solvePolygonParticle(Contact *contact)
Definition: collisionsolver.cc:1083
StepCore::RigidBody::setVelocity
void setVelocity(const Vector2d &velocity)
Set velocity of the particle.
Definition: rigidbody.h:172
StepCore::Vector2d
Eigen::Vector2d Vector2d
Two-dimensional vector with double components.
Definition: vector.h:29
StepCore::Disk
Rigid disk.
Definition: rigidbody.h:285
StepCore::GJKCollisionSolver::checkDiskParticle
int checkDiskParticle(Contact *contact)
Definition: collisionsolver.cc:769
StepCore::RigidBody::angularVelocity
double angularVelocity() const
Get angular velocity of the body.
Definition: rigidbody.h:179
StepCore::Object
Root of the StepCore classes hierarchy.
Definition: object.h:57
StepCore::Contact::DiskParticleType
Definition: collisionsolver.h:61
StepCore::Contact::Contacted
Bodies are contacted but resting.
Definition: collisionsolver.h:51
StepCore::RigidBody::position
const Vector2d & position() const
Get position of the center of mass of the body.
Definition: rigidbody.h:160
StepCore::STEPCORE_SUPER_CLASS
STEPCORE_SUPER_CLASS(CollisionSolver)
StepCore::Contact::Separating
Bodies are contacted but moving apart.
Definition: collisionsolver.h:50
StepCore::Contact::Intersected
Bodies are interpenetrating.
Definition: collisionsolver.h:53
StepCore::RigidBody
Rigid body.
Definition: rigidbody.h:144
StepCore::ConstraintsInfo::forceMin
VectorXd forceMin
Constraints force lower limit.
Definition: world.h:233
collisionsolver.h
CollisionSolver interface.
StepCore::ConstraintsInfo::constraintsCount
int constraintsCount
Number of constraints equations.
Definition: world.h:219
StepCore::GJKCollisionSolver::addContact
void addContact(Body *body0, Body *body1)
Definition: collisionsolver.cc:1248
StepCore::ConstraintsInfo::jacobian
DynSparseRowMatrix jacobian
Position-derivative of constraints values.
Definition: world.h:225
StepCore::QT_TRANSLATE_NOOP
QT_TRANSLATE_NOOP("ObjectClass","GJKCollisionSolver")
StepCore::GJKCollisionSolver::solvePolygonDisk
int solvePolygonDisk(Contact *contact)
Definition: collisionsolver.cc:1035
StepCore::RigidBody::mass
double mass() const
Get mass of the body.
Definition: rigidbody.h:208
StepCore::Contact::Colliding
Bodies are collising.
Definition: collisionsolver.h:52
StepCore::GJKCollisionSolver
Discrete collision solver using Gilbert-Johnson-Keerthi distance algorithm.
Definition: collisionsolver.h:154
StepCore::GJKCollisionSolver::checkCache
void checkCache(BodyList &bodies)
Definition: collisionsolver.cc:1209
StepCore::RigidBody::setAngularVelocity
void setAngularVelocity(double angularVelocity)
Set angular velocity of the body.
Definition: rigidbody.h:181
StepCore::Contact::UnknownType
Definition: collisionsolver.h:56
StepCore::GJKCollisionSolver::bodyRemoved
void bodyRemoved(BodyList &bodies, Body *body)
Definition: collisionsolver.cc:1234
StepCore::Contact::pointsCount
int pointsCount
Count of contact points (either one or two)
Definition: collisionsolver.h:70
StepCore::GJKCollisionSolver::solveDiskDisk
int solveDiskDisk(Contact *contact)
Definition: collisionsolver.cc:1131
StepCore::RigidBody::inertia
double inertia() const
Get inertia "tensor" of the body.
Definition: rigidbody.h:213
StepCore::Contact::points
Vector2d points[2]
Contact point coordinated.
Definition: collisionsolver.h:72
StepCore::RigidBody::pointLocalToWorld
Vector2d pointLocalToWorld(const Vector2d &p) const
Translate local coordinates on body to world coordinates.
Definition: rigidbody.cc:201
StepCore::MetaObject::ABSTRACT
Class is abstract.
Definition: object.h:180
StepCore::CollisionSolver::_toleranceAbs
double _toleranceAbs
Definition: collisionsolver.h:137
StepCore::RigidBody::velocity
const Vector2d & velocity() const
Get velocity of the center of mass of the body.
Definition: rigidbody.h:170
StepCore::BodyList
std::vector< Body * > BodyList
List of pointers to Body.
Definition: world.h:300
StepCore::QT_TR_NOOP
QT_TR_NOOP("Errors class for CoulombForce")
StepCore::STEPCORE_UNITS_1
STEPCORE_UNITS_1
Definition: world.cc:43
StepCore::GJKCollisionSolver::checkPolygonParticle
int checkPolygonParticle(Contact *contact)
Definition: collisionsolver.cc:541
StepCore::STEPCORE_PROPERTY_RW
STEPCORE_PROPERTY_RW(double, depth, QT_TRANSLATE_NOOP("PropertyName","depth"), QT_TRANSLATE_NOOP("Units","J"), QT_TR_NOOP("Potential depth"), depth, setDepth) STEPCORE_PROPERTY_RW(double
StepCore::GJKCollisionSolver::_contacts
ContactValueList _contacts
Definition: collisionsolver.h:207
StepCore::Contact::PolygonParticleType
Definition: collisionsolver.h:59
StepCore::Contact::normal
Vector2d normal
Contact normal (pointing from body0 to body1)
Definition: collisionsolver.h:68
StepCore::GJKCollisionSolver::checkContact
int checkContact(Contact *contact)
Definition: collisionsolver.cc:828
StepCore::CollisionSolver
Collision solver interface.
Definition: collisionsolver.h:85
StepCore::Contact::Unknown
Contact state was not (can not) be determined (if state == Unknown all other fields are not used) ...
Definition: collisionsolver.h:47
StepCore::Particle
Particle with mass.
Definition: particle.h:103
StepCore::GJKCollisionSolver::checkPolygonDisk
int checkPolygonDisk(Contact *contact)
Definition: collisionsolver.cc:347
StepCore::GJKCollisionSolver::_contactsIsValid
bool _contactsIsValid
Definition: collisionsolver.h:208
StepCore::Contact::DiskDiskType
Definition: collisionsolver.h:60
StepCore::GJKCollisionSolver::checkDiskDisk
int checkDiskDisk(Contact *contact)
Definition: collisionsolver.cc:732
StepCore::GJKCollisionSolver::checkPolygonPolygon
int checkPolygonPolygon(Contact *contact)
Definition: collisionsolver.cc:39
StepCore::Contact::normalDerivative
Vector2d normalDerivative
Time derivative of contact normal (only if state == Contacted)
Definition: collisionsolver.h:69
StepCore::Contact::pointsState
int pointsState[2]
Contact point states.
Definition: collisionsolver.h:71
StepCore::STEPCORE_PROPERTY_R_D
setRmin setRminVariance STEPCORE_PROPERTY_R_D(double, rectPressureVariance, QT_TRANSLATE_NOOP("PropertyName","rectPressureVariance"), QT_TRANSLATE_NOOP("Units","Pa"), QT_TR_NOOP("Variance of pressure of particles in the measureRect"), rectPressureVariance) STEPCORE_PROPERTY_R_D(double
StepCore::BasePolygon
Base class for all polygons.
Definition: rigidbody.h:308
particle.h
Particle and ChargedParticle classes.
StepCore::Contact::PolygonPolygonType
Definition: collisionsolver.h:57
StepCore::Contact::_w1
int _w1[2]
Definition: collisionsolver.h:77
StepCore::Particle::position
const Vector2d & position() const
Get position of the particle.
Definition: particle.h:117
StepCore::STEPCORE_META_OBJECT
STEPCORE_META_OBJECT(CollisionSolver, QT_TRANSLATE_NOOP("ObjectClass","CollisionSolver"),"CollisionSolver", MetaObject::ABSTRACT, STEPCORE_SUPER_CLASS(Object), STEPCORE_PROPERTY_RW(double, toleranceAbs, QT_TRANSLATE_NOOP("PropertyName","toleranceAbs"), STEPCORE_UNITS_1, QT_TR_NOOP("Allowed absolute tolerance"), toleranceAbs, setToleranceAbs) STEPCORE_PROPERTY_R_D(double, localError, QT_TRANSLATE_NOOP("PropertyName","localError"), STEPCORE_UNITS_1, QT_TR_NOOP("Maximal local error during last step"), localError)) STEPCORE_META_OBJECT(GJKCollisionSolver
StepCore::Vector2dList
std::vector< Vector2d, Eigen::aligned_allocator< Vector2d > > Vector2dList
Definition: types.h:117
StepCore::Contact::type
int type
Contact type (used internally)
Definition: collisionsolver.h:63
StepCore::GJKCollisionSolver::solvePolygonPolygon
int solvePolygonPolygon(Contact *contact)
Definition: collisionsolver.cc:974
StepCore::Body::variablesOffset
int variablesOffset() const
Offset of body's variables in global arrays (meaningless if the body is not a part of the world) ...
Definition: world.h:181
StepCore::Particle::velocity
const Vector2d & velocity() const
Get velocity of the particle.
Definition: particle.h:122
StepCore::GJKCollisionSolver::checkContacts
int checkContacts(BodyList &bodies, bool collisions=false, int *count=NULL)
Check (and update) state of the contact.
Definition: collisionsolver.cc:839
StepCore::Contact::Separated
Bodies are far away.
Definition: collisionsolver.h:49
StepCore::ConstraintsInfo::collisionFlag
bool collisionFlag
True if there is a collision to be resolved.
Definition: world.h:238
StepCore::Contact::vrel
double vrel[2]
Relative velocities at contact points.
Definition: collisionsolver.h:73
StepCore::Contact::body1
Body * body1
Body1.
Definition: collisionsolver.h:65
StepCore::Disk::radius
double radius() const
Get disk radius.
Definition: rigidbody.h:297
StepCore::ConstraintsInfo
Constraints information structure XXX: Move it to constraintsolver.h.
Definition: world.h:216
StepCore::Contact::distance
double distance
Distance between bodies.
Definition: collisionsolver.h:67
StepCore::GJKCollisionSolver::getContactsInfo
void getContactsInfo(ConstraintsInfo &info, bool collisions=false)
Fill the constraint info structure with the contacts computed by checkContacts()
Definition: collisionsolver.cc:862
StepCore::GJKCollisionSolver::solveDiskParticle
int solveDiskParticle(Contact *contact)
Definition: collisionsolver.cc:1152
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:43:06 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

step/stepcore

Skip menu "step/stepcore"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdeedu API Reference

Skip menu "kdeedu API Reference"
  • Analitza
  •     lib
  • kalgebra
  • kalzium
  •   libscience
  • kanagram
  • kig
  •   lib
  • klettres
  • kstars
  • libkdeedu
  •   keduvocdocument
  • marble
  • parley
  • rocs
  •   App
  •   RocsCore
  •   VisualEditor
  •   stepcore

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal