/** @file PointHashGrid.h @maintainer Morgan McGuire, http://graphics.cs.williams.edu @created 2008-07-01 @edited 2009-05-28 Copyright 2000-2010, Morgan McGuire. All rights reserved. */ #ifndef G3D_PointHashGrid_h #define G3D_PointHashGrid_h #include "G3D/platform.h" #include "G3D/EqualsTrait.h" #include "G3D/HashTrait.h" #include "G3D/Vector3.h" #include "G3D/Vector3int32.h" #include "G3D/Array.h" #include "G3D/Table.h" #include "G3D/AABox.h" #include "G3D/Sphere.h" #include "G3D/SmallArray.h" namespace G3D { /** Storage of data in a sparse 3D grid of point-based data. The space cost for n elements is O(n). For data with approximately uniform density (with respect to the radius hint), the time cost of searching for neighbors is O(1). Value must be supported by a G3D::PositionTrait and G3D::EqualsTrait. Overloads are provided for common G3D classes like G3D::Vector3. For example:
    class EqualsFunc {
    public:
        static bool equals(const Data& p, const Data& q) {
            return p == q;
        }
    };
    
    class PosFunc {
    public:
        static void getPosition(const Data& d, Vector3& pos) {
            pos = d.location;
        }
    };
    PointHashGrid grid;
   
   If the Value class defines operator==, the Equalsfunc is optional:
   
    PointHashGrid grid;
   
*/
templateposition * m_cellWidth*/
    CellTable           m_data;
    MemoryManager::Ref  m_memoryManager;
    /** Intentionally unimplemented: prevent copy construction. */
    PointHashGrid(const ThisType&);
    /** Intentionally unimplemented: prevent assignment. */
    PointHashGrid& operator=(const ThisType&);
    /** Locate the cell and index within that cell containing v. Called by
        remove() and contains(). */
    bool find(const Value&    v, 
              Vector3int32&   foundCellCoord, 
              Cell*&          foundCell, 
              int&            index) {
        
        Vector3 pos;
        PosFunc::getPosition(v, pos);
        Vector3int32 cellCoord;
        getCellCoord(pos, cellCoord);
        for (int i = 0; i < 27; ++i) {
            Vector3int32 c = cellCoord + m_offsetArray[i];
            Cell* cell = m_data.getPointer(c);
            if (cell != NULL) {
                // The cell exists
                for (int j = 0; j < cell->size(); ++j) {
                    if (EqualsFunc::equals((*cell)[j].value, v)) {
                        foundCell = cell;
                        index = j;
                        foundCellCoord = c;
                        return true;
                    }
                }
            }            
        }
        // Not found
        return false;        
    }
    /** Given a real-space position, returns the cell coord 
        containing it.*/
    inline void getCellCoord(const Vector3& pos, Vector3int32& cellCoord) const {
        for (int a = 0; a < 3; ++a) {
            cellCoord[a] = iFloor(pos[a] * m_invCellWidth);
        }
    }
    /** Initializes m_offsetArray. */
    void initOffsetArray() {
        int i = 0;
        Vector3int32 d;
        for (d.x = -1; d.x <= +1; ++d.x) {
            for (d.y = -1; d.y <= +1; ++d.y) {
                for (d.z = -1; d.z <= +1; ++d.z) {
                    m_offsetArray[i] = d;
                    ++i;
                }
            }
        }
        
        // Put (0, 0, 0) first, so that contains() is most likely to find
        // the value quickly.
        i = (1 * 3 + 1) * 3 + 1;
        debugAssert(m_offsetArray[i] == Vector3int32(0,0,0));
        Vector3int32 temp = m_offsetArray[0];
        m_offsetArray[0] = m_offsetArray[i];
        m_offsetArray[i] = temp;
    }
