#ifndef IMAGE_REF_H
#define IMAGE_REF_H
#include <cassert>
#include "object.h"
namespace mimas {
/** To represent a displacement in an image.
Used by image iterator */
struct dist2D{
dist2D(int x = 0, int y = 0):
width(x), height(y){}
int width;
int height;
};
/** Wrapper for read-only access of image-data.
This class is used for wrapping raw constant data to make it accessible to
the Mimas-library. */
template<
typename T,
typename TPtr = const T* >
class const_image_ref: public object
{
public:
/** Default constructor.
Creates an empty image. */
const_image_ref(void): data(NULL), width(0), height(0) { dummy = T(); }
///
const_image_ref( TPtr _data, int _width, int _height ):
data(_data), width(_width), height(_height) { dummy = T(); }
///
template< typename OPtr >
const_image_ref( const const_image_ref< T, OPtr > &_imgref ):
data( _imgref.rawData() ),
width( _imgref.getWidth() ), height( _imgref.getHeight() )
{ dummy = T(); }
///
class const_iterator{
public:
typedef T value_type;
typedef const value_type * MoveX;
struct MoveY{
MoveY(unsigned int width = 0):
width(width),offset(0){
}
void operator++(void){
offset += width;
}
//postfix operator. There is no difference as we don't return any value
//but avoid any warning message
void operator++(int){
offset += width;
}
void operator--(void){
offset -= width;
}
//postfix operator. There is no difference as we don't return any value
//but avoid any warning message
void operator--(int){
offset -= width;
}
MoveY & operator+=(int n)
{
offset += width * n;
return *this;
}
MoveY & operator-=(int n)
{
offset -= width * n;
return *this;
}
int operator-(const MoveY &y2) const
{
return (offset - y2.offset)/width;
}
MoveY & operator=(const MoveY &y2)
{
offset = y2.offset;
width = y2.width;
return *this;
}
bool operator==(const MoveY &y2) const
{
return (offset == y2.offset) && (width == y2.width);
}
bool operator<(const MoveY &y2) const
{
return offset < y2.offset;
}
unsigned int width;
unsigned int offset;
};
MoveX x;
MoveY y;
const_iterator(const value_type *data = NULL, unsigned int width = 0):
x(data), y(width) {}
const_iterator(const const_iterator & rhs)
{
x = rhs.x;
y = MoveY(rhs.y.width);
y.offset = rhs.y.offset;
}
const_iterator & operator=(const const_iterator & rhs)
{
x = rhs.x;
y = rhs.y;
return *this;
}
const_iterator & operator+=(const dist2D & dist)
{
x += dist.width;
y += dist.height;
return *this;
}
const_iterator & operator-=(const dist2D & dist)
{
x -= dist.width;
y -= dist.height;
return *this;
}
const_iterator operator+(const dist2D & dist) const
{
const_iterator k(*this);
k += dist;
return k;
}
const_iterator operator-(const dist2D & dist) const
{
const_iterator k(*this);
k -= dist;
return k;
}
//mechanism to check the iterator of both images are of same width.
dist2D operator-(const const_iterator & rhs) const
{
#ifndef NDEBUG
if(y.width != rhs.y.width){
std::cerr<<"const_iterator (in image.h): you cannot compare"
"2 iterators if both images don't have the same width" <<std::endl;
}
#endif
return dist2D(x - rhs.x, (y.offset - rhs.y.offset)/ rhs.y.width);
}
bool operator==(const const_iterator & imIt) const
{
return (x == imIt.x) && (y == imIt);
}
const value_type & operator*()
{
return *(x + y.offset);
}
const value_type operator*() const
{
return *(x + y.offset);
}
const value_type &operator[](const dist2D dist)
{
return *(x + y.offset + dist.width + dist.height * y.width);
}
const value_type operator[](const dist2D dist) const
{
return *(x + y.offset + dist.width + dist.height * y.width);
}
};
/// Width of image.
int getWidth(void) const { return width; }
/// Height of image.
int getHeight(void) const { return height; }
/// Size
int getSize(void) const { return width * height; }
/** Get const-reference to a pixel.
This method includes clipping! Specifying out-of-image
coordinates will result in a const-reference to the dummy
pixel.
@param x x-coordinate
@param y y-coordinate
@see pixel
@see dummy */
const T &getPixel( int x, int y ) const {
if ( x>=0 && y>=0 && x<getWidth() && y<getHeight() )
return data[ y * getWidth() + x ];
else
return dummy;
}
/** Get const-reference to a pixel.
No clipping!
@param x x-coordinate
@param y y-coordinate
@see getPixel */
const T& pixel( int x, int y ) const {
assert( x>=0 && y>=0 && x<getWidth() && y<getHeight() );
return data[ y * getWidth() + x ];
}
/// Read-only access to data.
const T *rawData( void ) const {
return data;
}
///
bool initialised( void ) const {
assert( ( data != NULL ) == ( width > 0 && height > 0 ) );
return data != NULL;
}
//to return const values
inline const_iterator upperLeft(void) const
{
return const_iterator(data,getWidth());
}
inline const_iterator lowerRight(void) const
{
const_iterator t(data,getWidth());
t.x += getWidth();
t.y += getHeight();
return t;
}
inline const_iterator ul(void) const
{
return const_iterator(data,getWidth());
}
inline const_iterator lr(void) const
{
const_iterator t(data,getWidth());
t.x += getWidth();
t.y += getHeight();
return t;
}
protected:
/** Data-pointer.
Pointer to the data in row-major format. */
TPtr data;
int width;
int height;
T dummy;
};
/** Wrapper to access image-data.
This class is used for wrapping raw data for the purpose of making it
accessible to the Mimas-library. */
template< typename T >
class image_ref: public const_image_ref< T, T* >
{
public:
/**iterator
implementation of iterator for images as described in the paper
STL-style generic programming with images
by Ullrich Kothe
Still not thoroughly tested
@author Manuel Boissenin */
class iterator {
public:
typedef T value_type;
typedef value_type * MoveX;
struct MoveY{
MoveY(unsigned int width = 0):
width(width),offset(0) {
// std::cerr<< "constructor MoveY"<<std::endl;
}
void operator++(void){
offset += width;
}
//postfix operator. There is no difference as we don't return any value
//but avoid any warning message
void operator++(int) {
offset += width;
}
void operator--(void) {
offset -= width;
}
//postfix operator. There is no difference as we don't return any value
//but avoid any warning message
void operator--(int) {
offset -= width;
}
MoveY & operator+=(int n)
{
offset += width * n;
return *this;
}
MoveY & operator-=(int n)
{
offset -= width * n;
return *this;
}
int operator-(const MoveY &y2) const
{
return (offset - y2.offset)/width;
}
MoveY & operator=(const MoveY &y2)
{
offset = y2.offset;
width = y2.width;
return *this;
}
bool operator==(const MoveY &y2) const
{
return (offset == y2.offset) && (width == y2.width);
}
bool operator<(const MoveY &y2) const
{
return offset < y2.offset;
}
unsigned int width;
unsigned int offset;
};
MoveX x;
MoveY y;
iterator(value_type *data = NULL, unsigned int width = 0):
x(data), y(width) {}
iterator(const iterator & rhs)
{
x = rhs.x;
y = MoveY(rhs.y.width);
y.offset = rhs.y.offset;
}
iterator & operator=(const iterator & rhs)
{
//std::cerr<< "operator= iterator"<<std::endl;
x = rhs.x;
y = rhs.y;
return *this;
}
iterator & operator+=(const dist2D & dist)
{
x += dist.width;
y += dist.height;
return *this;
}
iterator & operator-=(const dist2D & dist)
{
x -= dist.width;
y -= dist.height;
return *this;
}
iterator operator+(const dist2D & dist) const
{
iterator k(*this);
k += dist;
return k;
}
iterator operator-(const dist2D & dist) const
{
iterator k(*this);
k -= dist;
return k;
}
//mechanism to check the iterator of both images are of same width.
dist2D operator-(const iterator & rhs) const
{
#ifndef NDEBUG
if(y.width != rhs.y.width){
std::cerr<<"Image iterator (in image.h): you cannot compare"
"2 iterators if both images don't have the same width" <<std::endl;
}
#endif
return dist2D(x - rhs.x, (y.offset - rhs.y.offset)/ rhs.y.width);
}
bool operator==(const iterator & imIt) const
{
return (x == imIt.x) && (y == imIt);
}
value_type & operator*()
{
return *(x + y.offset);
}
value_type operator*() const
{
return *(x + y.offset);
}
value_type &operator[](const dist2D dist)
{
return *(x + y.offset + dist.width + (signed)( dist.height * y.width ) );
}
value_type operator[](const dist2D dist) const
{
return *(x + y.offset + dist.width + (signed)( dist.height * y.width ) );
}
};
/** Default constructor.
Creates an empty image. */
image_ref(void) {}
/** Copy constructor.
The data-pointer of the other object is copied (i.e. the data will be
shared). */
explicit image_ref( const image_ref< T > &_imgref ):
const_image_ref< T, T* >( _imgref ) {}
///
image_ref( T *_data, int _width, int _height ):
const_image_ref< T, T* >( _data, _width, _height ) {}
/// Fill all pixel with a value.
virtual void fill( const T &initVal ) {
int size = image_ref< T >::getSize();
std::fill( image_ref< T >::data,
image_ref< T >::data + size, initVal );
};
/** Get reference to a pixel.
This method includes clipping! Specifying out-of-image
coordinates will result in a reference to a dummy pixel.
@param x x-coordinate
@param y y-coordinate
@see pixel
@see dummy */
T &getPixel( int x, int y ) {
if ( x>=0 && y>=0 &&
x<image_ref< T >::getWidth() &&
y<image_ref< T >::getHeight() )
return image_ref< T >::data
[ y * image_ref< T >::getWidth() + x ];
else
return image_ref< T >::dummy;
}
/** Get const-reference to a pixel.
This method includes clipping! Specifying out-of-image
coordinates will result in a const-reference to the dummy
pixel.
@param x x-coordinate
@param y y-coordinate
@see pixel
@see dummy */
const T &getPixel( int x, int y ) const {
if ( x>=0 && y>=0 &&
x<image_ref< T >::getWidth() &&
y<image_ref< T >::getHeight() )
return image_ref< T >::data
[ y * image_ref< T >::getWidth() + x ];
else
return image_ref< T >::dummy;
}
/** Set value of a pixel.
This method includes clipping!
@param x x-coordinate
@param y y-coordinate
@param val New value.
@see pixel */
virtual void setPixel( int x, int y, T val ) {
if ( x>=0 &&
y>=0 &&
x<image_ref< T >::getWidth() &&
y<image_ref< T >::getHeight() )
image_ref< T >::data
[ y * image_ref< T >::getWidth() + x ] = val;
}
/** Get reference to a pixel.
No clipping!
@param x x-coordinate
@param y y-coordinate
@see setPixel */
T& pixel( int x, int y ) {
assert( x>=0 && y>=0 && x<image_ref< T >::getWidth()&& y<image_ref< T >::getHeight() );
return image_ref< T >::data
[ y * image_ref< T >::getWidth() + x ];
}
/** Get const-reference to a pixel.
No clipping!
@param x x-coordinate
@param y y-coordinate
@see getPixel */
const T& pixel( int x, int y ) const {
assert( x>=0 && y>=0 &&
x<image_ref< T >::getWidth() &&
y<image_ref< T >::getHeight() );
return image_ref< T >::data
[ y * image_ref< T >::getWidth() + x ];
}
/// Read-only access to data.
const T *rawData( void ) const {
return image_ref< T >::data;
}
/// Access to aggregated data.
T *rawData(void) {
return image_ref< T >::data;
}
inline iterator upperLeft(void)
{
return iterator(image_ref< T >::data,
image_ref< T >::getWidth());
}
inline iterator lowerRight(void)
{
iterator t(image_ref< T >::data,
image_ref< T >::getWidth());
t.x += image_ref< T >::getWidth();
t.y += image_ref< T >::getHeight();
return t;
}
//For lazy guys/pals/mates/fellows only!!!
//the same as uperLeft
inline iterator ul(void)
{
return iterator(image_ref< T >::data,
image_ref< T >::getWidth());
}
//the same as lowerRight
inline iterator lr(void)
{
iterator t(image_ref< T >::data,
image_ref< T >::getWidth());
t.x += image_ref< T >::getWidth();
t.y += image_ref< T >::getHeight();
return t;
}
};
}
#endif