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