#include <boost/gil/dynamic_step.hpp>
#include <boost/gil/iterator_from_2d.hpp>
+#include <boost/assert.hpp>
+
#include <cstddef>
#include <iterator>
///
////////////////////////////////////////////////////////////////////////////////////////
template <typename Loc> // Models 2D Pixel Locator
-class image_view {
+class image_view
+{
public:
-
-// aliases required by ConstRandomAccessNDImageViewConcept
+ // aliases required by ConstRandomAccessNDImageViewConcept
static const std::size_t num_dimensions=2;
using value_type = typename Loc::value_type;
using reference = typename Loc::reference; // result of dereferencing
using reverse_iterator = std::reverse_iterator<iterator>;
using size_type = std::size_t;
-// aliases required by ConstRandomAccess2DImageViewConcept
+ // aliases required by ConstRandomAccess2DImageViewConcept
using xy_locator = locator;
using x_iterator = typename xy_locator::x_iterator; // pixel iterator along a row
using y_iterator = typename xy_locator::y_iterator; // pixel iterator along a column
using x_coord_t = typename xy_locator::x_coord_t;
using y_coord_t = typename xy_locator::y_coord_t;
- template <typename Deref> struct add_deref
+ template <typename Deref>
+ struct add_deref
{
using type = image_view<typename Loc::template add_deref<Deref>::type>;
- static type make(const image_view<Loc>& iv, const Deref& d)
+ static type make(image_view<Loc> const& view, Deref const& d)
{
- return type(iv.dimensions(), Loc::template add_deref<Deref>::make(iv.pixels(),d));
+ return type(view.dimensions(), Loc::template add_deref<Deref>::make(view.pixels(), d));
}
};
image_view() : _dimensions(0,0) {}
- template <typename View> image_view(const View& iv) : _dimensions(iv.dimensions()), _pixels(iv.pixels()) {}
+ image_view(image_view const& img_view)
+ : _dimensions(img_view.dimensions()), _pixels(img_view.pixels())
+ {}
- template <typename L2> image_view(const point_t& sz , const L2& loc) : _dimensions(sz), _pixels(loc) {}
- template <typename L2> image_view(coord_t width, coord_t height, const L2& loc) : _dimensions(x_coord_t(width),y_coord_t(height)), _pixels(loc) {}
+ template <typename View>
+ image_view(View const& view) : _dimensions(view.dimensions()), _pixels(view.pixels()) {}
- template <typename View> image_view& operator=(const View& iv) { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; }
- image_view& operator=(const image_view& iv) { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; }
+ template <typename L2>
+ image_view(point_t const& dims, L2 const& loc) : _dimensions(dims), _pixels(loc) {}
- template <typename View> bool operator==(const View& v) const { return pixels()==v.pixels() && dimensions()==v.dimensions(); }
- template <typename View> bool operator!=(const View& v) const { return !(*this==v); }
+ template <typename L2>
+ image_view(coord_t width, coord_t height, L2 const& loc)
+ : _dimensions(x_coord_t(width), y_coord_t(height)), _pixels(loc)
+ {}
- template <typename L2> friend void swap(image_view<L2>& x, image_view<L2>& y);
+ template <typename View>
+ image_view& operator=(View const& view)
+ {
+ _pixels = view.pixels();
+ _dimensions = view.dimensions();
+ return *this;
+ }
+
+ image_view& operator=(image_view const& view)
+ {
+ // TODO: Self-assignment protection?
+ _pixels = view.pixels();
+ _dimensions = view.dimensions();
+ return *this;
+ }
+
+ template <typename View>
+ bool operator==(View const &view) const
+ {
+ return pixels() == view.pixels() && dimensions() == view.dimensions();
+ }
+
+ template <typename View>
+ bool operator!=(View const& view) const
+ {
+ return !(*this == view);
+ }
+
+ template <typename L2>
+ friend void swap(image_view<L2> &lhs, image_view<L2> &rhs);
/// \brief Exchanges the elements of the current view with those of \a other
/// in constant time.
swap(*this, other);
}
+ auto dimensions() const -> point_t const&
+ {
+ return _dimensions;
+ }
+
+ auto pixels() const -> locator const&
+ {
+ return _pixels;
+ }
+
+ auto width() const -> x_coord_t
+ {
+ return dimensions().x;
+ }
+
+ auto height() const -> y_coord_t
+ {
+ return dimensions().y;
+ }
+
+ auto num_channels() const -> std::size_t
+ {
+ return gil::num_channels<value_type>::value;
+ }
+
+ bool is_1d_traversable() const
+ {
+ return _pixels.is_1d_traversable(width());
+ }
+
/// \brief Returns true if the view has no elements, false otherwise.
///
/// \note Required by the Collection concept
/// \see https://www.boost.org/libs/utility/Collection.html
- bool empty() const { return !(width() > 0 && height() > 0); }
+ bool empty() const
+ {
+ return !(width() > 0 && height() > 0);
+ }
/// \brief Returns a reference to the first element in raster order.
///
/// \note Required by the ForwardCollection, since view model the concept.
/// \see https://www.boost.org/libs/utility/Collection.html
- reference front() const { return *begin(); }
+ auto front() const -> reference
+ {
+ BOOST_ASSERT(!empty());
+ return *begin();
+ }
/// \brief Returns a reference to the last element in raster order.
///
/// \note Required by the ForwardCollection, since view model the concept.
/// \see https://www.boost.org/libs/utility/Collection.html
- reference back() const { return *rbegin(); }
-
- const point_t& dimensions() const { return _dimensions; }
- const locator& pixels() const { return _pixels; }
- x_coord_t width() const { return dimensions().x; }
- y_coord_t height() const { return dimensions().y; }
- std::size_t num_channels() const { return gil::num_channels<value_type>::value; }
- bool is_1d_traversable() const { return _pixels.is_1d_traversable(width()); }
+ auto back() const -> reference
+ {
+ BOOST_ASSERT(!empty());
+ return *rbegin();
+ }
//\{@
/// \name 1D navigation
- size_type size() const { return width()*height(); }
- iterator begin() const { return iterator(_pixels,_dimensions.x); }
- iterator end() const { return begin()+(difference_type)size(); } // potential performance problem!
- reverse_iterator rbegin() const { return reverse_iterator(end()); }
- reverse_iterator rend() const { return reverse_iterator(begin()); }
- reference operator[](difference_type i) const { return begin()[i]; } // potential performance problem!
- iterator at(difference_type i)const { return begin()+i; }
- iterator at(const point_t& p) const { return begin()+p.y*width()+p.x; }
- iterator at(x_coord_t x, y_coord_t y)const { return begin()+y*width()+x; }
+ auto size() const -> size_type
+ {
+ return width() * height();
+ }
+
+ auto begin() const -> iterator
+ {
+ return iterator(_pixels, _dimensions.x);
+ }
+
+ auto end() const -> iterator
+ {
+ // potential performance problem!
+ return begin() + static_cast<difference_type>(size());
+ }
+
+ auto rbegin() const -> reverse_iterator
+ {
+ return reverse_iterator(end());
+ }
+ auto rend() const -> reverse_iterator
+ {
+ return reverse_iterator(begin());
+ }
+
+ auto operator[](difference_type i) const -> reference
+ {
+ BOOST_ASSERT(i < static_cast<difference_type>(size()));
+ return begin()[i]; // potential performance problem!
+ }
+
+ auto at(difference_type i) const ->iterator
+ {
+ BOOST_ASSERT(i < size());
+ return begin() + i;
+ }
+
+ auto at(point_t const& p) const -> iterator
+ {
+ BOOST_ASSERT(0 <= p.x && p.x < width());
+ BOOST_ASSERT(0 <= p.y && p.y < height());
+ return begin() + p.y * width() + p.x;
+ }
+
+ auto at(x_coord_t x, y_coord_t y) const -> iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ BOOST_ASSERT(0 <= y && y < height());
+ return begin() + y * width() + x;
+ }
//\}@
//\{@
/// \name 2-D navigation
- reference operator()(const point_t& p) const { return _pixels(p.x,p.y); }
- reference operator()(x_coord_t x, y_coord_t y)const { return _pixels(x,y); }
- template <std::size_t D> typename axis<D>::iterator axis_iterator(const point_t& p) const { return _pixels.template axis_iterator<D>(p); }
- xy_locator xy_at(x_coord_t x, y_coord_t y) const { return _pixels+point_t(x_coord_t(x),y_coord_t(y)); }
- locator xy_at(const point_t& p) const { return _pixels+p; }
+ auto operator()(point_t const& p) const -> reference
+ {
+ BOOST_ASSERT(0 <= p.x && p.x < width());
+ BOOST_ASSERT(0 <= p.y && p.y < height());
+ return _pixels(p.x, p.y);
+ }
+
+ auto operator()(x_coord_t x, y_coord_t y) const -> reference
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ BOOST_ASSERT(0 <= y && y < height());
+ return _pixels(x, y);
+ }
+
+ template <std::size_t D>
+ auto axis_iterator(point_t const& p) const -> typename axis<D>::iterator
+ {
+ // allow request for iterators from inclusive range of [begin, end]
+ BOOST_ASSERT(0 <= p.x && p.x <= width());
+ BOOST_ASSERT(0 <= p.y && p.y <= height());
+ return _pixels.template axis_iterator<D>(p);
+ }
+
+ auto xy_at(x_coord_t x, y_coord_t y) const -> xy_locator
+ {
+ // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
+ BOOST_ASSERT(x < width());
+ BOOST_ASSERT(y < height());
+ return _pixels + point_t(x, y);
+ }
+
+ auto xy_at(point_t const& p) const -> locator
+ {
+ // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
+ BOOST_ASSERT(p.x < width());
+ BOOST_ASSERT(p.y < height());
+ return _pixels + p;
+ }
//\}@
//\{@
/// \name X navigation
- x_iterator x_at(x_coord_t x, y_coord_t y) const { return _pixels.x_at(x,y); }
- x_iterator x_at(const point_t& p) const { return _pixels.x_at(p); }
- x_iterator row_begin(y_coord_t y) const { return x_at(0,y); }
- x_iterator row_end(y_coord_t y) const { return x_at(width(),y); }
+ auto x_at(x_coord_t x, y_coord_t y) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= x && x <= width()); // allow request for [begin, end] inclusive
+ BOOST_ASSERT(0 <= y && y < height());
+ return _pixels.x_at(x, y);
+ }
+
+ auto x_at(point_t const& p) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= p.x && p.x <= width()); // allow request for [begin, end] inclusive
+ BOOST_ASSERT(0 <= p.y && p.y < height());
+ return _pixels.x_at(p);
+ }
+
+ auto row_begin(y_coord_t y) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= y && y < height());
+ return x_at(0, y);
+ }
+
+ auto row_end(y_coord_t y) const -> x_iterator
+ {
+ BOOST_ASSERT(0 <= y && y < height());
+ return x_at(width(), y);
+ }
//\}@
//\{@
/// \name Y navigation
- y_iterator y_at(x_coord_t x, y_coord_t y) const { return xy_at(x,y).y(); }
- y_iterator y_at(const point_t& p) const { return xy_at(p).y(); }
- y_iterator col_begin(x_coord_t x) const { return y_at(x,0); }
- y_iterator col_end(x_coord_t x) const { return y_at(x,height()); }
+ auto y_at(x_coord_t x, y_coord_t y) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ BOOST_ASSERT(0 <= y && y <= height()); // allow request for [begin, end] inclusive
+ return xy_at(x, y).y();
+ }
+
+ auto y_at(point_t const& p) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= p.x && p.x < width());
+ BOOST_ASSERT(0 <= p.y && p.y <= height()); // allow request for [begin, end] inclusive
+ return xy_at(p).y();
+ }
+
+ auto col_begin(x_coord_t x) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ return y_at(x, 0);
+ }
+
+ auto col_end(x_coord_t x) const -> y_iterator
+ {
+ BOOST_ASSERT(0 <= x && x < width());
+ return y_at(x, height());
+ }
//\}@
private:
- template <typename L2> friend class image_view;
+ template <typename L2>
+ friend class image_view;
point_t _dimensions;
xy_locator _pixels;
/////////////////////////////
template <typename L>
-struct dynamic_x_step_type<image_view<L> > {
- using type = image_view<typename dynamic_x_step_type<L>::type>;
+struct dynamic_x_step_type<image_view<L>>
+{
+ using type = image_view<typename gil::dynamic_x_step_type<L>::type>;
};
/////////////////////////////
/////////////////////////////
template <typename L>
-struct dynamic_y_step_type<image_view<L> > {
- using type = image_view<typename dynamic_y_step_type<L>::type>;
+struct dynamic_y_step_type<image_view<L>>
+{
+ using type = image_view<typename gil::dynamic_y_step_type<L>::type>;
};
/////////////////////////////
/////////////////////////////
template <typename L>
-struct transposed_type<image_view<L> > {
+struct transposed_type<image_view<L>>
+{
using type = image_view<typename transposed_type<L>::type>;
};