blob: 1e3f64655fdd5f06cbf48cbd3f014a5e24daac9a [file] [log] [blame]
/*
Copyright 2005-2007 Adobe Systems Incorporated
Use, modification and distribution are subject to the Boost Software License,
Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
See http://opensource.adobe.com/gil for most recent version including documentation.
*/
/*************************************************************************************************/
#ifndef GIL_ITERATOR_FROM_2D_H
#define GIL_ITERATOR_FROM_2D_H
////////////////////////////////////////////////////////////////////////////////////////
/// \file
/// \brief pixel step iterator, pixel image iterator and pixel dereference iterator
/// \author Lubomir Bourdev and Hailin Jin \n
/// Adobe Systems Incorporated
/// \date 2005-2007 \n Last updated on September 18, 2007
///
////////////////////////////////////////////////////////////////////////////////////////
#include <cassert>
#include <boost/iterator/iterator_facade.hpp>
#include "gil_concept.hpp"
#include "gil_config.hpp"
#include "pixel_iterator.hpp"
#include "locator.hpp"
namespace boost { namespace gil {
////////////////////////////////////////////////////////////////////////////////////////
///
/// ITERATOR FROM 2D ADAPTOR
///
////////////////////////////////////////////////////////////////////////////////////////
/// \defgroup PixelIteratorModelFromLocator iterator_from_2d
/// \ingroup PixelIteratorModel
/// \brief An iterator over two-dimensional locator. Useful for iterating over the pixels of an image view. Models PixelIteratorConcept, PixelBasedConcept, HasDynamicXStepTypeConcept
/// \ingroup PixelIteratorModelFromLocator PixelBasedModel
/// \brief Provides 1D random-access navigation to the pixels of the image. Models: PixelIteratorConcept, PixelBasedConcept, HasDynamicXStepTypeConcept
///
/// Pixels are traversed from the top to the bottom row and from the left to the right
/// within each row
template <typename Loc2> // Models PixelLocatorConcept
class iterator_from_2d : public iterator_facade<iterator_from_2d<Loc2>,
typename Loc2::value_type,
std::random_access_iterator_tag,
typename Loc2::reference,
typename Loc2::coord_t> {
GIL_CLASS_REQUIRE(Loc2, boost::gil, PixelLocatorConcept)
public:
typedef iterator_facade<iterator_from_2d<Loc2>,
typename Loc2::value_type,
std::random_access_iterator_tag,
typename Loc2::reference,
typename Loc2::coord_t> parent_t;
typedef typename parent_t::reference reference;
typedef typename parent_t::difference_type difference_type;
typedef typename Loc2::x_iterator x_iterator;
typedef typename Loc2::point_t point_t;
std::ptrdiff_t width() const { return _width; } // number of pixels per image row
std::ptrdiff_t x_pos() const { return _coords.x; } // current x position
std::ptrdiff_t y_pos() const { return _coords.y; } // current y position
/// For some reason operator[] provided by iterator_adaptor returns a custom class that is convertible to reference
/// We require our own reference because it is registered in iterator_traits
reference operator[](difference_type d) const { return *(*this+d); }
bool is_1d_traversable() const { return _p.is_1d_traversable(width()); } // is there no gap at the end of each row?
x_iterator& x() { return _p.x(); }
iterator_from_2d(){}
iterator_from_2d(const Loc2& p, std::ptrdiff_t width, std::ptrdiff_t x=0, std::ptrdiff_t y=0) : _coords(x,y), _width(width), _p(p) {}
iterator_from_2d(const iterator_from_2d& pit) : _coords(pit._coords), _width(pit._width), _p(pit._p) {}
template <typename Loc> iterator_from_2d(const iterator_from_2d<Loc>& pit) : _coords(pit._coords), _width(pit._width), _p(pit._p) {}
private:
template <typename Loc> friend class iterator_from_2d;
friend class boost::iterator_core_access;
reference dereference() const { return *_p; }
void increment() {
++_coords.x;
++_p.x();
if (_coords.x>=_width) {
_coords.x=0;
++_coords.y;
_p+=point_t(-_width,1);
}
}
void decrement() {
--_coords.x;
--_p.x();
if (_coords.x<0) {
_coords.x=_width-1;
--_coords.y;
_p+=point_t(_width,-1);
}
}
GIL_FORCEINLINE void advance(difference_type d) {
if (_width==0) return; // unfortunately we need to check for that. Default-constructed images have width of 0 and the code below will throw if executed.
point_t delta;
if (_coords.x+d>=0) { // not going back to a previous row?
delta.x=(_coords.x+(std::ptrdiff_t)d)%_width - _coords.x;
delta.y=(_coords.x+(std::ptrdiff_t)d)/_width;
} else {
delta.x=(_coords.x+(std::ptrdiff_t)d*(1-_width))%_width -_coords.x;
delta.y=-(_width-_coords.x-(std::ptrdiff_t)d-1)/_width;
}
_p+=delta;
_coords.x+=delta.x;
_coords.y+=delta.y;
}
difference_type distance_to(const iterator_from_2d& it) const {
if (_width==0) return 0;
return (it.y_pos()-_coords.y)*_width + (it.x_pos()-_coords.x);
}
bool equal(const iterator_from_2d& it) const {
assert(_width==it.width()); // they must belong to the same image
return _coords==it._coords && _p==it._p;
}
point2<std::ptrdiff_t> _coords;
std::ptrdiff_t _width;
Loc2 _p;
};
template <typename Loc> // Models PixelLocatorConcept
struct const_iterator_type<iterator_from_2d<Loc> > {
typedef iterator_from_2d<typename Loc::const_t> type;
};
template <typename Loc> // Models PixelLocatorConcept
struct iterator_is_mutable<iterator_from_2d<Loc> > : public iterator_is_mutable<typename Loc::x_iterator> {};
/////////////////////////////
// HasDynamicXStepTypeConcept
/////////////////////////////
template <typename Loc>
struct dynamic_x_step_type<iterator_from_2d<Loc> > {
typedef iterator_from_2d<typename dynamic_x_step_type<Loc>::type> type;
};
/////////////////////////////
// PixelBasedConcept
/////////////////////////////
template <typename Loc> // Models PixelLocatorConcept
struct color_space_type<iterator_from_2d<Loc> > : public color_space_type<Loc> {};
template <typename Loc> // Models PixelLocatorConcept
struct channel_mapping_type<iterator_from_2d<Loc> > : public channel_mapping_type<Loc> {};
template <typename Loc> // Models PixelLocatorConcept
struct is_planar<iterator_from_2d<Loc> > : public is_planar<Loc> {};
template <typename Loc> // Models PixelLocatorConcept
struct channel_type<iterator_from_2d<Loc> > : public channel_type<Loc> {};
} } // namespace boost::gil
#endif