1 /*
2     Copyright 2008 Intel Corporation
3 
4     Use, modification and distribution are subject to the Boost Software License,
5     Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6     http://www.boost.org/LICENSE_1_0.txt).
7 */
8 #ifndef BOOST_POLYGON_TRANSFORM_HPP
9 #define BOOST_POLYGON_TRANSFORM_HPP
10 #include "isotropy.hpp"
11 #include "point_3d_concept.hpp"
12 namespace boost { namespace polygon{
13 // Transformation of Coordinate Systems
14 // Enum meaning:
15 // Select which direction_3d to change the positive direction of each
16 // axis in the old coordinate system to map it to the new coordiante system.
17 // The first direction_3d listed for each enum is the direction to map the
18 // positive horizontal direction to.
19 // The second direction_3d listed for each enum is the direction to map the
20 // positive vertical direction to.
21 // The third direction_3d listed for each enum is the direction to map the
22 // positive proximal direction to.
23 // The zero position bit (LSB) indicates whether the horizontal axis flips
24 // when transformed.
25 // The 1st postion bit indicates whether the vertical axis flips when
26 // transformed.
27 // The 2nd position bit indicates whether the horizontal and vertical axis
28 // swap positions when transformed.
29 // Note that the first eight values are the complete set of 2D transforms.
30 // The 3rd position bit indicates whether the proximal axis flips when
31 // transformed.
32 // The 4th position bit indicates whether the proximal and horizontal axis are
33 // swapped when transformed.  It changes the meaning of the 2nd position bit
34 // to mean that the horizontal and vertical axis are swapped in their new
35 // positions, naturally.
36 // The 5th position bit (MSB) indicates whether the proximal and vertical axis
37 // are swapped when transformed.  It is mutually exclusive with the 4th postion
38 // bit, making the maximum legal value 48 (decimal).  It similarly changes the
39 // meaning of the 2nd position bit to mean that the horizontal and vertical are
40 // swapped in their new positions.
41 // Enum Values:
42 // 000000 EAST NORTH UP
43 // 000001 WEST NORTH UP
44 // 000010 EAST SOUTH UP
45 // 000011 WEST SOUTH UP
46 // 000100 NORTH EAST UP
47 // 000101 SOUTH EAST UP
48 // 000110 NORTH WEST UP
49 // 000111 SOUTH WEST UP
50 // 001000 EAST NORTH DOWN
51 // 001001 WEST NORTH DOWN
52 // 001010 EAST SOUTH DOWN
53 // 001011 WEST SOUTH DOWN
54 // 001100 NORTH EAST DOWN
55 // 001101 SOUTH EAST DOWN
56 // 001110 NORTH WEST DOWN
57 // 001111 SOUTH WEST DOWN
58 // 010000 UP NORTH EAST
59 // 010001 DOWN NORTH EAST
60 // 010010 UP SOUTH EAST
61 // 010011 DOWN SOUTH EAST
62 // 010100 NORTH UP EAST
63 // 010101 SOUTH UP EAST
64 // 010110 NORTH DOWN EAST
65 // 010111 SOUTH DOWN EAST
66 // 011000 UP NORTH WEST
67 // 011001 DOWN NORTH WEST
68 // 011010 UP SOUTH WEST
69 // 011011 DOWN SOUTH WEST
70 // 011100 NORTH UP WEST
71 // 011101 SOUTH UP WEST
72 // 011110 NORTH DOWN WEST
73 // 011111 SOUTH DOWN WEST
74 // 100000 EAST UP NORTH
75 // 100001 WEST UP NORTH
76 // 100010 EAST DOWN NORTH
77 // 100011 WEST DOWN NORTH
78 // 100100 UP EAST NORTH
79 // 100101 DOWN EAST NORTH
80 // 100110 UP WEST NORTH
81 // 100111 DOWN WEST NORTH
82 // 101000 EAST UP SOUTH
83 // 101001 WEST UP SOUTH
84 // 101010 EAST DOWN SOUTH
85 // 101011 WEST DOWN SOUTH
86 // 101100 UP EAST SOUTH
87 // 101101 DOWN EAST SOUTH
88 // 101110 UP WEST SOUTH
89 // 101111 DOWN WEST SOUTH
90 class axis_transformation {
91 public:
92   // Enum Names and values
93   // NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0,
94   // ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0,
95   // WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X = 1,
96   // ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y = 2,
97   // WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3,
98   // NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY = 4,
99   // SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5,
100   // NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6,
101   // SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7,
102   // END_2D_TRANSFORM = 7,
103   // END = 8, EAST_NORTH_DOWN = 8,
104   // WND = 9, WEST_NORTH_DOWN = 9,
105   // ESD = 10, EAST_SOUTH_DOWN = 10,
106   // WSD = 11, WEST_SOUTH_DOWN = 11,
107   // NED = 12, NORTH_EAST_DOWN = 12,
108   // SED = 13, SOUTH_EAST_DOWN = 13,
109   // NWD = 14, NORTH_WEST_DOWN = 14,
110   // SWD = 15, SOUTH_WEST_DOWN = 15,
111   // UNE = 16, UP_NORTH_EAST = 16,
112   // DNE = 17, DOWN_NORTH_EAST = 17,
113   // USE = 18, UP_SOUTH_EAST = 18,
114   // DSE = 19, DOWN_SOUTH_EAST = 19,
115   // NUE = 20, NORTH_UP_EAST = 20,
116   // SUE = 21, SOUTH_UP_EAST = 21,
117   // NDE = 22, NORTH_DOWN_EAST = 22,
118   // SDE = 23, SOUTH_DOWN_EAST = 23,
119   // UNW = 24, UP_NORTH_WEST = 24,
120   // DNW = 25, DOWN_NORTH_WEST = 25,
121   // USW = 26, UP_SOUTH_WEST = 26,
122   // DSW = 27, DOWN_SOUTH_WEST = 27,
123   // NUW = 28, NORTH_UP_WEST = 28,
124   // SUW = 29, SOUTH_UP_WEST = 29,
125   // NDW = 30, NORTH_DOWN_WEST = 30,
126   // SDW = 31, SOUTH_DOWN_WEST = 31,
127   // EUN = 32, EAST_UP_NORTH = 32,
128   // WUN = 33, WEST_UP_NORTH = 33,
129   // EDN = 34, EAST_DOWN_NORTH = 34,
130   // WDN = 35, WEST_DOWN_NORTH = 35,
131   // UEN = 36, UP_EAST_NORTH = 36,
132   // DEN = 37, DOWN_EAST_NORTH = 37,
133   // UWN = 38, UP_WEST_NORTH = 38,
134   // DWN = 39, DOWN_WEST_NORTH = 39,
135   // EUS = 40, EAST_UP_SOUTH = 40,
136   // WUS = 41, WEST_UP_SOUTH = 41,
137   // EDS = 42, EAST_DOWN_SOUTH = 42,
138   // WDS = 43, WEST_DOWN_SOUTH = 43,
139   // UES = 44, UP_EAST_SOUTH = 44,
140   // DES = 45, DOWN_EAST_SOUTH = 45,
141   // UWS = 46, UP_WEST_SOUTH = 46,
142   // DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47
143   enum ATR {
144     NULL_TRANSFORM = 0, BEGIN_TRANSFORM = 0,
145     ENU = 0, EAST_NORTH_UP = 0, EN = 0, EAST_NORTH = 0,
146     WNU = 1, WEST_NORTH_UP = 1, WN = 1, WEST_NORTH = 1, FLIP_X       = 1,
147     ESU = 2, EAST_SOUTH_UP = 2, ES = 2, EAST_SOUTH = 2, FLIP_Y       = 2,
148     WSU = 3, WEST_SOUTH_UP = 3, WS = 3, WEST_SOUTH = 3, FLIP_XY      = 3,
149     NEU = 4, NORTH_EAST_UP = 4, NE = 4, NORTH_EAST = 4, SWAP_XY      = 4,
150     SEU = 5, SOUTH_EAST_UP = 5, SE = 5, SOUTH_EAST = 5, ROTATE_LEFT  = 5,
151     NWU = 6, NORTH_WEST_UP = 6, NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6,
152     SWU = 7, SOUTH_WEST_UP = 7, SW = 7, SOUTH_WEST = 7, FLIP_SWAP_XY = 7, END_2D_TRANSFORM = 7,
153     END = 8, EAST_NORTH_DOWN = 8, FLIP_Z = 8,
154     WND = 9, WEST_NORTH_DOWN = 9,
155     ESD = 10, EAST_SOUTH_DOWN = 10,
156     WSD = 11, WEST_SOUTH_DOWN = 11,
157     NED = 12, NORTH_EAST_DOWN = 12,
158     SED = 13, SOUTH_EAST_DOWN = 13,
159     NWD = 14, NORTH_WEST_DOWN = 14,
160     SWD = 15, SOUTH_WEST_DOWN = 15,
161     UNE = 16, UP_NORTH_EAST = 16,
162     DNE = 17, DOWN_NORTH_EAST = 17,
163     USE = 18, UP_SOUTH_EAST = 18,
164     DSE = 19, DOWN_SOUTH_EAST = 19,
165     NUE = 20, NORTH_UP_EAST = 20,
166     SUE = 21, SOUTH_UP_EAST = 21,
167     NDE = 22, NORTH_DOWN_EAST = 22,
168     SDE = 23, SOUTH_DOWN_EAST = 23,
169     UNW = 24, UP_NORTH_WEST = 24,
170     DNW = 25, DOWN_NORTH_WEST = 25,
171     USW = 26, UP_SOUTH_WEST = 26,
172     DSW = 27, DOWN_SOUTH_WEST = 27,
173     NUW = 28, NORTH_UP_WEST = 28,
174     SUW = 29, SOUTH_UP_WEST = 29,
175     NDW = 30, NORTH_DOWN_WEST = 30,
176     SDW = 31, SOUTH_DOWN_WEST = 31,
177     EUN = 32, EAST_UP_NORTH = 32,
178     WUN = 33, WEST_UP_NORTH = 33,
179     EDN = 34, EAST_DOWN_NORTH = 34,
180     WDN = 35, WEST_DOWN_NORTH = 35,
181     UEN = 36, UP_EAST_NORTH = 36,
182     DEN = 37, DOWN_EAST_NORTH = 37,
183     UWN = 38, UP_WEST_NORTH = 38,
184     DWN = 39, DOWN_WEST_NORTH = 39,
185     EUS = 40, EAST_UP_SOUTH = 40,
186     WUS = 41, WEST_UP_SOUTH = 41,
187     EDS = 42, EAST_DOWN_SOUTH = 42,
188     WDS = 43, WEST_DOWN_SOUTH = 43,
189     UES = 44, UP_EAST_SOUTH = 44,
190     DES = 45, DOWN_EAST_SOUTH = 45,
191     UWS = 46, UP_WEST_SOUTH = 46,
192     DWS = 47, DOWN_WEST_SOUTH = 47, END_TRANSFORM = 47
193   };
194 
195   // Individual axis enum values indicate which axis an implicit individual
196   // axis will be mapped to.
197   // The value of the enum paired with an axis provides the information
198   // about what the axis will transform to.
199   // Three individual axis values, one for each axis, are equivalent to one
200   // ATR enum value, but easier to work with because they are independent.
201   // Converting to and from the individual axis values from the ATR value
202   // is a convenient way to implement tranformation related functionality.
203   // Enum meanings:
204   // PX: map to positive x axis
205   // NX: map to negative x axis
206   // PY: map to positive y axis
207   // NY: map to negative y axis
208   // PZ: map to positive z axis
209   // NZ: map to negative z axis
210   enum INDIVIDUAL_AXIS {
211     PX = 0,
212     NX = 1,
213     PY = 2,
214     NY = 3,
215     PZ = 4,
216     NZ = 5
217   };
218 
axis_transformation()219   inline axis_transformation() : atr_(NULL_TRANSFORM) {}
axis_transformation(ATR atr)220   inline axis_transformation(ATR atr) : atr_(atr) {}
axis_transformation(const axis_transformation & atr)221   inline axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {}
222   explicit axis_transformation(const orientation_3d& orient);
223   explicit axis_transformation(const direction_3d& dir);
224   explicit axis_transformation(const orientation_2d& orient);
225   explicit axis_transformation(const direction_2d& dir);
226 
227   // assignment operator
228   axis_transformation& operator=(const axis_transformation& a);
229 
230   // assignment operator
231   axis_transformation& operator=(const ATR& atr);
232 
233   // equivalence operator
234   bool operator==(const axis_transformation& a) const;
235 
236   // inequivalence operator
237   bool operator!=(const axis_transformation& a) const;
238 
239   // ordering
240   bool operator<(const axis_transformation& a) const;
241 
242   // concatenation operator
243   axis_transformation operator+(const axis_transformation& a) const;
244 
245   // concatenate this with that
246   axis_transformation& operator+=(const axis_transformation& a);
247 
248   // populate_axis_array writes the three INDIVIDUAL_AXIS values that the
249   // ATR enum value of 'this' represent into axis_array
250   void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const;
251 
252   // it is recommended that the directions stored in an array
253   // in the caller code for easier isotropic access by orientation value
get_directions(direction_2d & horizontal_dir,direction_2d & vertical_dir) const254   inline void get_directions(direction_2d& horizontal_dir,
255                              direction_2d& vertical_dir) const {
256     bool bit2 = (atr_ & 4) != 0;
257     bool bit1 = (atr_ & 2) != 0;
258     bool bit0 = (atr_ & 1) != 0;
259     vertical_dir = direction_2d((direction_2d_enum)(((int)(!bit2) << 1) + !bit1));
260     horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0));
261   }
262 
263   // it is recommended that the directions stored in an array
264   // in the caller code for easier isotropic access by orientation value
get_directions(direction_3d & horizontal_dir,direction_3d & vertical_dir,direction_3d & proximal_dir) const265   inline void get_directions(direction_3d& horizontal_dir,
266                              direction_3d& vertical_dir,
267                              direction_3d& proximal_dir) const {
268     bool bit5 = (atr_ & 32) != 0;
269     bool bit4 = (atr_ & 16) != 0;
270     bool bit3 = (atr_ & 8) != 0;
271     bool bit2 = (atr_ & 4) != 0;
272     bool bit1 = (atr_ & 2) != 0;
273     bool bit0 = (atr_ & 1) != 0;
274     proximal_dir = direction_3d((direction_2d_enum)((((int)(!bit4 & !bit5)) << 2) +
275                                                     ((int)(bit5) << 1) +
276                                                     !bit3));
277     vertical_dir = direction_3d((direction_2d_enum)((((int)((bit4 & bit2) | (bit5 & !bit2))) << 2)+
278                                                     ((int)(!bit5 & !bit2) << 1) +
279                                                     !bit1));
280     horizontal_dir = direction_3d((direction_2d_enum)((((int)((bit5 & bit2) |
281                                                               (bit4 & !bit2))) << 2) +
282                                                       ((int)(bit2 & !bit5) << 1) +
283                                                       !bit0));
284   }
285 
286   // combine_axis_arrays concatenates this_array and that_array overwriting
287   // the result into this_array
288   static void combine_axis_arrays (INDIVIDUAL_AXIS this_array[],
289                                    const INDIVIDUAL_AXIS that_array[]);
290 
291   // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values
292   // to the ATR enum value and sets 'this' to that value
293   void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]);
294 
295   // behavior is deterministic but undefined in the case where illegal
296   // combinations of directions are passed in.
297   axis_transformation& set_directions(const direction_2d& horizontal_dir,
298                                  const direction_2d& vertical_dir);
299   // behavior is deterministic but undefined in the case where illegal
300   // combinations of directions are passed in.
301   axis_transformation& set_directions(const direction_3d& horizontal_dir,
302                                  const direction_3d& vertical_dir,
303                                  const direction_3d& proximal_dir);
304 
305   // transform the two coordinates by reference using the 2D portion of this
306   template <typename coordinate_type>
307   void transform(coordinate_type& x, coordinate_type& y) const;
308 
309   // transform the three coordinates by reference
310   template <typename coordinate_type>
311   void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const;
312 
313   // invert the 2D portion of this
314   axis_transformation& invert_2d();
315 
316   // get the inverse of the 2D portion of this
317   axis_transformation inverse_2d() const;
318 
319   // invert this axis_transformation
320   axis_transformation& invert();
321 
322   // get the inverse axis_transformation of this
323   axis_transformation inverse() const;
324 
325   //friend std::ostream& operator<< (std::ostream& o, const axis_transformation& r);
326   //friend std::istream& operator>> (std::istream& i, axis_transformation& r);
327 
328 private:
329   ATR atr_;
330 };
331 
332 
333 // Scaling object to be used to store the scale factor for each axis
334 
335 // For use by the transformation object, in that context the scale factor
336 // is the amount that each axis scales by when transformed.
337 // If the horizontal value of the Scale is 10 that means the horizontal
338 // axis of the input is multiplied by 10 when the transformation is applied.
339 template <typename scale_factor_type>
340 class anisotropic_scale_factor {
341 public:
anisotropic_scale_factor()342   inline anisotropic_scale_factor()
343 #ifndef BOOST_POLYGON_MSVC
344     : scale_()
345 #endif
346   {
347     scale_[0] = 1;
348     scale_[1] = 1;
349     scale_[2] = 1;
350   }
anisotropic_scale_factor(scale_factor_type xscale,scale_factor_type yscale)351   inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale)
352 #ifndef BOOST_POLYGON_MSVC
353     : scale_()
354 #endif
355   {
356     scale_[0] = xscale;
357     scale_[1] = yscale;
358     scale_[2] = 1;
359   }
anisotropic_scale_factor(scale_factor_type xscale,scale_factor_type yscale,scale_factor_type zscale)360   inline anisotropic_scale_factor(scale_factor_type xscale, scale_factor_type yscale, scale_factor_type zscale)
361 #ifndef BOOST_POLYGON_MSVC
362     : scale_()
363 #endif
364   {
365     scale_[0] = xscale;
366     scale_[1] = yscale;
367     scale_[2] = zscale;
368   }
369 
370   // get a component of the anisotropic_scale_factor by orientation
371   scale_factor_type get(orientation_3d orient) const;
get(orientation_2d orient) const372   scale_factor_type get(orientation_2d orient) const { return get(orientation_3d(orient)); }
373 
374   // set a component of the anisotropic_scale_factor by orientation
375   void set(orientation_3d orient, scale_factor_type value);
set(orientation_2d orient,scale_factor_type value)376   void set(orientation_2d orient, scale_factor_type value) { set(orientation_3d(orient), value); }
377 
378   scale_factor_type x() const;
379   scale_factor_type y() const;
380   scale_factor_type z() const;
381   void x(scale_factor_type value);
382   void y(scale_factor_type value);
383   void z(scale_factor_type value);
384 
385   // concatination operator (convolve scale factors)
386   anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const;
387 
388   // concatinate this with that
389   const anisotropic_scale_factor& operator+=(const anisotropic_scale_factor& s);
390 
391   // transform this scale with an axis_transform
392   anisotropic_scale_factor& transform(axis_transformation atr);
393 
394   // scale the two coordinates
395   template <typename coordinate_type>
396   void scale(coordinate_type& x, coordinate_type& y) const;
397 
398   // scale the three coordinates
399   template <typename coordinate_type>
400   void scale(coordinate_type& x, coordinate_type& y, coordinate_type& z) const;
401 
402   // invert this scale factor to give the reverse scale factor
403   anisotropic_scale_factor& invert();
404 
405 private:
406   scale_factor_type scale_[3];
407 
408   //friend std::ostream& operator<< (std::ostream& o, const Scale& r);
409   //friend std::istream& operator>> (std::istream& i, Scale& r);
410 };
411 
412 // Transformation object, stores and provides services for transformations
413 
414 // Transformation object stores an axistransformation, a scale factor and a translation.
415 // The tranlation is the position of the origin of the new system of coordinates in the old system.
416 // The scale scales the coordinates before they are transformed.
417 template <typename coordinate_type>
418 class transformation {
419 public:
420   transformation();
421   transformation(axis_transformation atr);
422   transformation(axis_transformation::ATR atr);
423   template <typename point_type>
424   transformation(const point_type& p);
425   template <typename point_type>
426   transformation(axis_transformation atr, const point_type& p);
427   template <typename point_type>
428   transformation(axis_transformation atr, const point_type& referencePt, const point_type& destinationPt);
429   transformation(const transformation& tr);
430 
431   // equivalence operator
432   bool operator==(const transformation& tr) const;
433 
434   // inequivalence operator
435   bool operator!=(const transformation& tr) const;
436 
437   // ordering
438   bool operator<(const transformation& tr) const;
439 
440   // concatenation operator
441   transformation operator+(const transformation& tr) const;
442 
443   // concatenate this with that
444   const transformation& operator+=(const transformation& tr);
445 
446   // get the axis_transformation portion of this
get_axis_transformation() const447   inline axis_transformation get_axis_transformation() const {return atr_;}
448 
449   // set the axis_transformation portion of this
450   void set_axis_transformation(const axis_transformation& atr);
451 
452   // get the translation portion of this as a point3d
453   template <typename point_type>
454   void get_translation(point_type& translation) const;
455 
456   // set the translation portion of this with a point3d
457   template <typename point_type>
458   void set_translation(const point_type& p);
459 
460   // apply the 2D portion of this transformation to the two coordinates given
461   void transform(coordinate_type& x, coordinate_type& y) const;
462 
463   // apply this transformation to the three coordinates given
464   void transform(coordinate_type& x, coordinate_type& y, coordinate_type& z) const;
465 
466   // invert this transformation
467   transformation& invert();
468 
469   // get the inverse of this transformation
470   transformation inverse() const;
471 
get_directions(direction_2d & horizontal_dir,direction_2d & vertical_dir) const472   inline void get_directions(direction_2d& horizontal_dir,
473                              direction_2d& vertical_dir) const {
474     return atr_.get_directions(horizontal_dir, vertical_dir); }
475 
get_directions(direction_3d & horizontal_dir,direction_3d & vertical_dir,direction_3d & proximal_dir) const476   inline void get_directions(direction_3d& horizontal_dir,
477                              direction_3d& vertical_dir,
478                              direction_3d& proximal_dir) const {
479     return atr_.get_directions(horizontal_dir, vertical_dir, proximal_dir); }
480 
481 private:
482   axis_transformation atr_;
483   point_3d_data<coordinate_type> p_;
484 
485   template <typename point_type>
486   void construct_dispatch(axis_transformation atr, point_type p, point_concept tag);
487   template <typename point_type>
488   void construct_dispatch(axis_transformation atr, point_type p, point_3d_concept tag);
489   template <typename point_type>
490   void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_concept tag);
491   template <typename point_type>
492   void construct_dispatch(axis_transformation atr, point_type rp, point_type dp, point_3d_concept tag);
493 
494   //friend std::ostream& operator<< (std::ostream& o, const transformation& tr);
495   //friend std::istream& operator>> (std::istream& i, transformation& tr);
496 };
497 }
498 }
499 #include "detail/transform_detail.hpp"
500 #endif
501 
502