// // Copyright 2005-2007 Adobe Systems Incorporated // // Distributed under 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 // #ifndef BOOST_GIL_POINT_HPP #define BOOST_GIL_POINT_HPP #include #include #include #include #include namespace boost { namespace gil { /// \addtogroup PointModel /// /// Example: /// \code /// point 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 /// \brief 2D point both axes of which have the same dimension type /// \ingroup PointModel /// Models: Point2DConcept template class point { public: using value_type = T; template struct axis { using coord_t = value_type; }; static constexpr std::size_t num_dimensions = 2; point() = default; point(T px, T py) : x(px), y(py) {} point operator<<(std::ptrdiff_t shift) const { return point(x << shift, y << shift); } point operator>>(std::ptrdiff_t shift) const { return point(x >> shift, y >> shift); } point& operator+=(point const& p) { x += p.x; y += p.y; return *this; } point& operator-=(point const& p) { x -= p.x; y -= p.y; return *this; } point& operator/=(double d) { if (d < 0 || 0 < d) { x = static_cast(x / d); y = static_cast(y / d); } return *this; } point& operator*=(double d) { x = static_cast(x * d); y = static_cast(y * d); return *this; } T const& operator[](std::size_t i) const { return this->*mem_array[i]; } T& operator[](std::size_t i) { return this->*mem_array[i]; } T x{0}; T y{0}; private: // this static array of pointers to member variables makes operator[] safe // and doesn't seem to exhibit any performance penalty. static T point::* const mem_array[num_dimensions]; }; /// Alias template for backward compatibility with Boost <=1.68. template using point2 = point; /// Common type to represent 2D dimensions or in-memory size of image or view. /// @todo TODO: rename to dims_t or dimensions_t for purpose clarity? using point_t = point; template T point::* const point::mem_array[point::num_dimensions] = { &point::x, &point::y }; /// \ingroup PointModel template BOOST_FORCEINLINE bool operator==(const point& p1, const point& p2) { return p1.x == p2.x && p1.y == p2.y; } /// \ingroup PointModel template BOOST_FORCEINLINE bool operator!=(const point& p1, const point& p2) { return p1.x != p2.x || p1.y != p2.y; } /// \ingroup PointModel template BOOST_FORCEINLINE point operator+(const point& p1, const point& p2) { return { p1.x + p2.x, p1.y + p2.y }; } /// \ingroup PointModel template BOOST_FORCEINLINE point operator-(const point& p) { return { -p.x, -p.y }; } /// \ingroup PointModel template BOOST_FORCEINLINE point operator-(const point& p1, const point& p2) { return { p1.x - p2.x, p1.y - p2.y }; } /// \ingroup PointModel template BOOST_FORCEINLINE auto operator/(point const& p, D d) -> typename std::enable_if < std::is_arithmetic::value, point::type> >::type { static_assert(std::is_arithmetic::value, "denominator is not arithmetic type"); using result_type = typename detail::std_common_type::type; if (d < 0 || 0 < d) { double const x = static_cast(p.x) / static_cast(d); double const y = static_cast(p.y) / static_cast(d); return point{ static_cast(iround(x)), static_cast(iround(y))}; } else { return point{0, 0}; } } /// \ingroup PointModel template BOOST_FORCEINLINE auto operator*(point const& p, M m) -> typename std::enable_if < std::is_arithmetic::value, point::type> >::type { static_assert(std::is_arithmetic::value, "multiplier is not arithmetic type"); using result_type = typename detail::std_common_type::type; return point{p.x * m, p.y * m}; } /// \ingroup PointModel template BOOST_FORCEINLINE auto operator*(M m, point const& p) -> typename std::enable_if < std::is_arithmetic::value, point::type> >::type { static_assert(std::is_arithmetic::value, "multiplier is not arithmetic type"); using result_type = typename detail::std_common_type::type; return point{p.x * m, p.y * m}; } /// \ingroup PointModel template BOOST_FORCEINLINE T const& axis_value(point const& p) { static_assert(K < point::num_dimensions, "axis index out of range"); return p[K]; } /// \ingroup PointModel template BOOST_FORCEINLINE T& axis_value(point& p) { static_assert(K < point::num_dimensions, "axis index out of range"); return p[K]; } /// \addtogroup PointAlgorithm /// /// Example: /// \code /// assert(iround(point(3.1, 3.9)) == point(3,4)); /// \endcode /// \ingroup PointAlgorithm template inline point iround(point const& p) { static_assert(std::is_integral::value, "T is not integer"); return { static_cast(p.x), static_cast(p.y) }; } /// \ingroup PointAlgorithm inline point iround(point const& p) { return { iround(p.x), iround(p.y) }; } /// \ingroup PointAlgorithm inline point iround(point const& p) { return { iround(p.x), iround(p.y) }; } /// \ingroup PointAlgorithm inline point ifloor(point const& p) { return { ifloor(p.x), ifloor(p.y) }; } /// \ingroup PointAlgorithm inline point ifloor(point const& p) { return { ifloor(p.x), ifloor(p.y) }; } /// \ingroup PointAlgorithm inline point iceil(point const& p) { return { iceil(p.x), iceil(p.y) }; } /// \ingroup PointAlgorithm inline point iceil(point const& p) { return { iceil(p.x), iceil(p.y) }; } }} // namespace boost::gil #endif