diff --git a/src/db/db/db.pro b/src/db/db/db.pro index 7d2d2d563..3ac6db9e4 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -140,7 +140,8 @@ SOURCES = \ dbHierarchyBuilder.cc \ dbLocalOperation.cc \ dbHierProcessor.cc \ - dbDeepRegion.cc + dbDeepRegion.cc \ + dbHierNetworkProcessor.cc HEADERS = \ dbArray.h \ diff --git a/src/db/db/dbHierNetworkProcessor.cc b/src/db/db/dbHierNetworkProcessor.cc new file mode 100644 index 000000000..414d248a5 --- /dev/null +++ b/src/db/db/dbHierNetworkProcessor.cc @@ -0,0 +1,217 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "dbHierNetworkProcessor.h" +#include "dbShape.h" +#include "dbShapes.h" +#include "dbInstElement.h" +#include "dbPolygon.h" +#include "dbPolygonTools.h" +#include "dbBoxConvert.h" + +#include +#include + +namespace db +{ + +// ------------------------------------------------------------------------------ +// Connectivity implementation + +Connectivity::Connectivity () +{ + // .. nothing yet .. +} + +void +Connectivity::connect (unsigned int la, unsigned int lb) +{ + m_connected [la].insert (lb); + m_connected [lb].insert (la); + m_all_layers.insert (la); + m_all_layers.insert (lb); +} + +void +Connectivity::connect (unsigned int l) +{ + m_connected [l].insert (l); + m_all_layers.insert (l); +} + +Connectivity::layer_iterator +Connectivity::begin_layers () +{ + return m_all_layers.begin (); +} + +Connectivity::layer_iterator +Connectivity::end_layers () +{ + return m_all_layers.end (); +} + +Connectivity::layers_type s_empty_layers; + +Connectivity::layer_iterator +Connectivity::begin_connected (unsigned int layer) +{ + std::map::const_iterator i = m_connected.find (layer); + if (i == m_connected.end ()) { + return s_empty_layers.begin (); + } else { + return i->second.begin (); + } +} + +Connectivity::layer_iterator +Connectivity::end_connected (unsigned int layer) +{ + std::map::const_iterator i = m_connected.find (layer); + if (i == m_connected.end ()) { + return s_empty_layers.end (); + } else { + return i->second.end (); + } +} + +static bool +interaction_test (const db::PolygonRef &a, const db::PolygonRef &b) +{ + // TODO: this could be part of db::interact (including transformation) + if (a.obj ().is_box () && b.obj ().is_box ()) { + return db::interact (a.obj ().box ().transformed (b.trans ().inverted () * a.trans ()), b.obj ().box ()); + } else { + return db::interact (a.obj ().transformed (b.trans ().inverted () * a.trans ()), b.obj ()); + } +} + +template +bool Connectivity::interacts (const T &a, unsigned int la, T &b, unsigned int lb) const +{ + std::map::const_iterator i = m_connected.find (la); + if (i == m_connected.end () || i->second.find (lb) == i->second.end ()) { + return false; + } else { + return interaction_test (a, b); + } +} + +// explicit instantiations +template DB_PUBLIC bool Connectivity::interacts (const db::PolygonRef &a, unsigned int la, db::PolygonRef &b, unsigned int lb) const; + +// ------------------------------------------------------------------------------ +// ... + + +#if 0 +/** + * @brief Represents a cluster of shapes + * + * A cluster of shapes is a set of shapes which are connected in terms + * of a given connectivity. + */ +class LocalCluster +{ +public: + typedef size_t id_type; + + LocalCluster (); + + void connect (const db::Shape &a, unsigned int la, const db::Shape &b, unsigned int lb); + id_type id () const; + + // @@@ Trans is the transformation of the cluster to the shape (instance transformation) + void interacts (const db::Shape &s, unsigned int ls, const db::ICplxTrans &trans, const Connectivity &conn); + const db::Box &bbox () const; + +private: + friend class LocalClusters; + + void set_id (id_type id); +}; + +/** + * @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 +{ +public: + LocalClusters (); + + // @@@ 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); + + // @@@ Trans is the transformation of the clusters to the shape (instance transformation) + std::vector 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 interacting_clusters (const LocalClusters &c, const db::ICplxTrans &trans, const Connectivity &conn) const; +}; + +/** + * @brief Represents all clusters in a cell and their connections to child cells + * + * Connections to indirect children are made through empty dummy clusters. + * Also, connections between two clusters of different children without + * mediating cluster on cell level are made through empty dummy clusters. + * Hence, there is always a cluster in the parent cell which connects to + * clusters from child cells. + */ +class HierarchicalClusters +{ +public: + HierarchicalClusters (); + + LocalClusters &local (); + + // build local clusters + // determine local to cell cluster interactions -> top-down connection, maybe across dummy + // identify cell overlaps + // determine cell-to-cell cluster interactions -> make dummy cluster to connect both, connect to each child + // maybe across dummy cluster + // shall be called bottom-up + void build_clusters (const db::Cell &cell, const Connectivity &conn); + + // @@@ trans is the transformation from child to this (instance transformation) + // used by child clusters to verify whether they are connected somewhere in the parent + LocalCluster::id_type is_connected_to (LocalCluster::id_type id, const db::InstElement &trans) const; + + // connections to subcells (== pins?) + const std::vector > &top_down_connections (LocalCluster::id_type) const; + + // propagate all connected clusters to their parents + // -> creates new local clusters, removes them from their local set + // used by the merge step to form local-only clusters + // can be called bottom-up + void propagate_connected (); +}; +#endif + +} diff --git a/src/db/db/dbHierNetworkProcessor.h b/src/db/db/dbHierNetworkProcessor.h new file mode 100644 index 000000000..de1605328 --- /dev/null +++ b/src/db/db/dbHierNetworkProcessor.h @@ -0,0 +1,97 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_dbHierNetworkProcessor +#define HDR_dbHierNetworkProcessor + +#include "dbCommon.h" + +#include +#include + +namespace db { + +/** + * @brief Defines the connectivity + * + * Connectivity is defined in terms of layers. Certain layer pairs + * are connected when shapes on their layers interact. + * Connectivity includes intra-layer connectivity - i.e. + * shapes on a layer are not connected by default. They need to + * be connected explicitly using "connect(layer)". + */ +class DB_PUBLIC Connectivity +{ +public: + typedef std::set layers_type; + typedef layers_type::const_iterator layer_iterator; + + /** + * @brief Creates a connectivity object without any connections + */ + Connectivity (); + + /** + * @brief Adds inter-layer connectivity + */ + void connect (unsigned int la, unsigned int lb); + + /** + * @brief Adds intra-layer connectivity for layer l + */ + void connect (unsigned int l); + + /** + * @brief Begin iterator for the layers involved + */ + layer_iterator begin_layers (); + + /** + * @brief End iterator for the layers involved + */ + layer_iterator end_layers (); + + /** + * @brief Begin iterator for the layers connected to a specific layer + */ + layer_iterator begin_connected (unsigned int layer); + + /** + * @brief End iterator for the layers connected to a specific layer + */ + layer_iterator end_connected (unsigned int layer); + + /** + * @brief Returns true, if the given shapes on the given layers interact + */ + template + bool interacts (const T &a, unsigned int la, T &b, unsigned int lb) const; + +private: + layers_type m_all_layers; + std::map m_connected; +}; + +} + +#endif diff --git a/src/db/unit_tests/dbHierNetworkProcessorTests.cc b/src/db/unit_tests/dbHierNetworkProcessorTests.cc new file mode 100644 index 000000000..c049cfd0b --- /dev/null +++ b/src/db/unit_tests/dbHierNetworkProcessorTests.cc @@ -0,0 +1,117 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2018 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#include "tlUnitTest.h" +#include "dbHierNetworkProcessor.h" +#include "dbTestSupport.h" +#include "dbShapeRepository.h" +#include "dbPolygon.h" +#include "dbPath.h" +#include "dbText.h" + +static std::string l2s (db::Connectivity::layer_iterator b, db::Connectivity::layer_iterator e) +{ + std::string s; + for (db::Connectivity::layer_iterator i = b; i != e; ++i) { + if (! s.empty ()) { + s += ","; + } + s += tl::to_string (*i); + } + return s; +} + +TEST(1_Connectivity) +{ + db::Connectivity conn; + + EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), ""); + + conn.connect (0); + EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), "0"); + EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0"); + EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), ""); + + conn.connect (0, 1); + EXPECT_EQ (l2s (conn.begin_layers (), conn.end_layers ()), "0,1"); + EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1"); + EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0"); + + conn.connect (1); + EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0,1"); + + conn.connect (0, 2); + conn.connect (2); + + EXPECT_EQ (l2s (conn.begin_connected (0), conn.end_connected (0)), "0,1,2"); + EXPECT_EQ (l2s (conn.begin_connected (1), conn.end_connected (1)), "0,1"); + EXPECT_EQ (l2s (conn.begin_connected (2), conn.end_connected (2)), "0,2"); +} + +TEST(2_ShapeInteractions) +{ + db::Connectivity conn; + + conn.connect (0); + conn.connect (1); + conn.connect (0, 1); + + db::Polygon poly; + tl::from_string ("(0,0;0,1000;1000,1000;1000,0)", poly); + db::GenericRepository repo; + db::PolygonRef ref1 (poly, repo); + db::PolygonRef ref2 (poly.transformed (db::Trans (db::Vector (0, 10))), repo); + db::PolygonRef ref3 (poly.transformed (db::Trans (db::Vector (0, 2000))), repo); + + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false); + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false); +} + +TEST(2_ShapeInteractionsRealPolygon) +{ + db::Connectivity conn; + + conn.connect (0); + conn.connect (1); + conn.connect (0, 1); + + db::Polygon poly; + tl::from_string ("(0,0;0,1000;500,1000;500,1500;1000,1500;1000,0)", poly); + db::GenericRepository repo; + db::PolygonRef ref1 (poly, repo); + db::PolygonRef ref2 (poly.transformed (db::Trans (db::Vector (0, 10))), repo); + db::PolygonRef ref3 (poly.transformed (db::Trans (db::Vector (0, 2000))), repo); + db::PolygonRef ref4 (poly.transformed (db::Trans (db::Vector (0, 1500))), repo); + + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 0), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref2, 1), true); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 0), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 0), false); + EXPECT_EQ (conn.interacts (ref1, 0, ref4, 0), true); + EXPECT_EQ (conn.interacts (ref1, 0, ref3, 1), false); + EXPECT_EQ (conn.interacts (ref1, 1, ref2, 2), false); +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index b35a4ef9e..052a65b78 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -57,7 +57,8 @@ SOURCES = \ dbRecursiveShapeIteratorTests.cc \ dbHierProcessorTests.cc \ dbDeepRegionTests.cc \ - dbDeepShapeStoreTests.cc + dbDeepShapeStoreTests.cc \ + dbHierNetworkProcessorTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC