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
21 /// \addtogroup PointModel
22 ///
23 /// Example:
24 /// \code
25 /// point<std::ptrdiff_t> p(3,2);
26 /// assert((p[0] == p.x) && (p[1] == p.y));
27 /// assert(axis_value<0>(p) == 3);
28 /// assert(axis_value<1>(p) == 2);
29 /// \endcode
30
31 /// \brief 2D point both axes of which have the same dimension type
32 /// \ingroup PointModel
33 /// Models: Point2DConcept
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;
point(T px,T py)49 point(T px, T py) : x(px), y(py) {}
50
operator <<(std::ptrdiff_t shift) const51 point operator<<(std::ptrdiff_t shift) const
52 {
53 return point(x << shift, y << shift);
54 }
55
operator >>(std::ptrdiff_t shift) const56 point operator>>(std::ptrdiff_t shift) const
57 {
58 return point(x >> shift, y >> shift);
59 }
60
operator +=(point const & p)61 point& operator+=(point const& p)
62 {
63 x += p.x;
64 y += p.y;
65 return *this;
66 }
67
operator -=(point const & p)68 point& operator-=(point const& p)
69 {
70 x -= p.x;
71 y -= p.y;
72 return *this;
73 }
74
operator /=(double d)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
operator *=(double d)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
operator [](std::size_t i) const92 T const& operator[](std::size_t i) const
93 {
94 return this->*mem_array[i];
95 }
96
operator [](std::size_t i)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
111 /// Alias template for backward compatibility with Boost <=1.68.
112 template <typename T>
113 using point2 = point<T>;
114
115 /// Common type to represent 2D dimensions or in-memory size of image or view.
116 /// @todo TODO: rename to dims_t or dimensions_t for purpose clarity?
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
126 /// \ingroup PointModel
127 template <typename T>
128 BOOST_FORCEINLINE
operator ==(const point<T> & p1,const point<T> & p2)129 bool operator==(const point<T>& p1, const point<T>& p2)
130 {
131 return p1.x == p2.x && p1.y == p2.y;
132 }
133
134 /// \ingroup PointModel
135 template <typename T>
136 BOOST_FORCEINLINE
operator !=(const point<T> & p1,const point<T> & p2)137 bool operator!=(const point<T>& p1, const point<T>& p2)
138 {
139 return p1.x != p2.x || p1.y != p2.y;
140 }
141
142 /// \ingroup PointModel
143 template <typename T>
144 BOOST_FORCEINLINE
operator +(const point<T> & p1,const point<T> & p2)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
150 /// \ingroup PointModel
151 template <typename T>
152 BOOST_FORCEINLINE
operator -(const point<T> & p)153 point<T> operator-(const point<T>& p)
154 {
155 return { -p.x, -p.y };
156 }
157
158 /// \ingroup PointModel
159 template <typename T>
160 BOOST_FORCEINLINE
operator -(const point<T> & p1,const point<T> & p2)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
166 /// \ingroup PointModel
167 template <typename T, typename D>
168 BOOST_FORCEINLINE
operator /(point<T> const & p,D d)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
192 /// \ingroup PointModel
193 template <typename T, typename M>
194 BOOST_FORCEINLINE
operator *(point<T> const & p,M m)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
207 /// \ingroup PointModel
208 template <typename T, typename M>
209 BOOST_FORCEINLINE
operator *(M m,point<T> const & p)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
222 /// \ingroup PointModel
223 template <std::size_t K, typename T>
224 BOOST_FORCEINLINE
axis_value(point<T> const & p)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
231 /// \ingroup PointModel
232 template <std::size_t K, typename T>
233 BOOST_FORCEINLINE
axis_value(point<T> & p)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
240 /// \addtogroup PointAlgorithm
241 ///
242 /// Example:
243 /// \code
244 /// assert(iround(point<double>(3.1, 3.9)) == point<std::ptrdiff_t>(3,4));
245 /// \endcode
246
247 /// \ingroup PointAlgorithm
248 template <typename T>
iround(point<T> const & p)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
255 /// \ingroup PointAlgorithm
iround(point<float> const & p)256 inline point<std::ptrdiff_t> iround(point<float> const& p)
257 {
258 return { iround(p.x), iround(p.y) };
259 }
260
261 /// \ingroup PointAlgorithm
iround(point<double> const & p)262 inline point<std::ptrdiff_t> iround(point<double> const& p)
263 {
264 return { iround(p.x), iround(p.y) };
265 }
266
267 /// \ingroup PointAlgorithm
ifloor(point<float> const & p)268 inline point<std::ptrdiff_t> ifloor(point<float> const& p)
269 {
270 return { ifloor(p.x), ifloor(p.y) };
271 }
272
273 /// \ingroup PointAlgorithm
ifloor(point<double> const & p)274 inline point<std::ptrdiff_t> ifloor(point<double> const& p)
275 {
276 return { ifloor(p.x), ifloor(p.y) };
277 }
278
279 /// \ingroup PointAlgorithm
iceil(point<float> const & p)280 inline point<std::ptrdiff_t> iceil(point<float> const& p)
281 {
282 return { iceil(p.x), iceil(p.y) };
283 }
284
285 /// \ingroup PointAlgorithm
iceil(point<double> const & p)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
294