point.hpp 6.7 KB

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