mirror of https://github.com/KLayout/klayout.git
Merge pull request #580 from KLayout/drawing-performance2
Drawing performance2
This commit is contained in:
commit
e744eb32d1
|
|
@ -70,7 +70,11 @@ struct basic_array_iterator
|
|||
|
||||
virtual long index_a () const { return -1; }
|
||||
virtual long index_b () const { return -1; }
|
||||
|
||||
|
||||
virtual size_t quad_id () const { return 0; }
|
||||
virtual box_type quad_box () const { return box_type::world (); }
|
||||
virtual void skip_quad () { }
|
||||
|
||||
virtual disp_type get () const = 0;
|
||||
|
||||
virtual basic_array_iterator<Coord> *clone () const = 0;
|
||||
|
|
@ -111,8 +115,12 @@ struct ArrayBase
|
|||
|
||||
virtual bool equal (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool less (const ArrayBase *) const = 0;
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *) const = 0;
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self = false, void *parent = 0) const = 0;
|
||||
|
||||
bool in_repository;
|
||||
|
|
@ -554,6 +562,12 @@ struct regular_array
|
|||
return (m_a == d->m_a && m_b == d->m_b && m_amax == d->m_amax && m_bmax == d->m_bmax);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
return (m_a.equal (d->m_a) && m_b.equal (d->m_b) && m_amax == d->m_amax && m_bmax == d->m_bmax);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
|
|
@ -562,6 +576,14 @@ struct regular_array
|
|||
m_amax < d->m_amax || (m_amax == d->m_amax && m_bmax < d->m_bmax)))));
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_array<Coord> *d = static_cast<const regular_array<Coord> *> (b);
|
||||
return m_a.less (d->m_a) || (m_a.equal (d->m_a) && (
|
||||
m_b.less (d->m_b) || (m_b.equal (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;
|
||||
|
|
@ -702,6 +724,18 @@ struct regular_complex_array
|
|||
return regular_array<Coord>::equal (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
return regular_array<Coord>::fuzzy_equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (b);
|
||||
|
|
@ -714,6 +748,18 @@ struct regular_complex_array
|
|||
return regular_array<Coord>::less (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const regular_complex_array<Coord> *d = static_cast<const regular_complex_array<Coord> *> (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<Coord>::fuzzy_less (b);
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -806,6 +852,21 @@ struct iterated_array_iterator
|
|||
return new iterated_array_iterator <Coord> (*this);
|
||||
}
|
||||
|
||||
virtual size_t quad_id () const
|
||||
{
|
||||
return m_t.quad_id ();
|
||||
}
|
||||
|
||||
virtual box_type quad_box () const
|
||||
{
|
||||
return m_t.quad_box ();
|
||||
}
|
||||
|
||||
virtual void skip_quad ()
|
||||
{
|
||||
m_t.skip_quad ();
|
||||
}
|
||||
|
||||
private:
|
||||
box_tree_const_iterator m_b, m_e;
|
||||
box_tree_touching_iterator m_t;
|
||||
|
|
@ -964,6 +1025,20 @@ struct iterated_array
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (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->equal (*p2)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (b);
|
||||
|
|
@ -978,6 +1053,20 @@ struct iterated_array
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_array<Coord> *d = static_cast<const iterated_array<Coord> *> (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->equal (*p2)) {
|
||||
return (p1->less (*p2));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -1085,6 +1174,18 @@ struct iterated_complex_array
|
|||
return iterated_array<Coord>::equal (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
if (fabs (m_acos - d->m_acos) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
if (fabs (m_mag - d->m_mag) > epsilon) {
|
||||
return false;
|
||||
}
|
||||
return iterated_array<Coord>::fuzzy_equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (b);
|
||||
|
|
@ -1097,6 +1198,18 @@ struct iterated_complex_array
|
|||
return iterated_array<Coord>::less (b);
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
const iterated_complex_array<Coord> *d = static_cast<const iterated_complex_array<Coord> *> (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<Coord>::fuzzy_less (b);
|
||||
}
|
||||
|
||||
virtual complex_trans_type complex_trans (const simple_trans_type &s) const
|
||||
{
|
||||
return complex_trans_type (s, m_acos, m_mag);
|
||||
|
|
@ -1187,7 +1300,12 @@ struct single_complex_inst
|
|||
return true;
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
virtual bool fuzzy_equal (const ArrayBase *b) const
|
||||
{
|
||||
return equal (b);
|
||||
}
|
||||
|
||||
virtual bool less (const ArrayBase *b) const
|
||||
{
|
||||
const double epsilon = 1e-10;
|
||||
const single_complex_inst<Coord> *d = static_cast<const single_complex_inst<Coord> *> (b);
|
||||
|
|
@ -1200,6 +1318,11 @@ struct single_complex_inst
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool fuzzy_less (const ArrayBase *b) const
|
||||
{
|
||||
return less (b);
|
||||
}
|
||||
|
||||
virtual void mem_stat (MemStatistics *stat, MemStatistics::purpose_t purpose, int cat, bool no_self, void *parent) const
|
||||
{
|
||||
if (!no_self) {
|
||||
|
|
@ -1420,6 +1543,36 @@ struct array_iterator
|
|||
return mp_base ? mp_base->index_b () : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will return the quad ID
|
||||
*/
|
||||
size_t quad_id () const
|
||||
{
|
||||
return mp_base ? mp_base->quad_id () : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will return the quad bounding box
|
||||
*
|
||||
* Note that this method will only return a valid quad box is the quad_id is non-null.
|
||||
*
|
||||
* This method will return the bounding box of all array offsets in the quad.
|
||||
*/
|
||||
db::box<Coord> quad_box () const
|
||||
{
|
||||
return mp_base ? mp_base->quad_box () : db::box<Coord>::world ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For iterators supporting quads (iterated arrays), this method will skip the current quad
|
||||
*/
|
||||
void skip_quad ()
|
||||
{
|
||||
if (mp_base) {
|
||||
mp_base->skip_quad ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
trans_type m_trans;
|
||||
basic_array_iterator <Coord> *mp_base;
|
||||
|
|
@ -1592,6 +1745,32 @@ struct array
|
|||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The iterated array constructor
|
||||
*
|
||||
* This is basically a convenience function that creates
|
||||
* an appropriate basic_array object.
|
||||
*/
|
||||
template <class Iter>
|
||||
array (const Obj &obj, const trans_type &trans, Iter from, Iter to)
|
||||
: m_obj (obj), m_trans (trans), mp_base (new iterated_array <coord_type> (from, to))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The complex iterated array constructor
|
||||
*
|
||||
* This is basically a convenience function that creates
|
||||
* an appropriate basic_array object.
|
||||
*/
|
||||
template <class Iter>
|
||||
array (const Obj &obj, const complex_trans_type &ct, Iter from, Iter to)
|
||||
: m_obj (obj), m_trans (ct), mp_base (new iterated_complex_array <coord_type> (ct.rcos (), ct.mag (), from, to))
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The singular complex instance constructor
|
||||
*
|
||||
|
|
@ -1835,6 +2014,32 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the bounding box from the iterator's current quad
|
||||
*
|
||||
* The bounding box is that of all objects in the current quad and
|
||||
* is confined to the array's total bounding box.
|
||||
*/
|
||||
template <class Iter, class BoxConv>
|
||||
box_type quad_box (const Iter &iter, const BoxConv &bc) const
|
||||
{
|
||||
box_type bb;
|
||||
if (mp_base) {
|
||||
bb = mp_base->bbox (box_type (0, 0, 0, 0));
|
||||
}
|
||||
bb &= iter.quad_box ();
|
||||
|
||||
if (mp_base) {
|
||||
if (mp_base->is_complex ()) {
|
||||
return bb * box_type (mp_base->complex_trans (simple_trans_type (m_trans)) * bc (m_obj));
|
||||
} else {
|
||||
return bb * (m_trans * bc (m_obj));
|
||||
}
|
||||
} else {
|
||||
return bb * (m_trans * bc (m_obj));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The number of single instances in the array
|
||||
*/
|
||||
|
|
@ -1918,6 +2123,21 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare operator for equality (fuzzy version)
|
||||
*/
|
||||
bool equal (const array<Obj, Trans> &d) const
|
||||
{
|
||||
if (! mp_base) {
|
||||
return (m_trans.equal (d.m_trans) && m_obj == d.m_obj && ! d.mp_base);
|
||||
} else {
|
||||
if (! m_trans.equal (d.m_trans) || ! (m_obj == d.m_obj) || type () != d.type ()) {
|
||||
return false;
|
||||
}
|
||||
return mp_base && mp_base->fuzzy_equal (d.mp_base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A sorting order criterion
|
||||
*/
|
||||
|
|
@ -1943,6 +2163,31 @@ struct array
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief A fuzzy sorting order criterion
|
||||
*/
|
||||
bool less (const array<Obj, Trans> &d) const
|
||||
{
|
||||
if (! (m_obj == d.m_obj)) {
|
||||
return (m_obj < d.m_obj);
|
||||
}
|
||||
if (! m_trans.equal (d.m_trans)) {
|
||||
return m_trans.less (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->fuzzy_less (d.mp_base);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compare operator
|
||||
*
|
||||
|
|
@ -2263,7 +2508,7 @@ struct array
|
|||
}
|
||||
db::mem_stat (stat, purpose, cat, m_obj, true, (void *) this);
|
||||
if (mp_base) {
|
||||
db::mem_stat (stat, purpose, cat, *mp_base, false, (void *) this);
|
||||
mp_base->mem_stat (stat, purpose, cat, false, (void *) this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -168,40 +168,43 @@ public:
|
|||
typedef typename Tree::coord_type coord_type;
|
||||
typedef typename Tree::box_type box_type;
|
||||
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, unsigned int quad)
|
||||
: m_center (center)
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, const box_type &qbox, unsigned int quad)
|
||||
{
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
m_lenq[i] = 0;
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
mp_children[i] = 0;
|
||||
}
|
||||
mp_parent = (box_tree_node *)((char *) parent + quad);
|
||||
if (parent) {
|
||||
parent->mp_children [quad] = this;
|
||||
point_type corner;
|
||||
if (quad == 0) {
|
||||
corner = qbox.upper_right ();
|
||||
} else if (quad == 1) {
|
||||
corner = qbox.upper_left ();
|
||||
} else if (quad == 2) {
|
||||
corner = qbox.lower_left ();
|
||||
} else if (quad == 3) {
|
||||
corner = qbox.lower_right ();
|
||||
}
|
||||
|
||||
init (parent, center, corner, quad);
|
||||
}
|
||||
|
||||
~box_tree_node ()
|
||||
{
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mp_children [i]) {
|
||||
delete mp_children [i];
|
||||
mp_children [i] = 0;
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
delete c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box_tree_node *clone (box_tree_node *parent = 0, unsigned int quad = 0) const
|
||||
{
|
||||
box_tree_node *n = new box_tree_node (parent, m_center, quad);
|
||||
for (unsigned int i = 0; i < 5; ++i) {
|
||||
n->m_lenq[i] = m_lenq[i];
|
||||
}
|
||||
box_tree_node *n = new box_tree_node (parent, m_center, m_corner, quad);
|
||||
n->m_lenq = m_lenq;
|
||||
n->m_len = m_len;
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
if (mp_children[i]) {
|
||||
mp_children[i]->clone (n, i);
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
c->clone (n, i);
|
||||
} else {
|
||||
n->m_childrefs [i] = m_childrefs [i];
|
||||
}
|
||||
}
|
||||
return n;
|
||||
|
|
@ -209,17 +212,39 @@ public:
|
|||
|
||||
box_tree_node *child (int i) const
|
||||
{
|
||||
return mp_children [i];
|
||||
if ((m_childrefs [i] & 1) == 0) {
|
||||
return reinterpret_cast<box_tree_node *> (m_childrefs [i]);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void lenq (int i, size_t l)
|
||||
{
|
||||
m_lenq[i + 1] = l;
|
||||
if (i < 0) {
|
||||
m_lenq = l;
|
||||
} else {
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
c->m_len = l;
|
||||
} else {
|
||||
m_childrefs [i] = l * 2 + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t lenq (int i) const
|
||||
{
|
||||
return m_lenq[i + 1];
|
||||
if (i < 0) {
|
||||
return m_lenq;
|
||||
} else {
|
||||
box_tree_node *c = child (i);
|
||||
if (c) {
|
||||
return c->m_len;
|
||||
} else {
|
||||
return m_childrefs [i] >> 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
box_tree_node *parent () const
|
||||
|
|
@ -238,8 +263,8 @@ public:
|
|||
stat->add (typeid (*this), (void *) this, sizeof (*this), sizeof (*this), parent, purpose, cat);
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (mp_children [i]) {
|
||||
mp_children [i]->mem_stat (stat, purpose, cat, no_self, parent);
|
||||
if (child (i)) {
|
||||
child (i)->mem_stat (stat, purpose, cat, no_self, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -249,14 +274,52 @@ public:
|
|||
return m_center;
|
||||
}
|
||||
|
||||
box_type quad_box (int quad) const
|
||||
{
|
||||
box_type qb = box_type::world ();
|
||||
if (parent ()) {
|
||||
qb = box_type (m_corner, parent ()->center ());
|
||||
}
|
||||
|
||||
switch (quad) {
|
||||
case 0: return box_type (m_center, qb.upper_right ());
|
||||
case 1: return box_type (m_center, qb.upper_left ());
|
||||
case 2: return box_type (m_center, qb.lower_left ());
|
||||
case 3: return box_type (m_center, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
box_tree_node *mp_parent;
|
||||
size_t m_lenq [5];
|
||||
box_tree_node *mp_children [4];
|
||||
point_type m_center;
|
||||
size_t m_lenq, m_len;
|
||||
size_t m_childrefs [4];
|
||||
point_type m_center, m_corner;
|
||||
|
||||
box_tree_node (const box_tree_node &d);
|
||||
box_tree_node &operator= (const box_tree_node &d);
|
||||
|
||||
box_tree_node (box_tree_node *parent, const point_type ¢er, const point_type &corner, unsigned int quad)
|
||||
{
|
||||
init (parent, center, corner, quad);
|
||||
}
|
||||
|
||||
void init (box_tree_node *parent, const point_type ¢er, const point_type &corner, unsigned int quad)
|
||||
{
|
||||
m_center = center;
|
||||
m_corner = corner;
|
||||
|
||||
m_lenq = m_len = 0;
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
m_childrefs [i] = 0;
|
||||
}
|
||||
|
||||
mp_parent = (box_tree_node *)((char *) parent + quad);
|
||||
if (parent) {
|
||||
m_len = (parent->m_childrefs [quad] >> 1);
|
||||
parent->m_childrefs [quad] = size_t (this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -459,28 +522,9 @@ public:
|
|||
box_type quad_box () const
|
||||
{
|
||||
if (! mp_node) {
|
||||
|
||||
return box_type::world ();
|
||||
|
||||
} else {
|
||||
|
||||
point_type c = mp_node->center ();
|
||||
box_type qb;
|
||||
if (! mp_node->parent ()) {
|
||||
qb = box_type::world ();
|
||||
} else {
|
||||
point_type pc = mp_node->parent ()->center ();
|
||||
qb = box_type (c - (pc - c), pc);
|
||||
}
|
||||
|
||||
switch (m_quad) {
|
||||
case 0: return box_type (c, qb.upper_right ());
|
||||
case 1: return box_type (c, qb.upper_left ());
|
||||
case 2: return box_type (c, qb.lower_left ());
|
||||
case 3: return box_type (c, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
|
||||
return mp_node->quad_box (m_quad);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -577,12 +621,16 @@ private:
|
|||
return m_quad < 4;
|
||||
}
|
||||
|
||||
// down one level
|
||||
// down as many levels as required for the next non-empty quad
|
||||
// returns true if this is possible
|
||||
bool down ()
|
||||
{
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (c) {
|
||||
while (true) {
|
||||
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (! c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_node = c;
|
||||
m_quad = -1;
|
||||
|
|
@ -595,12 +643,11 @@ private:
|
|||
// nothing to visit: up again
|
||||
up ();
|
||||
return false;
|
||||
} else {
|
||||
} else if (m_quad < 0) {
|
||||
// stay in main chunk
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -670,7 +717,7 @@ private:
|
|||
* whose box overlaps or touches a specified test box.
|
||||
*/
|
||||
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100>
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100, unsigned int thin_aspect = 4>
|
||||
class box_tree
|
||||
{
|
||||
public:
|
||||
|
|
@ -1175,7 +1222,16 @@ private:
|
|||
|
||||
// the bins are: overall, ur, ul, ll, lr, empty
|
||||
element_iterator qloc [6] = { from, from, from, from, from, from };
|
||||
point_type center (bbox.center ());
|
||||
point_type center;
|
||||
if (bbox.width () < bbox.height () / thin_aspect) {
|
||||
// separate by height only
|
||||
center = point_type (bbox.left (), bbox.bottom () + bbox.height () / 2);
|
||||
} else if (bbox.height () < bbox.width () / thin_aspect) {
|
||||
// separate by width only
|
||||
center = point_type (bbox.left () + bbox.width () / 2, bbox.bottom ());
|
||||
} else {
|
||||
center = bbox.center ();
|
||||
}
|
||||
|
||||
for (element_iterator e = from; e != to; ++e) {
|
||||
|
||||
|
|
@ -1224,7 +1280,7 @@ private:
|
|||
if (nn >= min_quads) {
|
||||
|
||||
// create a new node representing this tree
|
||||
box_tree_node *node = new box_tree_node (parent, center, quad);
|
||||
box_tree_node *node = new box_tree_node (parent, center, bbox, quad);
|
||||
if (parent == 0) {
|
||||
mp_root = node;
|
||||
}
|
||||
|
|
@ -1460,28 +1516,9 @@ public:
|
|||
box_type quad_box () const
|
||||
{
|
||||
if (! mp_node) {
|
||||
|
||||
return box_type::world ();
|
||||
|
||||
} else {
|
||||
|
||||
point_type c = mp_node->center ();
|
||||
box_type qb;
|
||||
if (! mp_node->parent ()) {
|
||||
qb = box_type::world ();
|
||||
} else {
|
||||
point_type pc = mp_node->parent ()->center ();
|
||||
qb = box_type (c - (pc - c), pc);
|
||||
}
|
||||
|
||||
switch (m_quad) {
|
||||
case 0: return box_type (c, qb.upper_right ());
|
||||
case 1: return box_type (c, qb.upper_left ());
|
||||
case 2: return box_type (c, qb.lower_left ());
|
||||
case 3: return box_type (c, qb.lower_right ());
|
||||
default: return qb;
|
||||
}
|
||||
|
||||
return mp_node->quad_box (m_quad);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1578,12 +1615,16 @@ private:
|
|||
return m_quad < 4;
|
||||
}
|
||||
|
||||
// down one level
|
||||
// down as many levels as required for the next non-empty quad
|
||||
// returns true if this is possible
|
||||
bool down ()
|
||||
{
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (c) {
|
||||
while (true) {
|
||||
|
||||
box_tree_node *c = mp_node->child (m_quad);
|
||||
if (! c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mp_node = c;
|
||||
m_quad = -1;
|
||||
|
|
@ -1596,12 +1637,11 @@ private:
|
|||
// nothing to visit: up again
|
||||
up ();
|
||||
return false;
|
||||
} else {
|
||||
} else if (m_quad < 0) {
|
||||
// stay in main chunk
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1638,7 +1678,7 @@ private:
|
|||
* is sorted.
|
||||
*/
|
||||
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100>
|
||||
template <class Box, class Obj, class BoxConv, size_t min_bin = 100, size_t min_quads = 100, unsigned int thin_aspect = 4>
|
||||
class unstable_box_tree
|
||||
{
|
||||
public:
|
||||
|
|
@ -2103,7 +2143,16 @@ private:
|
|||
}
|
||||
|
||||
obj_iterator qloc [5] = { from, from, from, from, from };
|
||||
point_type center (bbox.center ());
|
||||
point_type center;
|
||||
if (bbox.width () < bbox.height () / thin_aspect) {
|
||||
// separate by height only
|
||||
center = point_type (bbox.left (), bbox.bottom () + bbox.height () / 2);
|
||||
} else if (bbox.height () < bbox.width () / thin_aspect) {
|
||||
// separate by width only
|
||||
center = point_type (bbox.left () + bbox.width () / 2, bbox.bottom ());
|
||||
} else {
|
||||
center = bbox.center ();
|
||||
}
|
||||
|
||||
for (obj_iterator e = from; e != to; ++e) {
|
||||
|
||||
|
|
@ -2158,7 +2207,7 @@ private:
|
|||
if (nn >= min_quads) {
|
||||
|
||||
// create a new node representing this tree
|
||||
box_tree_node *node = new box_tree_node (parent, center, quad);
|
||||
box_tree_node *node = new box_tree_node (parent, center, bbox, quad);
|
||||
if (parent == 0) {
|
||||
mp_root = node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,6 +283,12 @@ namespace std
|
|||
h = hfunc (b, h);
|
||||
h = hfunc (na, h);
|
||||
h = hfunc (nb, h);
|
||||
} else if (o.size () > 1) {
|
||||
// iterated array
|
||||
typename db::array <db::CellInst, db::simple_trans<C> >::iterator i = o.begin ();
|
||||
while (! (++i).at_end ()) {
|
||||
h = hfunc (*i, h);
|
||||
}
|
||||
}
|
||||
|
||||
if (o.is_complex ()) {
|
||||
|
|
|
|||
|
|
@ -241,16 +241,28 @@ Instance::to_string (bool resolve_cell_name) const
|
|||
r = "cell_index=" + tl::to_string (ci.object ().cell_index ());
|
||||
}
|
||||
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans ().to_string ();
|
||||
} else {
|
||||
r += " " + (*ci.begin ()).to_string ();
|
||||
}
|
||||
|
||||
db::vector<coord_type> a, b;
|
||||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans ().to_string ();
|
||||
} else {
|
||||
r += " " + (*ci.begin ()).to_string ();
|
||||
}
|
||||
|
||||
r += " array=(" + a.to_string () + "," + b.to_string () + " " + tl::to_string (amax) + "x" + tl::to_string (bmax) + ")";
|
||||
|
||||
} else {
|
||||
|
||||
for (db::CellInstArray::iterator i = ci.begin (); ! i.at_end (); ++i) {
|
||||
if (ci.is_complex ()) {
|
||||
r += " " + ci.complex_trans (*i).to_string ();
|
||||
} else {
|
||||
r += " " + (*i).to_string ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (has_prop_id ()) {
|
||||
|
|
@ -640,13 +652,12 @@ OverlappingInstanceIteratorTraits::init (instance_iterator<OverlappingInstanceIt
|
|||
// ChildCellIterator implementation
|
||||
|
||||
ChildCellIterator::ChildCellIterator ()
|
||||
: m_iter (), m_end (), mp_insts (0)
|
||||
: m_iter (), m_end ()
|
||||
{ }
|
||||
|
||||
ChildCellIterator::ChildCellIterator (const instances_type *insts)
|
||||
: m_iter (insts->begin_sorted_insts ()),
|
||||
m_end (insts->end_sorted_insts ()),
|
||||
mp_insts (insts)
|
||||
m_end (insts->end_sorted_insts ())
|
||||
{ }
|
||||
|
||||
cell_index_type
|
||||
|
|
|
|||
|
|
@ -945,7 +945,6 @@ public:
|
|||
|
||||
private:
|
||||
inst_iterator_type m_iter, m_end;
|
||||
const instances_type *mp_insts;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1189,6 +1189,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl;
|
||||
} else if (ci.size () > 1) {
|
||||
enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl;
|
||||
} else {
|
||||
enough (tl::info) << "" << tl::noendl;
|
||||
}
|
||||
|
|
@ -1208,6 +1210,8 @@ PrintingDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperti
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
enough (tl::info) << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]" << tl::noendl;
|
||||
} else if (ci.size () > 1) {
|
||||
enough (tl::info) << " (+" << (ci.size () - 1) << " irregular locations)" << tl::noendl;
|
||||
} else {
|
||||
enough (tl::info) << "" << tl::noendl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -546,9 +546,13 @@ ShapeIterator::advance_aref (int &mode)
|
|||
|
||||
if (mode && m_array_iterator_valid) {
|
||||
|
||||
if (mode > 0) {
|
||||
if (mode == 1) {
|
||||
array_iterator *arr_iter = (array_iterator *) m_ad.iter;
|
||||
++*arr_iter;
|
||||
} else if (mode == 2) {
|
||||
// skip array quad -> skip rest of array quad and move to shape in the next quad or to end
|
||||
do_skip_array_quad ();
|
||||
mode = 1;
|
||||
} else {
|
||||
// skip quad -> skip rest of array and move to next shape array
|
||||
skip_array (); // sets m_array_iterator_valid = false
|
||||
|
|
@ -810,9 +814,100 @@ ShapeIterator::quad_box () const
|
|||
return quad_box_generic<OverlappingRegionTag, db::unstable_layer_tag> ();
|
||||
}
|
||||
}
|
||||
|
||||
return db::Box ();
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
void
|
||||
ShapeIterator::do_skip_array_quad_iter ()
|
||||
{
|
||||
Iter *arr_iter = (Iter *) m_ad.iter;
|
||||
arr_iter->skip_quad ();
|
||||
}
|
||||
|
||||
void
|
||||
ShapeIterator::do_skip_array_quad ()
|
||||
{
|
||||
if (m_array_iterator_valid) {
|
||||
if (m_type == PolygonPtrArray) {
|
||||
do_skip_array_quad_iter<polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == SimplePolygonPtrArray) {
|
||||
do_skip_array_quad_iter<simple_polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == PathPtrArray) {
|
||||
do_skip_array_quad_iter<path_ptr_array_iterator_type> ();
|
||||
} else if (m_type == TextPtrArray) {
|
||||
do_skip_array_quad_iter<text_ptr_array_iterator_type> ();
|
||||
} else if (m_type == BoxArray) {
|
||||
do_skip_array_quad_iter<box_array_iterator_type> ();
|
||||
} else if (m_type == ShortBoxArray) {
|
||||
do_skip_array_quad_iter<short_box_array_iterator_type> ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iter>
|
||||
size_t
|
||||
ShapeIterator::get_array_quad_id () const
|
||||
{
|
||||
Iter *arr_iter = (Iter *) m_ad.iter;
|
||||
return arr_iter->quad_id ();
|
||||
}
|
||||
|
||||
size_t
|
||||
ShapeIterator::array_quad_id () const
|
||||
{
|
||||
if (m_array_iterator_valid) {
|
||||
if (m_type == PolygonPtrArray) {
|
||||
return get_array_quad_id<polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == SimplePolygonPtrArray) {
|
||||
return get_array_quad_id<simple_polygon_ptr_array_iterator_type> ();
|
||||
} else if (m_type == PathPtrArray) {
|
||||
return get_array_quad_id<path_ptr_array_iterator_type> ();
|
||||
} else if (m_type == TextPtrArray) {
|
||||
return get_array_quad_id<text_ptr_array_iterator_type> ();
|
||||
} else if (m_type == BoxArray) {
|
||||
return get_array_quad_id<box_array_iterator_type> ();
|
||||
} else if (m_type == ShortBoxArray) {
|
||||
return get_array_quad_id<short_box_array_iterator_type> ();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Iter, class Array>
|
||||
db::Box
|
||||
ShapeIterator::get_array_quad_box () const
|
||||
{
|
||||
const Array *arr = m_array.basic_ptr (typename Array::tag ());
|
||||
Iter *arr_iter = (Iter *) m_ad.iter;
|
||||
db::box_convert<typename Array::object_type> bc;
|
||||
return arr->quad_box (*arr_iter, bc);
|
||||
}
|
||||
|
||||
db::Box
|
||||
ShapeIterator::array_quad_box () const
|
||||
{
|
||||
if (m_array_iterator_valid) {
|
||||
if (m_type == PolygonPtrArray) {
|
||||
return get_array_quad_box<polygon_ptr_array_iterator_type, polygon_ptr_array_type> ();
|
||||
} else if (m_type == SimplePolygonPtrArray) {
|
||||
return get_array_quad_box<simple_polygon_ptr_array_iterator_type, simple_polygon_ptr_array_type> ();
|
||||
} else if (m_type == PathPtrArray) {
|
||||
return get_array_quad_box<path_ptr_array_iterator_type, path_ptr_array_type> ();
|
||||
} else if (m_type == TextPtrArray) {
|
||||
return get_array_quad_box<text_ptr_array_iterator_type, text_ptr_array_type> ();
|
||||
} else if (m_type == BoxArray) {
|
||||
return get_array_quad_box<box_array_iterator_type, box_array_type> ();
|
||||
} else if (m_type == ShortBoxArray) {
|
||||
return get_array_quad_box<short_box_array_iterator_type, short_box_array_type> ();
|
||||
}
|
||||
}
|
||||
|
||||
return db::Box::world ();
|
||||
}
|
||||
|
||||
void
|
||||
ShapeIterator::cleanup ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -319,6 +319,33 @@ public:
|
|||
advance (-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the arrays quad ID
|
||||
*
|
||||
* The arrays quad ID is a unique identifier for the current quad for iterated arrays. This can be used to
|
||||
* detect whether the iterator entered a new quad and optimize the search in that case.
|
||||
*/
|
||||
size_t array_quad_id () const;
|
||||
|
||||
/**
|
||||
* @brief Gets the quad box
|
||||
*
|
||||
* Gets the box the current quad uses. This box may be larger than the actual shape containers
|
||||
* bounding box. Specifically if there is no quad tree at all, this box is the world box.
|
||||
*/
|
||||
db::Box array_quad_box () const;
|
||||
|
||||
/**
|
||||
* @brief Skips the current quad
|
||||
*
|
||||
* Moves to the next quad. This method can be used to shortcut searching if we are inside
|
||||
* a quad that is not relevant for the search.
|
||||
*/
|
||||
void skip_array_quad ()
|
||||
{
|
||||
advance (2);
|
||||
}
|
||||
|
||||
private:
|
||||
// a helper union for the iter_size union
|
||||
// (basically computing the size required for all iterators for a certain shape/array type)
|
||||
|
|
@ -418,6 +445,12 @@ private:
|
|||
template <class Sh, class StableTag> db::Box quad_box_by_shape (OverlappingRegionTag) const;
|
||||
template <class RegionTag, class StableTag> db::Box quad_box_generic () const;
|
||||
|
||||
template <class Iter, class Array> db::Box get_array_quad_box () const;
|
||||
template <class Iter> size_t get_array_quad_id () const;
|
||||
|
||||
template <class Iter> void do_skip_array_quad_iter ();
|
||||
void do_skip_array_quad ();
|
||||
|
||||
template <class Sh, class StableTag, class RegionTag> bool advance_shape (int &mode);
|
||||
template <class Array> void init_array_iter (NoRegionTag);
|
||||
template <class Array> void init_array_iter (TouchingRegionTag);
|
||||
|
|
|
|||
|
|
@ -198,43 +198,52 @@ TextWriter::write (const db::Layout &layout)
|
|||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
|
||||
std::string pfx = "";
|
||||
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0) {
|
||||
pfx = "p $props";
|
||||
write_props (layout, inst->prop_id ());
|
||||
}
|
||||
|
||||
db::Vector a, b;
|
||||
unsigned long amax, bmax;
|
||||
|
||||
bool is_reg = inst->is_regular_array (a, b, amax, bmax);
|
||||
|
||||
*this << (is_reg ? "aref" : "sref") << pfx << " {" << layout.cell_name (inst->cell_index ()) << "}";
|
||||
for (db::CellInstArray::iterator i = inst->begin (); ! i.at_end (); ++i) {
|
||||
|
||||
db::Trans t = inst->front ();
|
||||
std::string pfx = "";
|
||||
|
||||
if (inst->has_prop_id () && inst->prop_id () != 0) {
|
||||
pfx = "p $props";
|
||||
write_props (layout, inst->prop_id ());
|
||||
}
|
||||
|
||||
*this << (is_reg ? "aref" : "sref") << pfx << " {" << layout.cell_name (inst->cell_index ()) << "}";
|
||||
|
||||
db::Trans t = *i;
|
||||
|
||||
if (inst->is_complex ()) {
|
||||
db::CellInstArray::complex_trans_type ct = inst->complex_trans (t);
|
||||
*this << " " << ct.angle ();
|
||||
*this << " " << (ct.is_mirror () ? 1 : 0);
|
||||
*this << " " << ct.mag ();
|
||||
} else {
|
||||
*this << " " << (t.rot () % 4) * 90.0;
|
||||
*this << " " << (t.is_mirror () ? 1 : 0);
|
||||
*this << " " << 1.0;
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
*this << " " << int (std::max ((unsigned long) 1, amax));
|
||||
*this << " " << int (std::max ((unsigned long) 1, bmax));
|
||||
}
|
||||
*this << " " << t.disp ();
|
||||
if (is_reg) {
|
||||
*this << " " << (t.disp () + a * (long) amax);
|
||||
*this << " " << (t.disp () + b * (long) bmax);
|
||||
}
|
||||
*this << endl ();
|
||||
|
||||
if (is_reg) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (inst->is_complex ()) {
|
||||
*this << " " << inst->complex_trans ().angle ();
|
||||
*this << " " << (inst->complex_trans ().is_mirror () ? 1 : 0);
|
||||
*this << " " << inst->complex_trans ().mag ();
|
||||
} else {
|
||||
*this << " " << (t.rot () % 4) * 90.0;
|
||||
*this << " " << (t.is_mirror () ? 1 : 0);
|
||||
*this << " " << 1.0;
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
*this << " " << int (std::max ((unsigned long) 1, amax));
|
||||
*this << " " << int (std::max ((unsigned long) 1, bmax));
|
||||
}
|
||||
*this << " " << t.disp ();
|
||||
if (is_reg) {
|
||||
*this << " " << (t.disp () + a * (long) amax);
|
||||
*this << " " << (t.disp () + b * (long) bmax);
|
||||
}
|
||||
*this << endl ();
|
||||
|
||||
}
|
||||
|
||||
end_sorted_section ();
|
||||
|
|
|
|||
|
|
@ -251,6 +251,8 @@ struct cell_inst_array_defs
|
|||
unsigned long na = 1, nb = 1;
|
||||
if (arr->is_regular_array (a, b, na, nb)) {
|
||||
*arr = C (arr->object (), t, a, b, na, nb);
|
||||
} else if (arr->is_iterated_array ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Can't set the transformation on an iterated array (layout not editable?)")));
|
||||
} else {
|
||||
*arr = C (arr->object (), t);
|
||||
}
|
||||
|
|
@ -262,6 +264,8 @@ struct cell_inst_array_defs
|
|||
unsigned long na = 1, nb = 1;
|
||||
if (arr->is_regular_array (a, b, na, nb)) {
|
||||
*arr = C (arr->object (), t, a, b, na, nb);
|
||||
} else if (arr->is_iterated_array ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Can't set the transformation on an iterated array (layout not editable?)")));
|
||||
} else {
|
||||
*arr = C (arr->object (), t);
|
||||
}
|
||||
|
|
@ -292,6 +296,8 @@ struct cell_inst_array_defs
|
|||
s += "*";
|
||||
s += tl::to_string (nb);
|
||||
s += "]";
|
||||
} else if (arr->size () > 1) {
|
||||
s += std::string (" (+") + tl::to_string (arr->size () - 1) + " irregular locations)";
|
||||
}
|
||||
|
||||
return s;
|
||||
|
|
@ -303,14 +309,27 @@ struct cell_inst_array_defs
|
|||
{
|
||||
typedef db::array<db::CellInst, db::simple_trans<typename T::target_coord_type> > target_array;
|
||||
|
||||
std::vector<typename C::vector_type> iterated;
|
||||
std::vector<typename target_array::vector_type> iterated_transformed;
|
||||
typename C::vector_type a, b;
|
||||
unsigned long amax = 0, bmax = 0;
|
||||
|
||||
if (arr.is_regular_array (a, b, amax, bmax)) {
|
||||
if (arr.is_complex ()) {
|
||||
return target_array (arr.object (), t * arr.complex_trans () * t.inverted (), t * a, t * b, amax, bmax);
|
||||
} else {
|
||||
return target_array (arr.object (), typename target_array::trans_type (t * typename C::complex_trans_type (arr.front ()) * t.inverted ()), t * a, t * b, amax, bmax);
|
||||
}
|
||||
} else if (arr.is_iterated_array (&iterated)) {
|
||||
iterated_transformed.reserve (iterated.size ());
|
||||
for (typename std::vector<typename C::vector_type>::const_iterator i = iterated.begin (); i != iterated.end (); ++i) {
|
||||
iterated_transformed.push_back (t * *i);
|
||||
}
|
||||
if (arr.is_complex ()) {
|
||||
return target_array (arr.object (), t * arr.complex_trans () * t.inverted (), iterated_transformed.begin (), iterated_transformed.end ());
|
||||
} else {
|
||||
return target_array (arr.object (), typename target_array::trans_type (t * typename C::complex_trans_type (arr.front ()) * t.inverted ()), iterated_transformed.begin (), iterated_transformed.end ());
|
||||
}
|
||||
} else if (arr.is_complex ()) {
|
||||
return target_array (arr.object (), t * arr.complex_trans () * t.inverted ());
|
||||
} else {
|
||||
|
|
@ -352,93 +371,17 @@ struct cell_inst_array_defs
|
|||
|
||||
static bool less (const C *i, const C &other)
|
||||
{
|
||||
if (i->object ().cell_index () != other.object ().cell_index ()) {
|
||||
return i->object ().cell_index () < other.object ().cell_index ();
|
||||
}
|
||||
|
||||
db::vector<coord_type> a, b;
|
||||
unsigned long na = 1, nb = 1;
|
||||
bool r = i->is_regular_array (a, b, na, nb);
|
||||
|
||||
db::vector<coord_type> aother, bother;
|
||||
unsigned long naother = 1, nbother = 1;
|
||||
bool rother = other.is_regular_array (aother, bother, naother, nbother);
|
||||
|
||||
if (r != rother) {
|
||||
return r < rother;
|
||||
} else if (r) {
|
||||
if (a.not_equal (aother)) {
|
||||
return a.less (aother);
|
||||
}
|
||||
if (b.not_equal (bother)) {
|
||||
return b.less (bother);
|
||||
}
|
||||
if (na != naother) {
|
||||
return na < naother;
|
||||
}
|
||||
if (nb != nbother) {
|
||||
return nb < nbother;
|
||||
}
|
||||
}
|
||||
|
||||
bool c = i->is_complex ();
|
||||
bool cother = other.is_complex ();
|
||||
|
||||
if (c != cother) {
|
||||
return c < cother;
|
||||
} else if (c) {
|
||||
return i->complex_trans ().less (other.complex_trans ());
|
||||
} else {
|
||||
return i->front ().less (other.front ());
|
||||
}
|
||||
return i->less (other);
|
||||
}
|
||||
|
||||
static bool equal (const C *i, const C &other)
|
||||
{
|
||||
if (i->object ().cell_index () != other.object ().cell_index ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
db::vector<coord_type> a, b;
|
||||
unsigned long na = 1, nb = 1;
|
||||
bool r = i->is_regular_array (a, b, na, nb);
|
||||
|
||||
db::vector<coord_type> aother, bother;
|
||||
unsigned long naother = 1, nbother = 1;
|
||||
bool rother = other.is_regular_array (aother, bother, naother, nbother);
|
||||
|
||||
if (r != rother) {
|
||||
return false;
|
||||
} else if (r) {
|
||||
if (a.not_equal (aother)) {
|
||||
return false;
|
||||
}
|
||||
if (b.not_equal (bother)) {
|
||||
return false;
|
||||
}
|
||||
if (na != naother) {
|
||||
return false;
|
||||
}
|
||||
if (nb != nbother) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool c = i->is_complex ();
|
||||
bool cother = other.is_complex ();
|
||||
|
||||
if (c != cother) {
|
||||
return false;
|
||||
} else if (c) {
|
||||
return i->complex_trans ().equal (other.complex_trans ());
|
||||
} else {
|
||||
return i->front ().equal (other.front ());
|
||||
}
|
||||
return i->equal (other);
|
||||
}
|
||||
|
||||
static bool not_equal (const C *i, const C &other)
|
||||
{
|
||||
return ! equal (i, other);
|
||||
return ! i->equal (other);
|
||||
}
|
||||
|
||||
static gsi::Methods methods (bool new_doc)
|
||||
|
|
@ -508,7 +451,9 @@ struct cell_inst_array_defs
|
|||
) +
|
||||
gsi::method ("size", &C::size,
|
||||
"@brief Gets the number of single instances in the array\n"
|
||||
"If the instance represents a single instance, the count is 1. Otherwise it is na*nb."
|
||||
"If the instance represents a single instance, the count is 1. Otherwise it is na*nb. "
|
||||
"Starting with version 0.27, there may be iterated instances for which the size is larger than 1, but \\is_regular_array? will return false. "
|
||||
"In this case, use \\each_trans or \\each_cplx_trans to retrieve the individual placements of the iterated instance."
|
||||
) +
|
||||
gsi::method_ext ("cell_index", &cell_index,
|
||||
"@brief Gets the cell index of the cell instantiated \n"
|
||||
|
|
|
|||
|
|
@ -1031,4 +1031,92 @@ TEST(6U)
|
|||
|
||||
}
|
||||
|
||||
TEST(7)
|
||||
{
|
||||
Box2Box conv;
|
||||
TestTree t;
|
||||
|
||||
int n = 200000;
|
||||
|
||||
for (int i = n - 1; i >= 0; --i) {
|
||||
t.insert (db::Box (i * 10, 0, i * 10 + 5, 5));
|
||||
}
|
||||
t.sort (conv);
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7 lookup");
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 2000; ++i) {
|
||||
db::Coord sx = 0, sy = 0;
|
||||
TestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (2000, 0), db::Point (3000, 0)), conv);
|
||||
while (!it.at_end ()) {
|
||||
sx += abs (it->left ());
|
||||
sy += abs (it->bottom ());
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
EXPECT_EQ (sx, 252500);
|
||||
EXPECT_EQ (sy, 0);
|
||||
}
|
||||
EXPECT_EQ (n, size_t (101 * 2000));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7 traverse");
|
||||
db::Coord m = std::numeric_limits<db::Coord>::max ();
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
TestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (-m,-m), db::Point (m, m)), conv);
|
||||
while (!it.at_end ()) {
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ (n, t.size () * 10);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(7U)
|
||||
{
|
||||
Box2Box conv;
|
||||
UnstableTestTree t;
|
||||
|
||||
int n = 200000;
|
||||
|
||||
for (int i = n - 1; i >= 0; --i) {
|
||||
t.insert (db::Box (i * 10, 0, i * 10 + 5, 5));
|
||||
}
|
||||
t.sort (conv);
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7U lookup");
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 2000; ++i) {
|
||||
db::Coord sx = 0, sy = 0;
|
||||
UnstableTestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (2000, 0), db::Point (3000, 0)), conv);
|
||||
while (!it.at_end ()) {
|
||||
sx += abs (it->left ());
|
||||
sy += abs (it->bottom ());
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
EXPECT_EQ (sx, 252500);
|
||||
EXPECT_EQ (sy, 0);
|
||||
}
|
||||
EXPECT_EQ (n, size_t (101 * 2000));
|
||||
}
|
||||
|
||||
{
|
||||
tl::SelfTimer timer ("test 7U traverse");
|
||||
db::Coord m = std::numeric_limits<db::Coord>::max ();
|
||||
size_t n = 0;
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
UnstableTestTree::touching_iterator it = t.begin_touching (db::Box (db::Point (-m,-m), db::Point (m, m)), conv);
|
||||
while (!it.at_end ()) {
|
||||
++it;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ (n, t.size () * 10);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties &
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
m_os << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]";
|
||||
} else if (ci.size () > 1) {
|
||||
m_os << " (+" << (ci.size () - 1) << " irregular placements)";
|
||||
}
|
||||
if (ci.properties_id () != 0) {
|
||||
m_os << " [" << ci.properties_id () << "]" << std::endl;
|
||||
|
|
@ -112,6 +114,8 @@ TestDifferenceReceiver::print_cell_inst (const db::CellInstArrayWithProperties &
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
m_os << "[a=" << a.to_string () << ", b=" << b.to_string () << ", na=" << amax << ", nb=" << bmax << "]";
|
||||
} else if (ci.size () > 1) {
|
||||
m_os << " (+" << (ci.size () - 1) << " irregular placements)";
|
||||
}
|
||||
if (ci.properties_id () != 0) {
|
||||
m_os << " [" << ci.properties_id () << "]" << std::endl;
|
||||
|
|
|
|||
|
|
@ -702,7 +702,15 @@ BrowseInstancesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Lay
|
|||
|
||||
std::string aref;
|
||||
if (r > 1 || c > 1) {
|
||||
aref = tl::sprintf ("[%ld,%ld]", c, r);
|
||||
aref = "[";
|
||||
aref += tl::to_string (c);
|
||||
aref += ",";
|
||||
aref += tl::to_string (r);
|
||||
aref += "]";
|
||||
} else if (parent_inst.size () > 1) {
|
||||
aref = "(+";
|
||||
aref += tl::to_string (parent_inst.size () - 1);
|
||||
aref += "x)";
|
||||
}
|
||||
|
||||
std::string new_path;
|
||||
|
|
|
|||
|
|
@ -868,7 +868,15 @@ BrowseShapesForm::fill_cell_instances (const db::ICplxTrans &t, const db::Layout
|
|||
|
||||
std::string aref;
|
||||
if (r > 1 || c > 1) {
|
||||
aref = tl::sprintf ("[%ld,%ld]", c, r);
|
||||
aref = "[";
|
||||
aref += tl::to_string (c);
|
||||
aref += ",";
|
||||
aref += tl::to_string (r);
|
||||
aref += "]";
|
||||
} else if (parent_inst.size () > 1) {
|
||||
aref = "(+";
|
||||
aref += tl::to_string (parent_inst.size () - 1);
|
||||
aref += "x)";
|
||||
}
|
||||
|
||||
std::string new_path;
|
||||
|
|
|
|||
|
|
@ -809,15 +809,31 @@ RedrawThreadWorker::draw_boxes (bool drawing_context, db::cell_index_type ci, co
|
|||
|
||||
} else {
|
||||
|
||||
// The array (or single instance) must be iterated instance
|
||||
// by instance
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) {
|
||||
size_t qid = 0;
|
||||
|
||||
// The array (or single instance) must be iterated instance by instance
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) {
|
||||
|
||||
test_snapshot (0);
|
||||
db::ICplxTrans t (cell_inst.complex_trans (*p));
|
||||
db::Box new_vp = db::Box (t.inverted () * *v);
|
||||
draw_boxes (drawing_context, new_ci, trans * t, new_vp, level + 1);
|
||||
|
||||
if (p.quad_id () > 0 && p.quad_id () != qid) {
|
||||
|
||||
qid = p.quad_id ();
|
||||
|
||||
// if the quad is very small we don't gain anything from looking further into the quad - skip this one
|
||||
db::DBox qb = trans * cell_inst.quad_box (p, bc);
|
||||
if (qb.width () < 1.0 && qb.height () < 1.0) {
|
||||
p.skip_quad ();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++p;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -986,7 +1002,6 @@ RedrawThreadWorker::draw_box_properties (bool drawing_context, db::cell_index_ty
|
|||
++inst;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1582,6 +1597,8 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
db::Shape last_array;
|
||||
|
||||
size_t current_quad_id = 0;
|
||||
size_t current_array_quad_id = 0;
|
||||
|
||||
db::ShapeIterator shape (shapes.begin_touching (*v, db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::Paths, mp_prop_sel, m_inv_prop_sel));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
|
|
@ -1596,16 +1613,18 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
}
|
||||
|
||||
if (skip) {
|
||||
|
||||
shape.skip_quad ();
|
||||
continue;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (shape.in_array ()) {
|
||||
|
||||
bool simplified = false;
|
||||
|
||||
if (shape.in_array () && last_array != shape.array ()) {
|
||||
if (last_array != shape.array ()) {
|
||||
|
||||
last_array = shape.array ();
|
||||
current_array_quad_id = 0;
|
||||
|
||||
bool simplified = false;
|
||||
|
||||
if (last_array.type () == db::Shape::PolygonPtrArray) {
|
||||
simplified = draw_array_simplified<db::Shape::polygon_ptr_array_type> (mp_renderer.get (), last_array, frame, vertex, trans);
|
||||
|
|
@ -1619,17 +1638,42 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
simplified = draw_array_simplified<db::Shape::short_box_array_type> (mp_renderer.get (), last_array, frame, vertex, trans);
|
||||
}
|
||||
|
||||
if (simplified) {
|
||||
shape.finish_array ();
|
||||
// continue with the next shape, array or quad
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (simplified) {
|
||||
shape.finish_array ();
|
||||
} else {
|
||||
mp_renderer->draw (*shape, trans, fill, frame, vertex, text);
|
||||
++shape;
|
||||
} else {
|
||||
current_array_quad_id = 0;
|
||||
}
|
||||
|
||||
// try whether the array quad can be simplified
|
||||
|
||||
size_t aqid = shape.array_quad_id ();
|
||||
if (aqid != 0 && aqid != current_array_quad_id) {
|
||||
|
||||
current_array_quad_id = aqid;
|
||||
|
||||
db::DBox qbbox = trans * shape.array_quad_box ();
|
||||
if (qbbox.width () < 1.5 && qbbox.height () < 1.5) {
|
||||
|
||||
// draw a single box instead of the quad
|
||||
mp_renderer->draw (qbbox, fill, frame, vertex, text);
|
||||
shape.skip_array_quad ();
|
||||
|
||||
// continue with the next shape, array or quad
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mp_renderer->draw (*shape, trans, fill, frame, vertex, text);
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1727,7 +1771,9 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
|
||||
} else if (anything) {
|
||||
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ++p) {
|
||||
size_t qid = 0;
|
||||
|
||||
for (db::CellInstArray::iterator p = cell_inst.begin_touching (*v, bc); ! p.at_end (); ) {
|
||||
|
||||
if (! m_draw_array_border_instances ||
|
||||
p.index_a () <= 0 || (unsigned long)p.index_a () == amax - 1 || p.index_b () <= 0 || (unsigned long)p.index_b () == bmax - 1) {
|
||||
|
|
@ -1736,6 +1782,21 @@ RedrawThreadWorker::draw_layer_wo_cache (int from_level, int to_level, db::cell_
|
|||
db::Box new_vp = db::Box (t.inverted () * *v);
|
||||
draw_layer (from_level, to_level, new_ci, trans * t, new_vp, level + 1, fill, frame, vertex, text, update_snapshot);
|
||||
|
||||
if (p.quad_id () > 0 && p.quad_id () != qid) {
|
||||
|
||||
qid = p.quad_id ();
|
||||
|
||||
// if the quad is very small we don't gain anything from looking further into the quad - skip this one
|
||||
db::DBox qb = trans * cell_inst.quad_box (p, bc);
|
||||
if (qb.width () < 1.0 && qb.height () < 1.0) {
|
||||
p.skip_quad ();
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
++p;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -354,120 +354,130 @@ GDS2WriterBase::write_inst (double sf, const db::Instance &instance, bool normal
|
|||
|
||||
bool is_reg = instance.is_regular_array (a, b, amax, bmax);
|
||||
|
||||
db::Trans t = instance.front ();
|
||||
for (db::CellInstArray::iterator ii = instance.begin (); ! ii.at_end (); ++ii) {
|
||||
|
||||
if (normalize) {
|
||||
db::Trans t = *ii;
|
||||
|
||||
// try to normalize orthogonal arrays into "Cadence notation", that is
|
||||
// column and row vectors are positive in the coordinate system of the
|
||||
// rotated array.
|
||||
|
||||
if (is_reg) {
|
||||
if (normalize) {
|
||||
|
||||
if (amax < 2) {
|
||||
a = db::Vector ();
|
||||
}
|
||||
if (bmax < 2) {
|
||||
b = db::Vector ();
|
||||
}
|
||||
// try to normalize orthogonal arrays into "Cadence notation", that is
|
||||
// column and row vectors are positive in the coordinate system of the
|
||||
// rotated array.
|
||||
|
||||
// normalisation only works for orthogonal vectors, parallel to x or y axis, which are not parallel
|
||||
if ((a.x () == 0 || a.y () == 0) && (b.x () == 0 || b.y () == 0) && !((a.x () != 0 && b.x () != 0) || (a.y () != 0 && b.y () != 0))) {
|
||||
|
||||
db::FTrans fp = db::FTrans(t.rot ()).inverted ();
|
||||
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
if (is_reg) {
|
||||
|
||||
db::Vector p;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (amax < 2) {
|
||||
a = db::Vector ();
|
||||
}
|
||||
if (bmax < 2) {
|
||||
b = db::Vector ();
|
||||
}
|
||||
|
||||
db::Vector *q = (i == 0) ? &a : &b;
|
||||
unsigned long n = (i == 0) ? amax : bmax;
|
||||
// normalisation only works for orthogonal vectors, parallel to x or y axis, which are not parallel
|
||||
if ((a.x () == 0 || a.y () == 0) && (b.x () == 0 || b.y () == 0) && !((a.x () != 0 && b.x () != 0) || (a.y () != 0 && b.y () != 0))) {
|
||||
|
||||
db::FTrans fp = db::FTrans(t.rot ()).inverted ();
|
||||
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
|
||||
db::Vector p;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
|
||||
db::Vector *q = (i == 0) ? &a : &b;
|
||||
unsigned long n = (i == 0) ? amax : bmax;
|
||||
|
||||
if (n == 0) {
|
||||
*q = db::Vector ();
|
||||
} else {
|
||||
if (q->x () < 0) {
|
||||
p += db::Vector ((n - 1) * q->x (), 0);
|
||||
q->set_x (-q->x ());
|
||||
}
|
||||
if (q->y () < 0) {
|
||||
p += db::Vector (0, (n - 1) * q->y ());
|
||||
q->set_y (-q->y ());
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
*q = db::Vector ();
|
||||
} else {
|
||||
if (q->x () < 0) {
|
||||
p += db::Vector ((n - 1) * q->x (), 0);
|
||||
q->set_x (-q->x ());
|
||||
}
|
||||
if (q->y () < 0) {
|
||||
p += db::Vector (0, (n - 1) * q->y ());
|
||||
q->set_y (-q->y ());
|
||||
}
|
||||
}
|
||||
|
||||
if (a.x () != 0 || b.y () != 0) {
|
||||
std::swap (a, b);
|
||||
std::swap (amax, bmax);
|
||||
}
|
||||
|
||||
fp = db::FTrans (t.rot ());
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
|
||||
t = t * db::Trans (p);
|
||||
|
||||
}
|
||||
|
||||
if (a.x () != 0 || b.y () != 0) {
|
||||
std::swap (a, b);
|
||||
std::swap (amax, bmax);
|
||||
}
|
||||
|
||||
fp = db::FTrans (t.rot ());
|
||||
a.transform (fp);
|
||||
b.transform (fp);
|
||||
|
||||
t = t * db::Trans (p);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
write_record_size (4);
|
||||
write_record (is_reg ? sAREF : sSREF);
|
||||
|
||||
write_record_size (4);
|
||||
write_record (is_reg ? sAREF : sSREF);
|
||||
write_string_record (sSNAME, m_cell_name_map.cell_name (instance.cell_index ()));
|
||||
|
||||
write_string_record (sSNAME, m_cell_name_map.cell_name (instance.cell_index ()));
|
||||
if (t.rot () != 0 || instance.is_complex ()) {
|
||||
|
||||
if (t.rot () != 0 || instance.is_complex ()) {
|
||||
write_record_size (6);
|
||||
write_record (sSTRANS);
|
||||
write_short (t.is_mirror () ? 0x8000 : 0);
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sSTRANS);
|
||||
write_short (t.is_mirror () ? 0x8000 : 0);
|
||||
|
||||
if (instance.is_complex ()) {
|
||||
write_record_size (4 + 8);
|
||||
write_record (sMAG);
|
||||
write_double (instance.complex_trans ().mag ());
|
||||
write_record_size (4 + 8);
|
||||
write_record (sANGLE);
|
||||
write_double (instance.complex_trans ().angle ());
|
||||
} else {
|
||||
if ((t.rot () % 4) != 0) {
|
||||
if (instance.is_complex ()) {
|
||||
db::CellInstArray::complex_trans_type ct = instance.complex_trans (t);
|
||||
write_record_size (4 + 8);
|
||||
write_record (sMAG);
|
||||
write_double (ct.mag ());
|
||||
write_record_size (4 + 8);
|
||||
write_record (sANGLE);
|
||||
write_double ((t.rot () % 4) * 90.0);
|
||||
write_double (ct.angle ());
|
||||
} else {
|
||||
if ((t.rot () % 4) != 0) {
|
||||
write_record_size (4 + 8);
|
||||
write_record (sANGLE);
|
||||
write_double ((t.rot () % 4) * 90.0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
write_record_size (4 + 2 * 2);
|
||||
write_record (sCOLROW);
|
||||
if (amax > 32767 || bmax > 32767) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot write array references with more than 32767 columns or rows to GDS2 streams")));
|
||||
}
|
||||
write_short (std::max ((unsigned long) 1, bmax));
|
||||
write_short (std::max ((unsigned long) 1, amax));
|
||||
}
|
||||
|
||||
write_record_size (4 + (is_reg ? 3 : 1) * 2 * 4);
|
||||
write_record (sXY);
|
||||
write_int (scale (sf, t.disp ().x ()));
|
||||
write_int (scale (sf, t.disp ().y ()));
|
||||
|
||||
if (is_reg) {
|
||||
write_int (scale (sf, t.disp ().x () + b.x () * bmax));
|
||||
write_int (scale (sf, t.disp ().y () + b.y () * bmax));
|
||||
write_int (scale (sf, t.disp ().x () + a.x () * amax));
|
||||
write_int (scale (sf, t.disp ().y () + a.y () * amax));
|
||||
}
|
||||
|
||||
finish (layout, prop_id);
|
||||
|
||||
if (is_reg) {
|
||||
// we have already written all instances
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is_reg) {
|
||||
write_record_size (4 + 2 * 2);
|
||||
write_record (sCOLROW);
|
||||
if (amax > 32767 || bmax > 32767) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot write array references with more than 32767 columns or rows to GDS2 streams")));
|
||||
}
|
||||
write_short (std::max ((unsigned long) 1, bmax));
|
||||
write_short (std::max ((unsigned long) 1, amax));
|
||||
}
|
||||
|
||||
write_record_size (4 + (is_reg ? 3 : 1) * 2 * 4);
|
||||
write_record (sXY);
|
||||
write_int (scale (sf, t.disp ().x ()));
|
||||
write_int (scale (sf, t.disp ().y ()));
|
||||
|
||||
if (is_reg) {
|
||||
write_int (scale (sf, t.disp ().x () + b.x () * bmax));
|
||||
write_int (scale (sf, t.disp ().y () + b.y () * bmax));
|
||||
write_int (scale (sf, t.disp ().x () + a.x () * amax));
|
||||
write_int (scale (sf, t.disp ().y () + a.y () * amax));
|
||||
}
|
||||
|
||||
finish (layout, prop_id);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -2018,6 +2018,8 @@ OASISReader::do_read_placement (unsigned char r,
|
|||
|
||||
db::Vector pos (mm_placement_x.get (), mm_placement_y.get ());
|
||||
|
||||
const std::vector<db::Vector> *points = 0;
|
||||
|
||||
if ((m & 0x8) && read_repetition ()) {
|
||||
|
||||
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
||||
|
|
@ -2042,6 +2044,42 @@ OASISReader::do_read_placement (unsigned char r,
|
|||
instances.push_back (inst);
|
||||
}
|
||||
|
||||
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
||||
|
||||
db::CellInstArray inst;
|
||||
|
||||
if (mag_set || angle < 0) {
|
||||
|
||||
db::ICplxTrans ct (mag, angle_deg, mirror, pos);
|
||||
|
||||
db::CellInstArray::iterated_complex_array_type array (ct.rcos (), ct.mag ());
|
||||
array.reserve (points->size () + 1);
|
||||
array.insert (db::Vector ());
|
||||
array.insert (points->begin (), points->end ());
|
||||
array.sort ();
|
||||
|
||||
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
||||
db::Trans (ct), layout.array_repository ().insert (array));
|
||||
|
||||
} else {
|
||||
|
||||
db::CellInstArray::iterated_array_type array;
|
||||
array.reserve (points->size () + 1);
|
||||
array.insert (db::Vector ());
|
||||
array.insert (points->begin (), points->end ());
|
||||
array.sort ();
|
||||
|
||||
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
||||
db::Trans (angle, mirror, pos), layout.array_repository ().insert (array));
|
||||
|
||||
}
|
||||
|
||||
if (pp.first) {
|
||||
instances_with_props.push_back (db::CellInstArrayWithProperties (inst, pp.second));
|
||||
} else {
|
||||
instances.push_back (inst);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
RepetitionIterator p = mm_repetition.get ().begin ();
|
||||
|
|
|
|||
|
|
@ -1965,11 +1965,35 @@ OASISWriter::write (const db::CellInstArray &inst, db::properties_id_type prop_i
|
|||
{
|
||||
m_progress.set (mp_stream->pos ());
|
||||
|
||||
std::vector<db::Vector> pts;
|
||||
db::Vector a, b;
|
||||
unsigned long amax, bmax;
|
||||
bool is_reg = inst.is_regular_array (a, b, amax, bmax);
|
||||
|
||||
if (is_reg && (amax > 1 || bmax > 1)) {
|
||||
if (inst.is_iterated_array (&pts) && pts.size () > 1) {
|
||||
|
||||
// Remove the first point which is implicitly contained in the repetition
|
||||
// Note: we can do so because below we instantiate the shape at the front of the array which includes
|
||||
// the first transformation already.
|
||||
db::Vector po = pts.front ();
|
||||
std::vector<db::Vector>::iterator pw = pts.begin();
|
||||
for (std::vector<db::Vector>::iterator p = pw + 1; p != pts.end (); ++p) {
|
||||
*pw++ = *p - po;
|
||||
}
|
||||
pts.erase (pw, pts.end ());
|
||||
|
||||
db::IrregularRepetition *rep_base = new db::IrregularRepetition ();
|
||||
rep_base->points ().swap (pts);
|
||||
db::Repetition array_rep (rep_base);
|
||||
|
||||
if (rep != db::Repetition ()) {
|
||||
for (db::RepetitionIterator r = rep.begin (); ! r.at_end (); ++r) {
|
||||
write_inst_with_rep (inst, prop_id, *r, array_rep);
|
||||
}
|
||||
} else {
|
||||
write_inst_with_rep (inst, prop_id, db::Vector (), array_rep);
|
||||
}
|
||||
|
||||
} else if (inst.is_regular_array (a, b, amax, bmax) && (amax > 1 || bmax > 1)) {
|
||||
|
||||
// we cannot use the repetition - instead we write every single instance and use the repetition
|
||||
// for the array information
|
||||
|
|
|
|||
|
|
@ -224,6 +224,10 @@ RdbDifferenceReceiver::produce_cell_inst (const db::CellInstArrayWithProperties
|
|||
unsigned long amax, bmax;
|
||||
if (ci.is_regular_array (a, b, amax, bmax)) {
|
||||
r += tl::sprintf (" [a=%s, b=%s, na=%ld, nb=%ld]", a.to_string (), b.to_string (), amax, bmax);
|
||||
} else if (ci.size () > 1) {
|
||||
r += " (+";
|
||||
r += tl::to_string (ci.size () - 1);
|
||||
r += " irregular placements)";
|
||||
}
|
||||
|
||||
item->add_value (r);
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ bool TestBase::do_test (bool editable, bool slow)
|
|||
{
|
||||
m_editable = editable;
|
||||
m_slow = slow;
|
||||
m_any_failed = false;
|
||||
|
||||
// Ensures the test temp directory is present
|
||||
std::string tmpdir = tl::combine_path (tl::absolute_file_path (testtmp ()), m_testdir);
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ class DBCellInst_TestClass < TestBase
|
|||
assert_equal(at.trans.to_s, "r90 0,0")
|
||||
assert_equal(at.cplx_trans.to_s, "r135 *1 0,0")
|
||||
|
||||
assert_equal(at < a, true)
|
||||
assert_equal(at < a, false)
|
||||
assert_equal(at < atdup, false)
|
||||
assert_equal(a < at, false)
|
||||
assert_equal(a < at, true)
|
||||
assert_equal(atdup < at, false)
|
||||
assert_equal(a != at, true)
|
||||
assert_equal(a == at, false)
|
||||
|
|
@ -143,9 +143,9 @@ class DBCellInst_TestClass < TestBase
|
|||
assert_equal(at.cplx_trans.to_s, "r135 *1 0,0")
|
||||
assert_equal(at.to_s, "#0 r135 *1 0,0 [-20,10*3;-40,30*5]")
|
||||
|
||||
assert_equal(at < a, true)
|
||||
assert_equal(at < a, false)
|
||||
assert_equal(at < atdup, false)
|
||||
assert_equal(a < at, false)
|
||||
assert_equal(a < at, true)
|
||||
assert_equal(atdup < at, false)
|
||||
assert_equal(a != at, true)
|
||||
assert_equal(a == at, false)
|
||||
|
|
@ -210,9 +210,9 @@ class DBCellInst_TestClass < TestBase
|
|||
assert_equal(at.trans.to_s, "r90 0,0")
|
||||
assert_equal(at.cplx_trans.to_s, "r135 *1 0,0")
|
||||
|
||||
assert_equal(at < a, true)
|
||||
assert_equal(at < a, false)
|
||||
assert_equal(at < atdup, false)
|
||||
assert_equal(a < at, false)
|
||||
assert_equal(a < at, true)
|
||||
assert_equal(atdup < at, false)
|
||||
assert_equal(a != at, true)
|
||||
assert_equal(a == at, false)
|
||||
|
|
@ -272,9 +272,9 @@ class DBCellInst_TestClass < TestBase
|
|||
assert_equal(at.cplx_trans.to_s, "r135 *1 0,0")
|
||||
assert_equal(at.to_s, "#0 r135 *1 0,0 [-20,10*3;-40,30*5]")
|
||||
|
||||
assert_equal(at < a, true)
|
||||
assert_equal(at < a, false)
|
||||
assert_equal(at < atdup, false)
|
||||
assert_equal(a < at, false)
|
||||
assert_equal(a < at, true)
|
||||
assert_equal(atdup < at, false)
|
||||
assert_equal(a != at, true)
|
||||
assert_equal(a == at, false)
|
||||
|
|
|
|||
Loading…
Reference in New Issue