mirror of https://github.com/KLayout/klayout.git
WIP: hier network processor: local cluster set
This commit is contained in:
parent
e918cc74b0
commit
f7f9f4f1fc
|
|
@ -60,13 +60,13 @@ Connectivity::connect (unsigned int l)
|
|||
}
|
||||
|
||||
Connectivity::layer_iterator
|
||||
Connectivity::begin_layers ()
|
||||
Connectivity::begin_layers () const
|
||||
{
|
||||
return m_all_layers.begin ();
|
||||
}
|
||||
|
||||
Connectivity::layer_iterator
|
||||
Connectivity::end_layers ()
|
||||
Connectivity::end_layers () const
|
||||
{
|
||||
return m_all_layers.end ();
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ Connectivity::end_layers ()
|
|||
Connectivity::layers_type s_empty_layers;
|
||||
|
||||
Connectivity::layer_iterator
|
||||
Connectivity::begin_connected (unsigned int layer)
|
||||
Connectivity::begin_connected (unsigned int layer) const
|
||||
{
|
||||
std::map<unsigned int, layers_type>::const_iterator i = m_connected.find (layer);
|
||||
if (i == m_connected.end ()) {
|
||||
|
|
@ -85,7 +85,7 @@ Connectivity::begin_connected (unsigned int layer)
|
|||
}
|
||||
|
||||
Connectivity::layer_iterator
|
||||
Connectivity::end_connected (unsigned int layer)
|
||||
Connectivity::end_connected (unsigned int layer) const
|
||||
{
|
||||
std::map<unsigned int, layers_type>::const_iterator i = m_connected.find (layer);
|
||||
if (i == m_connected.end ()) {
|
||||
|
|
@ -244,6 +244,19 @@ private:
|
|||
|
||||
}
|
||||
|
||||
template <class T>
|
||||
typename local_cluster<T>::shape_iterator local_cluster<T>::begin (unsigned int l) const
|
||||
{
|
||||
static tree_type s_empty_tree;
|
||||
|
||||
typename std::map<unsigned int, tree_type>::const_iterator i = m_shapes.find (l);
|
||||
if (i == m_shapes.end ()) {
|
||||
return s_empty_tree.begin_flat ();
|
||||
} else {
|
||||
return i->second.begin_flat ();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
local_cluster<T>::interacts (const local_cluster<T> &other, const db::ICplxTrans &trans, const Connectivity &conn) const
|
||||
|
|
@ -287,34 +300,177 @@ template class DB_PUBLIC local_cluster<db::PolygonRef>;
|
|||
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// local_cluster implementation
|
||||
// local_clusters implementation
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* @brief Represents a collection of clusters in a cell
|
||||
*
|
||||
* After all shapes in a cell are connected, the cluster collection is filled if
|
||||
* disconnected clusters.
|
||||
*/
|
||||
class LocalClusters
|
||||
template <class T>
|
||||
local_clusters<T>::local_clusters ()
|
||||
: m_needs_update (false)
|
||||
{
|
||||
public:
|
||||
LocalClusters ();
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
// @@@ needs to be fast(!)
|
||||
LocalCluster::id_type cluster_id_for_shape (const db::Shape &s, unsigned int ls) const;
|
||||
const LocalCluster &cluster (LocalCluster::id_type id) const;
|
||||
LocalCluster &create_cluster ();
|
||||
void remove_cluster (LocalCluster::id_type id);
|
||||
cluster_iterator find (const db::Box ®ion);
|
||||
template <class T>
|
||||
void local_clusters<T>::clear ()
|
||||
{
|
||||
m_needs_update = false;
|
||||
m_clusters.clear ();
|
||||
m_bbox = box_type ();
|
||||
}
|
||||
|
||||
// @@@ Trans is the transformation of the clusters to the shape (instance transformation)
|
||||
std::vector<unsigned int> interacting_clusters (const db::Shape &s, unsigned int ls, const db::ICplxTrans &trans, const Connectivity &conn) const;
|
||||
// @@@ Trans is the transformation of the clusters to the clusters looked up (instance transformation)
|
||||
std::vector<unsigned int> interacting_clusters (const LocalClusters &c, const db::ICplxTrans &trans, const Connectivity &conn) const;
|
||||
template <class T>
|
||||
const local_cluster<T> &
|
||||
local_clusters<T>::cluster_by_id (typename local_cluster<T>::id_type id) const
|
||||
{
|
||||
// by convention the ID is the index + 1 so 0 can be used as "nil"
|
||||
tl_assert (id > 0 && id <= m_clusters.size ());
|
||||
return m_clusters.objects ().item (id - 1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
local_clusters<T>::remove_cluster (typename local_cluster<T>::id_type id)
|
||||
{
|
||||
tl_assert (id > 0 && id <= m_clusters.size ());
|
||||
// TODO: get rid of this const_cast by providing "delete by index"
|
||||
// m_clusters.erase (id - 1)
|
||||
local_cluster<T> *to_delete = const_cast<local_cluster<T> *> (& m_clusters.objects ().item (id - 1));
|
||||
m_clusters.erase (m_clusters.iterator_from_pointer (to_delete));
|
||||
m_needs_update = true;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
local_cluster<T> *
|
||||
local_clusters<T>::insert ()
|
||||
{
|
||||
typename tree_type::iterator i = m_clusters.insert (local_cluster<T> ());
|
||||
i->set_id (i.index () + 1);
|
||||
m_needs_update = true;
|
||||
return i.operator-> ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
local_clusters<T>::ensure_sorted ()
|
||||
{
|
||||
if (! m_needs_update) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sort the shape trees
|
||||
m_clusters.sort (local_cluster_box_convert<T> ());
|
||||
|
||||
// recompute bounding box
|
||||
m_bbox = box_type ();
|
||||
for (typename tree_type::const_iterator i = m_clusters.begin (); i != m_clusters.end (); ++i) {
|
||||
m_bbox += i->bbox ();
|
||||
}
|
||||
|
||||
m_needs_update = false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class T, class BoxTree>
|
||||
struct cluster_building_receiver
|
||||
: public db::box_scanner_receiver<T, unsigned int>
|
||||
{
|
||||
typedef typename local_cluster<T>::id_type id_type;
|
||||
|
||||
cluster_building_receiver (local_clusters<T> &clusters, const db::Connectivity &conn)
|
||||
: mp_clusters (&clusters), mp_conn (&conn)
|
||||
{
|
||||
// .. nothing yet..
|
||||
}
|
||||
|
||||
void add (const T *s1, unsigned int l1, const T *s2, unsigned int l2)
|
||||
{
|
||||
if (! mp_conn->interacts (*s1, l1, *s2, l2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
typename std::map<const T *, id_type>::const_iterator id1 = m_shape_to_cluster_id.find (s1);
|
||||
typename std::map<const T *, id_type>::const_iterator id2 = m_shape_to_cluster_id.find (s2);
|
||||
|
||||
if (id1 == m_shape_to_cluster_id.end ()) {
|
||||
|
||||
if (id2 == m_shape_to_cluster_id.end ()) {
|
||||
|
||||
local_cluster<T> *cluster = mp_clusters->insert ();
|
||||
cluster->add (*s1, l1);
|
||||
cluster->add (*s2, l2);
|
||||
|
||||
m_shape_to_cluster_id.insert (std::make_pair (s1, cluster->id ()));
|
||||
m_shape_to_cluster_id.insert (std::make_pair (s2, cluster->id ()));
|
||||
|
||||
} 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);
|
||||
m_shape_to_cluster_id.insert (std::make_pair (s1, id2->second));
|
||||
|
||||
}
|
||||
|
||||
} 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);
|
||||
m_shape_to_cluster_id.insert (std::make_pair (s2, id1->second));
|
||||
|
||||
} else if (id1->second != id2->second) {
|
||||
|
||||
// this shape connects two clusters: join them
|
||||
// NOTE: const_cast is in order - we know what we're doing.
|
||||
const_cast<local_cluster<T> &> (mp_clusters->cluster_by_id (id1->second)).join_with (mp_clusters->cluster_by_id (id2->second));
|
||||
mp_clusters->remove_cluster (id2->second);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void finish (const T *s, unsigned int l)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
local_clusters<T> *mp_clusters;
|
||||
const db::Connectivity *mp_conn;
|
||||
std::map<const T *, id_type> m_shape_to_cluster_id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
cluster_building_receiver<T, box_type> rec (*this, conn);
|
||||
bs.process (rec, 1 /*==touching*/, bc);
|
||||
}
|
||||
|
||||
// explicit instantiations
|
||||
template class DB_PUBLIC local_clusters<db::PolygonRef>;
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
// hier_clusters implementation
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* @brief Represents all clusters in a cell and their connections to child cells
|
||||
*
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "dbTrans.h"
|
||||
#include "dbBoxConvert.h"
|
||||
#include "dbBoxTree.h"
|
||||
#include "dbCell.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
|
@ -67,22 +68,22 @@ public:
|
|||
/**
|
||||
* @brief Begin iterator for the layers involved
|
||||
*/
|
||||
layer_iterator begin_layers ();
|
||||
layer_iterator begin_layers () const;
|
||||
|
||||
/**
|
||||
* @brief End iterator for the layers involved
|
||||
*/
|
||||
layer_iterator end_layers ();
|
||||
layer_iterator end_layers () const;
|
||||
|
||||
/**
|
||||
* @brief Begin iterator for the layers connected to a specific layer
|
||||
*/
|
||||
layer_iterator begin_connected (unsigned int layer);
|
||||
layer_iterator begin_connected (unsigned int layer) const;
|
||||
|
||||
/**
|
||||
* @brief End iterator for the layers connected to a specific layer
|
||||
*/
|
||||
layer_iterator end_connected (unsigned int layer);
|
||||
layer_iterator end_connected (unsigned int layer) const;
|
||||
|
||||
/**
|
||||
* @brief Returns true, if the given shapes on the given layers interact
|
||||
|
|
@ -119,6 +120,8 @@ class DB_PUBLIC local_cluster
|
|||
public:
|
||||
typedef size_t id_type;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief Creates an empty cluster
|
||||
|
|
@ -170,10 +173,14 @@ public:
|
|||
return m_bbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the shape iterator for a given layer
|
||||
*/
|
||||
shape_iterator begin (unsigned int l) const;
|
||||
|
||||
private:
|
||||
template <typename> friend class local_clusters;
|
||||
template <typename> friend class interaction_receiver;
|
||||
typedef db::unstable_box_tree<box_type, T, db::box_convert<T> > tree_type;
|
||||
|
||||
void set_id (id_type id)
|
||||
{
|
||||
|
|
@ -195,6 +202,115 @@ private:
|
|||
box_type m_bbox;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A box converter for the local_cluster class
|
||||
*/
|
||||
template <class T>
|
||||
struct DB_PUBLIC local_cluster_box_convert
|
||||
{
|
||||
typedef typename local_cluster<T>::box_type box_type;
|
||||
typedef typename db::simple_bbox_tag complexity;
|
||||
|
||||
box_type operator() (const local_cluster<T> &c) const
|
||||
{
|
||||
return c.bbox ();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A collection of clusters
|
||||
*
|
||||
* Clusters are identified by their ID. This collection
|
||||
* supports cluster lookup by a box region and building
|
||||
* the clusters from a cell's shapes.
|
||||
*/
|
||||
template <class T>
|
||||
class DB_PUBLIC local_clusters
|
||||
{
|
||||
public:
|
||||
typedef typename local_cluster<T>::box_type box_type;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @brief Creates an empty collection
|
||||
*/
|
||||
local_clusters ();
|
||||
|
||||
/**
|
||||
* @brief Gets the cluster by ID
|
||||
*/
|
||||
const local_cluster<T> &cluster_by_id (typename local_cluster<T>::id_type id) const;
|
||||
|
||||
/**
|
||||
* @brief Clears the clusters
|
||||
*/
|
||||
void clear ();
|
||||
|
||||
/**
|
||||
* @brief Removes a cluster with the given ID
|
||||
*/
|
||||
void remove_cluster (typename local_cluster<T>::id_type id);
|
||||
|
||||
/**
|
||||
* @brief Gets the bounding box of the clusters
|
||||
*/
|
||||
box_type bbox () const
|
||||
{
|
||||
const_cast<local_clusters<T> *> (this)->ensure_sorted ();
|
||||
return m_bbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the clusters (begin iterator)
|
||||
*/
|
||||
const_iterator begin () const
|
||||
{
|
||||
return m_clusters.begin ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the clusters (end iterator)
|
||||
*/
|
||||
const_iterator end () const
|
||||
{
|
||||
return m_clusters.end ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the clusters touching a given region
|
||||
*/
|
||||
touching_iterator begin_touching (const box_type &box) const
|
||||
{
|
||||
const_cast<local_clusters<T> *> (this)->ensure_sorted ();
|
||||
return m_clusters.begin_touching (box, local_cluster_box_convert<T> ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Builds this collection from a cell and the given connectivity
|
||||
*
|
||||
* This method will only build the local clusters. Child cells
|
||||
* are not taken into account. Only the shape types listed in
|
||||
* shape_flags are taken.
|
||||
*/
|
||||
void build_clusters (const db::Cell &cell, db::ShapeIterator::flags_type shape_flags, const db::Connectivity &conn);
|
||||
|
||||
/**
|
||||
* @brief Creates and inserts a new clusters
|
||||
*
|
||||
* NOTE: the object should not be modified after sorting has taken place.
|
||||
*/
|
||||
local_cluster<T> *insert ();
|
||||
|
||||
private:
|
||||
void ensure_sorted ();
|
||||
|
||||
bool m_needs_update;
|
||||
box_type m_bbox;
|
||||
tree_type m_clusters;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "dbPolygon.h"
|
||||
#include "dbPath.h"
|
||||
#include "dbText.h"
|
||||
#include "dbLayout.h"
|
||||
|
||||
static std::string l2s (db::Connectivity::layer_iterator b, db::Connectivity::layer_iterator e)
|
||||
{
|
||||
|
|
@ -227,3 +228,98 @@ TEST(11_LocalClusterInteractDifferentLayers)
|
|||
cluster.add (db::PolygonRef (poly, repo), 1);
|
||||
EXPECT_EQ (cluster.interacts (cluster2, db::ICplxTrans (), conn), true);
|
||||
}
|
||||
|
||||
static std::string obj2string (const db::PolygonRef &ref)
|
||||
{
|
||||
return ref.obj ().transformed (ref.trans ()).to_string ();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string local_cluster_to_string (const db::local_cluster<T> &cluster, const db::Connectivity &conn)
|
||||
{
|
||||
std::string res;
|
||||
for (db::Connectivity::layer_iterator l = conn.begin_layers (); l != conn.end_layers (); ++l) {
|
||||
for (typename db::local_cluster<T>::shape_iterator s = cluster.begin (*l); ! s.at_end (); ++s) {
|
||||
if (! res.empty ()) {
|
||||
res += ";";
|
||||
}
|
||||
res += "[" + tl::to_string (*l) + "]" + obj2string (*s);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string local_clusters_to_string (const db::local_clusters<T> &clusters, const db::Connectivity &conn)
|
||||
{
|
||||
std::string s;
|
||||
for (typename db::local_clusters<T>::const_iterator c = clusters.begin (); c != clusters.end (); ++c) {
|
||||
if (! s.empty ()) {
|
||||
s += "\n";
|
||||
}
|
||||
s += "#" + tl::to_string (c->id ()) + ":" + local_cluster_to_string (*c, conn);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
TEST(20_LocalClustersBasic)
|
||||
{
|
||||
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::PolygonRef (poly.transformed (db::Trans (db::Vector (10, 20))), repo));
|
||||
|
||||
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)");
|
||||
|
||||
// one more shape creating a new cluster
|
||||
cell.shapes (2).insert (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo));
|
||||
|
||||
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)\n"
|
||||
"#2:[2](0,1100;0,2100;1000,2100;1000,1100)"
|
||||
);
|
||||
|
||||
// one more shape connecting these
|
||||
cell.shapes (2).insert (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1000))), repo));
|
||||
|
||||
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)"
|
||||
);
|
||||
|
||||
// one more shape opening a new cluster
|
||||
cell.shapes (1).insert (db::PolygonRef (poly.transformed (db::Trans (db::Vector (0, 1100))), repo));
|
||||
|
||||
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)\n"
|
||||
"#2:[1](0,1100;0,2100;1000,2100;1000,1100)"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue