You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
331 lines
13 KiB
331 lines
13 KiB
/* |
|
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_UTILITIES_H |
|
#define GIL_UTILITIES_H |
|
|
|
#include "gil_config.hpp" |
|
#include <functional> |
|
#include <boost/config/no_tr1/cmath.hpp> |
|
#include <cstddef> |
|
#include <algorithm> |
|
#include <utility> |
|
#include <iterator> |
|
#include <boost/static_assert.hpp> |
|
#include <boost/type_traits.hpp> |
|
#include <boost/mpl/size.hpp> |
|
#include <boost/mpl/distance.hpp> |
|
#include <boost/mpl/begin.hpp> |
|
#include <boost/mpl/find.hpp> |
|
#include <boost/mpl/range_c.hpp> |
|
#include <boost/iterator/iterator_adaptor.hpp> |
|
#include <boost/iterator/iterator_facade.hpp> |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
/// \file |
|
/// \brief Various utilities not specific to the image library. Some are non-standard STL extensions or generic iterator adaptors |
|
/// \author Lubomir Bourdev and Hailin Jin \n |
|
/// Adobe Systems Incorporated |
|
/// \date 2005-2007 \n Last updated on September 18, 2007 |
|
/// |
|
/// |
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
namespace boost { namespace gil { |
|
|
|
/** |
|
\addtogroup PointModel |
|
|
|
Example: |
|
\code |
|
point2<std::ptrdiff_t> p(3,2); |
|
assert((p[0] == p.x) && (p[1] == p.y)); |
|
assert(axis_value<0>(p) == 3); |
|
assert(axis_value<1>(p) == 2); |
|
\endcode |
|
*/ |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
// CLASS point2 |
|
/// |
|
/// \brief 2D point both axes of which have the same dimension type |
|
/// \ingroup PointModel |
|
/// Models: Point2DConcept |
|
/// |
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
template <typename T> |
|
class point2 { |
|
public: |
|
typedef T value_type; |
|
template <std::size_t D> struct axis { typedef value_type coord_t; }; |
|
static const std::size_t num_dimensions=2; |
|
|
|
point2() : x(0), y(0) {} |
|
point2(T newX, T newY) : x(newX), y(newY) {} |
|
point2(const point2& p) : x(p.x), y(p.y) {} |
|
~point2() {} |
|
|
|
point2& operator=(const point2& p) { x=p.x; y=p.y; return *this; } |
|
|
|
point2 operator<<(std::ptrdiff_t shift) const { return point2(x<<shift,y<<shift); } |
|
point2 operator>>(std::ptrdiff_t shift) const { return point2(x>>shift,y>>shift); } |
|
point2& operator+=(const point2& p) { x+=p.x; y+=p.y; return *this; } |
|
point2& operator-=(const point2& p) { x-=p.x; y-=p.y; return *this; } |
|
point2& operator/=(double t) { x/=t; y/=t; return *this; } |
|
|
|
const T& operator[](std::size_t i) const { return this->*mem_array[i]; } |
|
T& operator[](std::size_t i) { return this->*mem_array[i]; } |
|
|
|
T x,y; |
|
private: |
|
// this static array of pointers to member variables makes operator[] safe and doesn't seem to exhibit any performance penalty |
|
static T point2<T>::* const mem_array[num_dimensions]; |
|
}; |
|
|
|
template <typename T> |
|
T point2<T>::* const point2<T>::mem_array[point2<T>::num_dimensions] = { &point2<T>::x, &point2<T>::y }; |
|
|
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
bool operator==(const point2<T>& p1, const point2<T>& p2) { return (p1.x==p2.x && p1.y==p2.y); } |
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
bool operator!=(const point2<T>& p1, const point2<T>& p2) { return p1.x!=p2.x || p1.y!=p2.y; } |
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
point2<T> operator+(const point2<T>& p1, const point2<T>& p2) { return point2<T>(p1.x+p2.x,p1.y+p2.y); } |
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
point2<T> operator-(const point2<T>& p) { return point2<T>(-p.x,-p.y); } |
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
point2<T> operator-(const point2<T>& p1, const point2<T>& p2) { return point2<T>(p1.x-p2.x,p1.y-p2.y); } |
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
point2<double> operator/(const point2<T>& p, double t) { return t==0 ? point2<double>(0,0):point2<double>(p.x/t,p.y/t); } |
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
point2<T> operator*(const point2<T>& p, std::ptrdiff_t t) { return point2<T>(p.x*t,p.y*t); } |
|
/// \ingroup PointModel |
|
template <typename T> GIL_FORCEINLINE |
|
point2<T> operator*(std::ptrdiff_t t, const point2<T>& p) { return point2<T>(p.x*t,p.y*t); } |
|
|
|
/// \ingroup PointModel |
|
template <std::size_t K, typename T> GIL_FORCEINLINE |
|
const T& axis_value(const point2<T>& p) { return p[K]; } |
|
|
|
/// \ingroup PointModel |
|
template <std::size_t K, typename T> GIL_FORCEINLINE |
|
T& axis_value( point2<T>& p) { return p[K]; } |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
/// |
|
/// Rounding of real numbers / points to integers / integer points |
|
/// |
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
inline std::ptrdiff_t iround(float x ) { return static_cast<std::ptrdiff_t>(x + (x < 0.0f ? -0.5f : 0.5f)); } |
|
inline std::ptrdiff_t iround(double x) { return static_cast<std::ptrdiff_t>(x + (x < 0.0 ? -0.5 : 0.5)); } |
|
inline std::ptrdiff_t ifloor(float x ) { return static_cast<std::ptrdiff_t>(std::floor(x)); } |
|
inline std::ptrdiff_t ifloor(double x) { return static_cast<std::ptrdiff_t>(std::floor(x)); } |
|
inline std::ptrdiff_t iceil(float x ) { return static_cast<std::ptrdiff_t>(std::ceil(x)); } |
|
inline std::ptrdiff_t iceil(double x) { return static_cast<std::ptrdiff_t>(std::ceil(x)); } |
|
|
|
/** |
|
\addtogroup PointAlgorithm |
|
|
|
Example: |
|
\code |
|
assert(iround(point2<double>(3.1, 3.9)) == point2<std::ptrdiff_t>(3,4)); |
|
\endcode |
|
*/ |
|
|
|
/// \ingroup PointAlgorithm |
|
inline point2<std::ptrdiff_t> iround(const point2<float >& p) { return point2<std::ptrdiff_t>(iround(p.x),iround(p.y)); } |
|
/// \ingroup PointAlgorithm |
|
inline point2<std::ptrdiff_t> iround(const point2<double>& p) { return point2<std::ptrdiff_t>(iround(p.x),iround(p.y)); } |
|
/// \ingroup PointAlgorithm |
|
inline point2<std::ptrdiff_t> ifloor(const point2<float >& p) { return point2<std::ptrdiff_t>(ifloor(p.x),ifloor(p.y)); } |
|
/// \ingroup PointAlgorithm |
|
inline point2<std::ptrdiff_t> ifloor(const point2<double>& p) { return point2<std::ptrdiff_t>(ifloor(p.x),ifloor(p.y)); } |
|
/// \ingroup PointAlgorithm |
|
inline point2<std::ptrdiff_t> iceil (const point2<float >& p) { return point2<std::ptrdiff_t>(iceil(p.x), iceil(p.y)); } |
|
/// \ingroup PointAlgorithm |
|
inline point2<std::ptrdiff_t> iceil (const point2<double>& p) { return point2<std::ptrdiff_t>(iceil(p.x), iceil(p.y)); } |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
/// |
|
/// computing size with alignment |
|
/// |
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
template <typename T> |
|
inline T align(T val, std::size_t alignment) { |
|
return val+(alignment - val%alignment)%alignment; |
|
} |
|
|
|
/// \brief Helper base class for pixel dereference adaptors. |
|
/// \ingroup PixelDereferenceAdaptorModel |
|
/// |
|
template <typename ConstT, typename Value, typename Reference, typename ConstReference, |
|
typename ArgType, typename ResultType, bool IsMutable> |
|
struct deref_base : public std::unary_function<ArgType, ResultType> { |
|
typedef ConstT const_t; |
|
typedef Value value_type; |
|
typedef Reference reference; |
|
typedef ConstReference const_reference; |
|
BOOST_STATIC_CONSTANT(bool, is_mutable = IsMutable); |
|
}; |
|
|
|
/// \brief Composes two dereference function objects. Similar to std::unary_compose but needs to pull some typedefs from the component types. Models: PixelDereferenceAdaptorConcept |
|
/// \ingroup PixelDereferenceAdaptorModel |
|
/// |
|
template <typename D1, typename D2> |
|
class deref_compose : public deref_base< |
|
deref_compose<typename D1::const_t, typename D2::const_t>, |
|
typename D1::value_type, typename D1::reference, typename D1::const_reference, |
|
typename D2::argument_type, typename D1::result_type, D1::is_mutable && D2::is_mutable> |
|
{ |
|
public: |
|
D1 _fn1; |
|
D2 _fn2; |
|
|
|
typedef typename D2::argument_type argument_type; |
|
typedef typename D1::result_type result_type; |
|
|
|
deref_compose() {} |
|
deref_compose(const D1& x, const D2& y) : _fn1(x), _fn2(y) {} |
|
deref_compose(const deref_compose& dc) : _fn1(dc._fn1), _fn2(dc._fn2) {} |
|
template <typename _D1, typename _D2> deref_compose(const deref_compose<_D1,_D2>& dc) : _fn1(dc._fn1), _fn2(dc._fn2) {} |
|
|
|
result_type operator()(argument_type x) const { return _fn1(_fn2(x)); } |
|
result_type operator()(argument_type x) { return _fn1(_fn2(x)); } |
|
}; |
|
|
|
// reinterpret_cast is implementation-defined. Static cast is not. |
|
template <typename OutPtr, typename In> GIL_FORCEINLINE |
|
OutPtr gil_reinterpret_cast( In* p) { return static_cast<OutPtr>(static_cast<void*>(p)); } |
|
|
|
template <typename OutPtr, typename In> GIL_FORCEINLINE |
|
const OutPtr gil_reinterpret_cast_c(const In* p) { return static_cast<const OutPtr>(static_cast<const void*>(p)); } |
|
|
|
namespace detail { |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
/// |
|
/// \brief copy_n taken from SGI STL. |
|
/// |
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
template <class InputIter, class Size, class OutputIter> |
|
std::pair<InputIter, OutputIter> _copy_n(InputIter first, Size count, |
|
OutputIter result, |
|
std::input_iterator_tag) { |
|
for ( ; count > 0; --count) { |
|
*result = *first; |
|
++first; |
|
++result; |
|
} |
|
return std::pair<InputIter, OutputIter>(first, result); |
|
} |
|
|
|
template <class RAIter, class Size, class OutputIter> |
|
inline std::pair<RAIter, OutputIter> |
|
_copy_n(RAIter first, Size count, OutputIter result, std::random_access_iterator_tag) { |
|
RAIter last = first + count; |
|
return std::pair<RAIter, OutputIter>(last, std::copy(first, last, result)); |
|
} |
|
|
|
template <class InputIter, class Size, class OutputIter> |
|
inline std::pair<InputIter, OutputIter> |
|
_copy_n(InputIter first, Size count, OutputIter result) { |
|
return _copy_n(first, count, result, typename std::iterator_traits<InputIter>::iterator_category()); |
|
} |
|
|
|
template <class InputIter, class Size, class OutputIter> |
|
inline std::pair<InputIter, OutputIter> |
|
copy_n(InputIter first, Size count, OutputIter result) { |
|
return detail::_copy_n(first, count, result); |
|
} |
|
|
|
/// \brief identity taken from SGI STL. |
|
template <typename T> |
|
struct identity : public std::unary_function<T,T> { |
|
const T& operator()(const T& val) const { return val; } |
|
}; |
|
|
|
/*************************************************************************************************/ |
|
|
|
/// \brief plus function object whose arguments may be of different type. |
|
template <typename T1, typename T2> |
|
struct plus_asymmetric : public std::binary_function<T1,T2,T1> { |
|
T1 operator()(T1 f1, T2 f2) const { |
|
return f1+f2; |
|
} |
|
}; |
|
|
|
/*************************************************************************************************/ |
|
|
|
/// \brief operator++ wrapped in a function object |
|
template <typename T> |
|
struct inc : public std::unary_function<T,T> { |
|
T operator()(T x) const { return ++x; } |
|
}; |
|
|
|
/*************************************************************************************************/ |
|
|
|
/// \brief operator-- wrapped in a function object |
|
template <typename T> |
|
struct dec : public std::unary_function<T,T> { |
|
T operator()(T x) const { return --x; } |
|
}; |
|
|
|
/// \brief Returns the index corresponding to the first occurrance of a given given type in |
|
// a given MPL RandomAccessSequence (or size if the type is not present) |
|
template <typename Types, typename T> |
|
struct type_to_index |
|
: public mpl::distance<typename mpl::begin<Types>::type, |
|
typename mpl::find<Types,T>::type>::type {}; |
|
} // namespace detail |
|
|
|
|
|
|
|
/// \ingroup ColorSpaceAndLayoutModel |
|
/// \brief Represents a color space and ordering of channels in memory |
|
template <typename ColorSpace, typename ChannelMapping = mpl::range_c<int,0,mpl::size<ColorSpace>::value> > |
|
struct layout { |
|
typedef ColorSpace color_space_t; |
|
typedef ChannelMapping channel_mapping_t; |
|
}; |
|
|
|
/// \brief A version of swap that also works with reference proxy objects |
|
template <typename Value, typename T1, typename T2> // where value_type<T1> == value_type<T2> == Value |
|
void swap_proxy(T1& left, T2& right) { |
|
Value tmp = left; |
|
left = right; |
|
right = tmp; |
|
} |
|
|
|
/// \brief Run-time detection of whether the underlying architecture is little endian |
|
inline bool little_endian() { |
|
short tester = 0x0001; |
|
return *(char*)&tester!=0; |
|
} |
|
/// \brief Run-time detection of whether the underlying architecture is big endian |
|
inline bool big_endian() { |
|
return !little_endian(); |
|
} |
|
|
|
} } // namespace boost::gil |
|
|
|
#endif
|
|
|