Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/polygon/transform.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
1 // Boost.Polygon library point_data.hpp header file | |
2 | |
3 // Copyright (c) Intel Corporation 2008. | |
4 // Copyright (c) 2008-2012 Simonson Lucanus. | |
5 // Copyright (c) 2012-2012 Andrii Sydorchuk. | |
6 | |
7 // See http://www.boost.org for updates, documentation, and revision history. | |
8 // Use, modification and distribution is subject to the Boost Software License, | |
9 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
10 // http://www.boost.org/LICENSE_1_0.txt) | |
11 | |
12 #ifndef BOOST_POLYGON_TRANSFORM_HPP | |
13 #define BOOST_POLYGON_TRANSFORM_HPP | |
14 | |
15 #include "isotropy.hpp" | |
16 | |
17 namespace boost { | |
18 namespace polygon { | |
19 // Transformation of Coordinate System. | |
20 // Enum meaning: | |
21 // Select which direction_2d to change the positive direction of each | |
22 // axis in the old coordinate system to map it to the new coordiante system. | |
23 // The first direction_2d listed for each enum is the direction to map the | |
24 // positive horizontal direction to. | |
25 // The second direction_2d listed for each enum is the direction to map the | |
26 // positive vertical direction to. | |
27 // The zero position bit (LSB) indicates whether the horizontal axis flips | |
28 // when transformed. | |
29 // The 1st postion bit indicates whether the vertical axis flips when | |
30 // transformed. | |
31 // The 2nd position bit indicates whether the horizontal and vertical axis | |
32 // swap positions when transformed. | |
33 // Enum Values: | |
34 // 000 EAST NORTH | |
35 // 001 WEST NORTH | |
36 // 010 EAST SOUTH | |
37 // 011 WEST SOUTH | |
38 // 100 NORTH EAST | |
39 // 101 SOUTH EAST | |
40 // 110 NORTH WEST | |
41 // 111 SOUTH WEST | |
42 class axis_transformation { | |
43 public: | |
44 enum ATR { | |
45 NULL_TRANSFORM = 0, | |
46 BEGIN_TRANSFORM = 0, | |
47 EN = 0, EAST_NORTH = 0, | |
48 WN = 1, WEST_NORTH = 1, FLIP_X = 1, | |
49 ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, | |
50 WS = 3, WEST_SOUTH = 3, FLIP_XY = 3, | |
51 NE = 4, NORTH_EAST = 4, SWAP_XY = 4, | |
52 SE = 5, SOUTH_EAST = 5, ROTATE_LEFT = 5, | |
53 NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6, | |
54 SW = 7, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, | |
55 END_TRANSFORM = 7 | |
56 }; | |
57 | |
58 // Individual axis enum values indicate which axis an implicit individual | |
59 // axis will be mapped to. | |
60 // The value of the enum paired with an axis provides the information | |
61 // about what the axis will transform to. | |
62 // Three individual axis values, one for each axis, are equivalent to one | |
63 // ATR enum value, but easier to work with because they are independent. | |
64 // Converting to and from the individual axis values from the ATR value | |
65 // is a convenient way to implement tranformation related functionality. | |
66 // Enum meanings: | |
67 // PX: map to positive x axis | |
68 // NX: map to negative x axis | |
69 // PY: map to positive y axis | |
70 // NY: map to negative y axis | |
71 enum INDIVIDUAL_AXIS { | |
72 PX = 0, | |
73 NX = 1, | |
74 PY = 2, | |
75 NY = 3 | |
76 }; | |
77 | |
78 axis_transformation() : atr_(NULL_TRANSFORM) {} | |
79 explicit axis_transformation(ATR atr) : atr_(atr) {} | |
80 axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {} | |
81 | |
82 explicit axis_transformation(const orientation_2d& orient) { | |
83 const ATR tmp[2] = { | |
84 NORTH_EAST, // sort x, then y | |
85 EAST_NORTH // sort y, then x | |
86 }; | |
87 atr_ = tmp[orient.to_int()]; | |
88 } | |
89 | |
90 explicit axis_transformation(const direction_2d& dir) { | |
91 const ATR tmp[4] = { | |
92 SOUTH_EAST, // sort x, then y | |
93 NORTH_EAST, // sort x, then y | |
94 EAST_SOUTH, // sort y, then x | |
95 EAST_NORTH // sort y, then x | |
96 }; | |
97 atr_ = tmp[dir.to_int()]; | |
98 } | |
99 | |
100 // assignment operator | |
101 axis_transformation& operator=(const axis_transformation& a) { | |
102 atr_ = a.atr_; | |
103 return *this; | |
104 } | |
105 | |
106 // assignment operator | |
107 axis_transformation& operator=(const ATR& atr) { | |
108 atr_ = atr; | |
109 return *this; | |
110 } | |
111 | |
112 // equivalence operator | |
113 bool operator==(const axis_transformation& a) const { | |
114 return atr_ == a.atr_; | |
115 } | |
116 | |
117 // inequivalence operator | |
118 bool operator!=(const axis_transformation& a) const { | |
119 return !(*this == a); | |
120 } | |
121 | |
122 // ordering | |
123 bool operator<(const axis_transformation& a) const { | |
124 return atr_ < a.atr_; | |
125 } | |
126 | |
127 // concatenate this with that | |
128 axis_transformation& operator+=(const axis_transformation& a) { | |
129 bool abit2 = (a.atr_ & 4) != 0; | |
130 bool abit1 = (a.atr_ & 2) != 0; | |
131 bool abit0 = (a.atr_ & 1) != 0; | |
132 bool bit2 = (atr_ & 4) != 0; | |
133 bool bit1 = (atr_ & 2) != 0; | |
134 bool bit0 = (atr_ & 1) != 0; | |
135 int indexes[2][2] = { | |
136 { (int)bit2, (int)(!bit2) }, | |
137 { (int)abit2, (int)(!abit2) } | |
138 }; | |
139 int zero_bits[2][2] = { | |
140 {bit0, bit1}, {abit0, abit1} | |
141 }; | |
142 int nbit1 = zero_bits[0][1] ^ zero_bits[1][indexes[0][1]]; | |
143 int nbit0 = zero_bits[0][0] ^ zero_bits[1][indexes[0][0]]; | |
144 indexes[0][0] = indexes[1][indexes[0][0]]; | |
145 indexes[0][1] = indexes[1][indexes[0][1]]; | |
146 int nbit2 = indexes[0][0] & 1; // swap xy | |
147 atr_ = (ATR)((nbit2 << 2) + (nbit1 << 1) + nbit0); | |
148 return *this; | |
149 } | |
150 | |
151 // concatenation operator | |
152 axis_transformation operator+(const axis_transformation& a) const { | |
153 axis_transformation retval(*this); | |
154 return retval+=a; | |
155 } | |
156 | |
157 // populate_axis_array writes the three INDIVIDUAL_AXIS values that the | |
158 // ATR enum value of 'this' represent into axis_array | |
159 void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const { | |
160 bool bit2 = (atr_ & 4) != 0; | |
161 bool bit1 = (atr_ & 2) != 0; | |
162 bool bit0 = (atr_ & 1) != 0; | |
163 axis_array[1] = (INDIVIDUAL_AXIS)(((int)(!bit2) << 1) + bit1); | |
164 axis_array[0] = (INDIVIDUAL_AXIS)(((int)(bit2) << 1) + bit0); | |
165 } | |
166 | |
167 // it is recommended that the directions stored in an array | |
168 // in the caller code for easier isotropic access by orientation value | |
169 void get_directions(direction_2d& horizontal_dir, | |
170 direction_2d& vertical_dir) const { | |
171 bool bit2 = (atr_ & 4) != 0; | |
172 bool bit1 = (atr_ & 2) != 0; | |
173 bool bit0 = (atr_ & 1) != 0; | |
174 vertical_dir = direction_2d((direction_2d_enum)(((int)(!bit2) << 1) + !bit1)); | |
175 horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0)); | |
176 } | |
177 | |
178 // combine_axis_arrays concatenates this_array and that_array overwriting | |
179 // the result into this_array | |
180 static void combine_axis_arrays(INDIVIDUAL_AXIS this_array[], | |
181 const INDIVIDUAL_AXIS that_array[]) { | |
182 int indexes[2] = { this_array[0] >> 1, this_array[1] >> 1 }; | |
183 int zero_bits[2][2] = { | |
184 { this_array[0] & 1, this_array[1] & 1 }, | |
185 { that_array[0] & 1, that_array[1] & 1 } | |
186 }; | |
187 this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] | | |
188 ((int)zero_bits[0][0] ^ | |
189 (int)zero_bits[1][indexes[0]])); | |
190 this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] | | |
191 ((int)zero_bits[0][1] ^ | |
192 (int)zero_bits[1][indexes[1]])); | |
193 } | |
194 | |
195 // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values | |
196 // to the ATR enum value and sets 'this' to that value | |
197 void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) { | |
198 int bit2 = ((int)this_array[0] & 2) != 0; // swap xy | |
199 int bit1 = ((int)this_array[1] & 1); | |
200 int bit0 = ((int)this_array[0] & 1); | |
201 atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); | |
202 } | |
203 | |
204 // behavior is deterministic but undefined in the case where illegal | |
205 // combinations of directions are passed in. | |
206 axis_transformation& set_directions(const direction_2d& horizontal_dir, | |
207 const direction_2d& vertical_dir) { | |
208 int bit2 = (static_cast<orientation_2d>(horizontal_dir).to_int()) != 0; | |
209 int bit1 = !(vertical_dir.to_int() & 1); | |
210 int bit0 = !(horizontal_dir.to_int() & 1); | |
211 atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0); | |
212 return *this; | |
213 } | |
214 | |
215 // transform the three coordinates by reference | |
216 template <typename coordinate_type> | |
217 void transform(coordinate_type& x, coordinate_type& y) const { | |
218 int bit2 = (atr_ & 4) != 0; | |
219 int bit1 = (atr_ & 2) != 0; | |
220 int bit0 = (atr_ & 1) != 0; | |
221 x *= -((bit0 << 1) - 1); | |
222 y *= -((bit1 << 1) - 1); | |
223 predicated_swap(bit2 != 0, x, y); | |
224 } | |
225 | |
226 // invert this axis_transformation | |
227 axis_transformation& invert() { | |
228 int bit2 = ((atr_ & 4) != 0); | |
229 int bit1 = ((atr_ & 2) != 0); | |
230 int bit0 = ((atr_ & 1) != 0); | |
231 // swap bit 0 and bit 1 if bit2 is 1 | |
232 predicated_swap(bit2 != 0, bit0, bit1); | |
233 bit1 = bit1 << 1; | |
234 atr_ = (ATR)(atr_ & (32+16+8+4)); // mask away bit0 and bit1 | |
235 atr_ = (ATR)(atr_ | bit0 | bit1); | |
236 return *this; | |
237 } | |
238 | |
239 // get the inverse axis_transformation of this | |
240 axis_transformation inverse() const { | |
241 axis_transformation retval(*this); | |
242 return retval.invert(); | |
243 } | |
244 | |
245 private: | |
246 ATR atr_; | |
247 }; | |
248 | |
249 // Scaling object to be used to store the scale factor for each axis. | |
250 // For use by the transformation object, in that context the scale factor | |
251 // is the amount that each axis scales by when transformed. | |
252 template <typename scale_factor_type> | |
253 class anisotropic_scale_factor { | |
254 public: | |
255 anisotropic_scale_factor() { | |
256 scale_[0] = 1; | |
257 scale_[1] = 1; | |
258 } | |
259 anisotropic_scale_factor(scale_factor_type xscale, | |
260 scale_factor_type yscale) { | |
261 scale_[0] = xscale; | |
262 scale_[1] = yscale; | |
263 } | |
264 | |
265 // get a component of the anisotropic_scale_factor by orientation | |
266 scale_factor_type get(orientation_2d orient) const { | |
267 return scale_[orient.to_int()]; | |
268 } | |
269 | |
270 // set a component of the anisotropic_scale_factor by orientation | |
271 void set(orientation_2d orient, scale_factor_type value) { | |
272 scale_[orient.to_int()] = value; | |
273 } | |
274 | |
275 scale_factor_type x() const { | |
276 return scale_[HORIZONTAL]; | |
277 } | |
278 | |
279 scale_factor_type y() const { | |
280 return scale_[VERTICAL]; | |
281 } | |
282 | |
283 void x(scale_factor_type value) { | |
284 scale_[HORIZONTAL] = value; | |
285 } | |
286 | |
287 void y(scale_factor_type value) { | |
288 scale_[VERTICAL] = value; | |
289 } | |
290 | |
291 // concatination operator (convolve scale factors) | |
292 anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const { | |
293 anisotropic_scale_factor<scale_factor_type> retval(*this); | |
294 return retval += s; | |
295 } | |
296 | |
297 // concatinate this with that | |
298 const anisotropic_scale_factor& operator+=( | |
299 const anisotropic_scale_factor& s) { | |
300 scale_[0] *= s.scale_[0]; | |
301 scale_[1] *= s.scale_[1]; | |
302 return *this; | |
303 } | |
304 | |
305 // transform this scale with an axis_transform | |
306 anisotropic_scale_factor& transform(axis_transformation atr) { | |
307 direction_2d dirs[2]; | |
308 atr.get_directions(dirs[0], dirs[1]); | |
309 scale_factor_type tmp[2] = {scale_[0], scale_[1]}; | |
310 for (int i = 0; i < 2; ++i) { | |
311 scale_[orientation_2d(dirs[i]).to_int()] = tmp[i]; | |
312 } | |
313 return *this; | |
314 } | |
315 | |
316 // scale the two coordinates | |
317 template <typename coordinate_type> | |
318 void scale(coordinate_type& x, coordinate_type& y) const { | |
319 x = scaling_policy<coordinate_type>::round( | |
320 (scale_factor_type)x * get(HORIZONTAL)); | |
321 y = scaling_policy<coordinate_type>::round( | |
322 (scale_factor_type)y * get(HORIZONTAL)); | |
323 } | |
324 | |
325 // invert this scale factor to give the reverse scale factor | |
326 anisotropic_scale_factor& invert() { | |
327 x(1/x()); | |
328 y(1/y()); | |
329 return *this; | |
330 } | |
331 | |
332 private: | |
333 scale_factor_type scale_[2]; | |
334 }; | |
335 | |
336 // Transformation object, stores and provides services for transformations. | |
337 // Consits of axis transformation, scale factor and translation. | |
338 // The tranlation is the position of the origin of the new coordinate system of | |
339 // in the old system. Coordinates are scaled before they are transformed. | |
340 template <typename coordinate_type> | |
341 class transformation { | |
342 public: | |
343 transformation() : atr_(), p_(0, 0) {} | |
344 explicit transformation(axis_transformation atr) : atr_(atr), p_(0, 0) {} | |
345 explicit transformation(axis_transformation::ATR atr) : atr_(atr), p_(0, 0) {} | |
346 transformation(const transformation& tr) : atr_(tr.atr_), p_(tr.p_) {} | |
347 | |
348 template <typename point_type> | |
349 explicit transformation(const point_type& p) : atr_(), p_(0, 0) { | |
350 set_translation(p); | |
351 } | |
352 | |
353 template <typename point_type> | |
354 transformation(axis_transformation atr, | |
355 const point_type& p) : atr_(atr), p_(0, 0) { | |
356 set_translation(p); | |
357 } | |
358 | |
359 template <typename point_type> | |
360 transformation(axis_transformation atr, | |
361 const point_type& referencePt, | |
362 const point_type& destinationPt) : atr_(), p_(0, 0) { | |
363 transformation<coordinate_type> tmp(referencePt); | |
364 transformation<coordinate_type> rotRef(atr); | |
365 transformation<coordinate_type> tmpInverse = tmp.inverse(); | |
366 point_type decon(referencePt); | |
367 deconvolve(decon, destinationPt); | |
368 transformation<coordinate_type> displacement(decon); | |
369 tmp += rotRef; | |
370 tmp += tmpInverse; | |
371 tmp += displacement; | |
372 (*this) = tmp; | |
373 } | |
374 | |
375 // equivalence operator | |
376 bool operator==(const transformation& tr) const { | |
377 return (atr_ == tr.atr_) && (p_ == tr.p_); | |
378 } | |
379 | |
380 // inequivalence operator | |
381 bool operator!=(const transformation& tr) const { | |
382 return !(*this == tr); | |
383 } | |
384 | |
385 // ordering | |
386 bool operator<(const transformation& tr) const { | |
387 return (atr_ < tr.atr_) || ((atr_ == tr.atr_) && (p_ < tr.p_)); | |
388 } | |
389 | |
390 // concatenation operator | |
391 transformation operator+(const transformation& tr) const { | |
392 transformation<coordinate_type> retval(*this); | |
393 return retval+=tr; | |
394 } | |
395 | |
396 // concatenate this with that | |
397 const transformation& operator+=(const transformation& tr) { | |
398 coordinate_type x, y; | |
399 transformation<coordinate_type> inv = inverse(); | |
400 inv.transform(x, y); | |
401 p_.set(HORIZONTAL, p_.get(HORIZONTAL) + x); | |
402 p_.set(VERTICAL, p_.get(VERTICAL) + y); | |
403 // concatenate axis transforms | |
404 atr_ += tr.atr_; | |
405 return *this; | |
406 } | |
407 | |
408 // get the axis_transformation portion of this | |
409 axis_transformation get_axis_transformation() const { | |
410 return atr_; | |
411 } | |
412 | |
413 // set the axis_transformation portion of this | |
414 void set_axis_transformation(const axis_transformation& atr) { | |
415 atr_ = atr; | |
416 } | |
417 | |
418 // get the translation | |
419 template <typename point_type> | |
420 void get_translation(point_type& p) const { | |
421 assign(p, p_); | |
422 } | |
423 | |
424 // set the translation | |
425 template <typename point_type> | |
426 void set_translation(const point_type& p) { | |
427 assign(p_, p); | |
428 } | |
429 | |
430 // apply the 2D portion of this transformation to the two coordinates given | |
431 void transform(coordinate_type& x, coordinate_type& y) const { | |
432 y -= p_.get(VERTICAL); | |
433 x -= p_.get(HORIZONTAL); | |
434 atr_.transform(x, y); | |
435 } | |
436 | |
437 // invert this transformation | |
438 transformation& invert() { | |
439 coordinate_type x = p_.get(HORIZONTAL), y = p_.get(VERTICAL); | |
440 atr_.transform(x, y); | |
441 x *= -1; | |
442 y *= -1; | |
443 p_ = point_data<coordinate_type>(x, y); | |
444 atr_.invert(); | |
445 return *this; | |
446 } | |
447 | |
448 // get the inverse of this transformation | |
449 transformation inverse() const { | |
450 transformation<coordinate_type> ret_val(*this); | |
451 return ret_val.invert(); | |
452 } | |
453 | |
454 void get_directions(direction_2d& horizontal_dir, | |
455 direction_2d& vertical_dir) const { | |
456 return atr_.get_directions(horizontal_dir, vertical_dir); | |
457 } | |
458 | |
459 private: | |
460 axis_transformation atr_; | |
461 point_data<coordinate_type> p_; | |
462 }; | |
463 } // polygon | |
464 } // boost | |
465 | |
466 #endif // BOOST_POLYGON_TRANSFORM_HPP |