Mercurial > hg > vamp-build-and-test
diff DEPENDENCIES/generic/include/boost/polygon/transform.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDENCIES/generic/include/boost/polygon/transform.hpp Tue Aug 05 11:11:38 2014 +0100 @@ -0,0 +1,466 @@ +// Boost.Polygon library point_data.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 WEST +class axis_transformation { + public: + enum ATR { + NULL_TRANSFORM = 0, + BEGIN_TRANSFORM = 0, + EN = 0, EAST_NORTH = 0, + WN = 1, WEST_NORTH = 1, FLIP_X = 1, + ES = 2, EAST_SOUTH = 2, FLIP_Y = 2, + WS = 3, WEST_SOUTH = 3, FLIP_XY = 3, + NE = 4, NORTH_EAST = 4, SWAP_XY = 4, + SE = 5, SOUTH_EAST = 5, ROTATE_LEFT = 5, + NW = 6, NORTH_WEST = 6, ROTATE_RIGHT = 6, + SW = 7, 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