WIP: property collection in net clusters, more tests.

This commit is contained in:
Matthias Koefferlein 2018-12-09 23:24:32 +01:00
parent eb8abaf5a5
commit ef0e0d38c2
9 changed files with 554 additions and 45 deletions

View File

@ -156,6 +156,16 @@ local_cluster<T>::clear ()
m_shapes.clear ();
m_needs_update = false;
m_bbox = box_type ();
m_attrs.clear ();
}
template <class T>
void
local_cluster<T>::add_attr (attr_id a)
{
if (a > 0) {
m_attrs.insert (a);
}
}
template <class T>
@ -175,6 +185,8 @@ local_cluster<T>::join_with (const local_cluster<T> &other)
other_tree.insert (s->second.begin (), s->second.end ());
}
m_attrs.insert (other.m_attrs.begin (), other.m_attrs.end ());
m_needs_update = true;
}
@ -427,7 +439,7 @@ namespace
template <class T, class BoxTree>
struct cluster_building_receiver
: public db::box_scanner_receiver<T, unsigned int>
: public db::box_scanner_receiver<T, std::pair<unsigned int, unsigned int> >
{
typedef typename local_cluster<T>::id_type id_type;
@ -437,9 +449,9 @@ struct cluster_building_receiver
// .. nothing yet..
}
void add (const T *s1, unsigned int l1, const T *s2, unsigned int l2)
void add (const T *s1, std::pair<unsigned int, unsigned int> p1, const T *s2, std::pair<unsigned int, unsigned int> p2)
{
if (! mp_conn->interacts (*s1, l1, *s2, l2)) {
if (! mp_conn->interacts (*s1, p1.first, *s2, p2.first)) {
return;
}
@ -451,8 +463,10 @@ struct cluster_building_receiver
if (id2 == m_shape_to_cluster_id.end ()) {
local_cluster<T> *cluster = mp_clusters->insert ();
cluster->add (*s1, l1);
cluster->add (*s2, l2);
cluster->add (*s1, p1.first);
cluster->add (*s2, p2.first);
cluster->add_attr (p1.second);
cluster->add_attr (p2.second);
m_shape_to_cluster_id.insert (std::make_pair (s1, cluster->id ()));
m_shape_to_cluster_id.insert (std::make_pair (s2, cluster->id ()));
@ -460,7 +474,9 @@ struct cluster_building_receiver
} else {
// NOTE: const_cast is in order - we know what we're doing.
const_cast<local_cluster<T> &> (mp_clusters->cluster_by_id (id2->second)).add (*s1, l1);
local_cluster<T> &c2 = const_cast<local_cluster<T> &> (mp_clusters->cluster_by_id (id2->second));
c2.add (*s1, p1.first);
c2.add_attr (p1.second);
m_shape_to_cluster_id.insert (std::make_pair (s1, id2->second));
}
@ -468,7 +484,9 @@ struct cluster_building_receiver
} else if (id2 == m_shape_to_cluster_id.end ()) {
// NOTE: const_cast is in order - we know what we're doing.
const_cast<local_cluster<T> &> (mp_clusters->cluster_by_id (id1->second)).add (*s2, l2);
local_cluster<T> &c1 = const_cast<local_cluster<T> &> (mp_clusters->cluster_by_id (id1->second));
c1.add (*s2, p2.first);
c1.add_attr (p2.second);
m_shape_to_cluster_id.insert (std::make_pair (s2, id1->second));
} else if (id1->second != id2->second) {
@ -481,13 +499,14 @@ struct cluster_building_receiver
}
}
void finish (const T *s, unsigned int l)
void finish (const T *s, std::pair<unsigned int, unsigned> p)
{
// if the shape has not been handled yet, insert a single cluster with only this shape
typename std::map<const T *, id_type>::const_iterator id = m_shape_to_cluster_id.find (s);
if (id == m_shape_to_cluster_id.end ()) {
local_cluster<T> *cluster = mp_clusters->insert ();
cluster->add (*s, l);
cluster->add (*s, p.first);
cluster->add_attr (p.second);
}
}
@ -503,14 +522,14 @@ template <class T>
void
local_clusters<T>::build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn)
{
db::box_scanner<T, unsigned int> bs;
db::box_scanner<T, std::pair<unsigned int, unsigned int> > bs;
typename T::tag object_tag;
db::box_convert<T> bc;
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
const db::Shapes &shapes = cell.shapes (*l);
for (db::Shapes::shape_iterator s = shapes.begin (shape_flags); ! s.at_end (); ++s) {
bs.insert (s->basic_ptr (object_tag), *l);
bs.insert (s->basic_ptr (object_tag), std::make_pair (*l, (attr_id) s->prop_id ()));
}
}
@ -1361,6 +1380,19 @@ recursive_cluster_shape_iterator<T>::recursive_cluster_shape_iterator (const hie
}
}
template <class T>
std::vector<ClusterInstance> recursive_cluster_shape_iterator<T>::inst_path () const
{
std::vector<db::ClusterInstance> p;
if (!m_conn_iter_stack.empty ()) {
p.reserve (m_conn_iter_stack.size ());
for (size_t i = 0; i < m_conn_iter_stack.size () - 1; ++i) {
p.push_back (*m_conn_iter_stack [i].first);
}
}
return p;
}
template <class T>
recursive_cluster_shape_iterator<T> &recursive_cluster_shape_iterator<T>::operator++ ()
{
@ -1427,6 +1459,78 @@ void recursive_cluster_shape_iterator<T>::down (db::cell_index_type ci, typename
// explicit instantiations
template class DB_PUBLIC recursive_cluster_shape_iterator<db::PolygonRef>;
// ------------------------------------------------------------------------------
// recursive_cluster_iterator implementation
template <class T>
recursive_cluster_iterator<T>::recursive_cluster_iterator (const hier_clusters<T> &hc, db::cell_index_type ci, typename local_cluster<T>::id_type id)
: mp_hc (&hc), m_id (id)
{
down (ci, id);
}
template <class T>
std::vector<ClusterInstance> recursive_cluster_iterator<T>::inst_path () const
{
std::vector<db::ClusterInstance> p;
if (!m_conn_iter_stack.empty ()) {
p.reserve (m_conn_iter_stack.size ());
for (size_t i = 0; i < m_conn_iter_stack.size () - 1; ++i) {
p.push_back (*m_conn_iter_stack [i].first);
}
}
return p;
}
template <class T>
recursive_cluster_iterator<T> &recursive_cluster_iterator<T>::operator++ ()
{
next_conn ();
return *this;
}
template <class T>
void recursive_cluster_iterator<T>::next_conn ()
{
while (m_conn_iter_stack.back ().first == m_conn_iter_stack.back ().second) {
up ();
if (m_conn_iter_stack.empty ()) {
return;
}
++m_conn_iter_stack.back ().first;
}
if (m_conn_iter_stack.back ().first != m_conn_iter_stack.back ().second) {
const ClusterInstance &cli = *m_conn_iter_stack.back ().first;
down (cli.inst ().inst_ptr.cell_index (), cli.id ());
}
}
template <class T>
void recursive_cluster_iterator<T>::up ()
{
m_conn_iter_stack.pop_back ();
m_cell_index_stack.pop_back ();
}
template <class T>
void recursive_cluster_iterator<T>::down (db::cell_index_type ci, typename db::local_cluster<T>::id_type id)
{
const connected_clusters<T> &clusters = mp_hc->clusters_per_cell (ci);
const typename connected_clusters<T>::connections_type &conn = clusters.connections_for_cluster (id);
m_cell_index_stack.push_back (ci);
m_conn_iter_stack.push_back (std::make_pair (conn.begin (), conn.end ()));
}
// explicit instantiations
template class DB_PUBLIC recursive_cluster_iterator<db::PolygonRef>;
// ------------------------------------------------------------------------------
// incoming_cluster_connections implementation

View File

@ -123,6 +123,9 @@ public:
typedef typename T::box_type box_type;
typedef db::unstable_box_tree<box_type, T, db::box_convert<T> > tree_type;
typedef typename tree_type::flat_iterator shape_iterator;
typedef unsigned int attr_id;
typedef std::set<attr_id> attr_set;
typedef attr_set::const_iterator attr_iterator;
/**
* @brief Creates an empty cluster
@ -179,6 +182,31 @@ public:
*/
shape_iterator begin (unsigned int l) const;
/**
* @brief Adds the given attribute to the attribute set
*
* Attributes are arbitary IDs attached to clusters.
* The attribute value 0 is reserved for "no attribute" and is not
* put into the set.
*/
void add_attr (attr_id a);
/**
* @brief Gets the attribute iterator (begin)
*/
attr_iterator begin_attr () const
{
return m_attrs.begin ();
}
/**
* @brief Gets the attribute iterator (end)
*/
attr_iterator end_attr () const
{
return m_attrs.end ();
}
private:
template <typename> friend class local_clusters;
template <typename> friend class interaction_receiver;
@ -201,6 +229,7 @@ private:
bool m_needs_update;
std::map<unsigned int, tree_type> m_shapes;
box_type m_bbox;
attr_set m_attrs;
};
/**
@ -231,6 +260,7 @@ class DB_PUBLIC local_clusters
public:
typedef typename local_cluster<T>::id_type id_type;
typedef typename local_cluster<T>::box_type box_type;
typedef typename local_cluster<T>::attr_id attr_id;
typedef db::box_tree<box_type, local_cluster<T>, local_cluster_box_convert<T> > tree_type;
typedef typename tree_type::touching_iterator touching_iterator;
typedef typename tree_type::const_iterator const_iterator;
@ -669,6 +699,13 @@ public:
return m_shape_iter.operator-> ();
}
/**
* @brief Returns the instantiation path of the current cluster
*
* The call path's root is the initial cell
*/
std::vector<ClusterInstance> inst_path () const;
/**
* @brief Returns the transformation applicable for transforming the shape to the root cluster
*/
@ -718,6 +755,73 @@ private:
void down (db::cell_index_type ci, typename db::local_cluster<T>::id_type id, const db::ICplxTrans &t);
};
/**
* @brief A recursive cluster iterator for the clusters itself
*
* This iterator will deliver the child clusters of a specific cluster.
*/
template <class T>
class DB_PUBLIC recursive_cluster_iterator
{
public:
/**
* @brief Constructor
*/
recursive_cluster_iterator (const hier_clusters<T> &hc, db::cell_index_type ci, typename local_cluster<T>::id_type id);
/**
* @brief Returns a value indicating whether there are any more shapes
*/
bool at_end () const
{
return m_cell_index_stack.empty ();
}
/**
* @brief Returns the cell index the shape lives in
*/
db::cell_index_type cell_index () const
{
return m_cell_index_stack.back ();
}
/**
* @brief Returns the id of the current cluster
*/
typename db::local_cluster<T>::id_type cluster_id () const
{
if (m_conn_iter_stack.size () <= 1) {
return m_id;
} else {
return m_conn_iter_stack [m_conn_iter_stack.size () - 2].first->id ();
}
}
/**
* @brief Returns the instantiation path of the current cluster
*
* The call path's root is the initial cell
*/
std::vector<ClusterInstance> inst_path () const;
/**
* @brief Increment operator
*/
recursive_cluster_iterator &operator++ ();
private:
typedef typename db::connected_clusters<T>::connections_type connections_type;
const hier_clusters<T> *mp_hc;
std::vector<db::cell_index_type> m_cell_index_stack;
std::vector<std::pair<typename connections_type::const_iterator, typename connections_type::const_iterator> > m_conn_iter_stack;
typename db::local_cluster<T>::id_type m_id;
void next_conn ();
void up ();
void down (db::cell_index_type ci, typename db::local_cluster<T>::id_type id);
};
/**
* @brief A connection to a cluster from a parent cluster
*/

