Boost GIL


point.hpp
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 
11 #include <boost/gil/utilities.hpp>
12 #include <boost/gil/detail/std_common_type.hpp>
13 
14 #include <boost/config.hpp>
15 
16 #include <cstddef>
17 #include <type_traits>
18 
19 namespace boost { namespace gil {
20 
30 
34 template <typename T>
35 class point
36 {
37 public:
38  using value_type = T;
39 
40  template<std::size_t D>
41  struct axis
42  {
43  using coord_t = value_type;
44  };
45 
46  static constexpr std::size_t num_dimensions = 2;
47 
48  point() = default;
49  point(T px, T py) : x(px), y(py) {}
50 
51  point operator<<(std::ptrdiff_t shift) const
52  {
53  return point(x << shift, y << shift);
54  }
55 
56  point operator>>(std::ptrdiff_t shift) const
57  {
58  return point(x >> shift, y >> shift);
59  }
60 
61  point& operator+=(point const& p)
62  {
63  x += p.x;
64  y += p.y;
65  return *this;
66  }
67 
68  point& operator-=(point const& p)
69  {
70  x -= p.x;
71  y -= p.y;
72  return *this;
73  }
74 
75  point& operator/=(double d)
76  {
77  if (d < 0 || 0 < d)
78  {
79  x = static_cast<T>(x / d);
80  y = static_cast<T>(y / d);
81  }
82  return *this;
83  }
84 
85  point& operator*=(double d)
86  {
87  x = static_cast<T>(x * d);
88  y = static_cast<T>(y * d);
89  return *this;
90  }
91 
92  T const& operator[](std::size_t i) const
93  {
94  return this->*mem_array[i];
95  }
96 
97  T& operator[](std::size_t i)
98  {
99  return this->*mem_array[i];
100  }
101 
102  T x{0};
103  T y{0};
104 
105 private:
106  // this static array of pointers to member variables makes operator[] safe
107  // and doesn't seem to exhibit any performance penalty.
108  static T point<T>::* const mem_array[num_dimensions];
109 };
110 
112 template <typename T>
113 using point2 = point<T>;
114 
117 using point_t = point<std::ptrdiff_t>;
118 
119 template <typename T>
120 T point<T>::* const point<T>::mem_array[point<T>::num_dimensions] =
121 {
122  &point<T>::x,
123  &point<T>::y
124 };
125 
127 template <typename T>
128 BOOST_FORCEINLINE
129 bool operator==(const point<T>& p1, const point<T>& p2)
130 {
131  return p1.x == p2.x && p1.y == p2.y;
132 }
133 
135 template <typename T>
136 BOOST_FORCEINLINE
137 bool operator!=(const point<T>& p1, const point<T>& p2)
138 {
139  return p1.x != p2.x || p1.y != p2.y;
140 }
141 
143 template <typename T>
144 BOOST_FORCEINLINE
145 point<T> operator+(const point<T>& p1, const point<T>& p2)
146 {
147  return { p1.x + p2.x, p1.y + p2.y };
148 }
149 
151 template <typename T>
152 BOOST_FORCEINLINE
153 point<T> operator-(const point<T>& p)
154 {
155  return { -p.x, -p.y };
156 }
157 
159 template <typename T>
160 BOOST_FORCEINLINE
161 point<T> operator-(const point<T>& p1, const point<T>& p2)
162 {
163  return { p1.x - p2.x, p1.y - p2.y };
164 }
165 
167 template <typename T, typename D>
168 BOOST_FORCEINLINE
169 auto operator/(point<T> const& p, D d)
170  -> typename std::enable_if
171  <
172  std::is_arithmetic<D>::value,
173  point<typename detail::std_common_type<T, D>::type>
174  >::type
175 {
176  static_assert(std::is_arithmetic<D>::value, "denominator is not arithmetic type");
177  using result_type = typename detail::std_common_type<T, D>::type;
178  if (d < 0 || 0 < d)
179  {
180  double const x = static_cast<double>(p.x) / static_cast<double>(d);
181  double const y = static_cast<double>(p.y) / static_cast<double>(d);
182  return point<result_type>{
183  static_cast<result_type>(iround(x)),
184  static_cast<result_type>(iround(y))};
185  }
186  else
187  {
188  return point<result_type>{0, 0};
189  }
190 }
191 
193 template <typename T, typename M>
194 BOOST_FORCEINLINE
195 auto operator*(point<T> const& p, M m)
196  -> typename std::enable_if
197  <
198  std::is_arithmetic<M>::value,
199  point<typename detail::std_common_type<T, M>::type>
200  >::type
201 {
202  static_assert(std::is_arithmetic<M>::value, "multiplier is not arithmetic type");
203  using result_type = typename detail::std_common_type<T, M>::type;
204  return point<result_type>{p.x * m, p.y * m};
205 }
206 
208 template <typename T, typename M>
209 BOOST_FORCEINLINE
210 auto operator*(M m, point<T> const& p)
211  -> typename std::enable_if
212  <
213  std::is_arithmetic<M>::value,
214  point<typename detail::std_common_type<T, M>::type>
215  >::type
216 {
217  static_assert(std::is_arithmetic<M>::value, "multiplier is not arithmetic type");
218  using result_type = typename detail::std_common_type<T, M>::type;
219  return point<result_type>{p.x * m, p.y * m};
220 }
221 
223 template <std::size_t K, typename T>
224 BOOST_FORCEINLINE
225 T const& axis_value(point<T> const& p)
226 {
227  static_assert(K < point<T>::num_dimensions, "axis index out of range");
228  return p[K];
229 }
230 
232 template <std::size_t K, typename T>
233 BOOST_FORCEINLINE
234 T& axis_value(point<T>& p)
235 {
236  static_assert(K < point<T>::num_dimensions, "axis index out of range");
237  return p[K];
238 }
239 
246 
248 template <typename T>
249 inline point<std::ptrdiff_t> iround(point<T> const& p)
250 {
251  static_assert(std::is_integral<T>::value, "T is not integer");
252  return { static_cast<std::ptrdiff_t>(p.x), static_cast<std::ptrdiff_t>(p.y) };
253 }
254 
256 inline point<std::ptrdiff_t> iround(point<float> const& p)
257 {
258  return { iround(p.x), iround(p.y) };
259 }
260 
262 inline point<std::ptrdiff_t> iround(point<double> const& p)
263 {
264  return { iround(p.x), iround(p.y) };
265 }
266 
268 inline point<std::ptrdiff_t> ifloor(point<float> const& p)
269 {
270  return { ifloor(p.x), ifloor(p.y) };
271 }
272 
274 inline point<std::ptrdiff_t> ifloor(point<double> const& p)
275 {
276  return { ifloor(p.x), ifloor(p.y) };
277 }
278 
280 inline point<std::ptrdiff_t> iceil(point<float> const& p)
281 {
282  return { iceil(p.x), iceil(p.y) };
283 }
284 
286 inline point<std::ptrdiff_t> iceil(point<double> const& p)
287 {
288  return { iceil(p.x), iceil(p.y) };
289 }
290 
291 }} // namespace boost::gil
292 
293 #endif