mirror of https://github.com/KLayout/klayout.git
Cell variant resolution by propagation, grid check now implementation hierarchically (with propagation)
This commit is contained in:
parent
5dc833970b
commit
a7bfaac424
|
|
@ -28,6 +28,7 @@
|
|||
#include "dbLayout.h"
|
||||
#include "dbTrans.h"
|
||||
#include "tlTypeTraits.h"
|
||||
#include "tlUtils.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -354,6 +355,123 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Commits the shapes for different variants to the current cell hierarchy
|
||||
*
|
||||
* This is an alternative approach and will push the variant shapes into the parent hierarchy.
|
||||
* "to_commit" initially is a set of shapes to commit for the given cell and variant.
|
||||
* This map is modified during the algorithm and should be discarded later.
|
||||
*/
|
||||
virtual void commit_shapes (db::Layout &layout, db::Cell &top_cell, unsigned int layer, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_commit)
|
||||
{
|
||||
if (to_commit.empty ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// NOTE: this implementation suffers from accumulation of propagated shapes: we add more levels of propagated
|
||||
// shapes if required. We don't clean up, because we do not know when a shape collection stops being required.
|
||||
|
||||
db::LayoutLocker locker (&layout);
|
||||
|
||||
std::set<db::cell_index_type> called;
|
||||
top_cell.collect_called_cells (called);
|
||||
called.insert (top_cell.cell_index ());
|
||||
|
||||
for (db::Layout::bottom_up_const_iterator c = layout.begin_bottom_up (); c != layout.end_bottom_up (); ++c) {
|
||||
|
||||
if (called.find (*c) == called.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
db::Cell &cell = layout.cell (*c);
|
||||
|
||||
std::map<db::ICplxTrans, size_t> &vvc = m_variants [*c];
|
||||
if (vvc.size () > 1) {
|
||||
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator vc = vvc.begin (); vc != vvc.end (); ++vc) {
|
||||
|
||||
for (db::Cell::const_iterator i = cell.begin (); ! i.at_end (); ++i) {
|
||||
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> >::const_iterator tc = to_commit.find (i->cell_index ());
|
||||
if (tc != to_commit.end ()) {
|
||||
|
||||
const std::map<db::ICplxTrans, db::Shapes> &vt = tc->second;
|
||||
|
||||
// NOTE: this will add one more commit slot for propagation ... but we don't clean up.
|
||||
// When would a cleanup happen?
|
||||
std::map<db::ICplxTrans, db::Shapes> &propagated = to_commit [*c];
|
||||
|
||||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
|
||||
|
||||
db::ICplxTrans t = i->complex_trans (*ia);
|
||||
db::ICplxTrans rt = m_red (vc->first * t);
|
||||
std::map<db::ICplxTrans, db::Shapes>::const_iterator v = vt.find (rt);
|
||||
if (v != vt.end ()) {
|
||||
|
||||
db::Shapes &ps = propagated [vc->first];
|
||||
tl::ident_map<db::Layout::properties_id_type> pm;
|
||||
|
||||
for (db::Shapes::shape_iterator si = v->second.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
ps.insert (*si, t, pm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// single variant -> we can commit any shapes we have kept for this cell directly to the cell
|
||||
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> >::iterator l = to_commit.find (*c);
|
||||
if (l != to_commit.end ()) {
|
||||
tl_assert (l->second.size () == 1);
|
||||
cell.shapes (layer).insert (l->second.begin ()->second);
|
||||
to_commit.erase (l);
|
||||
}
|
||||
|
||||
// for child cells, pull everything that needs to be committed to the parent
|
||||
|
||||
for (db::Cell::const_iterator i = cell.begin (); ! i.at_end (); ++i) {
|
||||
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> >::const_iterator tc = to_commit.find (i->cell_index ());
|
||||
if (tc != to_commit.end ()) {
|
||||
|
||||
const std::map<db::ICplxTrans, db::Shapes> &vt = tc->second;
|
||||
|
||||
for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) {
|
||||
|
||||
db::ICplxTrans t = i->complex_trans (*ia);
|
||||
db::ICplxTrans rt = m_red (vvc.begin ()->first * t);
|
||||
std::map<db::ICplxTrans, db::Shapes>::const_iterator v = vt.find (rt);
|
||||
|
||||
if (v != vt.end ()) {
|
||||
|
||||
tl::ident_map<db::Layout::properties_id_type> pm;
|
||||
|
||||
for (db::Shapes::shape_iterator si = v->second.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
cell.shapes (layer).insert (*si, t, pm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the variants for a given cell
|
||||
*
|
||||
|
|
@ -371,6 +489,19 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true, if variants have been built
|
||||
*/
|
||||
bool has_variants () const
|
||||
{
|
||||
for (std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> >::const_iterator i = m_variants.begin (); i != m_variants.end (); ++i) {
|
||||
if (i->second.size () > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, size_t> > m_variants;
|
||||
Reduce m_red;
|
||||
|
|
|
|||
|
|
@ -713,11 +713,82 @@ DeepRegion::to_string (size_t nmax) const
|
|||
return db::AsIfFlatRegion::to_string (nmax);
|
||||
}
|
||||
|
||||
static void produce_offgrid_markers (db::Shapes &markers, const db::Shapes &shapes, const db::ICplxTrans &tr, db::Coord g)
|
||||
{
|
||||
for (db::Shapes::shape_iterator si = shapes.begin (db::ShapeIterator::All); ! si.at_end (); ++si) {
|
||||
|
||||
db::Polygon poly;
|
||||
si->polygon (poly);
|
||||
|
||||
for (size_t i = 0; i < poly.holes () + 1; ++i) {
|
||||
|
||||
db::Polygon::polygon_contour_iterator b, e;
|
||||
|
||||
if (i == 0) {
|
||||
b = poly.begin_hull ();
|
||||
e = poly.end_hull ();
|
||||
} else {
|
||||
b = poly.begin_hole ((unsigned int) (i - 1));
|
||||
e = poly.end_hole ((unsigned int) (i - 1));
|
||||
}
|
||||
|
||||
for (db::Polygon::polygon_contour_iterator p = b; p != e; ++p) {
|
||||
db::Point pt = tr * *p;
|
||||
if ((pt.x () % g) != 0 || (pt.y () % g) != 0) {
|
||||
markers.insert (EdgePair (db::Edge (pt, pt), db::Edge (pt, pt)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EdgePairs
|
||||
DeepRegion::grid_check (db::Coord gx, db::Coord gy) const
|
||||
{
|
||||
// TODO: snap be optimized by forming grid variants etc.
|
||||
return db::AsIfFlatRegion::grid_check (gx, gy);
|
||||
if (gx <= 0 || gy <= 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Grid check requires a positive grid value")));
|
||||
}
|
||||
|
||||
if (gx != gy) {
|
||||
// no way doing this hierarchically ?
|
||||
return db::AsIfFlatRegion::grid_check (gx, gy);
|
||||
}
|
||||
|
||||
ensure_merged_polygons_valid ();
|
||||
|
||||
db::Layout &layout = m_merged_polygons.layout ();
|
||||
|
||||
db::cell_variants_collector<db::GridReducer> vars (gx);
|
||||
vars.collect (layout, m_merged_polygons.initial_cell ());
|
||||
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
|
||||
std::auto_ptr<db::DeepEdgePairs> res (new db::DeepEdgePairs (m_merged_polygons.derived ()));
|
||||
|
||||
for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &vv = vars.variants (c->cell_index ());
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
||||
|
||||
db::Shapes *markers;
|
||||
if (vv.size () == 1) {
|
||||
markers = & c->shapes (res->deep_layer ().layer ());
|
||||
} else {
|
||||
markers = & to_commit [c->cell_index ()] [v->first];
|
||||
}
|
||||
|
||||
produce_offgrid_markers (*markers, c->shapes (m_merged_polygons.layer ()), v->first, gx);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// propagate the markers with a similar algorithm used for producing the variants
|
||||
res->deep_layer ().commit_shapes (vars, to_commit);
|
||||
|
||||
return db::EdgePairs (res.release ());
|
||||
}
|
||||
|
||||
EdgePairs
|
||||
|
|
|
|||
|
|
@ -159,6 +159,19 @@ public:
|
|||
template <class VarCollector>
|
||||
void separate_variants (VarCollector &collector);
|
||||
|
||||
/**
|
||||
* @brief Commits shapes for variants to the existing cell hierarchy
|
||||
*
|
||||
* The "to_propagate" collection is a set of shapes per cell and variant. The
|
||||
* algorithm will put these shapes into the existing hierarchy putting the
|
||||
* shapes into the proper parent cells to resolve variants.
|
||||
*
|
||||
* This map will be modified by the algorithm and should be discarded
|
||||
* later.
|
||||
*/
|
||||
template <class VarCollector>
|
||||
void commit_shapes (VarCollector &collector, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_propagate);
|
||||
|
||||
/**
|
||||
* @brief Gets the shape store object
|
||||
* This is a pure const version to prevent manipulation of the store.
|
||||
|
|
@ -299,6 +312,21 @@ public:
|
|||
issue_variants (layout_index, var_map);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Commits shapes for variants to the existing cell hierarchy
|
||||
*
|
||||
* To use this method, first create a variant collector (db::cell_variant_collector) with the required
|
||||
* reducer and collect the variants. Then call this method on the desired layout index to commit the shapes for the
|
||||
* respective variants.
|
||||
*/
|
||||
template <class VarCollector>
|
||||
void commit_shapes (unsigned int layout_index, VarCollector &coll, unsigned int layer, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_commit)
|
||||
{
|
||||
tl_assert (is_valid_layout_index (layout_index));
|
||||
|
||||
coll.commit_shapes (layout (layout_index), initial_cell (layout_index), layer, to_commit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief For testing
|
||||
*/
|
||||
|
|
@ -538,6 +566,13 @@ void DeepLayer::separate_variants (VarCollector &collector)
|
|||
mp_store->separate_variants (m_layout, collector);
|
||||
}
|
||||
|
||||
template <class VarCollector>
|
||||
void DeepLayer::commit_shapes (VarCollector &collector, std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > &to_commit)
|
||||
{
|
||||
check_dss ();
|
||||
mp_store->commit_shapes (m_layout, collector, layer (), to_commit);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
|
|
|
|||
|
|
@ -392,3 +392,47 @@ TEST(100_OrientationVariantsWithLayout)
|
|||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/cell_variants_au1.gds");
|
||||
}
|
||||
|
||||
TEST(101_Propagation)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/cell_variants_l1.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::Shapes> > to_commit;
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0));
|
||||
unsigned int l2 = ly.insert_layer (db::LayerProperties (2, 0));
|
||||
|
||||
db::cell_variants_collector<db::MagnificationAndOrientationReducer> vb;
|
||||
vb.collect (ly, top_cell);
|
||||
|
||||
for (db::Layout::const_iterator c = ly.begin (); c != ly.end (); ++c) {
|
||||
|
||||
const std::map<db::ICplxTrans, size_t> &vv = vb.variants (c->cell_index ());
|
||||
for (std::map<db::ICplxTrans, size_t>::const_iterator v = vv.begin (); v != vv.end (); ++v) {
|
||||
|
||||
db::Shapes &out = to_commit [c->cell_index ()][v->first];
|
||||
for (db::Shapes::shape_iterator s = c->shapes (l1).begin (db::ShapeIterator::All); ! s.at_end (); ++s) {
|
||||
db::Box b = s->bbox ().transformed (v->first);
|
||||
b.enlarge (db::Vector (-100, 0));
|
||||
out.insert (b.transformed (v->first.inverted ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vb.commit_shapes (ly, top_cell, l2, to_commit);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, ly, tl::testsrc () + "/testdata/algo/cell_variants_au2.gds");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -969,7 +969,7 @@ TEST(17_SinglePolygonChecks)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(18_Checks)
|
||||
TEST(18_MultiPolygonChecks)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
|
|
@ -1013,6 +1013,41 @@ TEST(18_Checks)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(19_GridCheck)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/deep_region_l1.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
|
||||
unsigned int l3 = ly.get_layer (db::LayerProperties (3, 0));
|
||||
|
||||
db::Region r3 (db::RecursiveShapeIterator (ly, top_cell, l3), dss);
|
||||
db::Region r3_gc1;
|
||||
r3.grid_check (25, 25).polygons (r3_gc1, 100);
|
||||
db::Region r3_gc2;
|
||||
r3.grid_check (40, 40).polygons (r3_gc2, 100);
|
||||
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r3);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r3_gc1);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), r3_gc2);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au19.gds");
|
||||
}
|
||||
|
||||
TEST(100_Integration)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue