BVList.cc

Go to the documentation of this file.
00001 #include <esg/geometry/BVList.h>
00002 #include <esg/explorer/POGExplorer.h>
00003 #include <esg/explorer/NExtentsExplorer.h>
00004 #include <time.h>
00005 #include <assert.h>
00006 
00007 using namespace esg;
00008 
00009 unsigned BVList::qsortIndex;
00010 
00011 int BVList::qsortCompare(const void * pBV1, const void * pBV2)
00012 {
00013     Interval * i1 = &((*((BVNode**)pBV1))->extents[BVList::qsortIndex]);
00014     Interval * i2 = &((*((BVNode**)pBV2))->extents[BVList::qsortIndex]);
00015     double     e1 = i1->min + i1->max;
00016     double     e2 = i2->min + i2->max;
00017 
00018     return ((e1 < e2) ? -1 : ((e1 == e2) ? 0 : 1));
00019 }
00020 
00021 void BVList::_split_by_handles(List<BVNode>& srcList,
00022                                List<BVNode>& dstList,
00023                                unsigned      index)
00024 {
00025     float    median;
00026     unsigned i_rand;
00027     long int length  = (long int) srcList.length();
00028     BVNode*  pMedian = NULL;
00029 
00030     assert(length > 1);
00031     
00032     // find i-th element in list, i_rand = rand()%length = [0,length)
00033     //i_rand = (unsigned) (rand() % length);
00034     i_rand = (unsigned) ESG_INT_RAND(length);
00035     pMedian = srcList.iThItem(i_rand, false);
00036     assert(pMedian);
00037     (void) srcList.remove(pMedian);
00038     length--;
00039 
00040     median = pMedian->handle[index];
00041 
00042     BVNode * pNode = srcList.firstItem();
00043     for (register unsigned i = 0; i < (unsigned) length; i++) {
00044         //fprintf(stderr,"%u %u\n",i,length);
00045         
00046         if ((pNode->handle[index] < median) ||
00047             ((pNode->handle[index] == median) && (i < i_rand)))
00048         {
00049             // keep object in this (left) list
00050             pNode = srcList.nextItem();
00051         } else
00052         {                       /* move object to right son list */
00053             BVNode* pTmp = srcList.nextItem();
00054             dstList.append(srcList.remove(pNode));
00055             pNode = pTmp;
00056         }
00057     }   /* for */
00058 
00059     if (dstList.length() == 0) dstList.append(pMedian);
00060     else srcList.append(pMedian);
00061 }
00062 
00063 void BVList::_comp_handle(BVNode* pNode)
00064 {
00065     if (!pNode || !pNode->pObject) return;
00066     
00067     POGExplorer explorer;
00068     explorer.explore(*(pNode->pObject));
00069     Vector3 pog = explorer.result();
00070     Vector3 v;
00071     
00072     if (pog.x == MAX_VEC_VALUE ||
00073         pog.y == MAX_VEC_VALUE ||
00074         pog.z == MAX_VEC_VALUE)
00075     {
00076         for (register unsigned i = 0; i < _dirs; i++)
00077             pNode->handle[i] = MAXFLOAT;
00078         return;
00079     }
00080     
00081     for (register unsigned i = 0; i < _dirs; i++) {
00082         v.set(_dirMat[i][0], _dirMat[i][1], _dirMat[i][2]);
00083         pNode->handle[i] = pog.dot(v);
00084     }
00085 }
00086 
00087 void BVList::_comp_extents(BVNode* pNode)
00088 {
00089     if (!pNode || !pNode->pObject) return;
00090     
00091     NExtentsExplorer explorer(_dirMat, _dirs);
00092     explorer.explore(*(pNode->pObject));
00093 
00094     for (unsigned i = 0; i < _dirs; i++) 
00095         pNode->extents[i] = explorer.result(i);
00096 }
00097 
00098 
00099 unsigned BVList::_index_with_max_extent()
00100 {
00101 #ifdef WIN32
00102     Interval *d = new Interval [_dirs];
00103 #else
00104     Interval d[_dirs];
00105 #endif
00106     BVNode*  pNode = _pList->firstItem();
00107     
00108     while (pNode) {
00109         for (unsigned i = 0; i < _dirs; i++) {
00110             if (pNode->extents[i].min < d[i].min)
00111                 d[i].min = pNode->extents[i].min;
00112             if (pNode->extents[i].max > d[i].max)
00113                 d[i].max = pNode->extents[i].max;
00114         }
00115         pNode = _pList->nextItem();
00116     }
00117 
00118     unsigned ret  = 0;
00119     double   dist = -MAXDOUBLE;
00120     double   actDist;
00121     for (unsigned i = 0; i < _dirs; i++) {
00122         actDist = d[i].max - d[i].min;
00123         if (actDist > dist) { ret = i; dist = actDist; }
00124     }
00125 
00126 #ifdef WIN32
00127     delete [] d;
00128 #endif
00129     
00130     return ret;
00131 }
00132 
00133 void BVList::_build_area_table(BVNode** nodes, long a, long b, double *areas) const
00134 {
00135     long      imin, dir;
00136     double    tmin, tmax;
00137     Vector3   bmin(MAX_VEC_VALUE, MAX_VEC_VALUE, MAX_VEC_VALUE);
00138     Vector3   bmax(MIN_VEC_VALUE, MIN_VEC_VALUE, MIN_VEC_VALUE);
00139     Vector3   len;
00140     Interval* e;
00141 
00142     if (a < b) { imin = a; dir =  1; }
00143     else       { imin = b; dir = -1; }
00144 
00145     for (long i = a; i != (b + dir); i += dir) {
00146         e = nodes[i]->extents;
00147 
00148         tmin = e[0].min;
00149         tmax = e[0].max;
00150         if (tmin < bmin.x) { bmin.x = tmin; }
00151         if (tmax > bmax.x) { bmax.x = tmax; }
00152 
00153         tmin = e[1].min;
00154         tmax = e[1].max;
00155         if (tmin < bmin.y) { bmin.y = tmin; }
00156         if (tmax > bmax.y) { bmax.y = tmax; }
00157 
00158         tmin = e[2].min;
00159         tmax = e[2].max;
00160         if (tmin < bmin.z) { bmin.z = tmin; }
00161         if (tmax > bmax.z) { bmax.z = tmax; }
00162 
00163         len.set(bmax);
00164         len.sub(bmin);
00165 
00166         areas[i - imin] = len.x * (len.y + len.z) + len.y * len.z;
00167     }
00168 }
00169 
00170 unsigned BVList::_split_by_extent(List<BVNode>& list)
00171 {
00172     unsigned      i, size;
00173     BVNode**      qsortArray = NULL;
00174     double        bestIndex, newIndex;
00175     unsigned      bestLoc;
00176     double*       leftArea;
00177     double*       rightArea;
00178 
00179     size       = length();
00180     qsortIndex = _index_with_max_extent();
00181     qsortArray = new BVNode* [size];
00182     leftArea   = new double [size];
00183     rightArea  = new double [size];
00184     i          = 0;
00185     
00186     for (BVNode * pN = _pList->firstItem(); pN; pN = _pList->nextItem())
00187         qsortArray[i++] = pN;
00188     
00189     delete _pList;
00190     qsort((void*)qsortArray, size, sizeof(BVNode*), BVList::qsortCompare);
00191 
00192     _build_area_table(qsortArray, 0, size-1, leftArea);
00193     _build_area_table(qsortArray, size-1, 0, rightArea);
00194     
00195     bestIndex = rightArea[0] * (size - 3.);
00196     bestLoc   = 0;
00197     
00198     /*
00199      * Find the most effective point to split. The best location will be
00200      * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2
00201      * are the number of objects in the two groups and A1 and A2 are the
00202      * surface areas of the bounding boxes of the two groups.
00203      */
00204     for (i = 0; i < size - 1; i++) {
00205         newIndex = (i+1) * leftArea[i] + (size-1-i) * rightArea[i+1];
00206         if (newIndex < bestIndex) {
00207             bestIndex = newIndex;
00208             bestLoc = i;
00209         }
00210     }
00211     
00212     delete [] leftArea;
00213     delete [] rightArea;
00214 
00215     _pList = new List<BVNode>;
00216     for (i = 0; i < bestLoc + 1; i++) _pList->append(qsortArray[i]);
00217     for (i = bestLoc + 1; i < size; i++) list.append(qsortArray[i]);
00218 
00219     delete [] qsortArray;
00220 
00221     return qsortIndex;
00222 }
00223 
00224 unsigned BVList::_index_with_max_variation()
00225 {
00226     float     max_hodn;
00227     unsigned  max_variace = MAXUNSIGNED;
00228     float     hndl;
00229     double    ekohandle2, e2kohandle;
00230 
00231 #if defined(_MSC_VER)
00232     float    *variace = new float [_dirs];
00233 #else
00234     float     variace [_dirs];
00235 #endif
00236 
00237     variace[0] = 0;
00238 
00239     if (length() > 1) {
00240         for (register unsigned i = 0; i < _dirs; i++) {
00241             BVNode* pNode = _pList->firstItem();
00242             ekohandle2 = 0;
00243             e2kohandle = 0;
00244             while (pNode) {
00245                 hndl = pNode->handle[i];
00246                 ekohandle2 += (hndl * hndl);
00247                 e2kohandle += hndl;
00248                 pNode = _pList->nextItem();
00249             }
00250             ekohandle2 /= length();
00251             e2kohandle /= length();
00252             e2kohandle *= e2kohandle;
00253             variace[i]  = ekohandle2 - e2kohandle;
00254         }
00255         max_variace = 0;
00256         max_hodn = variace[0];
00257         for (register unsigned i = 1; i < _dirs; i++) {
00258             if (max_hodn < variace[i]) {
00259                 max_hodn = variace[i];
00260                 max_variace = i;
00261             }
00262         }
00263     }
00264 
00265 #if defined(_MSC_VER)
00266     delete [] variace;
00267 #endif
00268         
00269     return max_variace;
00270 }
00271 
00272 unsigned BVList::_split_by_variation(List<BVNode>& list)
00273 {
00274     if (length() < 2) return MAXUNSIGNED;
00275 
00276     unsigned      index, ll;
00277     unsigned      LL_room, RR_room;
00278     //time_t        t;
00279     List<BVNode>* rightList = new List<BVNode>;
00280     List<BVNode>* leftList  = _pList;
00281     
00282     LL_room = length() / 2;
00283     RR_room = length() - LL_room;
00284     
00285     if ((index = _index_with_max_variation()) == MAXUNSIGNED) return index;
00286 
00287     _pList = new List<BVNode>();
00288 
00289     //srand((unsigned)time(&t));
00290 
00291 #if 1
00292     while (true) { // rightList is always empty at this point
00293         if (leftList->length() > 1)
00294             _split_by_handles(*leftList, *rightList, index);
00295         if ((ll = leftList->length()) < LL_room) { // right list is too large
00296             LL_room -= ll;
00297             _pList->append(*leftList);
00298             List<BVNode>* pTmp = leftList;
00299             leftList = rightList;
00300             rightList = pTmp;;
00301         } else {
00302             if (ll == LL_room){ // we are done
00303                 _pList->append(*leftList);
00304                 list.append(*rightList);
00305                 break;
00306             } else { // left list is too large
00307                 RR_room -= rightList->length();
00308                 list.append(*rightList);
00309             }
00310         }
00311     }
00312 #endif
00313     
00314 #if 0
00315     while (leftList->length()) {  // rightList is always empty at this moment
00316         if (leftList->length() > LL_room) 
00317             _split_by_handles(*leftList, *rightList, index);
00318             
00319         if (rightList->length() == 0) {
00320             for (unsigned i = 0; i < LL_room; i++)
00321                 _pList->append(leftList->remove(leftList->firstItem()));
00322             while (leftList->length())
00323                 list.append(leftList->remove(leftList->firstItem()));
00324             //list.append(*leftList);
00325             continue;
00326         }
00327 
00328         if (leftList->length() == 0) {
00329             for (unsigned i = 0; i < RR_room; i++)
00330                 list.append(rightList->remove(rightList->firstItem()));
00331             while (rightList->length())
00332                 _pList->append(rightList->remove(rightList->firstItem()));
00333             //_pList->append(*rightList);
00334             continue;
00335         }
00336 
00337         if (rightList->length() <= RR_room) {
00338             RR_room -= rightList->length();
00339             while (rightList->length())
00340             list.append(rightList->remove(rightList->firstItem()));
00341             //list.append(*rightList);
00342         }
00343 
00344         if (leftList->length() <= LL_room) {
00345             LL_room -= leftList->length();
00346             while (leftList->length())
00347             _pList->append(leftList->remove(leftList->firstItem()));
00348             //_pList->append(*leftList);
00349             List<BVNode>* pTmp = leftList;
00350             leftList = rightList;
00351             rightList = pTmp;;
00352         }
00353     }
00354 #endif
00355     
00356     delete leftList;
00357     delete rightList;
00358 
00359     return index;
00360 }
00361 
00362 
00363 //------ public ----------
00364 
00365 BVList::BVList(unsigned s, const float (*m)[3])
00366     : _dirs(s), _dirMat(m)
00367 {
00368     _pList = new List<BVNode>();
00369 }
00370 
00371 BVList::~BVList()
00372 {
00373     while (BVNode* pNode=_pList->remove(_pList->firstItem())) { delete pNode; }
00374     delete _pList;
00375 }
00376 
00377 void BVList::append(SceneGraphObject* o)
00378 {
00379     BVNode* pnode = new BVNode(_dirs, o);
00380     _comp_handle(pnode);
00381     _comp_extents(pnode);
00382     _pList->append(pnode);
00383 }
00384 
00385 SceneGraphObject* BVList::remove(SceneGraphObject* pObj)
00386 {
00387     if (!pObj) return NULL;
00388     BVNode* pItem = _pList->firstItem();
00389     
00390     while (pItem && pItem->pObject != pObj)
00391         pItem = _pList->nextItem();
00392     
00393     if (pItem && pItem->pObject == pObj) {
00394         SceneGraphObject* pRet =  pItem->pObject;
00395         _pList->remove(pItem);
00396         return pRet;
00397     } else
00398         return NULL;
00399 }
00400 
00401 unsigned BVList::split(BVList& list, SplitStrategy splitStrategy)
00402 {
00403     if (length() < 2) return MAXUNSIGNED;
00404 
00405     switch (splitStrategy) {
00406     case SPLIT_BY_MAX_VARIATION:
00407         return _split_by_variation(*(list._pList));
00408         break;
00409     case SPLIT_BY_MAX_EXTENT:
00410         return _split_by_extent(*(list._pList));
00411         break;
00412     default:
00413         return MAXUNSIGNED;
00414     }
00415 }
00416 
00417 
00418 
00419 
00420 

Generated on Wed Jun 28 12:24:29 2006 for esg by  doxygen 1.4.6