#include "gpuCacheSpatialGrid.h" 
#include "gpuCacheSpatialGridWalker.h" 
#include "gpuCacheIsectUtil.h"
#include <maya/MPointArray.h>
SpatialGrid::SpatialGrid( 
    const gridPoint3<int>& numVoxels 
    )
    
    
    
    
    
    
    :   fBounds(boundingBox),
    fNumVoxels(numVoxels)
{
    
    
    
    double minSize[3] = { 0.01, 0.01, 0.01 };
    expandBBoxByPercentage( fBounds, 1.0, minSize );
    
    
    
    fVoxelSizes[0] = fBounds.width() / fNumVoxels[0];
    fVoxelSizes[1] = fBounds.height() / fNumVoxels[1];
    fVoxelSizes[2] = fBounds.depth() / fNumVoxels[2];
    
    
    if( fVoxelSizes[0] < 0.01 )
    {
        fVoxelSizes[0] = fBounds.width();
        fNumVoxels[0] = 1;
    }
    if( fVoxelSizes[1] < 0.01 )
    {
        fVoxelSizes[1] = fBounds.height();
        fNumVoxels[1] = 1;
    }
    if( fVoxelSizes[2] < 0.01 )
    {
        fVoxelSizes[2] = fBounds.depth();
        fNumVoxels[2] = 1;
    }
    
    
    fVoxels.clear();
    unsigned int totalVoxels = fNumVoxels[0] * fNumVoxels[1] * fNumVoxels[2];
    for( unsigned int i = 0; i < totalVoxels; i++ )
    {
        fVoxels.push_back(NULL);
    }
}
SpatialGrid::~SpatialGrid()
    
    
    
    
    
{
    int numVoxels = fNumVoxels[0] * fNumVoxels[1] * fNumVoxels[2];
    for( int v = 0; v < numVoxels; v++ )
    {
        if( fVoxels[v] != NULL )
        {
            delete fVoxels[v];
        }
    }
}
const gridPoint3<int>& SpatialGrid::getNumVoxels()
{
    return fNumVoxels;
}
void SpatialGrid::bounds( 
MPoint& lowerCorner, 
MPoint& upperCorner )
 
{
    lowerCorner = fBounds.min();
    upperCorner = fBounds.max();
}
{
    return fBounds;
}
int SpatialGrid::getLinearVoxelIndex( const gridPoint3<int>& index ) const
    
    
    
    
    
    
    
    
{
    return index[2]*(fNumVoxels[0]*fNumVoxels[1]) 
        + index[1]*fNumVoxels[0] 
    + index[0];
}
void 
    SpatialGrid::getVoxelRange(
    gridPoint3<int>& minIndices,
    gridPoint3<int>& maxIndices 
    ) const
    
    
    
    
    
    
{
    
    
    const MPoint& minPt = box.min();
 
    const MPoint& maxPt = box.max();
 
    
    
    getVoxelCoords( minPt, minIndices, NULL );
    getVoxelCoords( maxPt, maxIndices, NULL );
}
void SpatialGrid::getVoxelCoords( 
    gridPoint3<int>& coords,
    
    
    
    
    
    
    
    
{
    
    
    MPoint relPoint = point - fBounds.min();
 
    
    
    for( int axis = 0; axis < 3; axis++ )
    {
        
        
        float voxSpace = relPoint[axis] / fVoxelSizes[axis];
        coords[axis] = (int)floor( voxSpace );
        
        
        if( coords[axis] < 0 ) 
        {
            coords[axis] = 0;
        }
        else if( coords[axis] >= fNumVoxels[axis] )
        {
            coords[axis] = fNumVoxels[axis]-1;
        }
        
        
        if( residuals != NULL )
        {
            (*residuals)[axis] = fVoxelSizes[axis]*(voxSpace-coords[axis]);
        }
    }
}
void SpatialGrid::expandBBoxByPercentage( 
    double percentage,
    double min[3] 
)
    
    
    
    
    
    
    
    
    
    
    
    
{
    percentage += 1.0;
    
    
    if( min != NULL )
    {   
        if( w < min[0] )
        {
            w = min[0];
        }
        if( h < min[1] ) 
        {
            h = min[1];
        }
        if( d < min[2] )
        {
            d = min[2];
        }
    }
    
    
    offset *= (0.5f * percentage);
}
void SpatialGrid::getClosestVoxelCoords( 
    gridPoint3<int>& coords) const
    
    
    
    
    
    
{   
    MPoint c1 = fBounds.min() + 
MVector(fBounds.width()/4, fBounds.height()/4, fBounds.depth()/4);
 
    MPoint c2 = fBounds.max() - 
MVector(fBounds.width()/4, fBounds.height()/4, fBounds.depth()/4);
 
    if(bounds.contains(point)){
        relPoint = point - fBounds.min();
    } else {
        
        GPUCache::gpuCacheIsectUtil::getClosestPointOnBox(point, bounds, closestPoint);
        relPoint = closestPoint - fBounds.min();
    } 
    for( int axis = 0; axis < 3; axis++ )
    {
        
        
        float voxSpace = relPoint[axis] / fVoxelSizes[axis];
        coords[axis] = (int)floor( voxSpace );
    }
    
}
bool SpatialGrid::isValidVoxel(gridPoint3<int>& vox){
    if(vox[0]>=0 && vox[0]<fNumVoxels[0] && vox[1]>=0 && vox[1]<fNumVoxels[1] && vox[2]>=0 && vox[2]<fNumVoxels[2]) 
        return true;
    return false;
}
    SpatialGrid::getVoxelContents( 
    const gridPoint3<int>& index 
    )
    
    
    
    
    
    
{
    int linearIndex = getLinearVoxelIndex( index );
    if( fVoxels[linearIndex] == NULL )
    {
    }
    return fVoxels[linearIndex];
}
float SpatialGrid::getMemoryFootprint()
    
    
    
    
    
    
    
    
    
    
{
    int totalSize = 0;
    
    
    int numVoxels = fNumVoxels[0]*fNumVoxels[1]*fNumVoxels[2];
    for( int v = 0; v < numVoxels; v++ )
    {
        if( fVoxels[v] != NULL )
        {
            totalSize += fVoxels[v]->
length()*
sizeof(
unsigned int);
        }
    }
    
    
    return ((float)totalSize)/1024.0f;
}
SpatialGridWalker SpatialGrid::getRayIterator( 
    
    
    
    
    
    
    
    
{
    return SpatialGridWalker( origin, direction, this );
}