#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 tothe 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 messagevoid 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 messagevoid 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 NDEBUGif(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;}#endifreturn 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; }/// Sizeint getSize(void) const { return width * height; }/** Get const-reference to a pixel.This method includes clipping! Specifying out-of-imagecoordinates will result in a const-reference to the dummypixel.@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 ];elsereturn 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 valuesinline 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 itaccessible to the Mimas-library. */template< typename T >class image_ref: public const_image_ref< T, T* >{public:/**iteratorimplementation of iterator for images as described in the paperSTL-style generic programming with imagesby Ullrich KotheStill 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 messagevoid 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 messagevoid 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 NDEBUGif(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;}#endifreturn 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 beshared). */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-imagecoordinates 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 ];elsereturn image_ref< T >::dummy;}/** Get const-reference to a pixel.This method includes clipping! Specifying out-of-imagecoordinates will result in a const-reference to the dummypixel.@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 ];elsereturn 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 uperLeftinline iterator ul(void){return iterator(image_ref< T >::data,image_ref< T >::getWidth());}//the same as lowerRightinline 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