Introducing iterated arrays for instances

Iterated instances are created for OASIS files
using irregular repetitions in viewer mode.

Reason: this way, the same drawing optimization
than for iterated shape arrays can be applied.

As this is a new API feature, some adjustments
had to be made to incorporate them into the
code.
This commit is contained in:
Matthias Koefferlein 2020-06-04 12:17:34 +02:00
parent 9c4648a5b5
commit 999c065262
15 changed files with 342 additions and 211 deletions

View File

@ -1641,6 +1641,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
*

View File

@ -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 ()) {

View File

@ -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 ()) {

View File

@ -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;
}

View File

@ -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 ();

View File

@ -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,88 +371,12 @@ 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 < 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 == other;
}
static bool not_equal (const C *i, const C &other)
@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}
}
@ -1756,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) {
@ -1765,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;
}
}

View File

@ -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

View File

@ -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 ();

View File

@ -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

View File

@ -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);

View File

@ -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);