#ifndef __SpatialGrid_h 
#define __SpatialGrid_h 
#include <maya/MBoundingBox.h>
#include <maya/MIntArray.h>
#include <maya/MUintArray.h>
#include <vector>
template <class T>
class gridPoint3 {
public:
    gridPoint3(){}
    gridPoint3(T _1, T _2, T _3){
        fData[0] = _1;
        fData[1] = _2;
        fData[2] = _3;
        fCompareVal = fData[0]+3083*fData[1]+7919*fData[2]; 
    }
    operator T *(){return fData;}
    operator const T *() const{return fData;}
    double compareVal()const { return fCompareVal; }
    
    gridPoint3 operator+ (const gridPoint3& x) const{gridPoint3 y(x); y.fData[0]+=fData[0]; y.fData[1]+=fData[1]; y.fData[2]+=fData[2]; return y; }
    gridPoint3 operator+ (const T& x) const{ gridPoint3 y(*this); y.fData[0]+=x; y.fData[1]+=x; y.fData[2]+=x; return y; }
    gridPoint3 operator- (const T& x) const{ gridPoint3 y(*this); y.fData[0]-=x; y.fData[1]-=x; y.fData[2]-=x; return y; }
    gridPoint3 operator* (const gridPoint3& x) const{gridPoint3 y(x); y.fData[0]*=fData[0]; y.fData[1]*=fData[1]; y.fData[2]*=fData[2]; return y;}
    gridPoint3 operator* (const T& x)  const{ gridPoint3 y(*this); y.fData[0]*=x; y.fData[1]*=x; y.fData[2]*=x; return y; }
    gridPoint3& operator+= (const gridPoint3& x){ fData[0]+=x[0]; fData[1]+=x[1]; fData[2]+=x[2]; return *this;}
    gridPoint3& operator*= (const gridPoint3& x){fData[0]*=x[0]; fData[1]*=x[1]; fData[2]*=x[2]; return *this;}
    gridPoint3& operator*= (const T& x){fData[0]*=x;    fData[1]*=x;    fData[2]*=x;    return *this;}
    bool operator< (const gridPoint3& y) const{
        return fCompareVal < y.compareVal();
    }
private:
    T fData[3];
    double fCompareVal;
};
class SpatialGridWalker;
class SpatialGrid { 
public:
    
    
    
    SpatialGrid( 
const MBoundingBox& bound, 
const gridPoint3<int>& numVoxels );
    virtual ~SpatialGrid();
    
    
    
    SpatialGridWalker getRayIterator( 
const MPoint& origin,
    
    
    
    
    void getVoxelCoords( 
const MPoint& point, 
 
        gridPoint3<int>& coords, 
        MPoint *residual = NULL ) 
const;
 
    void getClosestVoxelCoords( 
const MPoint& point, 
 
        gridPoint3<int>& coords) const;
    bool isValidVoxel(gridPoint3<int>& vox);
    
    
    
        gridPoint3<int>& minIndices, 
        gridPoint3<int>& maxIndices ) const;
    
    
    MUintArray *            getVoxelContents( 
const gridPoint3<int>& index );
 
    
    
    const gridPoint3<int>&          getNumVoxels();
    virtual float           getMemoryFootprint();
    
    
    friend class SpatialGridWalker; 
private:
    
    
    void bounds( 
MPoint& lowCorner, 
 
    
    
    
    int getLinearVoxelIndex( const gridPoint3<int>& index ) const;
    
    
    
    
    gridPoint3<int>                     fNumVoxels;
    
    
    gridPoint3<float>                       fVoxelSizes;
    
    
    
    
    
    std::vector<MUintArray*>        fVoxels;
    void expandBBoxByPercentage( 
        double percentage,
        double min[3] 
    );
    
};
#endif