/* KLayout Layout Viewer Copyright (C) 2006-2017 Matthias Koefferlein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef HDR_dbTrans #define HDR_dbTrans #include "dbCommon.h" #include "dbPoint.h" #include "dbVector.h" #include "dbMatrix.h" #include "tlString.h" #include "tlAssert.h" #include #include #include namespace tl { class Extractor; } namespace db { template class complex_trans; template class simple_trans; template class disp_trans; template class fixpoint_trans; /** * @brief Provide the default predicates and properties for transformations for the coordinate type C */ template struct default_trans { typedef C coord_type; typedef C target_coord_type; typedef vector displacement_type; /** * @brief Mirror predicate * * If this predicate is true, the transformation will first mirror the coordinates * at the x-axis before applying transformations. */ bool is_mirror () const { return false; } /** * @brief This transformation is always unity */ bool is_unity () const { return true; } /** * @brief Orthogonal predicate * * This predicate tells if the transformation is orthogonal, i.e. does only provide rotations by * multiple of 90 degree. */ bool is_ortho () const { return true; } /** * @brief Magnification predicate * * This predicate tells if the transformation is magnifying */ bool is_mag () const { return false; } /** * @brief The default rotation code */ int rot () const { return 0; } /** * @brief The default rotation code */ fixpoint_trans fp_trans () const { return fixpoint_trans (0); } /** * @brief The default displacement */ displacement_type disp () const { return displacement_type (); } }; /** * @brief A dummy unit transformation * * This transformation is supplied in order to allow generic transformation * parameters being passed a "dummy" transformation. * Even though this transformation does not require a coordinate type, it is provided * to fulfil the contract. */ template struct unit_trans : public default_trans { typedef C coord_type; typedef C target_coord_type; typedef typename coord_traits::distance_type distance_type; typedef vector displacement_type; typedef unit_trans inverse_trans; /** * @brief The default constructor (unity transformation) */ unit_trans () { // .. nothing else .. } /** * @brief Copy ctor (which basically does nothing) */ template explicit unit_trans (const unit_trans &) { // .. nothing else .. } /** * @brief Downcast: does nothing */ explicit unit_trans (const simple_trans &) { // .. nothing else .. } /** * @brief Downcast: does nothing */ explicit unit_trans (const disp_trans &) { // .. nothing else .. } /** * @brief Downcast: does nothing */ template explicit unit_trans (const complex_trans &) { // .. nothing else .. } /** * @brief (dummy) equality */ bool operator== (unit_trans /*b*/) const { return true; } /** * @brief (dummy) fuzzy equality */ bool equal (unit_trans /*b*/) const { return true; } /** * @brief A (fuzzy) inequality test */ bool not_equal (const unit_trans &t) const { return ! equal (t); } /** * @brief (dummy) inequality */ bool operator!= (unit_trans /*b*/) const { return false; } /** * @brief (dummy) comparison */ bool operator< (unit_trans /*b*/) const { return false; } /** * @brief (dummy) fuzzy less comparison */ bool less (unit_trans /*b*/) const { return true; } /** * @brief Assignment (which basically does nothing) */ unit_trans &operator= (const unit_trans &) { return *this; } /** * @brief Inversion */ unit_trans inverted () const { return *this; } /** * @brief In-place inversion */ unit_trans invert () { return *this; } /** * @brief The transformation of a point */ point operator() (const point &p) const { return p; } /** * @brief The transformation of a vector */ vector operator() (const vector &p) const { return p; } /** * @brief The transformation of a point (non-operator version) */ point trans (const point &p) const { return p; } /** * @brief The transformation of a vector (non-operator version) */ vector trans (const vector &p) const { return p; } /** * @brief Transform a distance */ distance_type ctrans (distance_type d) const { return d; } /** * @brief String conversion */ std::string to_string () const { return std::string (""); } /** * @brief Conversion to a 2d matrix */ Matrix2d to_matrix2d () const { return Matrix2d (1.0, 0.0, 0.0, 1.0); } /** * @brief Conversion to a 3d matrix */ Matrix3d to_matrix3d () const { return Matrix3d (1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0); } }; /** * @brief Dummy Multiplication (concatenation) of unit transformations */ template inline unit_trans operator* (const unit_trans & /*t1*/, const unit_trans & /*t2*/) { return unit_trans(); } /** * @brief A fixpoint transformation * * The fixpoint transformation applies a rotation and/or mirroring operation. * Even though this transformation does not require a coordinate type, it is provided * to fulfil the contract. */ template class fixpoint_trans : public default_trans { public: typedef C coord_type; typedef C target_coord_type; typedef typename coord_traits::distance_type distance_type; typedef vector displacement_type; typedef fixpoint_trans inverse_trans; /** * @brief The default constructor (unity transformation) */ fixpoint_trans () : m_f (0) { // .. nothing else .. } /** * @brief Returns true, if the transformation is unity */ bool is_unity () const { return m_f == 0; } /** * @brief The standard constructor using angle and mirror flag * * The sequence of operations is: mirroring at x axis, * rotation, application of displacement. * * @param rot The rotation in units of 90 degree * @param mirrx True, if mirrored at x axis */ fixpoint_trans (int rot, bool mirrx) : m_f ((rot & 3) + (mirrx ? 4 : 0)) { // .. nothing else .. } /** * @brief The copy constructor * * @param d The source from which to copy */ template explicit fixpoint_trans (const fixpoint_trans &d) : m_f (d.rot ()) { } /** * @brief The standard constructor using a code rather than angle and mirror and no displacement * * @param f The rotation/mirror code (r0 .. m135 constants) */ explicit fixpoint_trans (int f) : m_f (f) { // .. nothing else .. } /** * @brief The rotation/mirror codes */ static const int r0 = 0; // No rotation static const int r90 = 1; // Rotation by 90 degree counterclockwise static const int r180 = 2; // Rotation by 180 degree counterclockwise static const int r270 = 3; // Rotation by 270 degree counterclockwise static const int m0 = 4; // Mirroring at x-axis static const int m45 = 5; // Mirroring at 45-degree axis static const int m90 = 6; // Mirroring at y-axis static const int m135 = 7; // Mirroring at 135-degree axis /** * @brief Inversion * * Returns the inverted transformation * * @return The inverted transformation */ fixpoint_trans inverted () const { fixpoint_trans t (*this); t.invert (); return t; } /** * @brief In-place inversion * * Inverts the transformation and replaces *this by the * inverted one. * * @return The inverted transformation */ fixpoint_trans invert () { if (m_f < 4) { m_f = (4 - m_f) & 3; } return *this; } /** * @brief Conversion to a 2d matrix */ Matrix2d to_matrix2d () const { vector tx = operator () (vector (1, 0)); vector ty = operator () (vector (0, 1)); return Matrix2d (tx.x (), ty.x (), tx.y (), ty.y ()); } /** * @brief Conversion to a 3d matrix */ Matrix3d to_matrix3d () const { return Matrix3d (to_matrix2d ()); } /** * @brief The transformation of a point * * The operator() method transforms the given point. * q = t(p) * * @param p The point to transform * @return The transformed point */ point operator() (const point &p) const { switch (m_f) { default: return point (p.x (), p.y ()); case 1: return point (-p.y (), p.x ()); case 2: return point (-p.x (), -p.y ()); case 3: return point (p.y (), -p.x ()); case 4: return point (p.x (), -p.y ()); case 5: return point (p.y (), p.x ()); case 6: return point (-p.x (), p.y ()); case 7: return point (-p.y (), -p.x ()); } } /** * @brief The transformation of a point (non-operator version) */ point trans (const point &p) const { return operator() (p); } /** * @brief The transformation of a vector * * The operator() method transforms the given vector. * q = t(p) * * @param p The point to transform * @return The transformed point */ vector operator() (const vector &p) const { switch (m_f) { default: return vector (p.x (), p.y ()); case 1: return vector (-p.y (), p.x ()); case 2: return vector (-p.x (), -p.y ()); case 3: return vector (p.y (), -p.x ()); case 4: return vector (p.x (), -p.y ()); case 5: return vector (p.y (), p.x ()); case 6: return vector (-p.x (), p.y ()); case 7: return vector (-p.y (), -p.x ()); } } /** * @brief The transformation of a vector (non-operator version) */ vector trans (const vector &p) const { return operator() (p); } /** * @brief Transform a fixpoint transformation */ fixpoint_trans ftrans (fixpoint_trans t) const { fixpoint_trans tt (*this); tt *= t; return tt; } /** * @brief Extract the fixpoint transformation part (this is identical to *this in this case) */ const fixpoint_trans &fp_trans () const { return *this; } /** * @brief Transform a distance */ distance_type ctrans (distance_type d) const { return d; } /** * @brief Multiplication (concatenation) of transformations * * The *= operator modifies the transformation by * replacing *this with *this * t (t is applied before *this). * * @param t The transformation to apply before * @return The modified transformation */ fixpoint_trans &operator*= (const fixpoint_trans &t) { m_f = ((m_f + (1 - ((m_f & 4) >> 1)) * t.m_f) & 3) + ((m_f ^ t.m_f) & 4); return *this; } /** * @brief A sorting criterion */ bool operator< (const fixpoint_trans &t) const { return m_f < t.m_f; } /** * @brief A (dummy) fuzzy less criterion */ bool less (const fixpoint_trans &t) const { return m_f < t.m_f; } /** * @brief Equality test */ bool operator== (const fixpoint_trans &t) const { return m_f == t.m_f; } /** * @brief Inequality test */ bool operator!= (const fixpoint_trans &t) const { return !operator== (t); } /** * @brief A (dummy) fuzzy equality test */ bool equal (const fixpoint_trans &t) const { return m_f == t.m_f; } /** * @brief A (dummy) fuzzy inequality test */ bool not_equal (const fixpoint_trans &t) const { return ! equal (t); } /** * @brief String conversion */ std::string to_string () const { const char *ms [] = { "r0", "r90", "r180", "r270", "m0", "m45", "m90", "m135" }; return std::string ((m_f < 0 || m_f >= 8) ? "*" : ms [m_f]); } /** * @brief Accessor to the rotation/mirror code */ int rot () const { return m_f; } /** * @brief Accessor to the angle (in units of 90 degree) */ int angle () const { return m_f & 3; } /** * @brief Mirror flag. * * The result of this operation is true, if the transformation is * mirroring, i.e. det(M) == -1. */ bool is_mirror () const { return m_f >= 4; } private: int m_f; }; /** * @brief Multiplication (concatenation) of transformations * * t = t1 * t2 is the resulting transformation that is effectively * applied if first t2 and then t1 is applied. * * @param t1 The transformation to apply last * @param t2 The transformation to apply first * @return t1 * t2 */ template inline fixpoint_trans operator* (const fixpoint_trans &t1, const fixpoint_trans &t2) { fixpoint_trans t (t1); t *= t2; return t; } /** * @brief Output stream insertion operator */ template inline std::ostream & operator<< (std::ostream &os, const fixpoint_trans &t) { return (os << t.to_string ()); } /** * @brief A displacement transformation * * The displacement transformation applies a displacement vector, but no rotation. */ template class disp_trans : public default_trans { public: typedef C coord_type; typedef C target_coord_type; typedef typename coord_traits::distance_type distance_type; typedef vector displacement_type; typedef disp_trans inverse_trans; /** * @brief The default constructor (unity transformation) */ disp_trans () : m_u () { // .. nothing else .. } /** * @brief The "conversion" from the unit transformation to a displacement */ explicit disp_trans (unit_trans) : m_u () { // .. nothing else .. } /** * @brief The copy constructor that converts also * * The copy constructor allows to convert between different * coordinate types, if possible. * * @param d The source from which to copy */ template explicit disp_trans (const disp_trans &d) : m_u (d.disp ()) { } /** * @brief The standard constructor using a displacement only (as vector) * * @param u The displacement */ explicit disp_trans (const displacement_type &u) : m_u (u.x (), u.y ()) { // .. nothing else .. } /** * @brief Downcast: extracts the displacement part of a complex transformation */ explicit disp_trans (const simple_trans &st) : m_u (st.disp ()) { // .. nothing else .. } /** * @brief Downcast: extracts the displacement part of a complex transformation */ template explicit disp_trans (const complex_trans &ct) : m_u (ct.disp ()) { // .. nothing else .. } /** * @brief Returns true, if the transformation is unity */ bool is_unity () const { return m_u.equal (displacement_type ()); } /** * @brief Inversion * * Returns the inverted transformation * * @return The inverted transformation */ disp_trans inverted () const { disp_trans t (*this); t.invert (); return t; } /** * @brief In-place inversion * * Inverts the transformation and replaces *this by the * inverted one. * * @return The inverted transformation */ disp_trans invert () { m_u = -m_u; return *this; } /** * @brief Conversion to a 2d matrix */ Matrix2d to_matrix2d () const { return Matrix2d (1.0, 0.0, 0.0, 1.0); } /** * @brief Conversion to a 3d matrix */ Matrix3d to_matrix3d () const { return Matrix3d (1.0, 0.0, 0.0, 1.0, m_u.x (), m_u.y (), 0.0, 0.0); } /** * @brief The transformation of a distance * * The ctrans method transforms the given distance. * e = t(d). For the displacement transformations, there * is no magnification and no modification of the distance * therefore. * * @param d The distance to transform * @return The transformed distance */ distance_type ctrans (distance_type d) const { return d; } /** * @brief The transformation of a point * * The operator() method transforms the given point. * q = t(p) * * @param p The point to transform * @return The transformed point */ point operator() (const point &p) const { return point (p) + m_u; } /** * @brief The transformation of a point (non-operator version) */ point trans (const point &p) const { return operator() (p); } /** * @brief The transformation of a vector * * The operator() method transforms the given vector. * q = t(p) * * @param p The vector to transform * @return The transformed vector */ vector operator() (const vector &p) const { return p; } /** * @brief The transformation of a vector (non-operator version) */ vector trans (const vector &p) const { return p; } /** * @brief Multiplication (concatenation) of transformations * * The *= operator modifies the transformation by * replacing *this with *this * t (t is applied before *this). * * @param t The transformation to apply before * @return The modified transformation */ disp_trans &operator*= (const disp_trans &t) { m_u += t.m_u; return *this; } /** * @brief A sorting criterion */ bool operator< (const disp_trans &t) const { return m_u < t.m_u; } /** * @brief A fuzzy sorting criterion */ bool less (const disp_trans &t) const { return m_u.less (t.m_u); } /** * @brief Equality test */ bool operator== (const disp_trans &t) const { return m_u == t.m_u; } /** * @brief Inequality test */ bool operator!= (const disp_trans &t) const { return !operator== (t); } /** * @brief A fuzzy equality test */ bool equal (const disp_trans &t) const { return m_u.equal (t.m_u); } /** * @brief A fuzzy inequality test */ bool not_equal (const disp_trans &t) const { return ! equal (t); } /** * @brief String conversion */ std::string to_string () const { return m_u.to_string (); } /** * @brief Gets the displacement */ const displacement_type &disp () const { return m_u; } /** * @brief Sets the displacement */ void disp (const displacement_type &u) { m_u = u; } /** * @brief Mirror predicate */ bool is_mirror () const { return false; } /** * @brief Extract the fixpoint transformation part (this is a r0 contribution in this case) */ fixpoint_trans fp_trans () const { return fixpoint_trans (); } private: displacement_type m_u; }; /** * @brief Multiplication (concatenation) of transformations * * t = t1 * t2 is the resulting transformation that is effectively * applied if first t2 and then t1 is applied. * * @param t1 The transformation to apply last * @param t2 The transformation to apply first * @return t1 * t2 */ template inline disp_trans operator* (const disp_trans &t1, const disp_trans &t2) { disp_trans t (t1); t *= t2; return t; } /** * @brief Output stream insertion operator */ template inline std::ostream & operator<< (std::ostream &os, const disp_trans &t) { return (os << t.to_string ()); } /** * @brief A simple transformation * * The simple transformation applies a displacement vector * and a simple fixpoint transformation. */ template class simple_trans : public fixpoint_trans { public: typedef C coord_type; typedef C target_coord_type; typedef typename coord_traits::distance_type distance_type; typedef vector displacement_type; typedef simple_trans inverse_trans; /** * @brief The default constructor (unity transformation) */ simple_trans () : fixpoint_trans (0), m_u () { // .. nothing else .. } /** * @brief Conversion constructor from a fixpoint transformation */ explicit simple_trans (fixpoint_trans f) : fixpoint_trans (f), m_u () { // .. nothing else .. } /** * @brief Conversion constructor from a unit transformation */ explicit simple_trans (unit_trans) : fixpoint_trans (0), m_u () { // .. nothing else .. } /** * @brief Conversion constructor from a displacement transformation */ explicit simple_trans (const disp_trans &d) : fixpoint_trans (0), m_u (d.disp ()) { // .. nothing else .. } /** * @brief The copy constructor * * @param d The source from which to copy */ simple_trans (const simple_trans &d) : fixpoint_trans (d.rot ()), m_u (d.disp ()) { } /** * @brief The copy constructor that converts to a different coordinate type also * * The copy constructor allows to convert between different * coordinate types, if possible. * * @param d The source from which to copy */ template explicit simple_trans (const simple_trans &d) : fixpoint_trans (d.rot ()), m_u (d.disp ()) { } /** * @brief The standard constructor using angle and mirror flag * * The sequence of operations is: mirroring at x axis, * rotation, application of displacement. * * @param rot The rotation in units of 90 degree * @param mirrx True, if mirrored at x axis * @param u The displacement */ simple_trans (int rot, bool mirrx, const vector &u) : fixpoint_trans (rot, mirrx), m_u (u) { // .. nothing else .. } /** * @brief The standard constructor for a displacement-only transformation * * @param u The displacement */ explicit simple_trans (const vector &u) : fixpoint_trans (), m_u (u) { // .. nothing else .. } /** * @brief The standard constructor using a code rather than angle and mirror * * @param f The rotation/mirror code (r0 .. m135 constants) * @param u The displacement */ simple_trans (int f, const vector &u) : fixpoint_trans (f), m_u (u) { // .. nothing else .. } /** * @brief Downcast: extracts the simple transformation part of a complex transformation */ template explicit simple_trans (const complex_trans &ct) : fixpoint_trans (ct.fp_trans ()), m_u (ct.disp ()) { // .. nothing else .. } /** * @brief The standard constructor using a code rather than angle and mirror and no displacement * * @param f The rotation/mirror code (r0 .. m135 constants) */ explicit simple_trans (int f) : fixpoint_trans (f), m_u () { // .. nothing else .. } /** * @brief Inversion * * Returns the inverted transformation * * @return The inverted transformation */ simple_trans inverted () const { simple_trans t (*this); t.invert (); return t; } /** * @brief In-place inversion * * Inverts the transformation and replaces *this by the * inverted one. * * @return The inverted transformation */ simple_trans invert () { fixpoint_trans::invert (); vector u = m_u; m_u = -operator() (u); return *this; } /** * @brief Returns true, if the transformation is unity */ bool is_unity () const { return m_u.equal (displacement_type ()) && fixpoint_trans::is_unity (); } /** * @brief The transformation of a distance * * The ctrans method transforms the given distance. * e = t(d). For the simple transformations, there * is no magnification and no modification of the distance * therefore. * * @param d The distance to transform * @return The transformed distance */ distance_type ctrans (distance_type d) const { return d; } /** * @brief The transformation of a point * * The operator() method transforms the given point. * q = t(p) * * @param p The point to transform * @return The transformed point */ point operator() (const point &p) const { return point (fixpoint_trans::operator() (p)) + m_u; } /** * @brief The transformation of a point (non-operator version) */ point trans (const point &p) const { return operator() (p); } /** * @brief The transformation of a vector * * The operator() method transforms the given vector. * q = t(p) * * @param p The point to transform * @return The transformed vector */ vector operator() (const vector &p) const { return vector (fixpoint_trans::operator() (p)); } /** * @brief The transformation of a vector (non-operator version) */ vector trans (const vector &p) const { return operator() (p); } /** * @brief Transform a fixpoint transformation */ fixpoint_trans ftrans (fixpoint_trans t) const { return fixpoint_trans::ftrans (t); } /** * @brief Conversion to a 2d matrix */ Matrix2d to_matrix2d () const { return fp_trans ().to_matrix2d (); } /** * @brief Conversion to a 3d matrix */ Matrix3d to_matrix3d () const { return Matrix3d (1.0, 0.0, 0.0, 1.0, m_u.x (), m_u.y (), 0.0, 0.0) * fp_trans ().to_matrix3d (); } /** * @brief Multiplication (concatenation) of transformations * * The *= operator modifies the transformation by * replacing *this with *this * t (t is applied before *this). * * @param t The transformation to apply before * @return The modified transformation */ simple_trans &operator*= (const simple_trans &t) { m_u += operator() (t.m_u); fixpoint_trans::operator*= (t); return *this; } /** * @brief A method version of operator*, mainly for automation purposes */ simple_trans concat (const simple_trans &t) const { simple_trans r (*this); r *= t; return r; } /** * @brief A sorting criterion */ bool operator< (const simple_trans &t) const { return fixpoint_trans::operator< (t) || (fixpoint_trans::operator== (t) && m_u < t.m_u); } /** * @brief A fuzzy sorting criterion */ bool less (const simple_trans &t) const { return fixpoint_trans::operator< (t) || (fixpoint_trans::operator== (t) && m_u.less (t.m_u)); } /** * @brief Equality test */ bool operator== (const simple_trans &t) const { return fixpoint_trans::operator== (t) && m_u == t.m_u; } /** * @brief Inequality test */ bool operator!= (const simple_trans &t) const { return !operator== (t); } /** * @brief A fuzzy equality test */ bool equal (const simple_trans &t) const { return fixpoint_trans::operator== (t) && m_u.equal (t.m_u); } /** * @brief A fuzzy inequality test */ bool not_equal (const simple_trans &t) const { return ! equal (t); } /** * @brief String conversion */ std::string to_string () const { std::string s1 = fixpoint_trans::to_string (); std::string s2 = m_u.to_string (); if (! s1.empty () && ! s2.empty ()) { return s1 + " " + s2; } else { return s1 + s2; } } /** * @brief Gets the displacement */ const displacement_type &disp () const { return m_u; } /** * @brief Sets the displacement */ void disp (const displacement_type &u) { m_u = u; } /** * @brief Accessor to the fp_trans */ const fixpoint_trans &fp_trans () const { return *this; } private: displacement_type m_u; }; /** * @brief Multiplication (concatenation) of transformations * * t = t1 * t2 is the resulting transformation that is effectively * applied if first t2 and then t1 is applied. * * @param t1 The transformation to apply last * @param t2 The transformation to apply first * @return t1 * t2 */ template inline simple_trans operator* (const simple_trans &t1, const simple_trans &t2) { simple_trans t (t1); t *= t2; return t; } /** * @brief Output stream insertion operator */ template inline std::ostream & operator<< (std::ostream &os, const simple_trans &t) { return (os << t.to_string ()); } /** * @brief A complex transformation * * A complex transformation provides magnification, mirroring at the x-axis, rotation by an arbitary * angle and a displacement. The template parameters for this transformation are * I (the input coordinate type), F (the output coordinate type) and R (the representation * type used internally for representing the floating-point members). */ template class complex_trans { public: typedef I coord_type; typedef F target_coord_type; typedef typename coord_traits::distance_type distance_type; typedef typename coord_traits::distance_type target_distance_type; typedef vector displacement_type; typedef complex_trans inverse_trans; typedef epsilon_f eps_f; /** * @brief The default constructor (unity transformation) */ complex_trans () : m_sin (0.0), m_cos (1.0), m_mag (1.0) { // .. nothing else .. } /** * @brief Conversion constructor from a unit transformation */ explicit complex_trans (unit_trans /*f*/) : m_sin (0.0), m_cos (1.0), m_mag (1.0) { // .. nothing else .. } /** * @brief Conversion constructor from a fixpoint transformation code */ explicit complex_trans (int fc) { db::fixpoint_trans f (fc); db::point t (1.0, 0.0); t = f (t); m_cos = t.x (); m_sin = t.y (); m_mag = f.is_mirror () ? -1.0 : 1.0; } /** * @brief Conversion constructor from a fixpoint transformation */ explicit complex_trans (fixpoint_trans f) { db::point t (1.0, 0.0); t = fixpoint_trans (f) (t); m_cos = t.x (); m_sin = t.y (); m_mag = f.is_mirror () ? -1.0 : 1.0; } /** * @brief Conversion constructor from a displacement transformation */ explicit complex_trans (const disp_trans &d) : m_u (d.disp ()), m_sin (0.0), m_cos (1.0), m_mag (1.0) { // .. nothing else .. } /** * @brief Conversion constructor from a simple transformation */ explicit complex_trans (const simple_trans &s) : m_u (s.disp ()) { db::point t (1.0, 0.0); t = fixpoint_trans (s.fp_trans ()) (t); m_cos = t.x (); m_sin = t.y (); m_mag = s.is_mirror () ? -1.0 : 1.0; } /** * @brief Migration constructor from a simple transformation to a complex transformation * * This constructor is supposed to support migration from a simple to a complex transformation * in an incremental fashion. Basically that means, that everything that is missing in the * simple transformation is added by additional parameters. * Specifically this added information is the magnification and the incremental rotation angle * to fill up the 90 degree multiples of the simple transformation to the desired rotation. * To save a trigonometric function computation, the added angle is given as the cosine of the * angle (a value from 1.0 representing 0 degree to 0.0 representing 90 degree). * * @param s The simple transformation to derive this transformation from * @param acos The cosine of the additional rotation angle * @param mag The magnification */ complex_trans (const simple_trans &s, double acos, double mag) : m_u (s.disp ()) { db::point t (1.0, 0.0); t = fixpoint_trans (s.fp_trans ()) (t); double asin = sqrt (1.0 - acos * acos); // we may to this since we know that the angle is between 0 and 90 degree m_cos = t.x () * acos - t.y () * asin; m_sin = t.x () * asin + t.y () * acos; m_mag = s.is_mirror () ? -mag : mag; } /** * @brief The standard constructor using a Matrix2d and a displacement * * @param m The matrix to take the rotation part of the transformation from * @param u The displacement * * The matrix must not contain shear components. */ complex_trans (double mag, double rot, bool mirrx, const displacement_type &u) : m_u (u) { tl_assert (mag > 0.0); m_mag = mirrx ? -mag : mag; rot *= M_PI / 180.0; m_sin = sin (rot); m_cos = cos (rot); } /** * @brief The standard constructor using a Matrix3d object * * @param m The matrix to take the transformation from * * The matrix must not represent perspective distortion nor shear. */ explicit complex_trans (const Matrix3d &m) : m_u (m.disp ()) { tl_assert (! m.has_shear ()); tl_assert (! m.has_perspective ()); std::pair mag = m.mag (); tl_assert (fabs (mag.first - mag.second) < 1e-10); double rot = m.angle () * M_PI / 180.0; m_mag = m.is_mirror () ? -mag.first : mag.first; m_sin = sin (rot); m_cos = cos (rot); } /** * @brief The standard constructor using a Matrix2d object * * The sequence of operations is: magnification, mirroring at x axis, * rotation, application of displacement. * * @param mag The magnification * @param rot The rotation angle in units of degree * @param mirrx True, if mirrored at x axis * @param u The displacement */ complex_trans (const Matrix2d &m, const vector &u) : m_u (u) { tl_assert (! m.has_shear ()); std::pair mag = m.mag (); tl_assert (fabs (mag.first - mag.second) < 1e-10); double rot = m.angle () * M_PI / 180.0; m_mag = m.is_mirror () ? -mag.first : mag.first; m_sin = sin (rot); m_cos = cos (rot); } /** * @brief The standard constructor using magnification only * * @param mag The magnification */ explicit complex_trans (double mag) { tl_assert (mag > 0.0); m_mag = mag; m_sin = 0.0; m_cos = 1.0; } /** * @brief The copy constructor that converts also * * The copy constructor allows to convert between different * coordinate types, if possible. * * @param d The source from which to copy */ template explicit complex_trans (const complex_trans &d) : m_u (d.m_u), m_sin (d.m_sin), m_cos (d.m_cos), m_mag (d.m_mag) { } /** * @brief The standard constructor using a displacement only * * @param u The displacement */ explicit complex_trans (const displacement_type &u) : m_u (u), m_sin (0.0), m_cos (1.0), m_mag (1.0) { // .. nothing else .. } /** * @brief Inversion * * Returns the inverted transformation. NOTE: in-place inversion is not supported since * for transformations where F != I, the inverse transformation is of a different type. * * @return The inverted transformation */ inverse_trans inverted () const { complex_trans inv; inv.m_mag = 1.0 / m_mag; inv.m_sin = -m_sin * (m_mag < 0.0 ? -1.0 : 1.0); inv.m_cos = m_cos; inv.m_u = inv.operator () (-m_u); return inverse_trans (inv); } /** * @brief In-place inversion * * Note that in general, in-place inversion may not be type-consistent if the input and output types * are different. The inversion is not a true inversion in the sense of inv(T) * T == 1 because of * potential rounding effects. */ complex_trans &invert () { complex_trans inv; inv.m_mag = 1.0 / m_mag; inv.m_sin = -m_sin * (m_mag < 0.0 ? -1.0 : 1.0); inv.m_cos = m_cos; inv.m_u = inv.operator () (-m_u); *this = complex_trans (inv); return *this; } /** * @brief The transformation of a distance * * The ctrans method transforms the given distance. * * @param d The distance to transform * @return The transformed distance */ target_distance_type ctrans (distance_type d) const { return coord_traits::rounded_distance (d * fabs (m_mag)); } /** * @brief Conversion to a 2d matrix */ Matrix2d to_matrix2d () const { return Matrix2d (m_cos * fabs (m_mag), -m_sin * m_mag, m_sin * fabs (m_mag), m_cos * m_mag); } /** * @brief Conversion to a 3d matrix */ Matrix3d to_matrix3d () const { return Matrix3d (m_cos * fabs (m_mag), -m_sin * m_mag, m_sin * fabs (m_mag), m_cos * m_mag, m_u.x (), m_u.y (), 0.0, 0.0); } /** * @brief The transformation of a point * * The operator() method transforms the given point. * q = t(p) * * @param p The point to transform * @return The transformed point */ point operator() (const point &p) const { db::point mp (m_cos * p.x () * fabs (m_mag) - m_sin * p.y () * m_mag, m_sin * p.x () * fabs (m_mag) + m_cos * p.y () * m_mag); return point (mp + m_u); } /** * @brief The transformation of a point (non-operator version) */ point trans (const point &p) const { return operator() (p); } /** * @brief The transformation of a vector * * The operator() method transforms the given vector. * q = t(p) * * @param p The vector to transform * @return The transformed vector */ vector operator() (const vector &p) const { db::vector mp (m_cos * p.x () * fabs (m_mag) - m_sin * p.y () * m_mag, m_sin * p.x () * fabs (m_mag) + m_cos * p.y () * m_mag); return db::vector (mp); } /** * @brief The transformation of a vector (non-operator version) */ vector trans (const vector &p) const { return operator() (p); } /** * @brief Test, whether this is a unit transformation */ bool is_unity () const { if (fabs (m_mag - 1.0) > eps_f ()) { return false; } if (fabs (m_sin) > eps_f ()) { return false; } if (fabs (m_cos - 1.0) > eps_f ()) { return false; } return fabs (m_u.x ()) <= db::epsilon_f () && fabs (m_u.y ()) <= db::epsilon_f (); } /** * @brief Test, if the transformation is an orthogonal transformation * * If the rotation is by a multiple of 90 degree, this method will return true. */ bool is_ortho () const { return fabs (m_sin * m_cos) <= eps_f (); } /** * @brief Return the respective rotation code if possible * * If this transformation is orthogonal (is_ortho () == true), then this method * will return the corresponding fixpoint transformation, not taking into account * magnification and displacement. If the transformation is not orthogonal, the result * reflects the quadrant the rotation goes into with the guarantee to reproduce the * correct quadrant in the exact case. */ int rot () const { return fp_trans ().rot (); } /** * @brief Return the respective fixpoint trans if possible * * If this transformation is orthogonal (is_ortho () == true), then this method * will return the corresponding fixpoint transformation, not taking into account * magnification and displacement. If the transformation is not orthogonal, the result * reflects the quadrant the rotation goes into with the guarantee to reproduce the * correct quadrant in the exact case. */ fixpoint_trans fp_trans () const { int c; if (m_cos > eps_f () && m_sin >= -eps_f ()) { c = 0 /*r0*/; } else if (m_cos <= eps_f () && m_sin > eps_f ()) { c = 1 /*r90*/; } else if (m_cos < -eps_f () && m_sin <= eps_f ()) { c = 2 /*r180*/; } else { c = 3 /*r270*/; } return fixpoint_trans (c + (m_mag < 0.0 ? 4 : 0)); } /** * @brief Read accessor for the angle * * To check, if the transformation represents a rotation by a angle that * is a multiple of 90 degree, use is_ortho. * * @return The rotation angle this transformation provides in degree units (0..360 deg). */ double angle () const { double a = atan2 (m_sin, m_cos) * (180.0 / M_PI); if (a < -eps_f ()) { a += 360.0; } else if (a <= eps_f ()) { a = 0.0; } return a; } /** * @brief Write accessor for the angle */ void angle (double rot) { rot *= M_PI / 180.0; m_sin = sin (rot); m_cos = cos (rot); } /** * @brief Read accessor to the cosine part of the transformation matrix */ double mcos () const { return m_cos; } /** * @brief Read accessor to the sine part of the transformation matrix */ double msin () const { return m_sin; } /** * @brief Read accessor to the magnification */ double mag () const { return fabs (m_mag); } /** * @brief Test, if the transformation is a magnifying one * * This is the recommended test for checking if the transformation represents * a magnification. */ bool is_mag () const { return fabs (fabs (m_mag) - 1.0) > eps_f (); } /** * @brief Write accessor to the magnification */ void mag (double m) { tl_assert (m > 0.0); m_mag = m_mag < 0.0 ? -m : m; } /** * @brief Test, if the transformation is mirroring */ bool is_mirror () const { return m_mag < 0.0; } /** * @brief Write accessor to the mirror flag */ void mirror (bool m) { m_mag = m ? -fabs (m_mag) : fabs (m_mag); } /** * @brief Read accessor to the displacement */ displacement_type disp () const { return displacement_type (m_u); } /** * @brief Write accessor to the displacement */ void disp (const displacement_type &u) { m_u = vector (u); } /** * @brief Multiplication (concatenation) of transformations - in-place version * * The *= operator modifies the transformation by * replacing *this with *this * t (t is applied before *this). * * @param t The transformation to apply before * @return The modified transformation */ complex_trans &operator*= (const complex_trans &t) { *this = concat_same (t); return *this; } /** * @brief Multiplication (concatenation) of transformations * * The * operator returns a transformation which is identical to the * *this * t (t is applied before *this). * * @param t The transformation to apply before * @return The concatenated transformation */ template complex_trans concat (const complex_trans &t) const { complex_trans res; double s1 = m_mag < 0.0 ? -1.0 : 1.0; db::vector tu (m_cos * t.m_u.x () * fabs (m_mag) - m_sin * t.m_u.y () * m_mag, m_sin * t.m_u.x () * fabs (m_mag) + m_cos * t.m_u.y () * m_mag); res.m_u = m_u + tu; res.m_mag = m_mag * t.m_mag; res.m_cos = m_cos * t.m_cos - s1 * m_sin * t.m_sin; res.m_sin = m_sin * t.m_cos + s1 * m_cos * t.m_sin; return res; } /** * @brief Multiplication (concatenation) of transformations of the same type * * The * operator returns a transformation which is identical to the * *this * t (t is applied before *this). * * The concatenation of two identical transformations is not strictly type-safe since * formally, the output type of the second transformation needs to be compatible with * the input type of the first. But transformation arithmetics is easier to do with * this definition. * * @param t The transformation to apply before * @return The concatenated transformation */ complex_trans concat_same (const complex_trans &t) const { // The concatenation is done with double as the intermediate type to avoid // rounding issues as far as possible. return complex_trans (*this).concat (complex_trans(t)); } /** * @brief Returns the transformation in a different coordinate system * * Given a transformation which turns the current coordinate system into a new one, * this method will compute the transformation as it would look like in the new * coordinate system. * * The mathematical definition is this: * * T = this * U = transformation into the new system * * T' = U * T * inverse(U) * * @param u The transformation into the new system * @return The transformation in the new system */ template complex_trans transform_into (const U &uin) const { // Note: preserving type consistency is a bit tedious here. We assume we can simply // return the same type as *this. Ideally *this would be of type (C,C). U would be // of type (C,F). Then the output would be (F,F). complex_trans u (uin); complex_trans uinv (u); uinv.invert (); return u.concat_same (*this).concat_same (uinv); } /** * @brief Retrieve the residual part of the angle * * The residual part is the cosine of the angle difference to the * lower next multiple of 90 degree. I.e. the residual part of 135 degree * would be cos(45 deg). */ double rcos () const { if (m_cos > eps_f () && m_sin >= -eps_f ()) { return m_cos; } else if (m_cos <= eps_f () && m_sin > eps_f ()) { return m_sin; } else if (m_cos < -eps_f () && m_sin <= eps_f ()) { return -m_cos; } else { return -m_sin; } } /** * @brief A sorting criterion */ bool operator< (const complex_trans &t) const { if (m_u != t.m_u) { return m_u < t.m_u; } if (fabs (m_sin - t.m_sin) > eps_f ()) { return m_sin < t.m_sin; } if (fabs (m_cos - t.m_cos) > eps_f ()) { return m_cos < t.m_cos; } if (fabs (m_mag - t.m_mag) > eps_f ()) { return m_mag < t.m_mag; } return false; } /** * @brief A (fuzzy) sorting criterion */ bool less (const complex_trans &t) const { if (! m_u.equal (t.m_u)) { return m_u.less (t.m_u); } if (fabs (m_sin - t.m_sin) > eps_f ()) { return m_sin < t.m_sin; } if (fabs (m_cos - t.m_cos) > eps_f ()) { return m_cos < t.m_cos; } if (fabs (m_mag - t.m_mag) > eps_f ()) { return m_mag < t.m_mag; } return false; } /** * @brief Equality test */ bool operator== (const complex_trans &t) const { return m_u == t.m_u && fabs (m_sin - t.m_sin) <= eps_f () && fabs (m_cos - t.m_cos) <= eps_f () && fabs (m_mag - t.m_mag) <= eps_f (); } /** * @brief Inequality test */ bool operator!= (const complex_trans &t) const { return !operator== (t); } /** * @brief A (fuzzy) equality test */ bool equal (const complex_trans &t) const { return m_u.equal (t.m_u) && fabs (m_sin - t.m_sin) <= eps_f () && fabs (m_cos - t.m_cos) <= eps_f () && fabs (m_mag - t.m_mag) <= eps_f (); } /** * @brief A (fuzzy) inequality test */ bool not_equal (const complex_trans &t) const { return ! equal (t); } /** * @brief Default string conversion */ std::string to_string () const { return to_string (false); } /** * @brief String conversion * * The lazy and micron flags allow to customize the output somewhat. * When lazy is set to true, output that is not required (i.e. magnification when 1) * is dropped. If dbu is set, the coordinates are multiplied with this factor to render micron units. */ std::string to_string (bool lazy, double dbu = 0.0) const { std::string s; if (is_mirror ()) { s += "m"; s += tl::to_string (angle () * 0.5); } else { s += "r"; s += tl::to_string (angle ()); } if (! lazy || is_mag ()) { s += tl::sprintf (" *%.9g", mag ()); } s += " "; s += m_u.to_string (dbu); return s; } private: template friend class complex_trans; vector m_u; R m_sin, m_cos; R m_mag; }; /** * @brief Multiplication (concatenation) of transformations * * t = t1 * t2 is the resulting transformation that is effectively * applied if first t2 and then t1 is applied. * * @param t1 The transformation to apply last * @param t2 The transformation to apply first * @return t1 * t2 */ template inline complex_trans operator* (const complex_trans &t1, const complex_trans &t2) { return t1.concat (t2); } /** * @brief Scaling of a complex transformation with a scalar * * The resulting complex transformation will reflex the original one plus * an additional magnification given by the factor m. * * @param t The original transformation * @param m The additional magnification * @return t1 * m */ template inline complex_trans operator* (const complex_trans &t1, double m) { complex_trans t (t1); t.mag (t.mag () * m); return t; } /** * @brief Output stream insertion operator */ template inline std::ostream & operator<< (std::ostream &os, const complex_trans &t) { return (os << t.to_string ()); } /** * @brief A combined transformation * * A combined transformation is the combination of two * transformations T1 and T2 (T=T1*T2). Although the multiplication * of two transformations may render the same result, but * usually is more efficient. To combine two different * transformations however, the combined_trans template * is better suited. */ template struct combined_trans { typedef typename T2::coord_type coord_type; typedef typename T1::target_coord_type target_coord_type; typedef combined_trans inverse_trans; /** * @brief Default constructor * * Creates a unity transformation */ combined_trans () : t1 (), t2 () { // .. nothing else .. } /** * @brief Standard constructor * * Takes two transformations and combines both. */ combined_trans (const T1 &_t1, const T2 &_t2) : t1 (_t1), t2 (_t2) { // .. nothing else .. } /** * @brief Inversion * * Inverts the transformation and returns the inverted * transformation which swaps T1 and T2 in the type definition. * * @return The inverted transformation */ inverse_trans inverted () const { return inverse_trans (t2.inverted (), t1.inverted ()); } /** * @brief The transformation of a point * * The operator() method transforms the given point. * q = t(p) * * @param p The point to transform * @return The transformed point */ template point operator() (const point &p) const { typedef typename T2::target_coord_type intern_coord_type; point q = t2.operator() (p); return t1.operator() (q); } /** * @brief The transformation of a vector * * The operator() method transforms the given point. * q = t(p) * * @param p The point to transform * @return The transformed point */ template vector operator() (const vector &p) const { typedef typename T2::target_coord_type intern_coord_type; vector q = t2.operator() (p); return t1.operator() (q); } /** * @brief The transformation of a distance * * The ctrans method transforms the given distance. * s = t(d) * * @param d The distance to transform * @return The transformed distance */ template target_coord_type ctrans (C p) const { typedef typename T2::target_coord_type intern_coord_type; intern_coord_type q = t2.ctrans (p); return t1.ctrans (q); } /** * @brief The transformation of a fixpoint transformation * * The ftrans method transforms the given fixpoint transformation. * f = t(f) * * @param f The fixpoint transformation to transform * @return The transformed fixpoint transformation */ template fixpoint_trans ftrans (fixpoint_trans f) const { return t1 (t2 (f)); } /** * @brief A sorting criterion */ bool operator< (const combined_trans &t) const { return t1 < t.t1 || (t1 == t.t1 && t2 < t.t2); } /** * @brief Equality test */ bool operator== (const combined_trans &t) const { return t1 == t.t1 && t2 == t.t2; } /** * @brief Inequality test */ bool operator!= (const combined_trans &t) const { return !operator== (t); } /** * @brief String conversion */ std::string to_string () const { std::string s1 = t1.to_string (); std::string s2 = t2.to_string (); if (! s1.empty () && ! s2.empty ()) { return s1 + " " + s2; } else { return s1 + s2; } } /** * @brief Accessor to the first part of the combined transformation */ const T1 &first () const { return t1; } /** * @brief Accessor to the second part of the combined transformation */ const T2 &second () const { return t2; } T1 t1; T2 t2; }; /** * @brief Output stream insertion operator */ template inline std::ostream & operator<< (std::ostream &os, const combined_trans &t) { return (os << t.to_string ()); } /** * @brief The standard unit transformation */ typedef unit_trans UnitTrans; /** * @brief The standard unit transformation for double coordinates */ typedef unit_trans DUnitTrans; /** * @brief The standard fixpoint transformation */ typedef fixpoint_trans FTrans; /** * @brief The standard fixpoint transformation for double types */ typedef fixpoint_trans DFTrans; /** * @brief The standard displacement transformation */ typedef disp_trans Disp; /** * @brief The double coordinate displacement transformation */ typedef disp_trans DDisp; /** * @brief The standard transformation */ typedef simple_trans Trans; /** * @brief The double coordinate transformation */ typedef simple_trans DTrans; /** * @brief The standard complex transformation that converts integer to integer coordinates */ typedef complex_trans ICplxTrans; /** * @brief The standard complex transformation */ typedef complex_trans CplxTrans; /** * @brief Specialization: concatenation of CplxTrans * * The combination of two of these objects is basically not allowed, since the * output and input types in not compatible. For sake of similicity however, we * allow this now. */ inline CplxTrans operator* (const CplxTrans &a, const CplxTrans &b) { return a.concat_same (b); } /** * @brief The inverse of the standard complex transformation */ typedef complex_trans VCplxTrans; /** * @brief Specialization: concatenation of VCplxTrans * * The combination of two of these objects is basically not allowed, since the * output and input types in not compatible. For sake of similicity however, we * allow this now. */ inline VCplxTrans operator* (const VCplxTrans &a, const VCplxTrans &b) { return a.concat_same (b); } /** * @brief The double coordinate complex transformation */ typedef complex_trans DCplxTrans; /** * @brief Transformation operator * * Transforms the point with the given transformation * (q = T * p). * * @param t The transformation to apply * @param p The point to transform * @return The transformed point */ template inline point operator* (const Tr &t, const point &p) { return t.operator() (point (p)); } /** * @brief Transformation operator * * Transforms the vector with the given transformation * (q = T * p). * * @param t The transformation to apply * @param p The vector to transform * @return The transformed vector */ template inline vector operator* (const Tr &t, const vector &p) { return t.operator() (vector (p)); } /** * @brief Fuzzy compare function for transformation objects */ template class trans_less_func { public: bool operator() (const T &a, const T &b) const { return a.less (b); } }; /** * @brief Fuzzy compare function for transformation objects */ template class trans_equal_func { public: bool operator() (const T &a, const T &b) const { return a.equal (b); } }; } // namespace db /** * @brief Special extractors for the transformations */ namespace tl { template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::UnitTrans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::DUnitTrans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::FTrans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::DFTrans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Trans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::DTrans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::Disp &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::DDisp &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::CplxTrans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::VCplxTrans &t); template<> DB_PUBLIC void extractor_impl (tl::Extractor &ex, db::DCplxTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::UnitTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::DUnitTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::FTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::DFTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Trans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::DTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::Disp &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::DDisp &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::CplxTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::VCplxTrans &t); template<> DB_PUBLIC bool test_extractor_impl (tl::Extractor &ex, db::DCplxTrans &t); } // namespace tl #endif