/* KLayout Layout Viewer Copyright (C) 2006-2016 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_dbArray #define HDR_dbArray #include "dbCommon.h" #include #include #include #include "dbTypes.h" #include "dbMemStatistics.h" #include "dbPoint.h" #include "dbBox.h" #include "dbBoxTree.h" #include "dbTrans.h" #include "dbShapeRepository.h" #include "tlException.h" namespace db { template struct array_iterator; template struct box_convert; /** * @brief The array iterator base class (internal) */ template struct basic_array_iterator { typedef Coord coord_type; typedef db::point point_type; typedef db::vector vector_type; typedef db::disp_trans disp_type; typedef db::box box_type; virtual ~basic_array_iterator () { // .. nothing yet .. } virtual void inc () = 0; virtual bool at_end () const = 0; virtual long index_a () const { return -1; } virtual long index_b () const { return -1; } virtual disp_type get () const = 0; virtual basic_array_iterator *clone () const = 0; }; /** * @brief A generic base class for all array incarnations */ struct ArrayBase { ArrayBase () : in_repository (false) { // .. nothing yet .. } virtual ~ArrayBase () { // .. nothing yet .. } virtual const ArrayBase *cast (const ArrayBase *other) const = 0; virtual ArrayBase *basic_clone () const = 0; virtual unsigned int type () const = 0; virtual bool equal (const ArrayBase *) const = 0; virtual bool less (const ArrayBase *) const = 0; virtual size_t mem_used () const = 0; virtual size_t mem_reqd () const = 0; bool in_repository; }; /** * @brief The array base class (internal) */ template struct basic_array : public ArrayBase { typedef Coord coord_type; typedef db::box box_type; typedef db::point point_type; typedef db::vector vector_type; typedef db::complex_trans complex_trans_type; typedef db::simple_trans simple_trans_type; typedef db::unit_trans unit_trans_type; typedef db::disp_trans disp_trans_type; typedef db::disp_trans disp_type; basic_array () { // .. nothing yet .. } virtual ~basic_array () { // .. nothing yet .. } virtual std::pair *, bool> begin_touching (const box_type &b) const = 0; virtual std::pair *, bool> begin () const = 0; virtual std::pair *, bool> begin_regular (long /*a*/, long /*b*/) const { return begin (); } virtual ArrayBase *basic_clone () const { return clone (); } virtual basic_array *clone () const = 0; virtual box_type bbox (const box_type &obox) const = 0; virtual size_t size () const = 0; virtual void invert (simple_trans_type &t) = 0; virtual bool is_regular_array (vector_type & /*a*/, vector_type & /*b*/, unsigned long & /*amax*/, unsigned long & /*bmax*/) const { return false; } virtual bool is_iterated_array (std::vector * /*v*/) { return false; } virtual bool is_complex () const { return false; } virtual complex_trans_type complex_trans (const simple_trans_type &s) const { return complex_trans_type (s); } virtual unsigned int type () const { return 0; } virtual const ArrayBase *cast (const ArrayBase *other) const { return dynamic_cast *> (other); } void transform (const unit_trans_type & /*st*/) { } void transform (const disp_trans_type & /*st*/) { } virtual void transform (const simple_trans_type & /*st*/) { } virtual void transform (const complex_trans_type & /*ct*/) { } }; /** * @brief A helper function to compare base class objects */ struct array_base_ptr_cmp_f { bool operator() (const ArrayBase *p1, const ArrayBase *p2) const { if (p1->type () != p2->type ()) { return p1->type () < p2->type (); } return p1->less (p2); } }; /** * @brief The array repository * * This repository may be used to hold the base objects * for compacter memory representation. Multiple array * objects may share the same base object. Base objects * stored herein have the "in_repository" flag set and * are managed by the repository. */ class DB_PUBLIC ArrayRepository { public: typedef std::set basic_repository; typedef std::vector repositories; ArrayRepository (); ArrayRepository (const ArrayRepository &d); ~ArrayRepository (); ArrayRepository &operator= (const ArrayRepository &d); template basic_array *insert (const basic_array &base) { repositories::iterator r; for (r = m_reps.begin (); r != m_reps.end (); ++r) { if ((*r->begin ())->cast (&base)) { break; } } if (r == m_reps.end ()) { m_reps.push_back (basic_repository ()); r = m_reps.end () - 1; } basic_repository::iterator f = r->find ((ArrayBase *) &base); if (f != r->end ()) { return dynamic_cast *> (*f); } else { basic_array *bb = base.clone (); bb->in_repository = true; r->insert (bb); return bb; } } size_t mem_used () const; size_t mem_reqd () const; private: repositories m_reps; void clear (); }; /** * @brief The array iterator specialization for the regular case (internal) * * The regular case is that the displacements are described as * P=a*A+b*B (a=[amin..amax),b=[bmin..bmax)). */ template struct regular_array_iterator : public basic_array_iterator { typedef typename basic_array_iterator::coord_type coord_type; typedef typename basic_array_iterator::point_type point_type; typedef typename basic_array_iterator::vector_type vector_type; typedef typename basic_array_iterator::box_type box_type; typedef typename basic_array_iterator::disp_type disp_type; regular_array_iterator (const vector_type &a, const vector_type &b, unsigned long amin, unsigned long amax, unsigned long bmin, unsigned long bmax) : m_a (a), m_b (b), m_amin (amin), m_amax (amax), m_bmin (bmin), m_bmax (bmax), m_ai (amin), m_bi (bmin) { // if there is no way to iterate for ai, just finish: if (m_amin >= m_amax) { m_bi = m_bmax; } } virtual ~regular_array_iterator () { // .. nothing yet .. } virtual disp_type get () const { return disp_type (vector_type (m_ai * m_a.x () + m_bi * m_b.x (), m_ai * m_a.y () + m_bi * m_b.y ())); } virtual void inc () { ++m_ai; if (m_ai >= m_amax) { m_ai = m_amin; ++m_bi; } } virtual bool at_end () const { return m_bi >= m_bmax; } virtual basic_array_iterator *clone () const { return new regular_array_iterator (*this); } virtual long index_a () const { return long (m_ai); } virtual long index_b () const { return long (m_bi); } private: vector_type m_a, m_b; unsigned long m_amin, m_amax, m_bmin, m_bmax; unsigned long m_ai, m_bi; }; /** * @brief The array specialization for the regular case (internal) * * The regular case is that the displacements are described as * P=O+a*A+b*B (a=[amin..amax),b=[bmin..bmax)). */ template struct regular_array : public basic_array { typedef typename basic_array::point_type point_type; typedef typename basic_array::vector_type vector_type; typedef typename basic_array::box_type box_type; typedef typename basic_array::coord_type coord_type; typedef typename basic_array::disp_type disp_type; typedef typename basic_array::simple_trans_type simple_trans_type; typedef typename basic_array::complex_trans_type complex_trans_type; regular_array (const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : m_a (a), m_b (b), m_amax (amax), m_bmax (bmax) { compute_det (); } virtual ~regular_array () { // .. nothing yet .. } virtual std::pair *, bool> begin_touching (const box_type &b) const { if (b.empty ()) { return std::make_pair (new regular_array_iterator (m_a, m_b, 0, 0, 0, 0), false); } else if (fabs (m_det) < 0.5) { return begin (); } else { std::pair ab [4] = { ab_coord (b.p1 ()), ab_coord (point_type (b.left (), b.top ())), ab_coord (point_type (b.right (), b.bottom ())), ab_coord (b.p2 ()) }; double amin = ab [0].first; double amax = ab [0].first; double bmin = ab [0].second; double bmax = ab [0].second; for (int i = 1; i < 4; ++i) { amin = std::min (amin, ab [i].first); amax = std::max (amax, ab [i].first); bmin = std::min (bmin, ab [i].second); bmax = std::max (bmax, ab [i].second); } unsigned long amini = 0; if (amin >= epsilon) { if (amin > double (std::numeric_limits ::max () - 1)) { amini = std::numeric_limits ::max () - 1; } else { amini = (unsigned long) (amin + 1.0 - epsilon); } if (amini > m_amax) { amini = m_amax; } } unsigned long amaxi = 0; if (amax >= -epsilon) { if (amax > double (std::numeric_limits ::max () - 1)) { amaxi = std::numeric_limits ::max () - 1; } else { amaxi = (unsigned long) (amax + epsilon) + 1; } if (amaxi > m_amax) { amaxi = m_amax; } } unsigned long bmini = 0; if (bmin >= epsilon) { if (bmin > double (std::numeric_limits ::max () - 1)) { bmini = std::numeric_limits ::max () - 1; } else { bmini = (unsigned long) (bmin + 1.0 - epsilon); } if (bmini > m_bmax) { bmini = m_bmax; } } unsigned long bmaxi = 0; if (bmax >= -epsilon) { if (bmax > double (std::numeric_limits ::max () - 1)) { bmaxi = std::numeric_limits ::max () - 1; } else { bmaxi = (unsigned long) (bmax + epsilon) + 1; } if (bmaxi > m_bmax) { bmaxi = m_bmax; } } return std::make_pair (new regular_array_iterator (m_a, m_b, amini, amaxi, bmini, bmaxi), false); } } virtual std::pair *, bool> begin_regular (long a, long b) const { return std::make_pair (new regular_array_iterator (m_a, m_b, (unsigned long) std::max (long (0), a), m_amax, (unsigned long) std::max (long (0), b), m_bmax), false); } virtual std::pair *, bool> begin () const { return std::make_pair (new regular_array_iterator (m_a, m_b, 0, m_amax, 0, m_bmax), false); } virtual basic_array *clone () const { return new regular_array (*this); } virtual box_type bbox (const box_type &obox) const { if (obox.empty ()) { return obox; } else { vector_type ma (m_a.x () * (m_amax - 1), m_a.y () * (m_amax - 1)); vector_type mb (m_b.x () * (m_bmax - 1), m_b.y () * (m_bmax - 1)); box_type b; if (m_amax > 0 && m_bmax > 0) { b += point_type (); b += point_type () + ma; b += point_type () + mb; b += point_type () + ma + mb; } return box_type (obox.p1 () + (b.p1 () - point_type ()), obox.p2 () + (b.p2 () - point_type ())); } } virtual size_t size () const { return m_amax * m_bmax; } virtual void invert (simple_trans_type &t) { t.invert (); db::fixpoint_trans f (t.rot ()); m_a = -f (m_a); m_b = -f (m_b); compute_det (); } virtual bool equal (const ArrayBase *b) const { const regular_array *d = static_cast *> (b); return (m_a == d->m_a && m_b == d->m_b && m_amax == d->m_amax && m_bmax == d->m_bmax); } virtual bool less (const ArrayBase *b) const { const regular_array *d = static_cast *> (b); return m_a < d->m_a || (m_a == d->m_a && ( m_b < d->m_b || (m_b == d->m_b && ( m_amax < d->m_amax || (m_amax == d->m_amax && m_bmax < d->m_bmax))))); } virtual bool is_regular_array (vector_type &a, vector_type &b, unsigned long &amax, unsigned long &bmax) const { a = m_a; b = m_b; amax = m_amax; bmax = m_bmax; return true; } virtual size_t mem_used () const { return sizeof (*this); } virtual size_t mem_reqd () const { return sizeof (*this); } virtual unsigned int type () const { return 1; } virtual void transform (const simple_trans_type &st) { m_a.transform (st.fp_trans ()); m_b.transform (st.fp_trans ()); compute_det (); } virtual void transform (const complex_trans_type &ct) { // transform with the matrix, do not displace, since a and b are displacements already m_a = vector_type (ct * m_a); m_b = vector_type (ct * m_b); compute_det (); } protected: vector_type m_a, m_b; unsigned long m_amax, m_bmax; double m_det; std::pair ab_coord (const point_type &p) const { double a = (double (p.x ()) * double (m_b.y ()) - double (p.y ()) * double (m_b.x ())) / m_det; double b = (double (m_a.x ()) * double (p.y ()) - double (m_a.y ()) * double (p.x ())) / m_det; return std::make_pair (a, b); } void compute_det () { m_det = double (m_a.x ()) * double (m_b.y ()) - double (m_a.y ()) * double (m_b.x ()); } }; /** * @brief The array specialization for the regular, complex case (internal) * * The regular case is that the displacements are described as * P=O+a*A+b*B (a=[amin..amax),b=[bmin..bmax)). * Each instance is magnified with the given magnification and subject to * further rotation by a residual angle given by acos, which is actually the cosine * of this angle. */ template struct regular_complex_array : public regular_array { typedef typename basic_array::point_type point_type; typedef typename basic_array::vector_type vector_type; typedef typename basic_array::box_type box_type; typedef typename basic_array::coord_type coord_type; typedef typename basic_array::disp_type disp_type; typedef typename basic_array::simple_trans_type simple_trans_type; typedef typename basic_array::complex_trans_type complex_trans_type; regular_complex_array (double acos, double mag, const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : regular_array (a, b, amax, bmax), m_acos (acos), m_mag (mag) { // .. nothing yet .. } virtual basic_array *clone () const { return new regular_complex_array (*this); } virtual void invert (simple_trans_type &t) { // recompute the array parameters such that every per-instance transformation // is inverted. complex_trans_type r = complex_trans_type (t, m_acos, m_mag).inverted (); m_mag = r.mag (); m_acos = r.rcos (); t = simple_trans_type (r); regular_array::m_a = -r (regular_array::m_a); regular_array::m_b = -r (regular_array::m_b); regular_array::compute_det (); } virtual bool equal (const ArrayBase *b) const { const regular_complex_array *d = static_cast *> (b); if (fabs (m_acos - d->m_acos) > epsilon) { return false; } if (fabs (m_mag - d->m_mag) > epsilon) { return false; } return regular_array::equal (b); } virtual bool less (const ArrayBase *b) const { const regular_complex_array *d = static_cast *> (b); if (fabs (m_acos - d->m_acos) > epsilon) { return m_acos < d->m_acos; } if (fabs (m_mag - d->m_mag) > epsilon) { return m_mag < d->m_mag; } return regular_array::less (b); } virtual complex_trans_type complex_trans (const simple_trans_type &s) const { return complex_trans_type (s, m_acos, m_mag); } virtual bool is_complex () const { return true; } virtual unsigned int type () const { return 2; } private: double m_acos, m_mag; }; /** * @brief The array iterator specialization for the iterated case (internal) * * The iterated case is where each placement is described by a displacement vector */ template struct iterated_array_iterator : public basic_array_iterator { typedef typename basic_array_iterator::coord_type coord_type; typedef typename basic_array_iterator::point_type point_type; typedef typename basic_array_iterator::vector_type vector_type; typedef typename basic_array_iterator::box_type box_type; typedef typename basic_array_iterator::disp_type disp_type; typedef box_convert box_convert_type; typedef unstable_box_tree box_tree_type; typedef typename box_tree_type::const_iterator box_tree_const_iterator; typedef typename box_tree_type::touching_iterator box_tree_touching_iterator; iterated_array_iterator (box_tree_const_iterator from, box_tree_const_iterator to) : m_normal (true) { m_b = from; m_e = to; } iterated_array_iterator (box_tree_touching_iterator from) : m_normal (false) { m_t = from; } virtual ~iterated_array_iterator () { // .. nothing yet .. } virtual disp_type get () const { return disp_type (m_normal ? *m_b : *m_t); } virtual void inc () { if (m_normal) { ++m_b; } else { ++m_t; } } virtual bool at_end () const { if (m_normal) { return m_b == m_e; } else { return m_t.at_end (); } } virtual basic_array_iterator *clone () const { return new iterated_array_iterator (*this); } private: box_tree_const_iterator m_b, m_e; box_tree_touching_iterator m_t; bool m_normal; }; /** * @brief The array specialization for the iterated case (internal) * * The iterated case is where each placement is described by a displacement vector */ template struct iterated_array : public basic_array { typedef typename basic_array::point_type point_type; typedef typename basic_array::vector_type vector_type; typedef typename basic_array::box_type box_type; typedef typename basic_array::coord_type coord_type; typedef typename basic_array::disp_type disp_type; typedef typename basic_array::simple_trans_type simple_trans_type; typedef typename basic_array::complex_trans_type complex_trans_type; typedef box_convert box_convert_type; typedef unstable_box_tree box_tree_type; typedef typename box_tree_type::const_iterator const_iterator; typedef typename box_tree_type::iterator iterator; typedef typename box_tree_type::touching_iterator touching_iterator; iterated_array () { // .. nothing yet .. } template iterated_array (I from, I to) { assign (from, to); } virtual ~iterated_array () { // .. nothing yet .. } void reserve (size_t n) { m_v.reserve (n); } void insert (const vector_type &p) { m_v.insert (p); m_box += point_type () + p; } template void assign (I from, I to) { m_v.clear (); m_v.insert (from, to); m_box = box_type (); for (I p = from; p != to; ++p) { m_box += point_type () + *p; } } template void insert (I from, I to) { m_v.insert (from, to); for (I p = from; p != to; ++p) { m_box += point_type () + *p; } } virtual bool is_iterated_array (std::vector *v) { if (v) { v->clear (); v->reserve (m_v.size ()); for (const_iterator p = m_v.begin (); p != m_v.end (); ++p) { v->push_back (*p); } } return true; } void sort () { m_v.sort (db::box_convert ()); } virtual std::pair *, bool> begin_touching (const box_type &b) const { if (b.empty ()) { return std::make_pair (new iterated_array_iterator (m_v.begin (), m_v.end ()), false); } else if (! b.touches (m_box)) { return std::make_pair (new iterated_array_iterator (m_v.end (), m_v.end ()), false); } else { box_convert_type bc; return std::make_pair (new iterated_array_iterator (m_v.begin_touching (b, bc)), false); } } virtual std::pair *, bool> begin () const { return std::make_pair (new iterated_array_iterator (m_v.begin (), m_v.end ()), false); } virtual basic_array *clone () const { return new iterated_array (*this); } virtual box_type bbox (const box_type &obox) const { if (obox.empty ()) { return obox; } else { return box_type (obox.p1 () + (m_box.p1 () - point_type ()), obox.p2 () + (m_box.p2 () - point_type ())); } } virtual size_t size () const { return m_v.size (); } virtual void invert (simple_trans_type &t) { t.invert (); db::fixpoint_trans f (t.rot ()); m_box = box_type (); for (iterator p = m_v.begin (); p != m_v.end (); ++p) { *p = -f (*p); m_box += point_type () + *p; } sort (); } virtual bool equal (const ArrayBase *b) const { const iterated_array *d = static_cast *> (b); if (m_v.size () != d->m_v.size ()) { return false; } for (const_iterator p1 = m_v.begin (), p2 = d->m_v.begin (); p1 != m_v.end (); ++p1, ++p2) { if (*p1 != *p2) { return false; } } return true; } virtual bool less (const ArrayBase *b) const { const iterated_array *d = static_cast *> (b); if (m_v.size () != d->m_v.size ()) { return (m_v.size () < d->m_v.size ()); } for (const_iterator p1 = m_v.begin (), p2 = d->m_v.begin (); p1 != m_v.end (); ++p1, ++p2) { if (*p1 != *p2) { return (*p1 < *p2); } } return false; } virtual size_t mem_used () const { return sizeof (*this) + db::mem_used (m_v) - sizeof (m_v); } virtual size_t mem_reqd () const { return sizeof (*this) + db::mem_reqd (m_v) - sizeof (m_v); } virtual unsigned int type () const { return 3; } virtual void transform (const complex_trans_type &ct) { m_box = box_type (); for (iterator p = m_v.begin (); p != m_v.end (); ++p) { *p = vector_type (ct * *p); m_box += point_type () + *p; } sort (); } virtual void transform (const simple_trans_type &st) { for (iterator p = m_v.begin (); p != m_v.end (); ++p) { *p = vector_type (st * *p); } m_box.transform (st); sort (); } protected: box_tree_type m_v; box_type m_box; }; /** * @brief The array specialization for the iterated, complex case (internal) * * The iterated case is that the displacements are described as * P=O+a*A+b*B (a=[amin..amax),b=[bmin..bmax)). * Each instance is magnified with the given magnification and subject to * further rotation by a residual angle given by acos, which is actually the cosine * of this angle. */ template struct iterated_complex_array : public iterated_array { typedef typename basic_array::point_type point_type; typedef typename basic_array::vector_type vector_type; typedef typename basic_array::box_type box_type; typedef typename basic_array::coord_type coord_type; typedef typename basic_array::disp_type disp_type; typedef typename basic_array::simple_trans_type simple_trans_type; typedef typename basic_array::complex_trans_type complex_trans_type; iterated_complex_array (double acos, double mag) : iterated_array (), m_acos (acos), m_mag (mag) { // .. nothing yet .. } template iterated_complex_array (double acos, double mag, I from, I to) : iterated_array (from, to), m_acos (acos), m_mag (mag) { // .. nothing yet .. } virtual basic_array *clone () const { return new iterated_complex_array (*this); } virtual void invert (simple_trans_type &t) { // recompute the array parameters such that every per-instance transformation // is inverted. This code is somewhat complex to maintain the splitting between // the simple transformation part and the residual given by m_acos and m_mag. complex_trans_type r = complex_trans_type (t, m_acos, m_mag).inverted (); m_mag = r.mag (); m_acos = r.rcos (); t = simple_trans_type (r); this->m_box = box_type (); for (typename iterated_array::iterator p = this->m_v.begin (); p != this->m_v.end (); ++p) { *p = -r (*p); this->m_box += point_type () + *p; } iterated_array::sort (); } virtual bool equal (const ArrayBase *b) const { const iterated_complex_array *d = static_cast *> (b); if (fabs (m_acos - d->m_acos) > epsilon) { return false; } if (fabs (m_mag - d->m_mag) > epsilon) { return false; } return iterated_array::equal (b); } virtual bool less (const ArrayBase *b) const { const iterated_complex_array *d = static_cast *> (b); if (fabs (m_acos - d->m_acos) > epsilon) { return m_acos < d->m_acos; } if (fabs (m_mag - d->m_mag) > epsilon) { return m_mag < d->m_mag; } return iterated_array::less (b); } virtual complex_trans_type complex_trans (const simple_trans_type &s) const { return complex_trans_type (s, m_acos, m_mag); } virtual bool is_complex () const { return true; } virtual unsigned int type () const { return 4; } private: double m_acos, m_mag; }; /** * @brief The array specialization for the single magnified case (internal) * * In the single case the displacement is 0. */ template struct single_complex_inst : public basic_array { typedef typename basic_array::point_type point_type; typedef typename basic_array::box_type box_type; typedef typename basic_array::coord_type coord_type; typedef typename basic_array::disp_type disp_type; typedef typename basic_array::complex_trans_type complex_trans_type; typedef typename basic_array::simple_trans_type simple_trans_type; single_complex_inst (double acos, double mag) : m_acos (acos), m_mag (mag) { // .. nothing yet .. } virtual std::pair *, bool> begin_touching (const box_type &b) const { return std::make_pair ((basic_array_iterator *) 0, ! b.contains (point_type (0, 0))); } virtual std::pair *, bool> begin () const { return std::make_pair ((basic_array_iterator *) 0, false); } virtual basic_array *clone () const { return new single_complex_inst (*this); } virtual box_type bbox (const box_type &obox) const { return obox; } virtual size_t size () const { return 1; } virtual void invert (simple_trans_type &t) { complex_trans_type r = complex_trans_type (t, m_acos, m_mag).inverted (); m_mag = r.mag (); m_acos = r.rcos (); t = simple_trans_type (r); } virtual bool equal (const ArrayBase *b) const { const double epsilon = 1e-10; const single_complex_inst *d = static_cast *> (b); if (fabs (m_mag - d->m_mag) > epsilon) { return false; } if (fabs (m_acos - d->m_acos) > epsilon) { return false; } return true; } virtual bool less (const ArrayBase *b) const { const double epsilon = 1e-10; const single_complex_inst *d = static_cast *> (b); if (fabs (m_mag - d->m_mag) > epsilon) { return m_mag < d->m_mag; } if (fabs (m_acos - d->m_acos) > epsilon) { return m_acos < d->m_acos; } return false; } virtual size_t mem_used () const { return sizeof (*this); } virtual size_t mem_reqd () const { return sizeof (*this); } virtual complex_trans_type complex_trans (const simple_trans_type &s) const { return complex_trans_type (s, m_acos, m_mag); } virtual bool is_complex () const { return true; } virtual unsigned int type () const { return 5; } private: double m_acos, m_mag; }; // this template computes the result type for the array iterator given // a transformation and the minimum required capabilities to represent a displacement template struct compute_result_trans { typedef T result_trans; }; template struct compute_result_trans > { typedef disp_trans result_trans; }; template struct compute_result_trans > { typedef disp_trans result_trans; }; /** * @brief The array iterator * * This facade object wraps the actual basic_array iterator * object. The iterator is not end-tested through comparing * with end() but rather querying the at_end() property. * This iterator as well acts as a single or zero instance * iterator if the base pointer is 0. */ template struct array_iterator { typedef Coord coord_type; typedef db::point point_type; typedef db::vector vector_type; typedef db::complex_trans complex_trans_type; typedef Trans trans_type; typedef typename compute_result_trans::result_trans result_type; // dummy definitions to satisfy iterator traits (without making much sense): typedef result_type reference; typedef result_type value_type; typedef void pointer_type; typedef void difference_type; typedef void pointer; typedef void iterator_category; /** * @brief The default constructor */ array_iterator () : m_trans (), mp_base (0), m_done (true) { // .. nothing yet .. } /** * @brief The iterator constructor * * The constructor will receive a basic_array_iterator object * and take over ownership over this. * This is a convenience constructor that combines the next two constructors. */ array_iterator (const trans_type &trans, std::pair *, bool> base) : m_trans (trans), mp_base (base.first), m_done (base.second) { // .. nothing yet .. } /** * @brief The iterator constructor * * The constructor will receive a basic_array_iterator object * and take over ownership over this. */ array_iterator (const trans_type &trans, db::basic_array_iterator *base) : m_trans (trans), mp_base (base), m_done (false) { // .. nothing yet .. } /** * @brief The single iterator constructor * * The constructor takes a flag indicating whether to represent * zero (true) or one (false) instance. */ array_iterator (const trans_type &trans, bool done) : m_trans (trans), mp_base (0), m_done (done) { // .. nothing yet .. } /** * @brief The copy constructor */ array_iterator (const array_iterator &d) : m_trans (d.m_trans), mp_base (0), m_done (d.m_done) { if (mp_base) { delete mp_base; } mp_base = d.mp_base ? d.mp_base->clone () : 0; } /** * @brief The assignment operator */ array_iterator &operator= (const array_iterator &d) { if (&d != this) { m_trans = d.m_trans; m_done = d.m_done; if (mp_base) { delete mp_base; } mp_base = d.mp_base ? d.mp_base->clone () : 0; } return *this; } /** * @brief The destructor * * This will delete the basic_array_iterator object passed * in the constructor */ ~array_iterator () { if (mp_base) { delete mp_base; } mp_base = 0; } /** * @brief The access operator * * This delivers a displacement vector that is associated with * the iterator's "position". */ result_type operator* () const { if (mp_base) { return result_type (mp_base->get ()) * result_type (m_trans); } else { return result_type (m_trans); } } /** * @brief Increment operator */ array_iterator &operator++ () { if (mp_base) { mp_base->inc (); } else { m_done = true; } return *this; } /** * @brief End test * * @return true, if the iterator is at the end. */ bool at_end () const { return mp_base ? mp_base->at_end () : m_done; } /** * @brief If the iterator is a regular iterator, get the "a" index * * If the iterator is not a regular one, returns -1. */ long index_a () const { return mp_base ? mp_base->index_a () : -1; } /** * @brief If the iterator is a regular iterator, get the "b" index * * If the iterator is not a regular one, returns -1. */ long index_b () const { return mp_base ? mp_base->index_b () : -1; } private: trans_type m_trans; basic_array_iterator *mp_base; bool m_done; }; /** * @brief The array container * * This is the facade object that wraps the array implementation * which is either a regular_array or another object derived * from a basic_array object. * Access to the object instances is through the iterators which * deliver the displacement vectors of the various instances, * possibly filtered by a box region. * * Arrays are currently used for creating shape and instance arrays. * There is a fundamental difference between shape and instance arrays: * while shape arrays can transform the object and must not make use * of complex transformation type arrays, instance arrays cannot transform * the object itself and must store every aspect of the transformation * in the array. Instance arrays thus make use of the complex type * feature of the array. */ template struct array { typedef typename Trans::coord_type coord_type; typedef db::box box_type; typedef db::point point_type; typedef db::vector vector_type; typedef db::complex_trans complex_trans_type; typedef db::simple_trans simple_trans_type; typedef db::disp_trans disp_trans_type; typedef db::unit_trans unit_trans_type; typedef Trans trans_type; typedef db::array_iterator iterator; typedef Obj object_type; typedef db::object_tag< array > tag; typedef db::iterated_array iterated_array_type; typedef db::iterated_complex_array iterated_complex_array_type; /** * @brief The default constructor */ array () : m_obj (), m_trans (), mp_base (0) { // .. nothing yet .. } /** * @brief The array constructor * * The array object takes over the ownership over the * basic_array object. * * @param obj The object to put into an array * @param base The basic_array object that describes the array further */ array (const Obj &obj, const trans_type &trans, basic_array *base) : m_obj (obj), m_trans (trans), mp_base (base) { // .. nothing yet .. } /** * @brief The regular array constructor * * This is basically a convenience function that creates * an appropriate basic_array object. */ array (const Obj &obj, const trans_type &trans, const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : m_obj (obj), m_trans (trans), mp_base (new regular_array (a, b, amax, bmax)) { // .. nothing yet .. } /** * @brief The regular array constructor using an array repository * * This is basically a convenience function that creates * an appropriate basic_array object. * It uses the array repository to store the base object rather than providing * it's own storage. */ array (const Obj &obj, const trans_type &trans, ArrayRepository &rep, const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : m_obj (obj), m_trans (trans), mp_base (rep.insert (regular_array (a, b, amax, bmax))) { // .. nothing yet .. } /** * @brief The singular array constructor * * This is basically a convenience function that creates * an appropriate basic_array object. * mp_base == 0 is implicitly a single-object array. */ explicit array (const Obj &obj, const trans_type &trans) : m_obj (obj), m_trans (trans), mp_base (0) { // .. nothing yet .. } /** * @brief The regular complex array constructor * * This is basically a convenience function that creates * an appropriate basic_array object. */ array (const Obj &obj, const trans_type &trans, double acos, double mag, const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : m_obj (obj), m_trans (trans), mp_base (new regular_complex_array (acos, mag, a, b, amax, bmax)) { // .. nothing yet .. } /** * @brief The regular complex array constructor * * This is basically a convenience function that creates * an appropriate basic_array object using a complex transformation. */ array (const Obj &obj, const complex_trans_type &ct, const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : m_obj (obj), m_trans (ct), mp_base (new regular_complex_array (ct.rcos (), ct.mag (), a, b, amax, bmax)) { // .. nothing yet .. } /** * @brief The regular complex array constructor using an array repository * * This is basically a convenience function that creates * an appropriate basic_array object. * It uses the array repository to store the base object rather than providing * it's own storage. */ array (const Obj &obj, const trans_type &trans, ArrayRepository &rep, double acos, double mag, const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : m_obj (obj), m_trans (trans), mp_base (rep.insert (regular_complex_array (acos, mag, a, b, amax, bmax))) { // .. nothing yet .. } /** * @brief The regular complex array constructor using an array repository * * This is basically a convenience function that creates * an appropriate basic_array object using a complex transformation. * It uses the array repository to store the base object rather than providing * it's own storage. */ array (const Obj &obj, const complex_trans_type &ct, ArrayRepository &rep, const vector_type &a, const vector_type &b, unsigned long amax, unsigned long bmax) : m_obj (obj), m_trans (ct), mp_base (rep.insert (regular_complex_array (ct.rcos (), ct.mag (), a, b, amax, bmax))) { // .. nothing yet .. } /** * @brief The singular complex instance constructor * * This is basically a convenience function that creates * an appropriate basic_array object. */ explicit array (const Obj &obj, const trans_type &trans, double acos, double mag) : m_obj (obj), m_trans (trans), mp_base (new single_complex_inst (acos, mag)) { // .. nothing yet .. } /** * @brief The singular complex instance constructor * * This is basically a convenience function that creates * an appropriate basic_array object using a complex transformation. */ explicit array (const Obj &obj, const complex_trans_type &ct) : m_obj (obj), m_trans (ct), mp_base (new single_complex_inst (ct.rcos (), ct.mag ())) { // .. nothing yet .. } /** * @brief The singular complex instance constructor * * This is basically a convenience function that creates * an appropriate basic_array object. * It uses the array repository to store the base object rather than providing * it's own storage. */ explicit array (const Obj &obj, const trans_type &trans, ArrayRepository &rep, double acos, double mag) : m_obj (obj), m_trans (trans), mp_base (rep.insert (single_complex_inst (acos, mag))) { // .. nothing yet .. } /** * @brief The singular complex instance constructor * * This is basically a convenience function that creates * an appropriate basic_array object using a complex transformation. * It uses the array repository to store the base object rather than providing * it's own storage. */ explicit array (const Obj &obj, const complex_trans_type &ct, ArrayRepository &rep) : m_obj (obj), m_trans (ct), mp_base (rep.insert (single_complex_inst (ct.rcos (), ct.mag ()))) { // .. nothing yet .. } /** * @brief The destructor * * This will delete the basic_array object that was passed * to the constructor. */ ~array () { if (mp_base && ! mp_base->in_repository) { delete mp_base; } mp_base = 0; } /** * @brief The copy constructor */ array (const array &d) : m_obj (d.m_obj), m_trans (d.m_trans), mp_base (0) { if (d.mp_base) { mp_base = d.mp_base->in_repository ? d.mp_base : d.mp_base->clone (); } } /** * @brief The copy constructor with array repository translation * * If the array repository pointer is 0, the d array will be detached from an repository. * Otherwise it will be translated to the given repository. */ array (const array &d, ArrayRepository *rep) : m_obj (d.m_obj), m_trans (d.m_trans), mp_base (0) { if (d.mp_base) { if (rep) { mp_base = rep->insert (*d.mp_base); } else { mp_base = d.mp_base->clone (); } } } /** * @brief The assignment operator */ array &operator= (const array &d) { if (&d != this) { m_trans = d.m_trans; m_obj = d.m_obj; if (mp_base && ! mp_base->in_repository) { delete mp_base; } if (d.mp_base) { mp_base = d.mp_base->in_repository ? d.mp_base : d.mp_base->clone (); } else { mp_base = 0; } } return *this; } /** * @brief The region-selective iterator * * There is no end() method. Rather use the at_end() method * of the iterator to determine the end of the sequence. * The iterator returned will report all object displacement * vectors of the objects that touch the given box and * possibly some more. */ template array_iterator begin_touching (const box_type &b, const BoxConv &bc) const { if (b.empty ()) { if (mp_base) { return array_iterator (m_trans, mp_base->begin_touching (box_type ())); } else { return array_iterator (m_trans, true); } } else if (b == box_type::world ()) { return begin (); } else if (mp_base) { box_type ob (bc (m_obj)); if (ob.empty ()) { return array_iterator (m_trans, mp_base->begin_touching (box_type ())); } else { if (mp_base->is_complex ()) { complex_trans_type ct = mp_base->complex_trans (simple_trans_type (m_trans)); ct.disp (typename complex_trans_type::displacement_type ()); ob = box_type (ct * ob); } else { ob.transform (db::fixpoint_trans (m_trans.rot ())); } vector_type d = m_trans.disp (); return array_iterator (m_trans, mp_base->begin_touching (box_type (point_type () + (b.p1 () - (ob.p2 () + d)), point_type () + (b.p2 () - (ob.p1 () + d))))); } } else { box_type ob (bc (m_obj)); if (ob.empty ()) { return array_iterator (m_trans, true); } else { vector_type d = m_trans.disp (); ob.transform (db::fixpoint_trans (m_trans.rot ())); return array_iterator (m_trans, ! box_type (point_type () + (b.p1 () - (ob.p2 () + d)), point_type () + (b.p2 () - (ob.p1 () + d))).contains (point_type ())); } } } /** * @brief The regular array member iterator * * This method delivers an array iterator pointing to the member with the given indexes, * provided the array is a regular one. If the array is not regular this method * will deliver the same iterator than begin (). * There is no end() method. Rather use the at_end() method * of the iterator to determine the end of the sequence. */ array_iterator begin (long a, long b) const { if (mp_base) { return array_iterator (m_trans, mp_base->begin_regular (a, b)); } else { return array_iterator (m_trans, false); } } /** * @brief The non-selective iterator * * There is no end() method. Rather use the at_end() method * of the iterator to determine the end of the sequence. */ array_iterator begin () const { if (mp_base) { return array_iterator (m_trans, mp_base->begin ()); } else { return array_iterator (m_trans, false); } } /** * @brief The bbox of the array */ template box_type bbox (const BoxConv &bc) const { if (mp_base) { if (mp_base->is_complex ()) { return mp_base->bbox (box_type (mp_base->complex_trans (simple_trans_type (m_trans)) * bc (m_obj))); } else { return mp_base->bbox (m_trans * bc (m_obj)); } } else { return m_trans * bc (m_obj); } } /** * @brief The raw bounding box of the array * * The raw bounding box is the box that encloses the array instantiation * points, ignoring the extensions of the object. * The raw bounding boxes can be accumulated for all arrays having the same * orientation, magnification and object. * bbox_from_raw_bbox can be used to compute the total bbox from such an * accumulated raw bounding box. This is for example exploitet in the * update_bbox method of db::cell. */ box_type raw_bbox () const { point_type d = m_trans (point_type ()); if (mp_base) { return mp_base->bbox (box_type (d, d)); } else { return box_type (d, d); } } /** * @brief The bbox of the array computed from the raw bounding box * * See "raw_bbox" for a description. */ template box_type bbox_from_raw_bbox (const box_type &rb, const BoxConv &bc) const { if (mp_base) { if (mp_base->is_complex ()) { return rb * (box_type (mp_base->complex_trans (simple_trans_type (m_trans.fp_trans ())) * bc (m_obj))); } else { return rb * (m_trans.fp_trans () * bc (m_obj)); } } else { return rb * (m_trans.fp_trans () * bc (m_obj)); } } /** * @brief The number of single instances in the array */ size_t size () const { if (mp_base) { return mp_base->size (); } else { return 1; } } /** * @brief Gets the simple component of the transformation * * This component does not include additional transformations due to complex * components and array-item displacements. */ const trans_type &front () const { return m_trans; } /** * @brief Access to the object in the instance */ Obj &object () { return m_obj; } /** * @brief Access to the object in the instance (const version) */ const Obj &object () const { return m_obj; } /** * @brief Invert an array reference */ void invert () { if (mp_base) { // Hint: detach from repository so we can invert if (mp_base->in_repository) { mp_base = mp_base->clone (); } // Hint: this assumes that the delegate does not carry a "superior" transformation over trans_type - // i.e. no complex trans inside arrays stating a unit_trans type for example. The assertion checks that. simple_trans_type t (m_trans); mp_base->invert (t); m_trans = trans_type (t); tl_assert (simple_trans_type (m_trans) == t); } else { m_trans.invert (); } } /** * @brief Compare operator for inequality */ bool operator!= (const array &d) const { return !operator== (d); } /** * @brief Compare operator for equality */ bool operator== (const array &d) const { if (! mp_base) { return (m_trans == d.m_trans && m_obj == d.m_obj && ! d.mp_base); } else { if (m_trans != d.m_trans || ! (m_obj == d.m_obj) || type () != d.type ()) { return false; } return mp_base && mp_base->equal (d.mp_base); } } /** * @brief A sorting order criterion */ bool operator< (const array &d) const { if (! (m_obj == d.m_obj)) { return (m_obj < d.m_obj); } if (m_trans != d.m_trans) { return (m_trans < d.m_trans); } if (type () != d.type ()) { return (type () < d.type ()); } if (mp_base == d.mp_base) { return false; } else if (! mp_base) { return true; } else if (! d.mp_base) { return false; } else { return mp_base->less (d.mp_base); } } /** * @brief Compare operator * * Implementation of a comparison operator that just * compares the object and the matrix part of the transformation. * Needed for sorting of cell instances for example. */ bool raw_less (const array &d) const { if (! (m_obj == d.m_obj)) { return (m_obj < d.m_obj); } if (m_trans.rot () != d.m_trans.rot ()) { return (m_trans.rot () < d.m_trans.rot ()); } if (is_complex () != d.is_complex ()) { return is_complex () < d.is_complex (); } if (is_complex ()) { complex_trans_type ct1 (complex_trans ()); complex_trans_type ct2 (d.complex_trans ()); if (ct1.mcos () != ct2.mcos ()) { return ct1.mcos () < ct2.mcos (); } if (ct1.msin () != ct2.msin ()) { return ct1.msin () < ct2.msin (); } if (ct1.mag () != ct2.mag ()) { return ct1.mag () < ct2.mag (); } } return false; } /** * @brief Compare operator (equal) * * Implementation of a comparison operator that just * compares the object and the matrix part of the transformation. * Needed for sorting of cell instances for example. */ bool raw_equal (const array &d) const { if (! (m_obj == d.m_obj)) { return false; } if (m_trans.rot () != d.m_trans.rot ()) { return false; } if (is_complex () != d.is_complex ()) { return false; } if (is_complex ()) { complex_trans_type ct1 (complex_trans ()); complex_trans_type ct2 (d.complex_trans ()); if (ct1.mcos () != ct2.mcos ()) { return false; } if (ct1.msin () != ct2.msin ()) { return false; } if (ct1.mag () != ct2.mag ()) { return false; } } return true; } /** * @brief Returns true, if the array lives in an array repository */ bool in_repository () const { return mp_base && mp_base->in_repository; } /** * @brief Test, if the array is a complex array * * Returns true if the array represents complex instances (that is, with magnification and * arbitrary rotation angles). */ bool is_complex () const { return mp_base && mp_base->is_complex (); } /** * @brief Return the type code * * Returns the type code of the array. Mainly used internally. */ int type () const { return mp_base ? mp_base->type () : 0; } /** * @brief Return the complex_transformation * * Returns the complex transformation that incorporates magnification and arbitrary angle rotation. * This method returns the complex transformation for the first element in the array. To obtain the * complex transformation for a specific element, use 'complex_trans (*iter)' instead. */ complex_trans_type complex_trans () const { return mp_base ? mp_base->complex_trans (simple_trans_type (m_trans)) : complex_trans_type (m_trans); } /** * @brief Return the complex_transformation * * Returns the complex transformation that incorporates magnification and arbitrary angle rotation * for a given base transformation. This method is intended to be used with the base transformation * delivered by an iterator. */ complex_trans_type complex_trans (const trans_type &trans) const { return mp_base ? mp_base->complex_trans (simple_trans_type (trans)) : complex_trans_type (trans); } /** * @brief Test, if the array is a regular one * * Returns true and the array parameters if the array is a regular * one. */ bool is_regular_array (vector_type &a, vector_type &b, unsigned long &amax, unsigned long &bmax) const { return mp_base && mp_base->is_regular_array (a, b, amax, bmax); } /** * @brief Test, if the array is an iterated one * * Returns true and the array parameters if the array is a iterated * one. If v is 0, no vector of points is returned */ bool is_iterated_array (std::vector *v = 0) const { return mp_base && mp_base->is_iterated_array (v); } /** * @brief The translation operator * * This operator is required since shape reference arrays are put into db::Layer objects * * Hint this method is supposed to be used for shape arrays. Instance arrays to not support the translate method currently. * TODO: this functionality should be put into the Shapes translate method rather than into this class ... */ void translate (const array &d, db::generic_repository &rep, db::ArrayRepository &array_rep) { m_obj.translate (d.m_obj, rep, array_rep); m_trans = d.m_trans; if (mp_base && ! mp_base->in_repository) { delete mp_base; } if (d.mp_base) { mp_base = d.mp_base->in_repository ? array_rep.insert (*d.mp_base) : d.mp_base->clone (); } else { mp_base = 0; } } /** * @brief The translation operator with transformation * * Hint this method is supposed to be used for shape arrays. Instance arrays to not support the translate method currently. * TODO: this functionality should be put into the Shapes translate method rather than into this class ... */ template void translate (const array &d, const T &t, db::generic_repository &rep, db::ArrayRepository &array_rep) { // Translate the array into the new system and if necessary, transform and translate the object translate_from (t, d, rep, array_rep); // remove the current delegate if (mp_base && ! mp_base->in_repository) { delete mp_base; mp_base = 0; } // transform the delegate if (d.mp_base) { basic_array *new_base = d.mp_base->clone (); new_base->transform (t); mp_base = array_rep.insert (*new_base); delete new_base; } } /** * @brief Collect memory usage statistics */ size_t mem_used () const { return sizeof (m_trans) + sizeof (mp_base) + db::mem_used (m_obj) + (mp_base ? mp_base->mem_used () : 0); } /** * @brief Collect memory requirement statistics */ size_t mem_reqd () const { return sizeof (m_trans) + sizeof (mp_base) + db::mem_reqd (m_obj) + (mp_base ? mp_base->mem_reqd () : 0); } /** * @brief Swap with another object * * This implementation does not require to reallocate the base pointer * which might speed up somewhat the sorting of cell instances. */ void swap (db::array &b) { std::swap (m_trans, b.m_trans); std::swap (m_obj, b.m_obj); std::swap (mp_base, b.mp_base); } /** * @brief For test purposes: return the delegate */ const ArrayBase *delegate () const { return mp_base; } /** * @brief In-place transformation of an array * * This method will transform the array specification according to the given transformation. * * @param tr The transformation to apply * @param rep The repository where to enter the new array or 0 if no repository should be used * * Hint: this method is supposed to be used for arrays with simple_transformation for the transformation type mainly. * The reason is that this method will create complex arrays from complex transformations. * Arrays based on reduced transformations (unit_trans, disp_trans) must not use complex arrays because that * is not supported currently. In other words, this method will not try to transform the object itself and rather * put all transformation aspects into the array, which does not work on reduced transformation types, except * if the applied transformation "tr" is also a reduced type. * If required, the remaining component can be computed from the previous complex transformation and the new one * using this formula: trem = t_new.inverted() * tr * t_old where t_new is complex_trans() or front() after this * method has been called and t_old is complex_trans() or front() before this method was called. * * Here is a table of compatibility: * Trans T Compatible * unit unit yes * unit disp,simple,complex in general not * disp unit,disp yes * disp simple,complex in general not * simple all yes * * For the non-compatible combinations, %translate is provided. This however requires that the object * can be transformed ("translated" in the more general sense). That specifically applies to * shape arrays and references which are based on unit or disp transformations. */ template void transform (const T &tr, db::ArrayRepository *array_rep = 0) { transform_from (tr, *this); if (mp_base) { // transform the delegate transform_delegate (tr, array_rep); } } /** * @brief Moves the arrays * * This is equivalent to transforming with a displacement */ void move (const vector_type &pt, db::ArrayRepository *array_rep = 0) { transform (disp_trans_type (pt), array_rep); } /** * @brief Transformation into a new system * * Arrays are transformed into a new system by applying a formal transformation * A' = T A Ti (Ti is the inverse of T). Hence T A = A' T. In other words: the transformation * T is propagated over the array A. This transformation is useful for transformation * of hierarchies, since the transformation T can be propagated further down in the hierarchy * therefore. * * See the remarks on "transform" regarding compatibility of the transformation argument and * the Trans type of this array. * * @param tr The transformation to apply * @param rep The repository where to enter the new array or 0 if no repository should be used */ template void transform_into (const T &tr, db::ArrayRepository *array_rep = 0) { transform_into_from (tr, *this); if (mp_base) { // transform the delegate transform_delegate (tr, array_rep); } } /** * @brief Transformation of an array */ template array transformed (const T &tr, db::ArrayRepository *array_rep = 0) const { array a (*this); a.transform (tr, array_rep); return a; } /** * @brief Transformation of an array into a new system * * See the "transform_into" method for details about this transformation. */ template array transformed_into (const T &tr, db::ArrayRepository *array_rep = 0) const { array a (*this); a.transform_into (tr, array_rep); return a; } private: Obj m_obj; trans_type m_trans; basic_array *mp_base; void transform_into_from (const unit_trans_type &tr, const array &d) { // .. nothing to do .. } void transform_into_from (const disp_trans_type &tr, const array &d) { if (is_complex ()) { complex_trans_type t = d.complex_trans ().transform_into (tr); m_trans = Trans (t); set_complex (t.mag (), t.rcos (), d); } else { simple_trans_type t = simple_trans_type (tr) * d.front () * simple_trans_type (tr.inverted ()); m_trans = Trans (t); } } void transform_into_from (const simple_trans_type &tr, const array &d) { if (is_complex ()) { complex_trans_type t = d.complex_trans ().transform_into (tr); m_trans = trans_type (t); set_complex (t.mag (), t.rcos (), d); } else { simple_trans_type t = tr * d.front () * tr.inverted (); m_trans = Trans (t); } } void transform_into_from (const complex_trans_type &tr, const array &d) { complex_trans_type t = d.complex_trans ().transform_into (tr); m_trans = trans_type (t); set_complex (t.mag (), t.rcos (), d); } void translate_from (const unit_trans_type &tr, const array &d, db::generic_repository &rep, db::ArrayRepository &array_rep) { // .. nothing to do .. } void translate_from (const disp_trans_type &tr, const array &d, db::generic_repository &rep, db::ArrayRepository &array_rep) { if (is_complex ()) { complex_trans_type t = complex_trans_type (tr) * d.complex_trans (); m_trans = trans_type (t); set_complex (t.mag (), t.rcos (), d); m_obj.translate (d.m_obj, complex_trans ().inverted () * complex_trans_type (t), rep, array_rep); } else { simple_trans_type t = simple_trans_type (tr) * simple_trans_type (d.front ()); m_trans = trans_type (t); m_obj.translate (d.m_obj, simple_trans_type (m_trans.inverted ()) * t, rep, array_rep); } } void translate_from (const simple_trans_type &tr, const array &d, db::generic_repository &rep, db::ArrayRepository &array_rep) { if (is_complex ()) { complex_trans_type t = complex_trans_type (tr) * d.complex_trans (); m_trans = trans_type (t); set_complex (t.mag (), t.rcos (), d); m_obj.translate (d.m_obj, complex_trans ().inverted () * complex_trans_type (t), rep, array_rep); } else { simple_trans_type t = tr * simple_trans_type (d.front ()); m_trans = trans_type (t); m_obj.translate (d.m_obj, simple_trans_type (m_trans.inverted ()) * t, rep, array_rep); } } void translate_from (const complex_trans_type &tr, const array &d, db::generic_repository &rep, db::ArrayRepository &array_rep) { if (is_complex ()) { complex_trans_type t = tr * d.complex_trans (); m_trans = trans_type (t); set_complex (t.mag (), t.rcos (), d); m_obj.translate (d.m_obj, complex_trans ().inverted () * complex_trans_type (t), rep, array_rep); } else { // don't create a complex array - delegate the transformation to the translate method complex_trans_type t = tr * complex_trans_type (d.front ()); m_trans = trans_type (t); m_obj.translate (d.m_obj, complex_trans_type (m_trans.inverted ()) * t, rep, array_rep); } } void transform_from (const unit_trans_type &tr, const array &d) { // .. nothing to do .. } void transform_from (const disp_trans_type &tr, const array &d) { m_trans = trans_type (simple_trans_type (tr) * simple_trans_type (d.front ())); } void transform_from (const simple_trans_type &tr, const array &d) { m_trans = trans_type (tr * simple_trans_type (d.front ())); } void transform_from (const complex_trans_type &tr, const array &d) { complex_trans_type t = tr * d.complex_trans (); // TODO: this only works properly if Trans is a simple_trans_type! m_trans = trans_type (t); set_complex (t.mag (), t.rcos (), d); } void set_complex (double mag, double rcos, const array &d) { basic_array *new_base = 0; // if we finally have a complex transformation, set a new base object if (fabs (mag - 1.0) > epsilon || fabs (rcos - 1.0) > epsilon) { // create a new base object with the transformed base vectors vector_type a, b; unsigned long amax, bmax; bool is_reg = d.is_regular_array (a, b, amax, bmax); std::vector v; bool is_iterated = d.is_iterated_array (&v); if (is_reg) { new_base = new regular_complex_array (rcos, mag, a, b, amax, bmax); } else if (is_iterated) { new_base = new iterated_complex_array (rcos, mag, v.begin (), v.end ()); } else { new_base = new single_complex_inst (rcos, mag); } } else if (d.is_complex ()) { // create a new base object with the transformed base vectors vector_type a, b; unsigned long amax, bmax; bool is_reg = d.is_regular_array (a, b, amax, bmax); std::vector v; bool is_iterated = d.is_iterated_array (&v); if (is_reg) { new_base = new regular_array (a, b, amax, bmax); } else if (is_iterated) { new_base = new iterated_array (v.begin (), v.end ()); } else { // a complex transformation delegate is no longer required if (mp_base && ! mp_base->in_repository) { delete mp_base; } mp_base = 0; } } if (new_base) { if (mp_base && ! mp_base->in_repository) { delete mp_base; } mp_base = new_base; } } template void transform_delegate (const T &tr, db::ArrayRepository *array_rep) { // transform the delegate if (! array_rep && ! mp_base->in_repository) { // special case: allow in-place transformation mp_base->transform (tr); } else { basic_array *new_base = mp_base->clone (); new_base->transform (tr); if (! mp_base->in_repository) { delete mp_base; } if (array_rep) { mp_base = array_rep->insert (*new_base); delete new_base; } else { mp_base = new_base; } } } }; template size_t mem_used (const array &x) { return x.mem_used (); } template size_t mem_reqd (const array &x) { return x.mem_reqd (); } } namespace std { // injecting a global std::swap for arrays into the // std namespace template void swap (db::array &a, db::array &b) { a.swap (b); } } // namespace std #endif