Subversion Repositories gelsvn

Rev

Rev 61 | Rev 443 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#ifndef __CELL_H
#define __CELL_H

#include <vector>
#include "CGLA/Vec3i.h"
#include "CGLA/BitMask.h"
#include "RGrid.h"

namespace Geometry 
{
        /** \brief Class template for a cell in a hierarchical grid.

                        The template arguments are the type and the cell dimension.
                        A Cell is much like an RGrid - except that a Cell may 
                        be coalesced into a single value and then split again
                        when a new value is inserted. Also cells are constrained to
                        be of size NxNxN where N=2^m for some m. This makes some things
                        faster.

                        The reason for making CELL_DIM a template argument rather 
                        than a constructor argument is that we generally have many 
                        cells   and do not wish that each cell contains its dimension. 
        */
        template<class T, int CELL_DIM, class ChildT>
        class Cell
        {
        public:
                typedef T DataType;

        private:
                bool touched;

                /// Linear array containing data of this Cell.
                std::vector<T> data;
                
                /** Return a bit mask used to mask indices. 
                                Some functions in this class are passed a Vec3i 
                                whose lower bits index into the cell. The mask is
                                used to select these lower bits before the 3D
                                index is converted to   a linear index.
                                
                                If you are wondering about why the static variable 
                                inside the function is not simply a static member of 
                                the class, check out item 47 og "Effective C++" by 
                                Scott Meyers.
                */
                static const CGLA::BitMask& get_bit_mask()
                {
                        static const CGLA::BitMask bit_mask(CELL_DIM);
                        return bit_mask;
                }

        public:

                /** Get dimensions of Cell. Returns only one value since 
                                x, y, and z dimensions are the same. */
                static int get_dim() 
                {
                        return CELL_DIM;
                }

        private:
                
                /** Get index. Computes an index into the linear array representation
                                of the voxels in the cell from a 3D grid index. The top bits (which
                                have been used to find this Cell) are masked out. */
                int get_idx(const CGLA::Vec3i& idx) const
                {
                        CGLA::Vec3i bot_idx = get_bit_mask().mask(idx);
                        return (bot_idx[2]*get_dim()+bot_idx[1])*get_dim()+bot_idx[0];
                }

        protected:

                /** Store a value in the Cell. If the Cell is 
                                coalesced, it is first resized to contain CELL_DIMS 
                                cubed voxels, and then the voxel is inserted. */
                void store_priv(const CGLA::Vec3i& p, const T& new_val) 
                {
                        if(is_coalesced()) split();
                        touched = true;
                        data[get_idx(p)] = new_val;
                }

                
        public:
        
                /** Create empty grid cell. A Cell contains initially a single value.
                                Reading (using operator[]) any voxel will yield this value. */
                Cell(const T& val): data(1,val), touched(false)
                {
                        assert(CELL_DIM==get_dim());
                }

                /** Clear cell. Removes Cell contents replacing it with a single
                                specified value. */
                void coalesce(const T& val) 
                {
                        data=std::vector<T>(1,val);
                        touched = true;
                }

                /// Split cell - causes memory to be reserved for CELL_DIM^3 voxels.
                void split()
                {
                        T val = data[0];
                        data.resize(CGLA::qbe(CELL_DIM), val);
                        touched = true;
                }

                /// Check if the cell is coalesced
                bool is_coalesced() const 
                {
                        // We rely on size() being constant time below.
                        // Probably this function should be changed.... it would be bad
                        // if it was slow ... very bad....
                        return data.size()==1;
                }

                
                /** Read access to voxel grid. This function is passed
                                a Vec3i and returns the corresponding voxel. If the
                                cell is coalesced, the single value stored is returned. */
                const T& operator[](const CGLA::Vec3i& p) const 
                {
                        if(is_coalesced()) return data[0];
                        return *(&data[get_idx(p)]);
                }

                void store(const CGLA::Vec3i& p, const T& new_val) 
                {
                        return static_cast<ChildT&>(*this).store(p,new_val);
                }
                
        
                /** Const get a pointer to the first element in the linear
                                array representation of the grid. */
                const T* get() const {return &data[0];}

                /** Non-const get a pointer to the first element in the linear
                                array representation of the grid. */
                T* get() 
                {
                        touched = true;
                        return &data[0];
                }

                void untouch() {touched=false;}
                void touch() {touched=true;}
                bool is_touched() const {return touched;}

        };

        
        template<class T, int CELL_DIM>
        class DefaultCell: public Cell<T,CELL_DIM,DefaultCell<T, CELL_DIM> >
        {
        public:
                DefaultCell(const T& val): Cell<T,CELL_DIM,DefaultCell>(val){}
                void store(const CGLA::Vec3i& p, const T& new_val) 
                {
                        store_priv(p, new_val);
                }
                
        };


}
#endif