| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 | // Boost.Polygon library transform.hpp header file// Copyright (c) Intel Corporation 2008.// Copyright (c) 2008-2012 Simonson Lucanus.// Copyright (c) 2012-2012 Andrii Sydorchuk.// See http://www.boost.org for updates, documentation, and revision history.// Use, modification and distribution is subject to the Boost Software License,// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at// http://www.boost.org/LICENSE_1_0.txt)#ifndef BOOST_POLYGON_TRANSFORM_HPP#define BOOST_POLYGON_TRANSFORM_HPP#include "isotropy.hpp"namespace boost {namespace polygon {// Transformation of Coordinate System.// Enum meaning:// Select which direction_2d to change the positive direction of each// axis in the old coordinate system to map it to the new coordiante system.// The first direction_2d listed for each enum is the direction to map the// positive horizontal direction to.// The second direction_2d listed for each enum is the direction to map the// positive vertical direction to.// The zero position bit (LSB) indicates whether the horizontal axis flips// when transformed.// The 1st postion bit indicates whether the vertical axis flips when// transformed.// The 2nd position bit indicates whether the horizontal and vertical axis// swap positions when transformed.// Enum Values://   000 EAST NORTH//   001 WEST NORTH//   010 EAST SOUTH//   011 WEST SOUTH//   100 NORTH EAST//   101 SOUTH EAST//   110 NORTH WEST//   111 SOUTH WESTclass axis_transformation { public:  enum ATR {#ifdef BOOST_POLYGON_ENABLE_DEPRECATED    EN = 0,    WN = 1,    ES = 2,    WS = 3,    NE = 4,    SE = 5,    NW = 6,    SW = 7,#endif    NULL_TRANSFORM = 0,    BEGIN_TRANSFORM = 0,    EAST_NORTH = 0,    WEST_NORTH = 1, FLIP_X       = 1,    EAST_SOUTH = 2, FLIP_Y       = 2,    WEST_SOUTH = 3, FLIP_XY      = 3,    NORTH_EAST = 4, SWAP_XY      = 4,    SOUTH_EAST = 5, ROTATE_LEFT  = 5,    NORTH_WEST = 6, ROTATE_RIGHT = 6,    SOUTH_WEST = 7, FLIP_SWAP_XY = 7,    END_TRANSFORM = 7  };  // Individual axis enum values indicate which axis an implicit individual  // axis will be mapped to.  // The value of the enum paired with an axis provides the information  // about what the axis will transform to.  // Three individual axis values, one for each axis, are equivalent to one  // ATR enum value, but easier to work with because they are independent.  // Converting to and from the individual axis values from the ATR value  // is a convenient way to implement tranformation related functionality.  // Enum meanings:  // PX: map to positive x axis  // NX: map to negative x axis  // PY: map to positive y axis  // NY: map to negative y axis  enum INDIVIDUAL_AXIS {    PX = 0,    NX = 1,    PY = 2,    NY = 3  };  axis_transformation() : atr_(NULL_TRANSFORM) {}  explicit axis_transformation(ATR atr) : atr_(atr) {}  axis_transformation(const axis_transformation& atr) : atr_(atr.atr_) {}  explicit axis_transformation(const orientation_2d& orient) {    const ATR tmp[2] = {      NORTH_EAST,  // sort x, then y      EAST_NORTH   // sort y, then x    };    atr_ = tmp[orient.to_int()];  }  explicit axis_transformation(const direction_2d& dir) {    const ATR tmp[4] = {      SOUTH_EAST,  // sort x, then y      NORTH_EAST,  // sort x, then y      EAST_SOUTH,  // sort y, then x      EAST_NORTH   // sort y, then x    };    atr_ = tmp[dir.to_int()];  }  // assignment operator  axis_transformation& operator=(const axis_transformation& a) {    atr_ = a.atr_;    return *this;  }  // assignment operator  axis_transformation& operator=(const ATR& atr) {    atr_ = atr;    return *this;  }  // equivalence operator  bool operator==(const axis_transformation& a) const {    return atr_ == a.atr_;  }  // inequivalence operator  bool operator!=(const axis_transformation& a) const {    return !(*this == a);  }  // ordering  bool operator<(const axis_transformation& a) const {    return atr_ < a.atr_;  }  // concatenate this with that  axis_transformation& operator+=(const axis_transformation& a) {    bool abit2 = (a.atr_ & 4) != 0;    bool abit1 = (a.atr_ & 2) != 0;    bool abit0 = (a.atr_ & 1) != 0;    bool bit2 = (atr_ & 4) != 0;    bool bit1 = (atr_ & 2) != 0;    bool bit0 = (atr_ & 1) != 0;    int indexes[2][2] = {      { (int)bit2, (int)(!bit2) },      { (int)abit2, (int)(!abit2) }    };    int zero_bits[2][2] = {      {bit0, bit1}, {abit0, abit1}    };    int nbit1 = zero_bits[0][1] ^ zero_bits[1][indexes[0][1]];    int nbit0 = zero_bits[0][0] ^ zero_bits[1][indexes[0][0]];    indexes[0][0] = indexes[1][indexes[0][0]];    indexes[0][1] = indexes[1][indexes[0][1]];    int nbit2 = indexes[0][0] & 1;  // swap xy    atr_ = (ATR)((nbit2 << 2) + (nbit1 << 1) + nbit0);    return *this;  }  // concatenation operator  axis_transformation operator+(const axis_transformation& a) const {    axis_transformation retval(*this);    return retval+=a;  }  // populate_axis_array writes the three INDIVIDUAL_AXIS values that the  // ATR enum value of 'this' represent into axis_array  void populate_axis_array(INDIVIDUAL_AXIS axis_array[]) const {    bool bit2 = (atr_ & 4) != 0;    bool bit1 = (atr_ & 2) != 0;    bool bit0 = (atr_ & 1) != 0;    axis_array[1] = (INDIVIDUAL_AXIS)(((int)(!bit2) << 1) + bit1);    axis_array[0] = (INDIVIDUAL_AXIS)(((int)(bit2) << 1) + bit0);  }  // it is recommended that the directions stored in an array  // in the caller code for easier isotropic access by orientation value  void get_directions(direction_2d& horizontal_dir,                      direction_2d& vertical_dir) const {    bool bit2 = (atr_ & 4) != 0;    bool bit1 = (atr_ & 2) != 0;    bool bit0 = (atr_ & 1) != 0;    vertical_dir = direction_2d((direction_2d_enum)(((int)(!bit2) << 1) + !bit1));    horizontal_dir = direction_2d((direction_2d_enum)(((int)(bit2) << 1) + !bit0));  }  // combine_axis_arrays concatenates this_array and that_array overwriting  // the result into this_array  static void combine_axis_arrays(INDIVIDUAL_AXIS this_array[],                                  const INDIVIDUAL_AXIS that_array[]) {    int indexes[2] = { this_array[0] >> 1, this_array[1] >> 1 };    int zero_bits[2][2] = {      { this_array[0] & 1, this_array[1] & 1 },      { that_array[0] & 1, that_array[1] & 1 }    };    this_array[0] = (INDIVIDUAL_AXIS)((int)this_array[0] |                                      ((int)zero_bits[0][0] ^                                       (int)zero_bits[1][indexes[0]]));    this_array[1] = (INDIVIDUAL_AXIS)((int)this_array[1] |                                      ((int)zero_bits[0][1] ^                                       (int)zero_bits[1][indexes[1]]));  }  // write_back_axis_array converts an array of three INDIVIDUAL_AXIS values  // to the ATR enum value and sets 'this' to that value  void write_back_axis_array(const INDIVIDUAL_AXIS this_array[]) {    int bit2 = ((int)this_array[0] & 2) != 0;  // swap xy    int bit1 = ((int)this_array[1] & 1);    int bit0 = ((int)this_array[0] & 1);    atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0);  }  // behavior is deterministic but undefined in the case where illegal  // combinations of directions are passed in.  axis_transformation& set_directions(const direction_2d& horizontal_dir,                                      const direction_2d& vertical_dir) {    int bit2 = (static_cast<orientation_2d>(horizontal_dir).to_int()) != 0;    int bit1 = !(vertical_dir.to_int() & 1);    int bit0 = !(horizontal_dir.to_int() & 1);    atr_ = ATR((bit2 << 2) + (bit1 << 1) + bit0);    return *this;  }  // transform the three coordinates by reference  template <typename coordinate_type>  void transform(coordinate_type& x, coordinate_type& y) const {    int bit2 = (atr_ & 4) != 0;    int bit1 = (atr_ & 2) != 0;    int bit0 = (atr_ & 1) != 0;    x *= -((bit0 << 1) - 1);    y *= -((bit1 << 1) - 1);    predicated_swap(bit2 != 0, x, y);  }  // invert this axis_transformation  axis_transformation& invert() {    int bit2 = ((atr_ & 4) != 0);    int bit1 = ((atr_ & 2) != 0);    int bit0 = ((atr_ & 1) != 0);    // swap bit 0 and bit 1 if bit2 is 1    predicated_swap(bit2 != 0, bit0, bit1);    bit1 = bit1 << 1;    atr_ = (ATR)(atr_ & (32+16+8+4));  // mask away bit0 and bit1    atr_ = (ATR)(atr_ | bit0 | bit1);    return *this;  }  // get the inverse axis_transformation of this  axis_transformation inverse() const {    axis_transformation retval(*this);    return retval.invert();  } private:  ATR atr_;};// Scaling object to be used to store the scale factor for each axis.// For use by the transformation object, in that context the scale factor// is the amount that each axis scales by when transformed.template <typename scale_factor_type>class anisotropic_scale_factor { public:  anisotropic_scale_factor() {    scale_[0] = 1;    scale_[1] = 1;  }  anisotropic_scale_factor(scale_factor_type xscale,                           scale_factor_type yscale) {    scale_[0] = xscale;    scale_[1] = yscale;  }  // get a component of the anisotropic_scale_factor by orientation  scale_factor_type get(orientation_2d orient) const {    return scale_[orient.to_int()];  }  // set a component of the anisotropic_scale_factor by orientation  void set(orientation_2d orient, scale_factor_type value) {    scale_[orient.to_int()] = value;  }  scale_factor_type x() const {    return scale_[HORIZONTAL];  }  scale_factor_type y() const {    return scale_[VERTICAL];  }  void x(scale_factor_type value) {    scale_[HORIZONTAL] = value;  }  void y(scale_factor_type value) {    scale_[VERTICAL] = value;  }  // concatination operator (convolve scale factors)  anisotropic_scale_factor operator+(const anisotropic_scale_factor& s) const {    anisotropic_scale_factor<scale_factor_type> retval(*this);    return retval += s;  }  // concatinate this with that  const anisotropic_scale_factor& operator+=(      const anisotropic_scale_factor& s) {    scale_[0] *= s.scale_[0];    scale_[1] *= s.scale_[1];    return *this;  }  // transform this scale with an axis_transform  anisotropic_scale_factor& transform(axis_transformation atr) {    direction_2d dirs[2];    atr.get_directions(dirs[0], dirs[1]);    scale_factor_type tmp[2] = {scale_[0], scale_[1]};    for (int i = 0; i < 2; ++i) {      scale_[orientation_2d(dirs[i]).to_int()] = tmp[i];    }    return *this;  }  // scale the two coordinates  template <typename coordinate_type>  void scale(coordinate_type& x, coordinate_type& y) const {    x = scaling_policy<coordinate_type>::round(        (scale_factor_type)x * get(HORIZONTAL));    y = scaling_policy<coordinate_type>::round(        (scale_factor_type)y * get(HORIZONTAL));  }  // invert this scale factor to give the reverse scale factor  anisotropic_scale_factor& invert() {    x(1/x());    y(1/y());    return *this;  } private:  scale_factor_type scale_[2];};// Transformation object, stores and provides services for transformations.// Consits of axis transformation, scale factor and translation.// The tranlation is the position of the origin of the new coordinate system of// in the old system. Coordinates are scaled before they are transformed.template <typename coordinate_type>class transformation { public:  transformation() : atr_(), p_(0, 0) {}  explicit transformation(axis_transformation atr) : atr_(atr), p_(0, 0) {}  explicit transformation(axis_transformation::ATR atr) : atr_(atr), p_(0, 0) {}  transformation(const transformation& tr) : atr_(tr.atr_), p_(tr.p_) {}  template <typename point_type>  explicit transformation(const point_type& p) : atr_(), p_(0, 0) {    set_translation(p);  }  template <typename point_type>  transformation(axis_transformation atr,                 const point_type& p) : atr_(atr), p_(0, 0) {    set_translation(p);  }  template <typename point_type>  transformation(axis_transformation atr,                 const point_type& referencePt,                 const point_type& destinationPt) : atr_(), p_(0, 0) {    transformation<coordinate_type> tmp(referencePt);    transformation<coordinate_type> rotRef(atr);    transformation<coordinate_type> tmpInverse = tmp.inverse();    point_type decon(referencePt);    deconvolve(decon, destinationPt);    transformation<coordinate_type> displacement(decon);    tmp += rotRef;    tmp += tmpInverse;    tmp += displacement;    (*this) = tmp;  }  // equivalence operator  bool operator==(const transformation& tr) const {    return (atr_ == tr.atr_) && (p_ == tr.p_);  }  // inequivalence operator  bool operator!=(const transformation& tr) const {    return !(*this == tr);  }  // ordering  bool operator<(const transformation& tr) const {    return (atr_ < tr.atr_) || ((atr_ == tr.atr_) && (p_ < tr.p_));  }  // concatenation operator  transformation operator+(const transformation& tr) const {    transformation<coordinate_type> retval(*this);    return retval+=tr;  }  // concatenate this with that  const transformation& operator+=(const transformation& tr) {    coordinate_type x, y;    transformation<coordinate_type> inv = inverse();    inv.transform(x, y);    p_.set(HORIZONTAL, p_.get(HORIZONTAL) + x);    p_.set(VERTICAL, p_.get(VERTICAL) + y);    // concatenate axis transforms    atr_ += tr.atr_;    return *this;  }  // get the axis_transformation portion of this  axis_transformation get_axis_transformation() const {    return atr_;  }  // set the axis_transformation portion of this  void set_axis_transformation(const axis_transformation& atr) {    atr_ = atr;  }  // get the translation  template <typename point_type>  void get_translation(point_type& p) const {    assign(p, p_);  }  // set the translation  template <typename point_type>  void set_translation(const point_type& p) {    assign(p_, p);  }  // apply the 2D portion of this transformation to the two coordinates given  void transform(coordinate_type& x, coordinate_type& y) const {    y -= p_.get(VERTICAL);    x -= p_.get(HORIZONTAL);    atr_.transform(x, y);  }  // invert this transformation  transformation& invert() {    coordinate_type x = p_.get(HORIZONTAL), y = p_.get(VERTICAL);    atr_.transform(x, y);    x *= -1;    y *= -1;    p_ = point_data<coordinate_type>(x, y);    atr_.invert();    return *this;  }  // get the inverse of this transformation  transformation inverse() const {    transformation<coordinate_type> ret_val(*this);    return ret_val.invert();  }  void get_directions(direction_2d& horizontal_dir,                      direction_2d& vertical_dir) const {    return atr_.get_directions(horizontal_dir, vertical_dir);  } private:  axis_transformation atr_;  point_data<coordinate_type> p_;};}  // polygon}  // boost#endif  // BOOST_POLYGON_TRANSFORM_HPP
 |