mirror of
https://github.com/KLayout/klayout.git
synced 2026-08-29 01:14:35 +02:00
WIP: property collection in net clusters, more tests.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Reference in New Issue
Block a user