public:
    /** 
        @param radiusHint the radius that will typically be used with 
        beginSphereIntersection and beginBoxIntersection. If two Values are equal,
        their positions must be within this radius as well.
    */
    PointHashGrid(float radiusHint, const MemoryManager::Ref& m = MemoryManager::create()) : m_size(0), m_memoryManager(m) {
        initOffsetArray();
        m_data.clearAndSetMemoryManager(m_memoryManager);
        debugAssertM(radiusHint > 0, "Cell radius must be positive");
        m_cellWidth = radiusHint;
        m_invCellWidth = 1.0f / m_cellWidth;
    }
    /**
       If radiusHint is negative, it is automatically chosen to put 
       about 5 values in each grid cell (which means about 27 * 5 
       values for each beginIntersection call).
    */
    PointHashGrid(const ArraygetPosition(v, p).  
        Multiple elements that are equal may be inserted; all copies will be
        in the data structure. */
    void insert(const Value& v) {
        Vector3 pos;
        PosFunc::getPosition(v, pos);
        Vector3int32 cellCoord;
        getCellCoord(pos, cellCoord);
        // See if the cell already exists
        Cell& cell = m_data.getCreate(cellCoord);
        if (cell.size() == 0) {
            // Use the same memory manager as for the whole class
            cell.clearAndSetMemoryManager(m_memoryManager);
        }
        Entry& entry    = cell.next();
        entry.value     = v;
        entry.position  = pos;
        // Update the bounds
        if (size() == 0) {
            m_bounds = AABox(pos);
        } else {
            m_bounds.merge(pos);
        }
        ++m_size;
        ++m_epoch;
    }
    /** Inserts all elements of the array. */
    void insert(const Array
        for (Grid::Iterator i = grid.begin(); i != grid.end(), ++i) {
        const Value& = *i;
        ...
        }
        
    */
    Iterator begin() const {
        return Iterator(this);
    }
    const Iterator& end() const {
        static const Iterator it;
        return it;
    }
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    // Forward declaration required by older gcc versions for friend declaration in BoxIterator
    class SphereIterator;
    class BoxIterator {
    private:
        friend class ThisType;
        friend class SphereIterator;
        bool                                    m_isEnd;
        const ThisType*                         m_grid;
        /** Lower bound on the boxes covered, inclusive. */
        Vector3int32                            m_lo;
        /** Upper bound on the boxes covered, inclusive.*/
        Vector3int32                            m_hi;
        
        /** If true, test values against m_box before returning them.*/
        bool                                    m_exact;
        /** The underlying box in 3D space */
        AABox                                   m_box;
        /** The iterator winds through the 3D grid between m_lo and (m_lo + m_extent) in
            Z,Y,X-major order.  This is the index keeping track of how
            far it has come */
        Vector3int32                            m_current;
        
        /** The current cell. */
        Cell*                                   m_cell;
        /** Index within m_cell of the current value */
        int                                     m_arrayIndex;
        const int                               m_epoch;
      
        /** Called from advance() */
        void advanceCell() {
            do {
                ++m_current.x;
                if (m_current.x > m_hi.x) {
                    m_current.x = m_lo.x;
                    ++m_current.y;
                    if (m_current.y > m_hi.y) {
                        m_current.y = m_lo.y;
                        ++m_current.z;
                        if (m_current.z > m_hi.z) {
                            m_isEnd = true;
                            return;
                        }
                    }
                }
                // Pick up the new cell
                m_cell = m_grid->m_data.getPointer(m_current);
                // Keep advancing if the cell does not exist
            } while ((m_cell == NULL) || (m_cell->size() == 0));
        }
        /** Advance to the next value */
        void advance() {
            debugAssert(! m_isEnd);
            do {
                ++m_arrayIndex;
                bool inConstructor = (m_cell == NULL);
                if (inConstructor || m_arrayIndex >= m_cell->size()) {
                    advanceCell();
                    m_arrayIndex = 0;
                    if (m_isEnd) {
                        // Ran out of values
                        return;
                    }
                    debugAssert(m_cell != NULL);
                }
                // Advance until we have a value that can be returned, either
                // because we don't care about exactness or because it is 
                // guaranteed to be within the box.
            } while (m_exact && ! m_box.contains(position()));
        }
        /** End iterator */
        BoxIterator() : m_isEnd(true), m_grid(NULL), m_exact(true), m_current(0,0,0), m_cell(NULL), m_arrayIndex(0), m_epoch(0) {}
        /** Begin iterator */
        BoxIterator(const ThisType* grid, bool exact, const AABox& box) : 
            m_isEnd(false),
            m_grid(grid),
            m_exact(exact),
            m_box(box),
            m_current(-1, 0 ,0),
            m_cell(NULL),
            m_arrayIndex(0),
            m_epoch(grid->m_epoch) { 
            m_grid->getCellCoord(box.low(), m_lo);
            m_grid->getCellCoord(box.high(), m_hi);
            
            // Get to the first value
            m_current = m_lo;
            // Back up one so that advancing takes us to the first
            --m_current.x;
            advance();
        }
        const Value& value() const {
            debugAssert(! m_isEnd);
            return (*m_cell)[m_arrayIndex].value;
        }
        /** Used by SphereIterator::advance() */
        const Vector3& position() const {
            debugAssert(! m_isEnd);
            return (*m_cell)[m_arrayIndex].position;
        }
        // Intentionally unimplemented
        BoxIterator& operator=(const BoxIterator&);
    public:
        inline bool operator!=(const BoxIterator& other) const {
            if (other.m_isEnd && m_isEnd) {
                return false;
            } else {
                return (m_isEnd         != other.m_isEnd) ||
                    (m_cell          != other.m_cell) || 
                    (m_arrayIndex    != other.m_arrayIndex);
            }
        }
        bool operator==(const BoxIterator& other) const {
            return !(*this != other);
        }
        /** Preincrement */
        BoxIterator& operator++() {
            debugAssert(! m_isEnd);
            debugAssertM(m_epoch == m_grid->m_epoch, 
                         "It is illegal to mutate the HashGrid "
                         "while iterating through it.");
            advance();
            return *this;
        }
        /** Post increment (slower) */
        BoxIterator operator++(int) {
            Iterator old = *this;
            ++(*this);
            return old;
        }
        const Value& operator*()  const { return  value(); }
        const Value* operator->() const { return &value(); }
        operator Value*()         const { return &value(); }
        bool hasMore() const {
            return ! m_isEnd;
        }
    }; // BoxIterator
    /** 
        Finds all values whose positions are within @a box.  It is an error to 
        mutate the PointHashGrid while iterating through it.
        @param exact If false, the iterator will execute more quickly but will likely return some
        values that lie outside the box. Set exact = false if you are going to test the 
        results against the yourself box anyway.
    */
    BoxIterator beginBoxIntersection(const AABox& box, bool exact = true) const {
        return BoxIterator(this, exact, box);
    }
    const BoxIterator& endBoxIntersection() const {
        static const BoxIterator it;
        return it;
    }
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    
    class SphereIterator {
    private:
        friend class ThisType;
        bool                m_isEnd;
        Sphere              m_sphere;
        BoxIterator         m_boxIterator;
        SphereIterator() : m_isEnd(true) {}
        void advance() {
            if (! m_boxIterator.hasMore()) {
                m_isEnd = true;
                return;
            }
            while (! m_sphere.contains(m_boxIterator.position())) {
                ++m_boxIterator;
                
                if (! m_boxIterator.hasMore()) {
                    m_isEnd = true;
                    return;
                }
            } 
        }
        static AABox getBoundingBox(const Sphere& s) {
            AABox box;
            s.getBounds(box);
            return box;
        }
        SphereIterator(const ThisType* grid, const Sphere& sphere) : 
            m_isEnd(false),
            m_sphere(sphere),
            m_boxIterator(grid, false, getBoundingBox(sphere)) {
			
            // Find the first element that is actually in the sphere,
            // not just the box.
            advance();
        }
        const Value& value() const {			
            return *m_boxIterator;
        }
        // TODO: if the sphere is very big compared to radius, check each
        // cell's box to see if the cell itself is actually inside the sphere
        // before iterating through it, since there may be many boxes outside the sphere.
        // Intentionally unimplemented
        SphereIterator& operator=(const SphereIterator&);
    public:
        inline bool operator!=(const SphereIterator& other) const {
            if (other.m_isEnd && m_isEnd) {
                return false;
            } else {
                return 
                    (m_isEnd         != other.m_isEnd) ||
                    (m_sphere        != other.m_sphere) ||
                    (m_boxIterator   != other.m_boxIterator);
            }
        }
        bool operator==(const SphereIterator& other) const {
            return !(*this != other);
        }
	
        /** Preincrement */
        SphereIterator& operator++() {
            debugAssert(! m_isEnd);
            ++m_boxIterator;
            advance();
            return *this;
        }
        /** Post increment (slower) */
        SphereIterator operator++(int) {
            Iterator old = *this;
            ++(*this);
            return old;
        }
        const Value& operator*()  const { return  value(); }
        const Value* operator->() const { return &value(); }
        operator Value*()         const { return &value(); }
        bool hasMore() const {
            return ! m_isEnd;
        }
    }; // SphereIterator
    /** 
        Finds all values whose positions are within @a sphere.  It is an error
        to mutate the HashGrid while iterating through it.
    */
    SphereIterator beginSphereIntersection(const Sphere& sphere) const {
        return SphereIterator(this, sphere);
    }
    const SphereIterator& endSphereIntersection() const {
        static const SphereIterator it;
        return it;
    }
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    /**
       Dereference to access the bounds() and size() [element count] of the underlying
       cell objet.
       Example:
       
       for(PointHashGrid::CellIterator iter = grid.beginCells(); iter != grid.endCells(); ++iter) {	
       entriesFound += iter->size();
       }
        
    */
    class CellIterator {
    private:
        friend class ThisType;
        bool                                    m_isEnd;
        const ThisType*                         m_grid;
        typename CellTable::Iterator            m_tableIterator;
        const int                               m_epoch;
        Cell& cell() {
            return m_tableIterator->value;
        }
    public:
        
        class CellObject {
            friend class CellIterator;
        private:
            const CellIterator* m_parent;
            CellObject() : m_parent(NULL) {}
        public:
            /** Returns the bounds on this cell */
            AABox bounds() const {
                const Vector3int32& k = m_parent->m_tableIterator->key;
                return AABox(Vector3(k) * m_parent->m_cellWidth, 
                             Vector3(k + Vector3int32(1, 1, 1)) * m_parent->m_cellWidth);
            }
            /** Number of elements inside this cell */
            int size() const {
                debugAssert(! m_parent->m_isEnd);
                return m_parent->m_tableIterator->value.size();
            }
        };
    private:
        /** Used to make the indirection work.*/
        CellObject m_indirection;
        /** End iterator. Note that the m_tableIterator is initialized to the end iterator
            of a temporary value!  This is ok because we'll never look at the value of the 
            m_tableIterator, since we're initializing the "end" Iterator.*/
        CellIterator() : 
            m_isEnd(true),
            m_grid(NULL),
            m_tableIterator( CellTable().end() ),
            m_epoch(0) {}
        
        CellIterator(const ThisType* grid) : 
            m_isEnd(false),
            m_grid(grid),
            m_tableIterator( grid->m_data.begin()),
            m_epoch(grid->m_epoch) {
            m_indirection.m_parent = this;
            m_isEnd = ! m_tableIterator.hasMore();
        }
        
        // Intentionally unimplemented
        CellIterator& operator=(const CellIterator&);
    public:
        const CellObject& operator*()  const { return  m_indirection; }
        const CellObject* operator->() const { return &m_indirection; }
        operator CellObject*()         const { return &m_indirection; }
        inline bool operator!=(const CellIterator& other) const {
            // != is called more often than == during iteration
            return !(
                     (m_isEnd && other.m_isEnd) ||
                     ((m_isEnd == other.m_isEnd) && 
                      (m_tableIterator != other.m_tableIterator)));
        }
        bool operator==(const CellIterator& other) const {
            return !(*this != other);
        }
        /** Preincrement */
        CellIterator& operator++() {
            debugAssertM(m_epoch == m_grid->m_epoch, 
                         "It is illegal to mutate the HashGrid while "
                         "iterating through it.");
            ++m_tableIterator;
            m_isEnd = ! m_tableIterator.hasMore();
            return *this;
        }
        /** Post increment (slower) */
        CellIterator operator++(int) {
            Iterator old = *this;
            ++(*this);
            return old;
        }
        bool hasMore() const {
            return ! m_isEnd;
        }
    }; // CellIterator
    /** Iterates through the non-empty cells.  This is intended primarily for
        debugging and visualizing the data structure.*/
    CellIterator beginCells() const {
        return CellIterator(this);
    }
    const CellIterator& endCells() const {
        static const CellIterator it;
        return it;
    }
    ///////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////
    /** Returns true if there is a value that is exactly equal to @a v. This will 
        check all neighboring cells to avoid roundoff error at cell boundaries. 
    */
    bool contains(const Value& v) const {
        Cell* cell = NULL;
        int   index = 0;
        Vector3int32 cellCoord;
        return const_cast