00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <stdio.h>
00010 #include <iostream>
00011 using namespace std;
00012 #include "collide_serial.h"
00013 #include "charm.h"
00014
00015 #define DEBUG_CHECKS 0 //Check invariants
00016
00017 static void print(const rSeg1d &s) {
00018 printf("[%.3g,%.3g]",s.getMin(),s.getMax());
00019 }
00020
00021 #if 0
00022 static void print(const vector3d &v) {
00023 printf("(%.3g,%.3g,%.3g) ",v.x,v.y,v.z);
00024 }
00025 #endif
00026 void bbox3d::print(const char *desc) const
00027 {
00028 if (desc) printf("%s: ",desc);
00029
00030
00031 printf("(%.3g,%.3g,%.3g) - (%.3g,%.3g,%.3g) ",
00032 axis(0).getMin(),axis(1).getMin(),axis(2).getMin(),
00033 axis(0).getMax(),axis(1).getMax(),axis(2).getMax());
00034 }
00035
00036 void CollideOctant::print(const char *desc) const
00037 {
00038 if (desc) printf("%s: ",desc);
00039 printf("%d home, %d boundary; ",nHome,length()-nHome);
00040 box.print("\nbbox");
00041 printf("\n");
00042 }
00043
00044 #if COLLIDE_STATS
00045 void stats::print(void)
00046 {
00047 const char *names[3]={"x","y","z"};
00048 int i;
00049 cout<<"---- Run-time statistics: ---"<<endl;
00050 cout<<"objects= "<<objects<<endl;
00051 cout<<"gridCells= "<<gridCells<<endl;
00052 cout<<"gridAdds= "<<gridAdds<<endl;
00053
00054 cout<<"gridSizes (ave)= ";
00055 for (i=0;i<3;i++) cout<<(double)gridSizes[i]/objects<<names[i]<<" ";
00056 cout<<endl;
00057
00058 cout<<"recursiveCalls= "<<recursiveCalls<<endl;
00059 cout<<"rejHomo = "<< rejHomo <<endl;
00060 cout<<"simpleCalls = "<< simpleCalls <<endl;
00061 cout<<"simpleFallbackCalls = "<< simpleFallbackCalls <<endl;
00062
00063 cout<<"splits = ";
00064 for (i=0;i<3;i++) cout<<splits[i]<<names[i]<<" ";
00065 cout<<endl;
00066 cout<<"splitFailures = ";
00067 for (i=0;i<3;i++) cout<<splitFailures[i]<<names[i]<<" ";
00068 cout<<endl;
00069
00070 cout<<"pivots = "<< pivots <<endl;
00071 cout<<"rejID = "<< rejID <<endl;
00072 cout<<"rejBbox = "<< rejBbox <<endl;
00073 cout<<"rejTerritory = ";
00074 for (i=0;i<3;i++) cout<<rejTerritory[i]<<names[i]<<" ";
00075 cout<<endl;
00076 cout<<"rejCollide = "<< rejCollide <<endl;
00077 cout<<"Collisions = "<< Collisions <<endl;
00078 }
00079 int stats::objects=0;
00080 int stats::gridCells=0;
00081 int stats::gridAdds=0;
00082 int stats::gridSizes[3]={0,0,0};
00083 int stats::recursiveCalls=0;
00084 int stats::simpleCalls=0;
00085 int stats::simpleFallbackCalls=0;
00086 int stats::splits[3]={0,0,0};
00087 int stats::splitFailures[3]={0,0,0};
00088 int stats::pivots=0;
00089 int stats::rejHomo=0;
00090 int stats::rejID=0;
00091 int stats::rejBbox=0;
00092 int stats::rejTerritory[3]={0,0,0};
00093 int stats::rejCollide=0;
00094 int stats::Collisions=0;
00095 #endif
00096
00097
00098 void CollideOctant::check(void) const
00099 {
00100 if (nHome>length()) CkAbort("nHome cannot exceed n");
00101 if (nHome<=0) CkAbort("nHome cannot be negative or zero");
00102 if (length()<0) CkAbort("n cannot be negative");
00103 if (box.isEmpty()) CkAbort("Bbox is empty");
00104 int i;
00105 for (i=0;i<nHome;i++)
00106 if (!box.contains(at(i)->getBbox().getSmallest()))
00107 CkAbort("'Home' element not in bbox");
00108 for (i=nHome;i<length();i++) {
00109 if (!box.intersects(at(i)->getBbox()))
00110 CkAbort("contained element does not touch us");
00111 vector3d s=at(i)->getBbox().getSmallest();
00112 if (box.containsOpen(s))
00113 CkAbort("non-home element should be home");
00114 }
00115 }
00116
00118
00119 CollideOctant::~CollideOctant() {}
00120 void CollideOctant::add(const CollideObjRec *p) {
00121 push_back(p);
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132 template <class T>
00133 inline void myswap(T &a,T &b) {T tmp(a);a=b;b=tmp;}
00134
00135 int CollideOctant::splitAt(int alongAxis)
00136 {
00137 CollideOctant &us=*this;
00138
00139
00140 int target=nHome/2;
00141 int lo=0, hi=nHome-1;
00142 int attempts=0;
00143 int l=-1,r=-1;
00144 STATS(splits[alongAxis]++)
00145 while (lo<hi) {
00146 attempts++; STATS(pivots++)
00147
00148
00149 int pivot = (lo/2)+(hi/2);
00150 #define val(x) us[x]->getBbox().axis(alongAxis).getMin()
00151 real pval=val(pivot);
00152
00153
00154 l=lo-1, r=hi+1;
00155 while (1) {
00156 real lval,rval;
00157 while ((lval=val(l+1))<pval) l++;
00158 while ((rval=val(r-1))>pval) r--;
00159 if (!(lval==pval && rval==pval))
00160 myswap(us[l+1],us[r-1]);
00161 else
00162 {
00163 bool finished=true;
00164 int i;
00165 for (i=l+2;i<=r-2;i++)
00166 if (val(i)!=pval) {finished=false;break;}
00167 if (finished) break;
00168 else myswap(us[l+1],us[i]);
00169 }
00170 }
00171 #if DEBUG_CHECKS //Check this step of the partitioning
00172
00173 if (l+1<0) CkAbort("L negative!\n");
00174 if (l>=nHome) CkAbort("L too big!\n");
00175 if (r<0) CkAbort("R negative!\n");
00176 if (r-1>=nHome) CkAbort("R too big!\n");
00177 for (int i=l+1;i<r;i++) if (val(i)!=pval) CkAbort("equals aren't!");
00178 for (int i=0;i<=l;i++) if (val(i)>=pval) CkAbort("lesses aren't!");
00179 for (int i=r;i<nHome;i++) if (val(i)<=pval) CkAbort("greaters aren't!");
00180 #endif
00181
00182 if (l<target && target<r) break;
00183 else if (target<=l) hi=l;
00184 else lo=r;
00185 }
00186 #if DEBUG_CHECKS //Check this step of the partitioning
00187
00188
00189 #endif
00190
00191 #if 1 //Try to split homes into separated (non-overlapping) pieces
00192 if (r<nHome) return r;
00193 else if (l>0) return l;
00194 else {
00195 STATS(splitFailures[alongAxis]++);
00196 return -1;
00197 }
00198 #else
00199
00200 return target;
00201 #endif
00202 }
00203
00204
00205
00206 CollideOctant *CollideOctant::divide(int alongAxis)
00207 {
00208 int oStart=nHome,oEnd=length();
00209 int i;
00210
00211
00212 int div=splitAt(alongAxis);
00213 if (div==-1) return NULL;
00214
00215
00216 CollideOctant &ret=*(new CollideOctant(length(),territory));
00217 CollideOctant &us=*this;
00218
00219
00220 ret.nHome=ret.length()=nHome-div;
00221 for (i=div;i<nHome;i++) ret[i-div]=us[i];
00222 us.nHome=us.length()=div;
00223 int ret_length=ret.length();
00224
00225
00226 us.box=us.at(0)->getBbox();
00227 ret.box=ret.at(0)->getBbox();
00228 for (i=length()-1;i>0;i--) us.box.add(us.at(i)->getBbox());
00229 for (i=ret_length-1;i>0;i--) ret.box.add(ret.at(i)->getBbox());
00230
00231
00232 for (i=length()-1;i>=0;i--)
00233 ret.addIfBoundary(at(i));
00234 for (i=ret_length-1;i>=0;i--)
00235 addIfBoundary(ret.at(i));
00236 for (i=oStart;i<oEnd;i++) {
00237 addIfBoundary(at(i));
00238 ret.addIfBoundary(at(i));
00239 }
00240
00241
00242
00243
00244 #if DEBUG_CHECKS //Debugging-- check invariants
00245 ret.check();
00246 us.check();
00247 #endif
00248 return &ret;
00249 }
00250
00252
00253
00254 template <class T>
00255 inline T mymax(T a,T b) {if (a>b) return a; return b;}
00256 template <class T>
00257 inline T mymin(T a,T b) {if (a<b) return a; return b;}
00258
00259
00260 static void simpleFindCollisions(const CollideOctant &o,CollisionList &dest)
00261 {
00262 STATS(simpleCalls++)
00263 int nH=o.getHome(),nI=o.getTotal();
00264 int h,i;
00265 for (h=0;h<nH;h++)
00266 for (i=0;i<nI;i++) {
00267 const CollideObjRec &a=*o[h];
00268 const CollideObjRec &b=*o[i];
00269 if (!a.id.shouldCollide(b.id)) {STATS(rejID++) continue;}
00270 const bbox3d &abox=a.getBbox();
00271 const bbox3d &bbox=b.getBbox();
00272 if (!abox.intersectsOpen(bbox)) {STATS(rejBbox++) continue;}
00273
00274
00275
00276 if (!o.x_inTerritory(mymax(abox.axis(0).getMin(),bbox.axis(0).getMin())))
00277 {STATS(rejTerritory[0]++) continue;}
00278 if (!o.y_inTerritory(mymax(abox.axis(1).getMin(),bbox.axis(1).getMin())))
00279 {STATS(rejTerritory[1]++) continue;}
00280 if (!o.z_inTerritory(mymax(abox.axis(2).getMin(),bbox.axis(2).getMin())))
00281 {STATS(rejTerritory[2]++) continue;}
00282
00283
00284 STATS(Collisions++)
00285 dest.add(a.id,b.id);
00286 }
00287 }
00288
00289 void CollideOctant::findCollisions(int splitAxis,CollisionList &dest)
00290 {
00291 if (getHome()==0) return;
00292 #if COLLIDE_IS_RECURSIVE
00293 STATS(recursiveCalls++)
00294
00295 #if 1
00296 int iprio=at(0)->id.prio, i;
00297 for (i=length()-1;i>0;i--)
00298 if (at(i)->id.prio!=iprio)
00299 break;
00300 if (i==0) {STATS(rejHomo++) return;}
00301 #endif
00302
00303 if (getHome()>COLLIDE_RECURSIVE_THRESH)
00304 {
00305 CollideOctant *n;
00306 int divideCount=0;
00307 do {
00308 n=divide(splitAxis);
00309 splitAxis=(splitAxis+1)%3;
00310 divideCount++;
00311 } while (n==NULL && divideCount<3);
00312 if (n==NULL)
00313 {
00314 STATS(simpleFallbackCalls++)
00315 simpleFindCollisions(*this,dest);
00316 } else {
00317 n->findCollisions(splitAxis,dest);
00318 delete n;
00319 findCollisions(splitAxis,dest);
00320 }
00321 } else
00322 #endif
00323 simpleFindCollisions(*this,dest);
00324 }
00325
00326
00327