point.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_POINT_HPP
  9. #define BOOST_GIL_POINT_HPP
  10. #include <boost/gil/utilities.hpp>
  11. #include <boost/config.hpp>
  12. #include <cstddef>
  13. #include <type_traits>
  14. namespace boost { namespace gil {
  15. /// \addtogroup PointModel
  16. ///
  17. /// Example:
  18. /// \code
  19. /// point<std::ptrdiff_t> p(3,2);
  20. /// assert((p[0] == p.x) && (p[1] == p.y));
  21. /// assert(axis_value<0>(p) == 3);
  22. /// assert(axis_value<1>(p) == 2);
  23. /// \endcode
  24. /// \brief 2D point both axes of which have the same dimension type
  25. /// \ingroup PointModel
  26. /// Models: Point2DConcept
  27. template <typename T>
  28. class point
  29. {
  30. public:
  31. using value_type = T;
  32. template<std::size_t D>
  33. struct axis
  34. {
  35. using coord_t = value_type;
  36. };
  37. static constexpr std::size_t num_dimensions = 2;
  38. point() = default;
  39. point(T px, T py) : x(px), y(py) {}
  40. point operator<<(std::ptrdiff_t shift) const
  41. {
  42. return point(x << shift, y << shift);
  43. }
  44. point operator>>(std::ptrdiff_t shift) const
  45. {
  46. return point(x >> shift, y >> shift);
  47. }
  48. point& operator+=(point const& p)
  49. {
  50. x += p.x;
  51. y += p.y;
  52. return *this;
  53. }
  54. point& operator-=(point const& p)
  55. {
  56. x -= p.x;
  57. y -= p.y;
  58. return *this;
  59. }
  60. point& operator/=(double d)
  61. {
  62. if (d < 0 || 0 < d)
  63. {
  64. x = static_cast<T>(x / d);
  65. y = static_cast<T>(y / d);
  66. }
  67. return *this;
  68. }
  69. point& operator*=(double d)
  70. {
  71. x = static_cast<T>(x * d);
  72. y = static_cast<T>(y * d);
  73. return *this;
  74. }
  75. T const& operator[](std::size_t i) const
  76. {
  77. return this->*mem_array[i];
  78. }
  79. T& operator[](std::size_t i)
  80. {
  81. return this->*mem_array[i];
  82. }
  83. T x{0};
  84. T y{0};
  85. private:
  86. // this static array of pointers to member variables makes operator[] safe
  87. // and doesn't seem to exhibit any performance penalty.
  88. static T point<T>::* const mem_array[num_dimensions];
  89. };
  90. /// Alias template for backward compatibility with Boost <=1.68.
  91. template <typename T>
  92. using point2 = point<T>;
  93. /// Common type to represent 2D dimensions or in-memory size of image or view.
  94. /// @todo TODO: rename to dims_t or dimensions_t for purpose clarity?
  95. using point_t = point<std::ptrdiff_t>;
  96. template <typename T>
  97. T point<T>::* const point<T>::mem_array[point<T>::num_dimensions] =
  98. {
  99. &point<T>::x,
  100. &point<T>::y
  101. };
  102. /// \ingroup PointModel
  103. template <typename T>
  104. BOOST_FORCEINLINE
  105. bool operator==(const point<T>& p1, const point<T>& p2)
  106. {
  107. return p1.x == p2.x && p1.y == p2.y;
  108. }
  109. /// \ingroup PointModel
  110. template <typename T>
  111. BOOST_FORCEINLINE
  112. bool operator!=(const point<T>& p1, const point<T>& p2)
  113. {
  114. return p1.x != p2.x || p1.y != p2.y;
  115. }
  116. /// \ingroup PointModel
  117. template <typename T>
  118. BOOST_FORCEINLINE
  119. point<T> operator+(const point<T>& p1, const point<T>& p2)
  120. {
  121. return { p1.x + p2.x, p1.y + p2.y };
  122. }
  123. /// \ingroup PointModel
  124. template <typename T>
  125. BOOST_FORCEINLINE
  126. point<T> operator-(const point<T>& p)
  127. {
  128. return { -p.x, -p.y };
  129. }
  130. /// \ingroup PointModel
  131. template <typename T>
  132. BOOST_FORCEINLINE
  133. point<T> operator-(const point<T>& p1, const point<T>& p2)
  134. {
  135. return { p1.x - p2.x, p1.y - p2.y };
  136. }
  137. /// \ingroup PointModel
  138. template <typename T, typename D>
  139. BOOST_FORCEINLINE
  140. auto operator/(point<T> const& p, D d) -> point<typename std::common_type<T, D>::type>
  141. {
  142. static_assert(std::is_arithmetic<D>::value, "denominator is not arithmetic type");
  143. using result_type = typename std::common_type<T, D>::type;
  144. if (d < 0 || 0 < d)
  145. {
  146. double const x = p.x / static_cast<double>(d);
  147. double const y = p.y / static_cast<double>(d);
  148. return point<result_type>{
  149. static_cast<result_type>(iround(x)),
  150. static_cast<result_type>(iround(y))};
  151. }
  152. else
  153. {
  154. return point<result_type>{0, 0};
  155. }
  156. }
  157. /// \ingroup PointModel
  158. template <typename T, typename M>
  159. BOOST_FORCEINLINE
  160. auto operator*(point<T> const& p, M m) -> point<typename std::common_type<T, M>::type>
  161. {
  162. static_assert(std::is_arithmetic<M>::value, "multiplier is not arithmetic type");
  163. using result_type = typename std::common_type<T, M>::type;
  164. return point<result_type>{p.x * m, p.y * m};
  165. }
  166. /// \ingroup PointModel
  167. template <typename T, typename M>
  168. BOOST_FORCEINLINE
  169. auto operator*(M m, point<T> const& p) -> point<typename std::common_type<T, M>::type>
  170. {
  171. static_assert(std::is_arithmetic<M>::value, "multiplier is not arithmetic type");
  172. using result_type = typename std::common_type<T, M>::type;
  173. return point<result_type>{p.x * m, p.y * m};
  174. }
  175. /// \ingroup PointModel
  176. template <std::size_t K, typename T>
  177. BOOST_FORCEINLINE
  178. T const& axis_value(point<T> const& p)
  179. {
  180. static_assert(K < point<T>::num_dimensions, "axis index out of range");
  181. return p[K];
  182. }
  183. /// \ingroup PointModel
  184. template <std::size_t K, typename T>
  185. BOOST_FORCEINLINE
  186. T& axis_value(point<T>& p)
  187. {
  188. static_assert(K < point<T>::num_dimensions, "axis index out of range");
  189. return p[K];
  190. }
  191. /// \addtogroup PointAlgorithm
  192. ///
  193. /// Example:
  194. /// \code
  195. /// assert(iround(point<double>(3.1, 3.9)) == point<std::ptrdiff_t>(3,4));
  196. /// \endcode
  197. /// \ingroup PointAlgorithm
  198. template <typename T>
  199. inline point<std::ptrdiff_t> iround(point<T> const& p)
  200. {
  201. static_assert(std::is_integral<T>::value, "T is not integer");
  202. return { static_cast<std::ptrdiff_t>(p.x), static_cast<std::ptrdiff_t>(p.y) };
  203. }
  204. /// \ingroup PointAlgorithm
  205. inline point<std::ptrdiff_t> iround(point<float> const& p)
  206. {
  207. return { iround(p.x), iround(p.y) };
  208. }
  209. /// \ingroup PointAlgorithm
  210. inline point<std::ptrdiff_t> iround(point<double> const& p)
  211. {
  212. return { iround(p.x), iround(p.y) };
  213. }
  214. /// \ingroup PointAlgorithm
  215. inline point<std::ptrdiff_t> ifloor(point<float> const& p)
  216. {
  217. return { ifloor(p.x), ifloor(p.y) };
  218. }
  219. /// \ingroup PointAlgorithm
  220. inline point<std::ptrdiff_t> ifloor(point<double> const& p)
  221. {
  222. return { ifloor(p.x), ifloor(p.y) };
  223. }
  224. /// \ingroup PointAlgorithm
  225. inline point<std::ptrdiff_t> iceil(point<float> const& p)
  226. {
  227. return { iceil(p.x), iceil(p.y) };
  228. }
  229. /// \ingroup PointAlgorithm
  230. inline point<std::ptrdiff_t> iceil(point<double> const& p)
  231. {
  232. return { iceil(p.x), iceil(p.y) };
  233. }
  234. }} // namespace boost::gil
  235. #endif