Rev 89 | Rev 595 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
#ifndef __GEOMETRY_ANCESTORGRID_H
#define __GEOMETRY_ANCESTORGRID_H
#include "CGLA/Vec3i.h"
namespace Geometry
{
/** \brief Class template is used as abstract ancestor of
voxel grids.
Strictly speaking, this class is not
abstract, since it does not have any virtual functions.
However, operator[]() and store() simply call
functions in derived classes. To do so, you must pass
the derived class as a template argument to this class
when you define the derived class. This is called the
Barton and Nackman trick. See Todd Veldhuizen,
"Techniques for Scientific C++" 1.3.3.
*/
template<typename T, class ChildT>
class AncestorGrid
{
public:
typedef T DataType;
private:
/// xyz dimensions of grid.
CGLA::Vec3i dims;
public:
/// Construct a grid of specified xyz dimensions.
AncestorGrid(int _x_dim, int _y_dim, int _z_dim):
dims(_x_dim,_y_dim,_z_dim) {}
/// Construct a grid of specified xyz dimensions.
AncestorGrid(const CGLA::Vec3i& _dims): dims(_dims) {}
/** Check if voxel is within grid bounds.
This function is passed a Vec3i, p, and returns true
if p is within the voxel grid. */
bool in_domain(const CGLA::Vec3i& p) const
{
for(int i=0; i<3; i++)
if (p[i]<0 || p[i] >= dims[i])
return false;
return true;
}
/** Get dimensions of grid.
This function returns a Vec3i with the dimensions
of the grid. */
const CGLA::Vec3i& get_dims() const {return dims;}
/// Get the corner having smallest coordinates.
const CGLA::Vec3i get_lo_corner() const {return CGLA::Vec3i(0);}
/// Get the corner having greatest coordinates.
const CGLA::Vec3i& get_hi_corner() const {return dims;}
/** Access (read only) a voxel in a grid.
This is the operator[] which is passed a Vec3i
and returns a const reference to a voxel.
This function is "statically virtual", i.e.
it simply calls the store function of a derived
class.
See below why there is no non-const operator[]
*/
const T& operator[](const CGLA::Vec3i& p) const
{
return static_cast<const ChildT&>(*this)[p];
}
/** Store a voxel in grid.
This function returns nothing but is passed a
Vec3i p and T value t and stores t at p in the
grid. This function is "statically virtual", i.e.
it simply calls the store function of a derived
class.
Yes, it would be simpler to provide a non-const
operator[], however, a non-const operator[] will
often be called even when no writing takes place.
(Scott Meyers, "More Effective C++, p. 218)
If a grid implementation allocates memory when
a voxel is accessed for writing, then it is a problem
that we cannot be sure a non-const operator[] is
called only if we are writing. We might then allocate
memory even if we just want to read.
*/
void store(const CGLA::Vec3i& p, const T& t)
{
return static_cast<ChildT&>(*this).store(p,t);
}
};
}
#endif