00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "collisionInterface.h"
00027
00028 #include <list>
00029
00030
00031 #include "debug.h"
00032
00033 extern "C" {
00034 #include <qhull_a.h>
00035 }
00036 #include <qmutex.h>
00037 extern QMutex qhull_mutex;
00038
00039 const int CollisionInterface::CONTACT_DUPLICATE_THRESHOLD = 3.0;
00040
00041 int CollisionInterface::mNextThreadId = 1;
00042 QMutex CollisionInterface::mMutex;
00043
00050 CollisionInterface::CollisionInterface()
00051 {
00052 int *threadId = new int(0);
00053 mThreadIdStorage.setLocalData( threadId );
00054 }
00055
00056 void
00057 CollisionInterface::newThread()
00058 {
00059 mMutex.lock();
00060 int *threadId = new int(mNextThreadId);
00061 mNextThreadId++;
00062 mMutex.unlock();
00063 mThreadIdStorage.setLocalData( threadId );
00064 }
00065
00066 int
00067 CollisionInterface::getThreadId()
00068 {
00069 int* threadId = mThreadIdStorage.localData();
00070 if (!threadId) return 0;
00071 return (*threadId);
00072 }
00073
00074 void
00075 CollisionInterface::compactContactSet(ContactReport *contacts)
00076 {
00077 if (contacts->size() < 2) return;
00078 DBGP("Compacting total contacts: " << contacts->size());
00079
00080 double NORMAL_TOLERANCE = 1e-3;
00081 double DISTANCE_TOLERANCE = 1.0e-1;
00082
00083
00084 std::list<ContactReport> contactGroups;
00085
00086
00087 ContactReport::iterator cp;
00088 std::list<ContactReport>::iterator sp;
00089 for (cp=contacts->begin(); cp!=contacts->end(); cp++) {
00090 for (sp=contactGroups.begin(); sp!=contactGroups.end(); sp++) {
00091 if ( sp->begin()->b1_normal % cp->b1_normal > 1.0-NORMAL_TOLERANCE) break;
00092 }
00093 if (sp == contactGroups.end()) {
00094 contactGroups.push_back(ContactReport());
00095 contactGroups.back().push_back(*cp);
00096 } else {
00097
00098 ContactReport::iterator it;
00099 for (it=sp->begin(); it!=sp->end(); it++) {
00100 vec3 dist = it->b1_pos - cp->b1_pos;
00101 if ( dist.len_sq() < DISTANCE_TOLERANCE) break;
00102 }
00103 if (it==sp->end()) sp->push_back(*cp);
00104 }
00105 }
00106
00107
00108 for (sp=contactGroups.begin(); sp!=contactGroups.end(); sp++) {
00109 DBGP("Set with same normal: " << sp->size());
00110 if (sp->size() > 1) replaceContactSetWithPerimeter(*sp);
00111 DBGP("Perimeter contacts: " << sp->size());
00112 }
00113
00114
00115 contacts->clear();
00116 for (sp=contactGroups.begin(); sp!=contactGroups.end(); sp++) {
00117 for (cp=sp->begin();cp!=sp->end();cp++) {
00118 contacts->push_back(*cp);
00119 }
00120 }
00121 }
00122
00123 void
00124 CollisionInterface::replaceContactSetWithPerimeter(ContactReport &contactSet)
00125 {
00126 if (contactSet.size() < 2) return;
00127
00128 double my_resabs = 1.0e-1;
00129
00130
00131 vec3 currLine, testLine;
00132 ContactReport::iterator endPt1 = contactSet.begin();
00133 ContactReport::iterator endPt2 = ++contactSet.begin();
00134 ContactReport::iterator cp;
00135 for (cp=contactSet.begin();cp!=contactSet.end();cp++) {
00136 currLine = endPt2->b1_pos - endPt1->b1_pos;
00137 testLine = cp->b1_pos - endPt1->b1_pos;
00138 vec3 crossProd = testLine * currLine;
00139 if ( crossProd.len() > my_resabs) break;
00140 double dot = testLine % currLine;
00141 if (dot < 0) endPt1 = cp;
00142 if (dot > currLine % currLine) endPt2 = cp;
00143 }
00144
00145 if (cp==contactSet.end()) {
00146
00147 ContactReport tmpSet;
00148 tmpSet.push_back(*endPt1);
00149 tmpSet.push_back(*endPt2);
00150 contactSet.clear();
00151 contactSet = tmpSet;
00152 return;
00153 }
00154
00155
00156 vec3 contactNormal = contactSet.begin()->b1_normal;
00157 vec3 normal = normalise(testLine * currLine);
00158 double Soffset = contactSet.begin()->b1_pos % normal;
00159 vec3 origin_pr = Soffset * normal;
00160
00161
00162 vec3 axis1 = normalise(testLine);
00163 vec3 axis2 = normal * axis1;
00164
00165 coordT *array = new coordT[contactSet.size()*2];
00166 coordT *ptr = &array[0];
00167 int ptCount = 0;
00168 for (cp=contactSet.begin(); cp!=contactSet.end(); cp++) {
00169 *ptr++ = (cp->b1_pos - position::ORIGIN) % axis1;
00170 *ptr++ = (cp->b1_pos - position::ORIGIN) % axis2;
00171 ptCount++;
00172 }
00173
00174 ContactReport tmpSet = contactSet;
00175 contactSet.clear();
00176
00177
00178 int exitcode,curlong,totlong;
00179 char options[200];
00180
00181
00182 qhull_mutex.lock();
00183
00184 bool ismalloc = False;
00185 FILE *qhfp = fopen("logfile","w");
00186 if (!qhfp) {
00187 fprintf(stderr,"Could not open qhull logfile!\n");
00188 qh_init_A(NULL, stdout, stderr, 0, NULL);
00189 } else {
00190 qh_init_A(NULL, qhfp, qhfp, 0, NULL);
00191 }
00192
00193 if(exitcode = setjmp(qh errexit)) {
00194 delete [] array;
00195 if (qhfp) fclose(qhfp);
00196 qhull_mutex.unlock();
00197 return;
00198 }
00199
00200 sprintf(options, "qhull n Pp");
00201 try {
00202 qh_initflags(options);
00203 qh_init_B(&array[0],ptCount, 2, ismalloc);
00204 qh_qhull();
00205 qh_check_output();
00206 } catch(...) {
00207
00208 DBGA("QHull CompactSet failed!!!");
00209
00210 contactSet.insert(contactSet.begin(), tmpSet.begin(), tmpSet.begin());
00211 delete [] array;
00212 fclose(qhfp);
00213 qhull_mutex.unlock();
00214 return;
00215 }
00216 fclose(qhfp);
00217
00218 vertexT *vertex;
00219 double x,y;
00220 ContactData tmpContact;
00221
00222
00223 FORALLvertices {
00224 x = vertex->point[0];
00225 y = vertex->point[1];
00226 tmpContact.b1_pos[0] = x * axis1[0] + y * axis2[0] + origin_pr[0];
00227 tmpContact.b1_pos[1] = x * axis1[1] + y * axis2[1] + origin_pr[1];
00228 tmpContact.b1_pos[2] = x * axis1[2] + y * axis2[2] + origin_pr[2];
00229 tmpContact.b1_normal = contactNormal;
00230
00231 for (cp=tmpSet.begin(); cp!=tmpSet.end(); cp++) {
00232 if (fabs(cp->b1_pos[0] - tmpContact.b1_pos[0]) < my_resabs &&
00233 fabs(cp->b1_pos[1] - tmpContact.b1_pos[1]) < my_resabs &&
00234 fabs(cp->b1_pos[2] - tmpContact.b1_pos[2]) < my_resabs &&
00235 fabs(cp->b1_normal[0] - tmpContact.b1_normal[0]) < my_resabs &&
00236 fabs(cp->b1_normal[1] - tmpContact.b1_normal[1]) < my_resabs &&
00237 fabs(cp->b1_normal[2] - tmpContact.b1_normal[2]) < my_resabs)
00238 break;
00239 }
00240 if (cp==tmpSet.end()) {
00241 } else {
00242 contactSet.push_back(*cp);
00243 }
00244 }
00245
00246 qh NOerrexit= True;
00247 qh_freeqhull(!qh_ALL);
00248 qh_memfreeshort (&curlong, &totlong);
00249 qhull_mutex.unlock();
00250 delete [] array;
00251 }
00252
00253 void
00254 CollisionInterface::removeContactDuplicates(ContactReport *contacts, double duplicateThreshold)
00255 {
00256 ContactReport::iterator it = contacts->begin();
00257 double threshSq = duplicateThreshold * duplicateThreshold;
00258
00259 while (it!=contacts->end()) {
00260
00261 bool removeMe = false;
00262 ContactReport::iterator it2 = it+1;
00263 while(it2 != contacts->end()) {
00264 if ( (it2->b1_pos - it->b1_pos).len_sq() > threshSq ||
00265 (it2->b2_pos - it->b2_pos).len_sq() > threshSq ) {
00266
00267 it2++;
00268 } else {
00269
00270 if (it->distSq < it2->distSq) {
00271
00272 it2 = contacts->erase(it2);
00273 } else {
00274
00275 removeMe = true;
00276 break;
00277 }
00278 }
00279 }
00280 if (removeMe) {
00281 it = contacts->erase(it);
00282 } else {
00283 it++;
00284 }
00285 }
00286 }