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
+115 -11
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
+104
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
*/
+335 -34
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");
}
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.