glc_octreenode.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 
00003  This file is part of the GLC-lib library.
00004  Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
00005  Version 2.0.0, packaged on July 2010.
00006 
00007  http://glc-lib.sourceforge.net
00008 
00009  GLC-lib is free software; you can redistribute it and/or modify
00010  it under the terms of the GNU Lesser General Public License as published by
00011  the Free Software Foundation; either version 3 of the License, or
00012  (at your option) any later version.
00013 
00014  GLC-lib is distributed in the hope that it will be useful,
00015  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  GNU Lesser General Public License for more details.
00018 
00019  You should have received a copy of the GNU Lesser General Public License
00020  along with GLC-lib; if not, write to the Free Software
00021  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00022 
00023  *****************************************************************************/
00025 
00026 #include "glc_octreenode.h"
00027 
00028 bool GLC_OctreeNode::m_useBoundingSphere= true;
00029 
00030 GLC_OctreeNode::GLC_OctreeNode(const GLC_BoundingBox& boundingBox, GLC_OctreeNode* pParent)
00031 : m_BoundingBox(boundingBox)
00032 , m_pParent(pParent)
00033 , m_Children()
00034 , m_3DViewInstanceSet()
00035 , m_Empty(true)
00036 {
00037 
00038 
00039 }
00040 
00041 GLC_OctreeNode::GLC_OctreeNode(const GLC_OctreeNode& octreeNode, GLC_OctreeNode* pParent)
00042 : m_BoundingBox(octreeNode.m_BoundingBox)
00043 , m_pParent(pParent)
00044 , m_Children()
00045 , m_3DViewInstanceSet(octreeNode.m_3DViewInstanceSet)
00046 , m_Empty(octreeNode.m_Empty)
00047 {
00048         if (!octreeNode.m_Children.isEmpty())
00049         {
00050                 const int size= octreeNode.m_Children.size();
00051                 for (int i= 0; i < size; ++i)
00052                 {
00053                         m_Children.append(new GLC_OctreeNode(*(octreeNode.m_Children.at(i)), this));
00054                 }
00055         }
00056 }
00057 
00058 GLC_OctreeNode::~GLC_OctreeNode()
00059 {
00060         const int size= m_Children.size();
00061         for (int i= 0; i < size; ++i)
00062         {
00063                 delete m_Children.at(i);
00064         }
00065 }
00066 
00067 bool GLC_OctreeNode::intersectionWithBoundingSphereUsed()
00068 {
00069         return m_useBoundingSphere;
00070 }
00071 
00072 QSet<GLC_3DViewInstance*> GLC_OctreeNode::setOfIntersectedInstances(const GLC_BoundingBox& bBox)
00073 {
00074         QSet<GLC_3DViewInstance*> instanceSet;
00075         if (intersect(bBox))
00076         {
00077                 QSet<GLC_3DViewInstance*>::iterator iInstance= m_3DViewInstanceSet.begin();
00078                 while (m_3DViewInstanceSet.constEnd() != iInstance)
00079                 {
00080                         if ((*iInstance)->boundingBox().intersect(bBox))
00081                         {
00082                                 instanceSet << *(iInstance);
00083                         }
00084                         ++iInstance;
00085                 }
00086                 const int childCount= m_Children.size();
00087                 for (int i= 0; i < childCount; ++i)
00088                 {
00089                         instanceSet.unite(m_Children[i]->setOfIntersectedInstances(bBox));
00090                 }
00091         }
00092 
00093         return instanceSet;
00094 }
00096 // Set Functions
00098 
00099 void GLC_OctreeNode::addChildren()
00100 {
00101         Q_ASSERT(m_Children.isEmpty());
00102         Q_ASSERT(!m_BoundingBox.isEmpty());
00103 
00104         const double xLower=  m_BoundingBox.lowerCorner().x();
00105         const double yLower=  m_BoundingBox.lowerCorner().y();
00106         const double zLower=  m_BoundingBox.lowerCorner().z();
00107 
00108         const double xUpper=  m_BoundingBox.upperCorner().x();
00109         const double dX= (xUpper - xLower) / 2.0;
00110         const double yUpper=  m_BoundingBox.upperCorner().y();
00111         const double dY= (yUpper - yLower) / 2.0;
00112         const double zUpper=  m_BoundingBox.upperCorner().z();
00113         const double dZ= (zUpper - zLower) / 2.0;
00114 
00115 
00116         // Add 8 Children
00117         GLC_Point3d lower;
00118         GLC_Point3d upper;
00119         GLC_OctreeNode* pOctreeNode= NULL;
00120 
00121         { // Child 1
00122                 lower.setVect(xLower, yLower, zLower);
00123                 upper.setVect(xLower + dX, yLower + dY, zLower + dZ);
00124                 GLC_BoundingBox box(lower, upper);
00125                 pOctreeNode= new GLC_OctreeNode(box, this);
00126                 m_Children.append(pOctreeNode);
00127         }
00128         { // Child 2
00129                 lower.setVect(xLower + dX, yLower, zLower);
00130                 upper.setVect(xUpper, yLower + dY, zLower + dZ);
00131                 GLC_BoundingBox box(lower, upper);
00132                 pOctreeNode= new GLC_OctreeNode(box, this);
00133                 m_Children.append(pOctreeNode);
00134         }
00135         { // Child 3
00136                 lower.setVect(xLower + dX, yLower + dY, zLower);
00137                 upper.setVect(xUpper, yUpper, zLower + dZ);
00138                 GLC_BoundingBox box(lower, upper);
00139                 pOctreeNode= new GLC_OctreeNode(box, this);
00140                 m_Children.append(pOctreeNode);
00141         }
00142         { // Child 4
00143                 lower.setVect(xLower, yLower + dY, zLower);
00144                 upper.setVect(xLower + dX, yUpper, zLower + dZ);
00145                 GLC_BoundingBox box(lower, upper);
00146                 pOctreeNode= new GLC_OctreeNode(box, this);
00147                 m_Children.append(pOctreeNode);
00148         }
00149         { // Child 5
00150                 lower.setVect(xLower, yLower, zLower + dZ);
00151                 upper.setVect(xLower + dX, yLower + dY, zUpper);
00152                 GLC_BoundingBox box(lower, upper);
00153                 pOctreeNode= new GLC_OctreeNode(box, this);
00154                 m_Children.append(pOctreeNode);
00155         }
00156         { // Child 6
00157                 lower.setVect(xLower + dX, yLower, zLower + dZ);
00158                 upper.setVect(xUpper, yLower + dY, zUpper);
00159                 GLC_BoundingBox box(lower, upper);
00160                 pOctreeNode= new GLC_OctreeNode(box, this);
00161                 m_Children.append(pOctreeNode);
00162         }
00163         { // Child 7
00164                 lower.setVect(xLower + dX, yLower + dY, zLower + dZ);
00165                 upper.setVect(xUpper, yUpper, zUpper);
00166                 GLC_BoundingBox box(lower, upper);
00167                 pOctreeNode= new GLC_OctreeNode(box, this);
00168                 m_Children.append(pOctreeNode);
00169         }
00170         { // Child 8
00171                 lower.setVect(xLower, yLower + dY, zLower + dZ);
00172                 upper.setVect(xLower + dX, yUpper, zUpper);
00173                 GLC_BoundingBox box(lower, upper);
00174                 pOctreeNode= new GLC_OctreeNode(box, this);
00175                 m_Children.append(pOctreeNode);
00176         }
00177 }
00178 
00179 
00180 void GLC_OctreeNode::addInstance(GLC_3DViewInstance* pInstance, int depth)
00181 {
00182         m_Empty= false;
00183         const GLC_BoundingBox instanceBox= pInstance->boundingBox();
00184         // Check if the instance's bounding box intersect this node bounding box
00185         if (intersect(instanceBox))
00186         {
00187                 if (0 == depth)
00188                 {
00189                         m_3DViewInstanceSet.insert(pInstance);
00190                 }
00191                 else
00192                 {
00193                         if (m_Children.isEmpty())
00194                         {
00195                                 // Create children
00196                                 addChildren();
00197                         }
00198                         QVector<bool> childIntersect(8);
00199                         bool allIntersect= true;
00200                         bool currentIntersect= false;
00201                         for (int i= 0; i < 8; ++i)
00202                         {
00203                                 currentIntersect= m_Children.at(i)->intersect(instanceBox);
00204                                 allIntersect= allIntersect && currentIntersect;
00205                                 childIntersect[i]= currentIntersect;
00206                         }
00207                         if (allIntersect)
00208                         {
00209                                 m_3DViewInstanceSet.insert(pInstance);
00210                         }
00211                         else
00212                         {
00213                                 for (int i= 0; i < 8; ++i)
00214                                 {
00215                                         if (childIntersect[i])
00216                                         {
00217                                                 m_Children[i]->addInstance(pInstance, depth - 1);
00218                                         }
00219                                 }
00220                         }
00221                 }
00222 
00223         }
00224 }
00225 
00226 
00227 void GLC_OctreeNode::updateViewableInstances(const GLC_Frustum& frustum, QSet<GLC_3DViewInstance*>* pInstanceSet)
00228 {
00229 
00230         bool firstCall= false;
00231         // Create the set of viewable instance if necessary
00232         if (NULL == pInstanceSet)
00233         {
00234                 pInstanceSet= new QSet<GLC_3DViewInstance*>();
00235                 firstCall= true;
00236         }
00237 
00238         // Test the localisation of current octree node
00239         GLC_Frustum::Localisation nodeLocalisation= frustum.localizeBoundingBox(m_BoundingBox);
00240         if (nodeLocalisation == GLC_Frustum::OutFrustum)
00241         {
00242                 disableViewFlag(pInstanceSet);
00243         }
00244         else if (nodeLocalisation == GLC_Frustum::InFrustum)
00245         {
00246                 unableViewFlag(pInstanceSet);
00247         }
00248         else // The current node intersect the frustum
00249         {
00250                 QSet<GLC_3DViewInstance*>::iterator iInstance= m_3DViewInstanceSet.begin();
00251                 while (m_3DViewInstanceSet.constEnd() != iInstance)
00252                 {
00253                         // Test if the instances is in the viewable set
00254                         if (!pInstanceSet->contains(*iInstance))
00255                         {
00256                                 GLC_3DViewInstance* pCurrentInstance= (*iInstance);
00257                                 // Test the localisation of the current instance
00258                                 GLC_Frustum::Localisation instanceLocalisation= frustum.localizeBoundingBox(pCurrentInstance->boundingBox());
00259 
00260                                 if (instanceLocalisation == GLC_Frustum::OutFrustum)
00261                                 {
00262                                         pCurrentInstance->setViewable(GLC_3DViewInstance::NoViewable);
00263                                 }
00264                                 else if (instanceLocalisation == GLC_Frustum::InFrustum)
00265                                 {
00266                                         pInstanceSet->insert(pCurrentInstance);
00267                                         pCurrentInstance->setViewable(GLC_3DViewInstance::FullViewable);
00268                                 }
00269                                 else
00270                                 {
00271                                         pInstanceSet->insert(pCurrentInstance);
00272                                         pCurrentInstance->setViewable(GLC_3DViewInstance::PartialViewable);
00273                                         //Update the geometries viewable property of the instance
00274                                         GLC_Matrix4x4 instanceMat= pCurrentInstance->matrix();
00275                                         const int size= pCurrentInstance->numberOfBody();
00276                                         for (int i= 0; i < size; ++i)
00277                                         {
00278                                                 // Get the geometry bounding box
00279                                                 GLC_BoundingBox geomBox= pCurrentInstance->geomAt(i)->boundingBox();
00280                                                 GLC_Point3d center(instanceMat * geomBox.center());
00281                                                 double radius= geomBox.boundingSphereRadius() * instanceMat.scalingX();
00282                                                 GLC_Frustum::Localisation geomLocalisation= frustum.localizeSphere(center, radius);
00283 
00284                                                 pCurrentInstance->setGeomViewable(i, geomLocalisation != GLC_Frustum::OutFrustum);
00285                                         }
00286                                 }
00287                         }
00288 
00289                         ++iInstance;
00290                 }
00291                 const int size= m_Children.size();
00292                 for (int i= 0; i < size; ++i)
00293                 {
00294                         m_Children.at(i)->updateViewableInstances(frustum, pInstanceSet);
00295                 }
00296         }
00297         if (firstCall) delete pInstanceSet;
00298 }
00299 
00300 
00301 void GLC_OctreeNode::removeEmptyChildren()
00302 {
00303         NodeList::iterator iList= m_Children.begin();
00304         while(m_Children.constEnd() != iList)
00305         {
00306                 GLC_OctreeNode* pCurrentChild= *iList;
00307                 if (pCurrentChild->isEmpty())
00308                 {
00309                         delete pCurrentChild;
00310                         iList= m_Children.erase(iList);
00311                 }
00312                 else
00313                 {
00314                         pCurrentChild->removeEmptyChildren();
00315                         if (pCurrentChild->isEmpty())
00316                         {
00317                                 delete pCurrentChild;
00318                                 iList= m_Children.erase(iList);
00319                         }
00320                         else ++iList;
00321                 }
00322         }
00323         // Update empty flag
00324         if (m_Children.isEmpty() && (NULL != m_pParent))
00325         {
00326                 if (1 == m_3DViewInstanceSet.size())
00327                 {
00328                         m_pParent->m_3DViewInstanceSet.insert(*(m_3DViewInstanceSet.begin()));
00329                         m_3DViewInstanceSet.clear();
00330                 }
00331                 m_Empty= m_3DViewInstanceSet.isEmpty();
00332         }
00333 }
00334 
00335 void GLC_OctreeNode::useBoundingSphereIntersection(bool use)
00336 {
00337         m_useBoundingSphere= use;
00338 }
00339 
00340 void GLC_OctreeNode::unableViewFlag(QSet<GLC_3DViewInstance*>* pInstanceSet)
00341 {
00342         QSet<GLC_3DViewInstance*>::iterator iInstance= m_3DViewInstanceSet.begin();
00343         while (m_3DViewInstanceSet.constEnd() != iInstance)
00344         {
00345                 if (!pInstanceSet->contains(*iInstance))
00346                 {
00347                         (*iInstance)->setViewable(GLC_3DViewInstance::FullViewable);
00348                         pInstanceSet->insert(*iInstance);
00349                 }
00350 
00351                 ++iInstance;
00352         }
00353         const int size= m_Children.size();
00354         for (int i= 0; i < size; ++i)
00355         {
00356                 m_Children.at(i)->unableViewFlag(pInstanceSet);
00357         }
00358 }
00359 
00360 
00361 void GLC_OctreeNode::disableViewFlag(QSet<GLC_3DViewInstance*>* pInstanceSet)
00362 {
00363         QSet<GLC_3DViewInstance*>::iterator iInstance= m_3DViewInstanceSet.begin();
00364         while (m_3DViewInstanceSet.constEnd() != iInstance)
00365         {
00366                 if (!pInstanceSet->contains(*iInstance))
00367                         (*iInstance)->setViewable(GLC_3DViewInstance::NoViewable);
00368 
00369                 ++iInstance;
00370         }
00371         const int size= m_Children.size();
00372         for (int i= 0; i < size; ++i)
00373         {
00374                 m_Children.at(i)->disableViewFlag(pInstanceSet);
00375         }
00376 }
00377 

SourceForge.net Logo

©2005-2010 Laurent Ribon