transform.hpp 15 KB

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