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