CubeModel.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                               SOFA :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 #include <sofa/component/collision/CubeModel.h>
00026 #include <sofa/core/ObjectFactory.h>
00027 #include <algorithm>
00028 #include <math.h>
00029 #include <sofa/helper/system/gl.h>
00030 
00031 namespace sofa
00032 {
00033 
00034 namespace component
00035 {
00036 
00037 namespace collision
00038 {
00039 
00040 SOFA_DECL_CLASS(Cube)
00041 
00042 using namespace sofa::defaulttype;
00043 
00044 int CubeModelClass = core::RegisterObject("Collision model representing a cube")
00045 .add< CubeModel >()
00046 .addAlias("Cube")
00047 ;
00048 
00049 CubeModel::CubeModel()
00050 {
00051 }
00052 
00053 void CubeModel::resize(int size)
00054 {
00055     int size0 = this->size;
00056     if (size == size0) return;
00057     // reset parent
00058     CollisionModel* parent = getPrevious();
00059     while(parent != NULL)
00060     {
00061         parent->resize(0);
00062         parent = parent->getPrevious();
00063     }
00064     this->core::CollisionModel::resize(size);
00065     this->elems.resize(size);
00066     this->parentOf.resize(size);
00067     // set additional indices
00068     for (int i=size0;i<size;++i)
00069     {
00070         this->elems[i].children.first=core::CollisionElementIterator(getNext(), i);
00071         this->elems[i].children.second=core::CollisionElementIterator(getNext(), i+1);
00072         this->parentOf[i] = i;
00073     }
00074 }
00075 
00076 void CubeModel::setParentOf(int childIndex, const Vector3& min, const Vector3& max)
00077 {
00078     int i = parentOf[childIndex];
00079     elems[i].minBBox = min;
00080     elems[i].maxBBox = max;
00081 }
00082 
00083 void CubeModel::setLeafCube(int cubeIndex, std::pair<core::CollisionElementIterator,core::CollisionElementIterator> children, const Vector3& min, const Vector3& max)
00084 {
00085     elems[cubeIndex].minBBox = min;
00086     elems[cubeIndex].maxBBox = max;
00087     elems[cubeIndex].children = children;
00088 }
00089 
00090 int CubeModel::addCube(Cube subcellsBegin, Cube subcellsEnd)
00091 {
00092     int i = size;
00093     this->core::CollisionModel::resize(size+1);
00094     elems.resize(size+1);
00095     //elems[i].subcells = std::make_pair(subcellsBegin, subcellsEnd);
00096     elems[i].subcells.first = subcellsBegin;
00097     elems[i].subcells.second = subcellsEnd;
00098     elems[i].children.first = core::CollisionElementIterator();
00099     elems[i].children.second = core::CollisionElementIterator();
00100     updateCube(i);
00101     return i;
00102 }
00103 
00104 void CubeModel::updateCube(int index)
00105 {
00106     const std::pair<Cube,Cube>& subcells = elems[index].subcells;
00107     if (subcells.first != subcells.second)
00108     {
00109         Cube c = subcells.first;
00110         Vector3 minBBox = c.minVect();
00111         Vector3 maxBBox = c.maxVect();
00112         ++c;
00113         while(c != subcells.second)
00114         {
00115             const Vector3& cmin = c.minVect();
00116             const Vector3& cmax = c.maxVect();
00117             for (int j=0;j<3;j++)
00118             {
00119                 if (cmax[j] > maxBBox[j]) maxBBox[j] = cmax[j];
00120                 if (cmin[j] < minBBox[j]) minBBox[j] = cmin[j];
00121             }
00122             ++c;
00123         }
00124         elems[index].minBBox = minBBox;
00125         elems[index].maxBBox = maxBBox;
00126     }
00127 }
00128 
00129 void CubeModel::updateCubes()
00130 {
00131     for (int i=0;i<size;i++)
00132         updateCube(i);
00133 }
00134 
00135 void CubeModel::draw(int index)
00136 {
00137     const Vector3& vmin = elems[index].minBBox;
00138     const Vector3& vmax = elems[index].maxBBox;
00139 
00140     glBegin(GL_LINES);
00141     {
00142             glVertex3d(vmin[0], vmin[1], vmin[2]);
00143             glVertex3d(vmin[0], vmin[1], vmax[2]);
00144             glVertex3d(vmin[0], vmax[1], vmin[2]);
00145             glVertex3d(vmin[0], vmax[1], vmax[2]);
00146             glVertex3d(vmax[0], vmin[1], vmin[2]);
00147             glVertex3d(vmax[0], vmin[1], vmax[2]);
00148             glVertex3d(vmax[0], vmax[1], vmin[2]);
00149             glVertex3d(vmax[0], vmax[1], vmax[2]);
00150 
00151             glVertex3d(vmin[0], vmin[1], vmin[2]);
00152             glVertex3d(vmin[0], vmax[1], vmin[2]);
00153             glVertex3d(vmin[0], vmin[1], vmax[2]);
00154             glVertex3d(vmin[0], vmax[1], vmax[2]);
00155             glVertex3d(vmax[0], vmin[1], vmin[2]);
00156             glVertex3d(vmax[0], vmax[1], vmin[2]);
00157             glVertex3d(vmax[0], vmin[1], vmax[2]);
00158             glVertex3d(vmax[0], vmax[1], vmax[2]);
00159 
00160             glVertex3d(vmin[0], vmin[1], vmin[2]);
00161             glVertex3d(vmax[0], vmin[1], vmin[2]);
00162             glVertex3d(vmin[0], vmax[1], vmin[2]);
00163             glVertex3d(vmax[0], vmax[1], vmin[2]);
00164             glVertex3d(vmin[0], vmin[1], vmax[2]);
00165             glVertex3d(vmax[0], vmin[1], vmax[2]);
00166             glVertex3d(vmin[0], vmax[1], vmax[2]);
00167             glVertex3d(vmax[0], vmax[1], vmax[2]);
00168     }
00169     glEnd();
00170 }
00171 
00172 void CubeModel::draw()
00173 {
00174     if (!isActive() || !((getNext()==NULL)?getContext()->getShowCollisionModels():getContext()->getShowBoundingCollisionModels())) return;
00175     glDisable(GL_LIGHTING);
00176     int level=0;
00177     CollisionModel* m = getPrevious();
00178     float color = 1.0f;
00179     while (m!=NULL)
00180     {
00181         m = m->getPrevious();
00182         ++level;
00183         color *= 0.5f;
00184     }
00185     if (isSimulated())
00186         glColor4f(1.0f, 1.0f, 1.0f, color);
00187     else
00188         glColor4f(1.0f, 1.0f, 0.0f, color);
00189     if (color < 1.0f)
00190     {
00191         glEnable(GL_BLEND);
00192         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00193         glDepthMask(0);
00194     }
00195     for (int i=0;i<size;i++)
00196     {
00197         draw(i);
00198     }
00199     if (color < 1.0f)
00200     {
00201         glDisable(GL_BLEND);
00202         glDepthMask(1);
00203     }
00204     if (getPrevious()!=NULL)
00205         getPrevious()->draw();
00206 }
00207 
00208 std::pair<core::CollisionElementIterator,core::CollisionElementIterator> CubeModel::getInternalChildren(int index) const
00209 {
00210     return elems[index].subcells;
00211 }
00212 
00213 std::pair<core::CollisionElementIterator,core::CollisionElementIterator> CubeModel::getExternalChildren(int index) const
00214 {
00215     return elems[index].children;
00216 /*
00217     core::CollisionElementIterator i1 = elems[index].leaf;
00218     if (!i1.valid())
00219     {
00220         return std::make_pair(core::CollisionElementIterator(),core::CollisionElementIterator());
00221     }
00222     else
00223     {
00224         core::CollisionElementIterator i2 = i1; ++i2;
00225         return std::make_pair(i1,i2);
00226     }
00227 */
00228 }
00229 
00230 bool CubeModel::isLeaf( int index ) const
00231 {
00232     return elems[index].children.first.valid();
00233 }
00234 
00235 class CubeModel::CubeSortPredicate
00236 {
00237     int axis;
00238 public:
00239     CubeSortPredicate(int axis) : axis(axis) {}
00240     bool operator()(const CubeData& c1,const CubeData& c2) const
00241     {
00242         double v1 = c1.minBBox[axis]+c1.maxBBox[axis];
00243         double v2 = c2.minBBox[axis]+c2.maxBBox[axis];
00244         return v1 < v2;
00245     }
00246     template<int Axis>
00247     static int sortCube(const void* p1, const void* p2)
00248     {
00249         const CubeModel::CubeData* c1 = (const CubeModel::CubeData*)p1;
00250         const CubeModel::CubeData* c2 = (const CubeModel::CubeData*)p2;
00251         double v1 = c1->minBBox[Axis] + c1->maxBBox[Axis];
00252         double v2 = c2->minBBox[Axis] + c2->maxBBox[Axis];
00253         
00254         if (v1 < v2)
00255             return -1;
00256         else if (v1 > v2)
00257             return 1;
00258         else
00259             return 0;
00260     }
00261 };
00262 
00263 void CubeModel::computeBoundingTree(int maxDepth)
00264 {
00265     //std::cout << ">CubeModel::computeBoundingTree("<<maxDepth<<")"<<std::endl;
00266     std::list<CubeModel*> levels;
00267     levels.push_front(createPrevious<CubeModel>());
00268     for (int i=0;i<maxDepth;i++)
00269         levels.push_front(levels.front()->createPrevious<CubeModel>());
00270     CubeModel* root = levels.front();
00271     //if (isStatic() && root->getPrevious() == NULL && !root->empty()) return; // No need to recompute BBox if immobile
00272     
00273     if (root->empty() || root->getPrevious() != NULL)
00274     {
00275         // Tree must be reconstructed
00276         //std::cout << "Building Tree with depth "<<maxDepth<<" from "<<size<<" elements.\n";
00277         // First remove extra levels
00278         while(root->getPrevious()!=NULL)
00279         {
00280             core::CollisionModel* m = root->getPrevious();
00281             root->setPrevious(m->getPrevious());
00282             delete m;
00283         }
00284         // Then clear all existing levels
00285         {
00286             for (std::list<CubeModel*>::iterator it = levels.begin(); it != levels.end(); ++it)
00287                 (*it)->resize(0);
00288         }
00289         // Then build root cell
00290         //std::cout << "CubeModel: add root cube"<<std::endl;
00291         root->addCube(Cube(this,0),Cube(this,size));
00292         // Construct tree by splitting cells along their biggest dimension
00293         std::list<CubeModel*>::iterator it = levels.begin();
00294         CubeModel* level = *it;
00295         ++it;
00296         int lvl = 0;
00297         while(it != levels.end())
00298         {
00299             //std::cout << "CubeModel: split level "<<lvl<<std::endl;
00300             CubeModel* clevel = *it;
00301             clevel->elems.reserve(level->size*2);
00302             for(Cube cell = Cube(level->begin()); level->end() != cell; ++cell)
00303             {
00304                 const std::pair<Cube,Cube>& subcells = cell.subcells();
00305                 int ncells = subcells.second.getIndex() - subcells.first.getIndex();
00306                 //std::cout << "CubeModel: level "<<lvl<<" cell "<<cell.getIndex()<<": current subcells "<<subcells.first.getIndex() << " - "<<subcells.second.getIndex()<<std::endl;
00307                 if (ncells > 4)
00308                 { // Only split cells with more than 4 childs
00309                     // Find the biggest dimension
00310                     int splitAxis;
00311                     Vector3 l = cell.maxVect()-cell.minVect();
00312                     int middle = subcells.first.getIndex()+(ncells+1)/2;
00313                     if(l[0]>l[1])
00314                         if (l[0]>l[2])
00315                             splitAxis = 0;
00316                         else
00317                             splitAxis = 2;
00318                     else
00319                         if (l[1]>l[2])
00320                             splitAxis = 1;
00321                         else
00322                             splitAxis = 2;
00323                     
00324                     // Separate cells on each side of the median cell
00325 
00326 #if defined(__GNUC__) && (__GNUC__ == 4) 
00327 // && (__GNUC_MINOR__ == 1) && (__GNUC_PATCHLEVEL__ == 1)
00328                     // there is apparently a bug in std::sort with GCC 4.x
00329                     if (splitAxis == 0)
00330                         qsort(&(elems[subcells.first.getIndex()]), subcells.second.getIndex()-subcells.first.getIndex(), sizeof(elems[0]), CubeSortPredicate::sortCube<0>);
00331                     else if (splitAxis == 1)
00332                         qsort(&(elems[subcells.first.getIndex()]), subcells.second.getIndex()-subcells.first.getIndex(), sizeof(elems[0]), CubeSortPredicate::sortCube<1>);
00333                     else
00334                         qsort(&(elems[subcells.first.getIndex()]), subcells.second.getIndex()-subcells.first.getIndex(), sizeof(elems[0]), CubeSortPredicate::sortCube<2>);
00335 #else
00336                     CubeSortPredicate sortpred(splitAxis);
00337                     //std::nth_element(elems.begin()+subcells.first.getIndex(),elems.begin()+middle,elems.begin()+subcells.second.getIndex(), sortpred);
00338                     std::sort(elems.begin()+subcells.first.getIndex(),elems.begin()+subcells.second.getIndex(), sortpred);
00339 #endif
00340 
00341                     // Create the two new subcells
00342                     Cube cmiddle(this, middle);
00343                     int c1 = clevel->addCube(subcells.first, cmiddle);
00344                     int c2 = clevel->addCube(cmiddle, subcells.second);
00345                     //std::cout << "L"<<lvl<<" cell "<<cell.getIndex()<<" split along "<<(splitAxis==0?'X':splitAxis==1?'Y':'Z')<<" in cell "<<c1<<" size "<<middle-subcells.first.getIndex()<<" and cell "<<c2<<" size "<<subcells.second.getIndex()-middle<<".\n";
00346                     //level->elems[cell.getIndex()].subcells = std::make_pair(Cube(clevel,c1),Cube(clevel,c2+1));
00347                     level->elems[cell.getIndex()].subcells.first = Cube(clevel,c1);
00348                     level->elems[cell.getIndex()].subcells.second = Cube(clevel,c2+1);
00349                 }
00350             }
00351             ++it;
00352             level = clevel;
00353             ++lvl;
00354         }
00355         // Finally update parentOf to reflect new cell order
00356         for (int i=0;i<size;i++)
00357             parentOf[elems[i].children.first.getIndex()] = i;
00358     }
00359     else
00360     {
00361         // Simply update the existing tree, starting from the bottom
00362         int lvl = 0;
00363         for (std::list<CubeModel*>::reverse_iterator it = levels.rbegin(); it != levels.rend(); it++)
00364         {
00365             //std::cout << "CubeModel: update level "<<lvl<<std::endl;
00366             (*it)->updateCubes();
00367             ++lvl;
00368         }
00369     }
00370     //std::cout << "<CubeModel::computeBoundingTree("<<maxDepth<<")"<<std::endl;
00371 }
00372 
00373 } // namespace collision
00374 
00375 } // namespace component
00376 
00377 } // namespace sofa
00378 

Generated on Sun Nov 23 02:33:11 2008 for Sofa by  doxygen 1.5.7.1