annotate DEPENDENCIES/generic/include/boost/polygon/transform.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
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