View File

@ -149,13 +149,21 @@ TEST(10_LocalClusterBasic)
EXPECT_EQ (cluster.id (), size_t (0));
cluster.add (db::PolygonRef (poly, repo), 0);
cluster.add_attr (1);
EXPECT_EQ (cluster.bbox ().to_string (), "(0,0;1000,1000)");
db::local_cluster<db::PolygonRef> cluster2;
cluster.add (db::PolygonRef (poly, repo).transformed (db::Trans (db::Vector (10, 20))), 1);
cluster2.add (db::PolygonRef (poly, repo).transformed (db::Trans (db::Vector (10, 20))), 1);
cluster2.add_attr (2);
cluster.join_with (cluster2);
EXPECT_EQ (cluster.bbox ().to_string (), "(0,0;1010,1020)");
EXPECT_EQ (cluster.begin_attr () == cluster.end_attr (), false);
db::local_cluster<db::PolygonRef>::attr_iterator a = cluster.begin_attr ();
EXPECT_EQ (*a++, 1u);
EXPECT_EQ (*a++, 2u);
EXPECT_EQ (a == cluster.end_attr (), true);
}
TEST(11_LocalClusterInteractBasic)
@ -248,6 +256,9 @@ static std::string local_cluster_to_string (const db::local_cluster<T> &cluster,
res += "[" + tl::to_string (*l) + "]" + obj2string (*s);
}
}
for (typename db::local_cluster<T>::attr_iterator a = cluster.begin_attr (); a != cluster.end_attr (); ++a) {
res += "%" + tl::to_string (*a);
}
return res;
}
@ -325,6 +336,67 @@ TEST(20_LocalClustersBasic)
);
}
TEST(21_LocalClustersBasicWithAttributes)
{
db::Layout layout;
db::Cell &cell = layout.cell (layout.add_cell ("TOP"));
db::GenericRepository &repo = layout.shape_repository ();
db::Connectivity conn;
conn.connect (0);
conn.connect (1);
conn.connect (2);
conn.connect (0, 1);
conn.connect (0, 2);
db::Polygon poly;
tl::from_string ("(0,0;0,1000;1000,1000;1000,0)", poly);
cell.shapes (0).insert (db::PolygonRef (poly, repo));
db::local_clusters<db::PolygonRef> clusters;
EXPECT_EQ (local_clusters_to_string (clusters, conn), "");
clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn);
EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0)");
// one more shape
cell.shapes (0).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (10, 20))), repo), 1));
clusters.clear ();
clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn);
EXPECT_EQ (local_clusters_to_string (clusters, conn), "#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1");
// one more shape creating a new cluster
cell.shapes (2).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo), 2));
clusters.clear ();
clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn);
EXPECT_EQ (local_clusters_to_string (clusters, conn),
"#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20)%1\n"
"#2:[2](0,1100;0,2100;1000,2100;1000,1100)%2"
);
// one more shape connecting these
cell.shapes (2).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1000))), repo), 3));
clusters.clear ();
clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn);
EXPECT_EQ (local_clusters_to_string (clusters, conn),
"#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)%1%2%3"
);
// one more shape opening a new cluster
cell.shapes (1).insert (db::PolygonRefWithProperties (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo), 4));
clusters.clear ();
clusters.build_clusters (cell, db::ShapeIterator::Polygons, conn);
EXPECT_EQ (local_clusters_to_string (clusters, conn),
"#1:[0](0,0;0,1000;1000,1000;1000,0);[0](10,20;10,1020;1010,1020;1010,20);[2](0,1000;0,2000;1000,2000;1000,1000);[2](0,1100;0,2100;1000,2100;1000,1100)%1%2%3\n"
"#2:[1](0,1100;0,2100;1000,2100;1000,1100)%4"
);
}
TEST(30_LocalConnectedClusters)
{
db::Layout layout;
@ -408,28 +480,234 @@ TEST(30_LocalConnectedClusters)
EXPECT_EQ (x.size (), size_t (0));
}
static void normalize_layer (db::Layout &layout, unsigned int layer)
static db::PolygonRef make_box (db::Layout &ly, const db::Box &box)
{
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
db::Shapes s (layout.is_editable ());
s.swap (c->shapes (layer));
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); !i.at_end (); ++i) {
db::Polygon poly;
i->polygon (poly);
c->shapes (layer).insert (db::PolygonRef (poly, layout.shape_repository ()));
}
}
return db::PolygonRef (db::Polygon (box), ly.shape_repository ());
}
static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const db::hier_clusters<db::PolygonRef> &hc, db::local_cluster<db::PolygonRef>::id_type cluster_id, const db::ICplxTrans &trans, const db::Connectivity &conn)
TEST(40_HierClustersBasic)
{
db::hier_clusters<db::PolygonRef> hc;
db::Layout ly;
unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0));
db::Cell &top = ly.cell (ly.add_cell ("TOP"));
top.shapes (l1).insert (make_box (ly, db::Box (0, 0, 1000, 1000)));
db::Cell &c1 = ly.cell (ly.add_cell ("C1"));
c1.shapes (l1).insert (make_box (ly, db::Box (0, 0, 2000, 500)));
top.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans ()));
db::Cell &c2 = ly.cell (ly.add_cell ("C2"));
c2.shapes (l1).insert (make_box (ly, db::Box (0, 0, 500, 2000)));
c2.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans ()));
top.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans ()));
db::Connectivity conn;
conn.connect (l1, l1);
hc.build (ly, top, db::ShapeIterator::Polygons, conn);
int n, nc;
const db::connected_clusters<db::PolygonRef> *cluster;
// 1 cluster in TOP with 2 connections
n = 0;
cluster = &hc.clusters_per_cell (top.cell_index ());
for (db::connected_clusters<db::PolygonRef>::const_iterator i = cluster->begin (); i != cluster->end (); ++i) {
++n;
}
EXPECT_EQ (n, 1);
EXPECT_EQ (cluster->bbox ().to_string (), "(0,0;1000,1000)")
nc = 0;
for (db::connected_clusters<db::PolygonRef>::connections_iterator i = cluster->begin_connections (); i != cluster->end_connections (); ++i) {
nc += i->second.size ();
}
EXPECT_EQ (nc, 2);
// 1 cluster in C1 without connection
n = 0;
cluster = &hc.clusters_per_cell (c1.cell_index ());
for (db::connected_clusters<db::PolygonRef>::const_iterator i = cluster->begin (); i != cluster->end (); ++i) {
++n;
}
EXPECT_EQ (n, 1);
EXPECT_EQ (cluster->bbox ().to_string (), "(0,0;2000,500)")
nc = 0;
for (db::connected_clusters<db::PolygonRef>::connections_iterator i = cluster->begin_connections (); i != cluster->end_connections (); ++i) {
nc += i->second.size ();
}
EXPECT_EQ (nc, 0);
// 1 cluster in C2 with one connection
n = 0;
cluster = &hc.clusters_per_cell (c2.cell_index ());
for (db::connected_clusters<db::PolygonRef>::const_iterator i = cluster->begin (); i != cluster->end (); ++i) {
++n;
}
EXPECT_EQ (n, 1);
EXPECT_EQ (cluster->bbox ().to_string (), "(0,0;500,2000)")
nc = 0;
for (db::connected_clusters<db::PolygonRef>::connections_iterator i = cluster->begin_connections (); i != cluster->end_connections (); ++i) {
nc += i->second.size ();
}
EXPECT_EQ (nc, 1);
}
static std::string path2string (const db::Layout &ly, db::cell_index_type ci, const std::vector<db::ClusterInstance> &path)
{
std::string res = ly.cell_name (ci);
for (std::vector<db::ClusterInstance>::const_iterator p = path.begin (); p != path.end (); ++p) {
res += "/";
res += ly.cell_name (p->inst ().inst_ptr.cell_index ());
}
return res;
}
static std::string rcsiter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_shape_iterator<db::PolygonRef> si)
{
std::string res;
while (! si.at_end ()) {
db::Polygon poly = si->obj ();
poly.transform (si->trans ());
poly.transform (si.trans ());
if (! res.empty ()) {
res += ";";
}
res += path2string (ly, ci, si.inst_path ());
res += ":";
res += poly.to_string ();
++si;
}
return res;
}
static std::string rciter2string (const db::Layout &ly, db::cell_index_type ci, db::recursive_cluster_iterator<db::PolygonRef> si)
{
std::string res;
while (! si.at_end ()) {
if (! res.empty ()) {
res += ";";
}
res += path2string (ly, ci, si.inst_path ());
++si;
}
return res;
}
TEST(41_HierClustersRecursiveClusterShapeIterator)
{
db::hier_clusters<db::PolygonRef> hc;
db::Layout ly;
unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0));
db::Cell &top = ly.cell (ly.add_cell ("TOP"));
top.shapes (l1).insert (make_box (ly, db::Box (0, 0, 1000, 1000)));
db::Cell &c1 = ly.cell (ly.add_cell ("C1"));
c1.shapes (l1).insert (make_box (ly, db::Box (0, 0, 2000, 500)));
top.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 10))));
db::Cell &c2 = ly.cell (ly.add_cell ("C2"));
c2.shapes (l1).insert (make_box (ly, db::Box (0, 0, 500, 2000)));
c2.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 20))));
top.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (0, 30))));
db::Connectivity conn;
conn.connect (l1, l1);
hc.build (ly, top, db::ShapeIterator::Polygons, conn);
std::string res;
int n = 0;
db::connected_clusters<db::PolygonRef> *cluster = &hc.clusters_per_cell (top.cell_index ());
for (db::connected_clusters<db::PolygonRef>::const_iterator i = cluster->begin (); i != cluster->end (); ++i) {
res = rcsiter2string (ly, top.cell_index (), db::recursive_cluster_shape_iterator<db::PolygonRef> (hc, l1, top.cell_index (), i->id ()));
++n;
}
EXPECT_EQ (n, 1);
EXPECT_EQ (res, "TOP:(0,0;0,1000;1000,1000;1000,0);TOP/C1:(0,10;0,510;2000,510;2000,10);TOP/C2:(0,30;0,2030;500,2030;500,30);TOP/C2/C1:(0,50;0,550;2000,550;2000,50)");
}
TEST(41_HierClustersRecursiveClusterIterator)
{
db::hier_clusters<db::PolygonRef> hc;
db::Layout ly;
unsigned int l1 = ly.insert_layer (db::LayerProperties (1, 0));
db::Cell &top = ly.cell (ly.add_cell ("TOP"));
top.shapes (l1).insert (make_box (ly, db::Box (0, 0, 1000, 1000)));
db::Cell &c1 = ly.cell (ly.add_cell ("C1"));
c1.shapes (l1).insert (make_box (ly, db::Box (0, 0, 2000, 500)));
top.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 10))));
db::Cell &c2 = ly.cell (ly.add_cell ("C2"));
c2.shapes (l1).insert (make_box (ly, db::Box (0, 0, 500, 2000)));
c2.insert (db::CellInstArray (db::CellInst (c1.cell_index ()), db::Trans (db::Vector (0, 20))));
top.insert (db::CellInstArray (db::CellInst (c2.cell_index ()), db::Trans (db::Vector (0, 30))));
db::Connectivity conn;
conn.connect (l1, l1);
hc.build (ly, top, db::ShapeIterator::Polygons, conn);
std::string res;
int n = 0;
db::connected_clusters<db::PolygonRef> *cluster = &hc.clusters_per_cell (top.cell_index ());
for (db::connected_clusters<db::PolygonRef>::const_iterator i = cluster->begin (); i != cluster->end (); ++i) {
res = rciter2string (ly, top.cell_index (), db::recursive_cluster_iterator<db::PolygonRef> (hc, top.cell_index (), i->id ()));
++n;
}
EXPECT_EQ (n, 1);
EXPECT_EQ (res, "TOP;TOP/C1;TOP/C2;TOP/C2/C1");
}
static void normalize_layer (db::Layout &layout, std::vector<std::string> &strings, unsigned int &layer)
{
unsigned int new_layer = layout.insert_layer ();
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
const db::Shapes &s = c->shapes (layer);
for (db::Shapes::shape_iterator i = s.begin (db::ShapeIterator::Texts | db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); !i.at_end (); ++i) {
if (! i->is_text ()) {
db::Polygon poly;
i->polygon (poly);
c->shapes (new_layer).insert (db::PolygonRef (poly, layout.shape_repository ()));
} else {
db::Polygon poly (i->bbox ());
unsigned int attr_id = (unsigned int) strings.size () + 1;
strings.push_back (i->text_string ());
c->shapes (new_layer).insert (db::PolygonRefWithProperties (db::PolygonRef (poly, layout.shape_repository ()), attr_id));
}
}
}
layer = new_layer;
}
static void copy_cluster_shapes (const std::string *&attrs, db::Shapes &out, db::cell_index_type ci, const db::hier_clusters<db::PolygonRef> &hc, db::local_cluster<db::PolygonRef>::id_type cluster_id, const db::ICplxTrans &trans, const db::Connectivity &conn)
{
// use property #1 to code the cell name
// use property #2 to code the attrs string for the first shape
db::PropertiesRepository &pr = out.layout ()->properties_repository ();
db::properties_id_type cell_pid = 0, cell_and_attr_pid = 0;
db::property_names_id_type pn_id = pr.prop_name_id (tl::Variant (1));
db::PropertiesRepository::properties_set pm;
pm.insert (std::make_pair (pn_id, tl::Variant (out.layout ()->cell_name (ci))));
db::properties_id_type cell_pid = pr.properties_id (pm);
cell_pid = pr.properties_id (pm);
if (attrs && ! attrs->empty ()) {
db::property_names_id_type pn2_id = pr.prop_name_id (tl::Variant (2));
pm.insert (std::make_pair (pn2_id, tl::Variant (*attrs)));
cell_and_attr_pid = pr.properties_id (pm);
}
const db::connected_clusters<db::PolygonRef> &clusters = hc.clusters_per_cell (ci);
const db::local_cluster<db::PolygonRef> &lc = clusters.cluster_by_id (cluster_id);
@ -438,7 +716,9 @@ static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
for (db::local_cluster<db::PolygonRef>::shape_iterator s = lc.begin (*l); ! s.at_end (); ++s) {
db::Polygon poly = s->obj ().transformed (trans * db::ICplxTrans (s->trans ()));
out.insert (db::PolygonWithProperties (poly, cell_pid));
out.insert (db::PolygonWithProperties (poly, cell_and_attr_pid > 0 ? cell_and_attr_pid : cell_pid));
cell_and_attr_pid = 0;
attrs = 0; // used
}
}
@ -452,7 +732,7 @@ static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const
db::ICplxTrans t = trans * i->inst ().complex_trans ();
db::cell_index_type cci = i->inst ().inst_ptr.cell_index ();
copy_cluster_shapes (out, cci, hc, i->id (), t, conn);
copy_cluster_shapes (attrs, out, cci, hc, i->id (), t, conn);
}
}
@ -460,12 +740,17 @@ static void copy_cluster_shapes (db::Shapes &out, db::cell_index_type ci, const
static void run_hc_test (tl::TestBase *_this, const std::string &file, const std::string &au_file)
{
db::Layout ly;
unsigned int l1 = 0, l2 = 0, l3 = 0;
unsigned int l0 = 0, l1 = 0, l2 = 0, l3 = 0;
{
db::LayerProperties p;
db::LayerMap lmap;
p.layer = 0;
p.datatype = 0;
lmap.map (db::LDPair (p.layer, p.datatype), l0 = ly.insert_layer ());
ly.set_properties (l0, p);
p.layer = 1;
p.datatype = 0;
lmap.map (db::LDPair (p.layer, p.datatype), l1 = ly.insert_layer ());
@ -493,9 +778,10 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std
reader.read (ly, options);
}
normalize_layer (ly, l1);
normalize_layer (ly, l2);
normalize_layer (ly, l3);
std::vector<std::string> strings;
normalize_layer (ly, strings, l1);
normalize_layer (ly, strings, l2);
normalize_layer (ly, strings, l3);
// connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3
db::Connectivity conn;
@ -519,12 +805,25 @@ static void run_hc_test (tl::TestBase *_this, const std::string &file, const std
continue;
}
// collect strings
std::string attrs;
for (db::recursive_cluster_iterator<db::PolygonRef> rc (hc, *td, *c); ! rc.at_end (); ++rc) {
const db::local_cluster<db::PolygonRef> &rcc = hc.clusters_per_cell (rc.cell_index ()).cluster_by_id (rc.cluster_id ());
for (db::local_cluster<db::PolygonRef>::attr_iterator a = rcc.begin_attr (); a != rcc.end_attr (); ++a) {
if (! attrs.empty ()) {
attrs += "/";
}
attrs += std::string (ly.cell_name (rc.cell_index ())) + ":" + strings[*a - 1];
}
}
net_layers.push_back (std::make_pair (0, ly.insert_layer ()));
unsigned int lout = net_layers.back ().second;
db::Shapes &out = ly.cell (*td).shapes (lout);
copy_cluster_shapes (out, *td, hc, *c, db::ICplxTrans (), conn);
const std::string *attrs_str = &attrs;
copy_cluster_shapes (attrs_str, out, *td, hc, *c, db::ICplxTrans (), conn);
db::Polygon::area_type area = 0;
for (db::Shapes::shape_iterator s = out.begin (db::ShapeIterator::All); ! s.at_end (); ++s) {
@ -586,9 +885,10 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str
reader.read (ly, options);
}
normalize_layer (ly, l1);
normalize_layer (ly, l2);
normalize_layer (ly, l3);
std::vector<std::string> strings;
normalize_layer (ly, strings, l1);
normalize_layer (ly, strings, l2);
normalize_layer (ly, strings, l3);
// connect 1 to 1, 1 to 2 and 1 to 3, but *not* 2 to 3
db::Connectivity conn;
@ -611,68 +911,69 @@ static void run_hc_test_with_backannotation (tl::TestBase *_this, const std::str
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/" + au_file);
}
TEST(41_HierClusters)
TEST(101_HierClusters)
{
run_hc_test (_this, "hc_test_l1.gds", "hc_test_au1.gds");
run_hc_test_with_backannotation (_this, "hc_test_l1.gds", "hc_test_au1b.gds");
}
TEST(42_HierClusters)
TEST(102_HierClusters)
{
run_hc_test (_this, "hc_test_l2.gds", "hc_test_au2.gds");
run_hc_test_with_backannotation (_this, "hc_test_l2.gds", "hc_test_au2b.gds");
}
TEST(43_HierClusters)
TEST(103_HierClusters)
{
run_hc_test (_this, "hc_test_l3.gds", "hc_test_au3.gds");
run_hc_test_with_backannotation (_this, "hc_test_l3.gds", "hc_test_au3b.gds");
}
TEST(44_HierClusters)
TEST(104_HierClusters)
{
run_hc_test (_this, "hc_test_l4.gds", "hc_test_au4.gds");
run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds");
}
TEST(45_HierClusters)
TEST(105_HierClusters)
{
run_hc_test (_this, "hc_test_l5.gds", "hc_test_au5.gds");
run_hc_test_with_backannotation (_this, "hc_test_l5.gds", "hc_test_au5b.gds");
}
TEST(46_HierClusters)
TEST(106_HierClusters)
{
run_hc_test (_this, "hc_test_l6.gds", "hc_test_au6.gds");
run_hc_test_with_backannotation (_this, "hc_test_l6.gds", "hc_test_au6b.gds");
}
TEST(47_HierClusters)
TEST(107_HierClusters)
{
run_hc_test (_this, "hc_test_l7.gds", "hc_test_au7.gds");
run_hc_test_with_backannotation (_this, "hc_test_l7.gds", "hc_test_au7b.gds");
}
TEST(48_HierClusters)
TEST(108_HierClusters)
{
run_hc_test (_this, "hc_test_l8.gds", "hc_test_au8.gds");
run_hc_test_with_backannotation (_this, "hc_test_l8.gds", "hc_test_au8b.gds");
}
TEST(49_HierClusters)
TEST(109_HierClusters)
{
run_hc_test (_this, "hc_test_l9.gds", "hc_test_au9.gds");
run_hc_test_with_backannotation (_this, "hc_test_l9.gds", "hc_test_au9b.gds");
}
TEST(50_HierClusters)
TEST(110_HierClusters)
{
run_hc_test (_this, "hc_test_l10.gds", "hc_test_au10.gds");
run_hc_test_with_backannotation (_this, "hc_test_l10.gds", "hc_test_au10b.gds");
}
TEST(51_HierClusters)
TEST(111_HierClusters)
{
run_hc_test (_this, "hc_test_l11.gds", "hc_test_au11.gds");
run_hc_test_with_backannotation (_this, "hc_test_l4.gds", "hc_test_au4b.gds");
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.