Ejemplo n.º 1
0
    //--
    void
    KDTreeNode::Construct(ISpatialObject* pObjectList, int i32ObjectCount,
                                         const Vector3& refVectorMin, const Vector3& refVectorMax)
    {        
        
        // [rad] Store voxel info
        m_vec3Max = refVectorMax;
        m_vec3Min = refVectorMin;
        
        // [rad] Split plane position is already stored
        
        
        ISpatialObject* pIter = pObjectList;  
        ISpatialObject* pObjectTemp;
        ISpatialObject* pObject;
                       
        // [rad] If there are no children, or there's less objects than bins,
        // store everything in this node
        if(!m_pChildLeft || !m_pChildRight || i32ObjectCount < s_i32BinCount)
        {
            // [rad] There's no splitpane and position is not important
            m_f32SplitPosition = 0.0f;
            //m_i32SplitPane = -1;
            
            // [rad] Copy elements...
            m_pObjects = pObjectList;
            m_i32ObjectCount = i32ObjectCount;
            m_i32ObjectTotal = i32ObjectCount;
            
            
            // [rad] Iterate through all elements and set this node as a containing cell
            pIter = m_pObjects;   
            while(pIter)
            {
                pIter->VSetCell(this);
                pIter = pIter->VGetNext();
            }
            
            return;
        }
        


        // [rad] Compute sizes
        float f32Span = m_vec3Max[m_i32SplitPane] - m_vec3Min[m_i32SplitPane];
        float f32BucketSize = f32Span / static_cast<float>(s_i32BinCount);
        float f32Offset = -m_vec3Min[m_i32SplitPane];
                
        int i32BinIndex;        
        int i32Index;
      

        
        // [rad] Clean prefix sums and previous values
        for(i32Index = 0; i32Index < s_i32BinCount; i32Index++)
        {
            s_vecBins.at(i32Index).first = 0;
            s_vecBins.at(i32Index).second = 0;
            
            s_vecSums.at(i32Index).first = 0;
            s_vecSums.at(i32Index).second = 0;
        }
        
        
        
        
        // [rad] Go linearly through the list and do binning
        pIter = pObjectList;        
        Vector3 vec3Center;
        float f32Radius;
        
        while(pIter)
        {
            // [rad] Get center and radius of this object
            vec3Center = pIter->VGetPosition();
            f32Radius = pIter->VGetRadius();
            
            // [rad] Increment proper bins
            i32BinIndex = static_cast<int>(floorf((f32Offset + vec3Center[m_i32SplitPane] - f32Radius) * s_i32BinCount / f32Span));
            s_vecBins[i32BinIndex].first++;
            
            i32BinIndex = static_cast<int>(floorf((f32Offset + vec3Center[m_i32SplitPane] + f32Radius) * s_i32BinCount / f32Span));
            s_vecBins[i32BinIndex].second++;
                        
           
            // [rad] iterate to next element in list
            pIter = pIter->VGetNext();
        }
        
        
        
        
        // [rad] Compute prefix sums
        int i32SumMin = 0;
        int i32SumMax = 0;

        
        for(i32Index = 0; i32Index < s_i32BinCount; i32Index++)
        {
            i32SumMin += s_vecBins.at(i32Index).first;
            i32SumMax += s_vecBins.at(i32Index).second;
            
            s_vecSums.at(i32Index).first = i32SumMin;
            s_vecSums.at(i32Index).second = i32SumMax;
        }
        
        
        
        // [rad] Compute split candidate
        int i32MinDiff = std::numeric_limits<int>::max();
        int i32BinDiff;
        int i32SplitPosition = 0;
        
        for(i32Index = 0; i32Index < s_i32BinCount; i32Index++)
        {
            i32BinDiff = abs(s_vecSums.at(i32Index).first - s_vecSums.at(s_i32BinCount - i32Index - 1).second);
            
            if(i32BinDiff < i32MinDiff)
            {
                // [rad] This is a good candidate
                i32MinDiff = i32BinDiff;
                i32SplitPosition = i32Index;
            }
        }
    
    
        
        // [rad] Find real split position
        //m_f32SplitPosition = ((i32SplitPosition * f32Span) / f32BucketSize) - f32Offset;
        m_f32SplitPosition = m_vec3Min[m_i32SplitPane] + i32SplitPosition * f32BucketSize;
        
        
        // [rad] Now go insert objects into child nodes
        ISpatialObject* pObjectListLeft = NULL;
        ISpatialObject* pObjectListRight = NULL;
        
        int i32CountLeft = 0;
        int i32CountRight = 0;
        
        pIter = pObjectList;        
        while(pIter)
        {
            pObject = pIter->VGetNext();
            
            // [rad] Get center and radius of this object
            vec3Center = pIter->VGetPosition();
            f32Radius = pIter->VGetRadius();
            
            
            // [rad] Check where this object belongs
            if(vec3Center[m_i32SplitPane] + f32Radius <= m_f32SplitPosition)
            {
                // [rad] Left child

                pIter->VSetNext(pObjectListLeft);
                pObjectListLeft = pIter;
                
                i32CountLeft++;
            }
            else if(vec3Center[m_i32SplitPane] - f32Radius >= m_f32SplitPosition)
            {
                // [rad] Right child
                
                pIter->VSetNext(pObjectListRight);
                pObjectListRight = pIter;
                
                i32CountRight++;
            }
            else
            {
                
                pIter->VSetCell(this);
                pIter->VSetNext(m_pObjects);
                m_pObjects = pIter;
                
                m_i32ObjectCount++;
            }
            
            pIter = pObject;
        }
        
        
        // [rad] We'll keep track of how many objects we have in this node 
        // and in children
        m_i32ObjectTotal += i32ObjectCount;
        
        
        Vector3 vec3Min = refVectorMin;
        vec3Min[m_i32SplitPane] = m_f32SplitPosition;
        
        Vector3 vec3Max = refVectorMax;
        vec3Max[m_i32SplitPane] = m_f32SplitPosition;
        
        // [rad] Recurse into left child
        m_pChildLeft->Construct(pObjectListLeft, i32CountLeft,
                                            refVectorMin, vec3Max);
                                            
                                            
        // [rad] Recurse into right child
        m_pChildRight->Construct(pObjectListRight, i32CountRight,
                                            vec3Min, refVectorMax);
    }
 //--
 void
 OctreeNode::AddObjects(ISpatialObject* pObjectList, int i32ObjectCount)
 {
     ISpatialObject* pIter;
     ISpatialObject* pObject;
     
     // [rad] Check if we can stop splitting
     if(i32ObjectCount < s_i32MinSplitCount)
     {
         m_pObjects = pObjectList;
         
         pIter = m_pObjects;   
         while(pIter)
         {
             pIter->VSetCell(this);
             pIter = pIter->VGetNext();
         }
         
         
         m_i32ObjectCount = i32ObjectCount;
         
         return;
     }
     
     
     
     int i32Index = 0;
     ISpatialObject* apChildObjects[8];
     int aiChildCounts[8];
     
     for(i32Index = 0; i32Index < 8; i32Index++)
     {
         apChildObjects[i32Index] = NULL;
         aiChildCounts[i32Index] = 0;
     }
     
     
     pIter = pObjectList;
     while(pIter)
     {
         pObject = pIter->VGetNext();
         
         int i32Position = 0;
         int i32Straddle = 0;
 
         float f32Radius = pIter->VGetRadius();
         Vector3 vec3Center = pIter->VGetPosition();
         
         
         for(i32Index = 0; i32Index < 3; i32Index++)
         {
             if(m_vec3Center[i32Index] < vec3Center[i32Index])
             {
                 if(m_vec3Center[i32Index] > vec3Center[i32Index] - f32Radius)
                 {
                     // [rad] Straddle occurs
                     i32Straddle = 1;
                     break;
                 }
                 else
                 {
                     i32Position |= (1 << i32Index);
                 }
             }
             else
             {
                 if(m_vec3Center[i32Index] < vec3Center[i32Index] + f32Radius)
                 {
                     // [rad] Straddle occurs
                     i32Straddle = 1;
                     break;
                 }
             }
         }
     
     
         if(!i32Straddle && m_pChildren[i32Position])
         {
             // [rad] Contained in existing child node
             //m_pChildren[i32Position]->AddObject(pObject);
             
             pIter->VSetNext(apChildObjects[i32Position]);
             apChildObjects[i32Position] = pIter;
         
             aiChildCounts[i32Position]++;
             
         }
         else
         {
             // [rad] Store this node for fast back-link
             pIter->VSetCell(this);
     
             // [rad] Straddling or no child node available
             pIter->VSetNext(m_pObjects);
             m_pObjects = pIter;
             
             m_i32ObjectCount++;
         }
         
         
         pIter = pObject;
     }
     
     
     // [rad] At this point
     for(i32Index = 0; i32Index < 8; i32Index++)
     {            
         // [rad] Delegate to children
         if(m_pChildren[i32Index] && aiChildCounts[i32Index])
         {
             m_pChildren[i32Index]->AddObjects(apChildObjects[i32Index], aiChildCounts[i32Index]);
         }
     }    
 }