WIP: Improved design of HierarchyBuilder, added tests.

This commit is contained in:
Matthias Koefferlein 2018-11-15 22:50:02 +01:00
parent 6f4988a764
commit 3f8825cfd1
26 changed files with 1091 additions and 232 deletions

View File

@ -136,7 +136,8 @@ SOURCES = \
dbFlatEdgePairs.cc \
dbOriginalLayerEdgePairs.cc \
dbEdgePairsDelegate.cc \
dbDeepShapeStore.cc
dbDeepShapeStore.cc \
dbHierarchyBuilder.cc
HEADERS = \
dbArray.h \
@ -242,7 +243,8 @@ HEADERS = \
dbFlatEdgePairs.h \
dbOriginalLayerEdgePairs.h \
dbEdgePairsDelegate.h \
dbDeepShapeStore.h
dbDeepShapeStore.h \
dbHierarchyBuilder.h
!equals(HAVE_QT, "0") {

View File

@ -21,4 +21,39 @@
*/
// ...
#include "dbDeepShapeStore.h"
namespace db
{
DeepLayer::DeepLayer (const DeepLayer &x)
: mp_store (x.mp_store), m_layout (x.m_layout), m_layer (x.m_layer)
{
// .. nothing yet ..
}
DeepLayer::DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer)
: mp_store (store), m_layout (layout), m_layer (layer)
{
// .. nothing yet ..
}
DeepShapeStore::DeepShapeStore ()
{
// @@@
}
DeepShapeStore::~DeepShapeStore ()
{
// @@@
}
DeepLayer DeepShapeStore::create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio, size_t max_vertex_count)
{
return DeepLayer (0, 0, 0); // @@@
}
}

View File

@ -30,6 +30,9 @@
#include "dbLayout.h"
#include "dbRecursiveShapeIterator.h"
#include <set>
#include <map>
namespace db {
class DeepShapeStore;
@ -81,9 +84,6 @@ private:
*/
DeepLayer (DeepShapeStore *store, unsigned int layout, unsigned int layer);
unsigned int layout () const { return m_layout; }
unsigned int layer () const { return m_layer; }
tl::weak_ptr<DeepShapeStore> mp_store;
unsigned int m_layout;
unsigned int m_layer;
@ -92,7 +92,7 @@ private:
/**
* @brief The "deep shape store" is a working model for the hierarchical ("deep") processor
*
* The deep shape store keep temporary data for the deep shape processor.
* The deep shape store keeps temporary data for the deep shape processor.
* It mainly consists of layout objects holding the hierarchy trees and layers
* for the actual shapes.
*
@ -110,10 +110,28 @@ public:
*/
DeepShapeStore ();
/**
* @brief The destructor
*/
~DeepShapeStore ();
/**
* @brief Inserts a polygon layer into the deep shape store
*
* This method will create a new layer inside the deep shape store as a
* working copy of the original layer. Preparation involves re-shaping
* the polygons so their bounding box is a better approximation and the
* polygon complexity is reduced. For this, the polygons are split
* into parts satisfying the area ratio (bounding box vs. polygon area)
* and maximum vertex count constraints.
*/
DeepLayer create_polygon_layer (const db::RecursiveShapeIterator &si, double max_area_ratio = 3.0, size_t max_vertex_count = 16);
private:
// no copying
DeepShapeStore (const DeepShapeStore &);
DeepShapeStore &operator= (const DeepShapeStore &);
};
}

View File

@ -24,10 +24,13 @@
#include "dbHierarchyBuilder.h"
#include "dbClip.h"
#include "dbRegion.h"
#include "dbPolygonTools.h"
namespace db
{
static HierarchyBuilderShapeInserter def_inserter;
// -------------------------------------------------------------------------------------------
int
@ -78,104 +81,82 @@ compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIter
// -------------------------------------------------------------------------------------------
static bool is_outside (const db::Box &obj, const std::set<db::Box> &region)
{
if (region.empty ()) {
return false;
}
for (std::set<db::Box>::const_iterator b = region.begin (); b != region.end (); ++b) {
if (obj.touches (*b)) {
return false;
}
}
return true;
}
static bool is_inside (const db::Box &obj, const std::set<db::Box> &region)
{
if (region.empty ()) {
return true;
}
for (std::set<db::Box>::const_iterator b = region.begin (); b != region.end (); ++b) {
if (obj.inside (*b)) {
return true;
}
}
if (is_outside (obj, region)) {
return false;
} else {
// TODO: basically a detailed analysis is required here
return false;
}
}
/**
* @brief Computes the clip variant (a box set) from a cell bbox, a region and a complex region (optional)
*/
static std::set<db::Box> compute_clip_variant (const db::Box &cell_bbox, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region)
static std::pair<bool, std::set<db::Box> > compute_clip_variant (const db::Box &cell_bbox, const db::ICplxTrans &trans, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region)
{
if (region == db::Box::world ()) {
return std::make_pair (true, std::set<db::Box> ());
}
db::ICplxTrans trans_inv (trans.inverted ());
db::Box region_in_cell = region.transformed (trans_inv);
std::set<db::Box> clip_variant;
if (region != db::Box::world () && ! cell_bbox.inside (region)) {
if (! cell_bbox.overlaps (region_in_cell)) {
// an empty clip variant should not happen, but who knows
return std::make_pair (false, std::set<db::Box> ());
}
db::Box rect_box = region & cell_bbox;
db::Box rect_box = region_in_cell & cell_bbox;
if (complex_region) {
if (complex_region) {
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (rect_box, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
if (rect_box.overlaps (*cr)) {
clip_variant.insert (rect_box * *cr);
}
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (region, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
db::Box cr_in_cell = (*cr).transformed (trans_inv);
if (rect_box.overlaps (cr_in_cell)) {
clip_variant.insert (rect_box * cr_in_cell);
}
if (clip_variant.empty ()) {
// an empty clip variant should not happen, but who knows
clip_variant.insert (db::Box ());
}
} else {
clip_variant.insert (rect_box);
}
if (clip_variant.empty ()) {
// an empty clip variant should not happen, but who knows
return std::make_pair (false, std::set<db::Box> ());
}
} else {
clip_variant.insert (rect_box);
}
return clip_variant;
return std::make_pair (true, clip_variant);
}
static void insert_clipped (const db::Box &box, const std::set<db::Box> &clip, db::Shapes &shapes)
HierarchyBuilder::HierarchyBuilder (db::Layout *target, unsigned int target_layer, HierarchyBuilderShapeReceiver *pipe)
: mp_target (target), m_initial_pass (true), m_target_layer (target_layer)
{
for (std::set<db::Box>::const_iterator b = clip.begin (); b != clip.end (); ++b) {
db::Box bb = *b & box;
if (! bb.empty ()) {
shapes.insert (bb);
}
}
mp_pipe = pipe ? pipe : &def_inserter;
}
static void insert_clipped (const db::Polygon &poly, const std::set<db::Box> &clip, db::Shapes &shapes)
HierarchyBuilder::HierarchyBuilder (db::Layout *target, HierarchyBuilderShapeReceiver *pipe)
: mp_target (target), m_initial_pass (true), m_target_layer (0)
{
// TODO: is this good way to clip a polygon at a complex boundary?
for (std::set<db::Box>::const_iterator b = clip.begin (); b != clip.end (); ++b) {
std::vector<db::Polygon> clipped_poly;
db::clip_poly (poly, *b, clipped_poly);
for (std::vector<db::Polygon>::const_iterator p = clipped_poly.begin (); p != clipped_poly.end (); ++p) {
shapes.insert (*p);
}
}
mp_pipe = pipe ? pipe : &def_inserter;
}
HierarchyBuilder::HierarchyBuilder (db::Layout *target, unsigned int target_layer, bool clip_shapes)
: mp_target (target), m_clip_shapes (clip_shapes), m_initial_pass (true), m_target_layer (target_layer)
HierarchyBuilder::~HierarchyBuilder ()
{
// .. nothing yet ..
}
void
HierarchyBuilder::set_shape_receiver (HierarchyBuilderShapeReceiver *pipe)
{
mp_pipe = pipe;
}
void
HierarchyBuilder::reset ()
{
m_initial_pass = true;
mp_initial_cell = 0;
m_cell_map.clear ();
m_cells_seen.clear ();
m_cell_stack.clear ();
m_cm_entry = cell_map_type::const_iterator ();
}
void
HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
{
@ -185,20 +166,32 @@ HierarchyBuilder::begin (const RecursiveShapeIterator *iter)
tl_assert (compare_iterators_with_respect_to_target_hierarchy (m_ref_iter, *iter) == 0);
}
m_cells_seen.clear ();
m_cm_entry = cell_map_type::const_iterator ();
m_cell_stack.clear ();
m_cells_seen.clear ();
std::pair<db::cell_index_type, std::set<db::Box> > key (iter->top_cell ()->cell_index (), std::set<db::Box> ());
m_cm_entry = m_cell_map.find (key);
if (m_cm_entry == m_cell_map.end ()) {
db::cell_index_type new_top_index = mp_target->add_cell (iter->layout ()->cell_name (key.first));
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_top_index)).first;
}
db::Cell &new_top = mp_target->cell (m_cm_entry->second);
m_cells_seen.insert (key);
db::Cell &new_top = mp_target->cell (mp_target->add_cell (iter->layout ()->cell_name (iter->top_cell ()->cell_index ())));
m_cell_stack.push_back (&new_top);
}
void
HierarchyBuilder::end (const RecursiveShapeIterator * /*iter*/)
{
tl_assert (m_cell_stack.size () == 1);
m_initial_pass = false;
m_cells_seen.clear ();
mp_initial_cell = m_cell_stack.back ();
m_cell_stack.pop_back ();
}
@ -217,7 +210,7 @@ HierarchyBuilder::leave_cell (const RecursiveShapeIterator * /*iter*/, const db:
m_cell_stack.pop_back ();
}
bool
HierarchyBuilder::new_inst_mode
HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
if (all) {
@ -238,67 +231,296 @@ HierarchyBuilder::new_inst (const RecursiveShapeIterator *iter, const db::CellIn
}
return (m_cells_seen.find (key) == m_cells_seen.end ());
// To see the cell once, use NI_single. If we did see the cell already, skip the whole instance array.
return (m_cells_seen.find (key) == m_cells_seen.end ()) ? NI_single : NI_skip;
} else {
// iterate by instance array members
return true;
// Iterate by instance array members
return NI_all;
}
}
bool
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region)
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{
db::Box cell_bbox = iter->layout ()->cell (inst.object ().cell_index ()).bbox ();
std::set<db::Box> clip_variant = compute_clip_variant (cell_bbox, region, complex_region);
if (all) {
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), clip_variant);
m_cm_entry = m_cell_map.find (key);
return true;
if (m_initial_pass) {
} else {
if (m_cm_entry == m_cell_map.end ()) {
std::string suffix;
if (! key.second.empty ()) {
suffix = "$CLIP_VAR";
}
db::cell_index_type new_cell = mp_target->add_cell ((std::string (iter->layout ()->cell_name (inst.object ().cell_index ())) + suffix).c_str ());
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
db::Box cell_bbox = iter->layout ()->cell (inst.object ().cell_index ()).bbox ();
std::pair<bool, std::set<db::Box> > clip_variant = compute_clip_variant (cell_bbox, trans, region, complex_region);
if (! clip_variant.first) {
return false;
}
db::CellInstArray new_inst (db::CellInst (m_cm_entry->second), trans);
m_cell_stack.back ()->insert (new_inst);
std::pair<db::cell_index_type, std::set<db::Box> > key (inst.object ().cell_index (), clip_variant.second);
m_cm_entry = m_cell_map.find (key);
if (m_initial_pass) {
if (m_cm_entry == m_cell_map.end ()) {
std::string suffix;
if (! key.second.empty ()) {
suffix = "$CLIP_VAR";
}
db::cell_index_type new_cell = mp_target->add_cell ((std::string (iter->layout ()->cell_name (inst.object ().cell_index ())) + suffix).c_str ());
m_cm_entry = m_cell_map.insert (std::make_pair (key, new_cell)).first;
}
db::CellInstArray new_inst (db::CellInst (m_cm_entry->second), trans);
m_cell_stack.back ()->insert (new_inst);
}
return (m_cells_seen.find (key) == m_cells_seen.end ());
}
return (m_cells_seen.find (key) == m_cells_seen.end ());
}
void
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/)
HierarchyBuilder::shape (const RecursiveShapeIterator * /*iter*/, const db::Shape &shape, const db::ICplxTrans & /*trans*/, const db::Box &region, const box_tree_type *complex_region)
{
tl_assert (m_cm_entry != m_cell_map.end () && m_cm_entry != cell_map_type::const_iterator ());
// TODO: property mapping?
db::Shapes &shapes = m_cell_stack.back ()->shapes (m_target_layer);
mp_pipe->push (shape, region, complex_region, &shapes);
}
if (m_cm_entry->first.second.empty () || is_inside (shape.bbox (), m_cm_entry->first.second)) {
// ---------------------------------------------------------------------------------------------
shapes.insert (shape);
ClippingHierarchyBuilderShapeReceiver::ClippingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe)
: mp_pipe (pipe ? pipe : &def_inserter)
{
// .. nothing yet ..
}
} else if (! is_outside (shape.bbox (), m_cm_entry->first.second)) {
void
ClippingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
static db::Box world = db::Box::world ();
if (region == world || is_inside (shape.bbox (), region, complex_region)) {
mp_pipe->push (shape, world, 0, target);
} else if (! is_outside (shape.bbox (), region, complex_region)) {
// clip the shape if required
if (! m_clip_shapes || shape.is_text () || shape.is_edge () || shape.is_edge_pair ()) {
shapes.insert (shape);
if (shape.is_text () || shape.is_edge () || shape.is_edge_pair ()) {
mp_pipe->push (shape, world, 0, target);
} else if (shape.is_box ()) {
insert_clipped (shape.box (), m_cm_entry->first.second, shapes);
insert_clipped (shape.box (), region, complex_region, target);
} else if (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) {
insert_clipped (shape.polygon (), m_cm_entry->first.second, shapes);
db::Polygon poly;
shape.polygon (poly);
insert_clipped (poly, region, complex_region, target);
}
}
}
void
ClippingHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
static db::Box world = db::Box::world ();
if (! complex_region) {
db::Box r = shape & region;
if (! r.empty()) {
mp_pipe->push (r, world, 0, target);
}
} else {
insert_clipped (shape, region, complex_region, target);
}
}
void
ClippingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
static db::Box world = db::Box::world ();
if (region == world || (shape.box ().inside (region) && ! complex_region)) {
mp_pipe->push (shape, world, 0, target);
} else {
insert_clipped (shape, region, complex_region, target);
}
}
bool
ClippingHierarchyBuilderShapeReceiver::is_inside (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region)
{
if (region == db::Box::world ()) {
return true;
}
if (box.inside (region)) {
db::Box rect_box = region & box;
if (complex_region) {
// TODO: this is not a real test for being inside a complex region
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (rect_box, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
if (rect_box.inside (*cr)) {
return true;
}
}
}
}
return false;
}
bool
ClippingHierarchyBuilderShapeReceiver::is_outside (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region)
{
if (region == db::Box::world ()) {
return false;
}
if (box.overlaps (region)) {
db::Box rect_box = region & box;
if (complex_region) {
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (rect_box, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
if (rect_box.overlaps (*cr)) {
return false;
}
}
} else {
return false;
}
}
return true;
}
void
ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
db::Box bb = box & region;
static db::Box world = db::Box::world ();
if (complex_region) {
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (bb, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
mp_pipe->push (*cr & bb, world, 0, target);
}
} else {
mp_pipe->push (bb, world, 0, target);
}
}
void
ClippingHierarchyBuilderShapeReceiver::insert_clipped (const db::Polygon &poly, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
std::vector<db::Polygon> clipped_poly;
static db::Box world = db::Box::world ();
if (complex_region) {
// TODO: is this good way to clip a polygon at a complex boundary?
for (db::RecursiveShapeReceiver::box_tree_type::overlapping_iterator cr = complex_region->begin_overlapping (region, db::box_convert<db::Box> ()); ! cr.at_end (); ++cr) {
db::clip_poly (poly, *cr & region, clipped_poly);
}
} else {
db::clip_poly (poly, region, clipped_poly);
}
for (std::vector<db::Polygon>::const_iterator p = clipped_poly.begin (); p != clipped_poly.end (); ++p) {
mp_pipe->push (*p, world, 0, target);
}
}
// ---------------------------------------------------------------------------------------------
ReducingHierarchyBuilderShapeReceiver::ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe, double area_ratio, size_t max_vertex_count)
: mp_pipe (pipe ? pipe : &def_inserter), m_area_ratio (area_ratio), m_max_vertex_count (max_vertex_count)
{
// .. nothing yet ..
}
void
ReducingHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
if (shape.is_text () || shape.is_edge () || shape.is_edge_pair ()) {
mp_pipe->push (shape, region, complex_region, target);
} else if (shape.is_box ()) {
mp_pipe->push (shape.box (), region, complex_region, target);
} else if (shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) {
db::Polygon poly;
shape.polygon (poly);
reduce (poly, region, complex_region, target);
}
}
void
ReducingHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
mp_pipe->push (shape, region, complex_region, target);
}
void
ReducingHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
reduce (shape, region, complex_region, target);
}
static double area_ratio (const db::Polygon &poly)
{
return double (poly.box ().area ()) / double (poly.area ());
}
void
ReducingHierarchyBuilderShapeReceiver::reduce (const db::Polygon &poly, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
{
size_t npoints = 0;
for (unsigned int c = 0; c < poly.holes () + 1; ++c) {
npoints += poly.contour (c).size ();
}
if (npoints > m_max_vertex_count || area_ratio (poly) > m_area_ratio) {
std::vector <db::Polygon> split_polygons;
db::split_polygon (poly, split_polygons);
for (std::vector <db::Polygon>::const_iterator sp = split_polygons.begin (); sp != split_polygons.end (); ++sp) {
reduce (*sp, region, complex_region, target);
}
} else {
mp_pipe->push (poly, region, complex_region, target);
}
}
// ---------------------------------------------------------------------------------------------
PolygonReferenceHierarchyBuilderShapeReceiver::PolygonReferenceHierarchyBuilderShapeReceiver (db::Layout *layout)
: mp_layout (layout)
{
// nothing yet ..
}
void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
if (shape.is_box () || shape.is_polygon () || shape.is_simple_polygon () || shape.is_path ()) {
db::Polygon poly;
shape.polygon (poly);
target->insert (db::PolygonRef (poly, mp_layout->shape_repository ()));
}
}
void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
target->insert (db::PolygonRef (db::Polygon (shape), mp_layout->shape_repository ()));
}
void PolygonReferenceHierarchyBuilderShapeReceiver::push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
target->insert (db::PolygonRef (shape, mp_layout->shape_repository ()));
}
}

View File

@ -43,6 +43,108 @@ namespace db
*/
int compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShapeIterator &iter1, const db::RecursiveShapeIterator &iter2);
/**
* @brief A class to receive shapes from the hierarchy builder
*
* This class can be reimplemented to implement clipping and/or
* simplification.
*/
class DB_PUBLIC HierarchyBuilderShapeReceiver
{
public:
HierarchyBuilderShapeReceiver () { }
virtual ~HierarchyBuilderShapeReceiver () { }
virtual void push (const db::Shape &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
virtual void push (const db::Box &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
virtual void push (const db::Polygon &shape, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
};
/**
* @brief A shape receiver that simply pushes into the target
*/
class DB_PUBLIC HierarchyBuilderShapeInserter
: public HierarchyBuilderShapeReceiver
{
public:
HierarchyBuilderShapeInserter () { }
virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
target->insert (shape);
}
virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
target->insert (shape);
}
virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target)
{
target->insert (shape);
}
};
/**
* @brief A clipping shape receiver that forwards to another one
*/
class DB_PUBLIC ClippingHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
ClippingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0);
virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
private:
void insert_clipped (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
void insert_clipped (const db::Polygon &poly, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
static bool is_inside (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region);
static bool is_outside (const db::Box &box, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region);
HierarchyBuilderShapeReceiver *mp_pipe;
};
/**
* @brief A polygon reducing shape receiver that forwards to another one
*/
class DB_PUBLIC ReducingHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
ReducingHierarchyBuilderShapeReceiver (HierarchyBuilderShapeReceiver *pipe = 0, double area_ratio = 3.0, size_t max_vertex_count = 16);
virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
private:
void reduce (const db::Polygon &poly, const db::Box &region, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
HierarchyBuilderShapeReceiver *mp_pipe;
double m_area_ratio;
size_t m_max_vertex_count;
};
/**
* @brief A polygon reference generating shape receiver that feeds a shapes array after turning the shapes into PolygonRefs
*/
class DB_PUBLIC PolygonReferenceHierarchyBuilderShapeReceiver
: public HierarchyBuilderShapeReceiver
{
public:
PolygonReferenceHierarchyBuilderShapeReceiver (db::Layout *layout);
virtual void push (const db::Shape &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Box &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
virtual void push (const db::Polygon &shape, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *target);
private:
db::Layout *mp_layout;
};
/**
* @brief A class building a hierarchy from a recursive shape iterator in push mode
*
@ -58,26 +160,55 @@ int compare_iterators_with_respect_to_target_hierarchy (const db::RecursiveShape
* rely on precisely the same hierarchy arrangement. This is not given with
* region selections.
*/
class HierarchyBuilder
class DB_PUBLIC HierarchyBuilder
: public db::RecursiveShapeReceiver
{
public:
typedef std::map<std::pair<db::cell_index_type, std::set<db::Box> >, db::cell_index_type> cell_map_type;
HierarchyBuilder (db::Layout *target, unsigned int target_layer, bool clip_shapes);
HierarchyBuilder (db::Layout *target, unsigned int target_layer, HierarchyBuilderShapeReceiver *pipe = 0);
HierarchyBuilder (db::Layout *target, HierarchyBuilderShapeReceiver *pipe = 0);
virtual ~HierarchyBuilder ();
/**
* @brief Installs a custom shape receiver
* The hierarchy builder will *NOT* take ownership of this object.
*/
void set_shape_receiver (HierarchyBuilderShapeReceiver *pipe);
virtual void begin (const RecursiveShapeIterator *iter);
virtual void end (const RecursiveShapeIterator * /*iter*/);
virtual void enter_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/);
virtual void leave_cell (const RecursiveShapeIterator * /*iter*/, const db::Cell * /*cell*/);
virtual bool new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans);
virtual void end (const RecursiveShapeIterator *iter);
virtual void enter_cell (const RecursiveShapeIterator *iter, const db::Cell *cell, const db::Box &region, const box_tree_type *complex_region);
virtual void leave_cell (const RecursiveShapeIterator *iter, const db::Cell *cell);
virtual new_inst_mode new_inst (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual bool new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all);
virtual void shape (const RecursiveShapeIterator *iter, const db::Shape &shape, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region);
/**
* @brief Sets the target layer - shapes will be put there
*/
void set_target_layer (unsigned int target_layer)
{
m_target_layer = target_layer;
}
/**
* @brief Reset the builder - performs a new initial pass
*/
void reset ();
/**
* @brief Gets the initial cell the builder produced
*/
db::Cell *initial_cell ()
{
return mp_initial_cell;
}
private:
tl::weak_ptr<db::Layout> mp_target;
bool m_clip_shapes;
HierarchyBuilderShapeReceiver *mp_pipe;
bool m_initial_pass;
db::RecursiveShapeIterator m_ref_iter;
cell_map_type m_cell_map;
@ -85,6 +216,7 @@ private:
cell_map_type::const_iterator m_cm_entry;
unsigned int m_target_layer;
std::vector<db::Cell *> m_cell_stack;
db::Cell *mp_initial_cell;
};
}

View File

@ -1511,6 +1511,24 @@ Layout::insert_layer (unsigned int index, const LayerProperties &props)
layer_properties_changed ();
}
unsigned int
Layout::get_layer (const db::LayerProperties &lp)
{
if (lp.is_null ()) {
// for a null layer info always create a layer
return insert_layer ();
} else {
// if we have a layer with the requested properties already, return this.
for (db::Layout::layer_iterator li = begin_layers (); li != end_layers (); ++li) {
if ((*li).second->log_equal (lp)) {
return (*li).first;
}
}
// otherwise create a new layer
return insert_layer (lp);
}
}
unsigned int
Layout::waste_layer () const
{

View File

@ -1447,6 +1447,14 @@ public:
*/
void insert_layer (unsigned int index, const LayerProperties &props = LayerProperties ());
/**
* @brief Gets or creates a layer with the given properties
*
* If there already is a layer matching the given properties, it's index will be
* returned. Otherwise a new layer with these properties is created.
*/
unsigned int get_layer (const db::LayerProperties &props);
/**
* @brief Insert a new special layer with the given properties
*

View File

@ -716,8 +716,10 @@ RecursiveShapeIterator::down (RecursiveShapeReceiver *receiver) const
m_inst_quad_id_stack.push_back (m_inst_quad_id);
bool ia = is_inactive ();
bool aoi = is_all_of_instance ();
mp_cell = &mp_layout->cell (m_inst->cell_index ());
set_inactive (ia);
set_all_of_instance (aoi);
m_trans = m_trans * m_inst->complex_trans (*m_inst_array);
@ -876,22 +878,34 @@ RecursiveShapeIterator::new_inst (RecursiveShapeReceiver *receiver) const
}
}
bool all_of_instance = false;
bool with_region = false;
if (m_local_region_stack.back () != box_type::world () && ! m_inst->cell_inst ().bbox (m_box_convert).inside (m_local_region_stack.back ())) {
if (receiver && ! receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), false)) {
m_inst_array = inst_array_iterator ();
} else {
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
}
with_region = true;
} else {
// TODO: optimization potential: only report all_of_instance == false, if not entirely within the complex region
bool all_of_instance = m_local_complex_region_stack.empty ();
if (receiver && ! receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance)) {
m_inst_array = inst_array_iterator ();
} else {
m_inst_array = m_inst->cell_inst ().begin ();
}
all_of_instance = m_local_complex_region_stack.empty ();
}
RecursiveShapeReceiver::new_inst_mode ni = RecursiveShapeReceiver::NI_all;
if (receiver) {
ni = receiver->new_inst (this, m_inst->cell_inst (), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), all_of_instance);
}
if (ni == RecursiveShapeReceiver::NI_skip) {
m_inst_array = inst_array_iterator ();
} else if (ni == RecursiveShapeReceiver::NI_single) {
// a singular iterator
m_inst_array = db::CellInstArray::iterator (m_inst->cell_inst ().front (), false);
} else if (with_region) {
m_inst_array = m_inst->cell_inst ().begin_touching (m_local_region_stack.back (), m_box_convert);
} else {
m_inst_array = m_inst->cell_inst ().begin ();
}
set_all_of_instance (all_of_instance);
new_inst_member (receiver);
if (! m_inst_array.at_end ()) {
@ -921,7 +935,7 @@ RecursiveShapeIterator::new_inst_member (RecursiveShapeReceiver *receiver) const
}
while (! m_inst_array.at_end () && receiver) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ())) {
if (receiver->new_inst_member (this, m_inst->cell_inst (), m_inst->complex_trans (*m_inst_array), m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back (), is_all_of_instance ())) {
break;
} else {
++m_inst_array;
@ -950,7 +964,7 @@ RecursiveShapeIterator::push (RecursiveShapeReceiver *receiver)
validate (receiver);
while (! at_end ()) {
receiver->shape (this, *m_shape, m_trans);
receiver->shape (this, *m_shape, m_trans, m_local_region_stack.back (), m_local_complex_region_stack.empty () ? 0 : &m_local_complex_region_stack.back ());
next (receiver);
}

View File

@ -548,7 +548,7 @@ public:
}
/**
* @brief Get the current depth
* @brief Gets the current depth
*
* Returns the number of hierarchy levels we are below top level currently.
*/
@ -559,7 +559,7 @@ public:
}
/**
* @brief Get the current shape
* @brief Gets the current shape
*
* Returns the shape currently referred to by the recursive iterator.
* This shape is not transformed yet and is located in the current cell.
@ -600,27 +600,25 @@ public:
bool at_end () const;
/**
* @brief Get the current cell's index
* @brief Gets the current cell's index
*/
db::cell_index_type cell_index () const
{
validate (0);
size_t c = reinterpret_cast<size_t> (mp_cell);
return reinterpret_cast<const cell_type *> (c - (c & size_t (1)))->cell_index ();
return cell ()->cell_index ();
}
/**
* @brief Get the current cell's reference
* @brief Gets the current cell's reference
*/
const cell_type *cell () const
{
validate (0);
size_t c = reinterpret_cast<size_t> (mp_cell);
return reinterpret_cast<const cell_type *> (c - (c & size_t (1)));
return reinterpret_cast<const cell_type *> (c - (c & size_t (3)));
}
/**
* @brief Increment the iterator (operator version)
* @brief Increments the iterator (operator version)
*/
RecursiveShapeIterator &operator++()
{
@ -749,7 +747,19 @@ private:
{
size_t c = reinterpret_cast<size_t> (mp_cell);
c -= (c & size_t (1));
mp_cell = reinterpret_cast<const db::Cell *> (c + a);
mp_cell = reinterpret_cast<const db::Cell *> (c + (a ? 1 : 0));
}
bool is_all_of_instance () const
{
return (reinterpret_cast<size_t> (mp_cell) & size_t (2)) != 0;
}
void set_all_of_instance (bool a) const
{
size_t c = reinterpret_cast<size_t> (mp_cell);
c -= (c & size_t (2));
mp_cell = reinterpret_cast<const db::Cell *> (c + (a ? 2 : 0));
}
};
@ -769,7 +779,19 @@ class DB_PUBLIC RecursiveShapeReceiver
public:
typedef RecursiveShapeIterator::box_tree_type box_tree_type;
/**
* @brief See new_inst for details.
*/
enum new_inst_mode { NI_all = 0, NI_single = 1, NI_skip = 2 };
/**
* @brief Constructor
*/
RecursiveShapeReceiver () { }
/**
* @brief Destructor
*/
virtual ~RecursiveShapeReceiver () { }
/**
@ -824,9 +846,12 @@ public:
*
* The "all" parameter is true, if all instances of the array will be addressed.
*
* If this method returns false, the instance (the whole array) is skipped and the cell is not entered.
* This method can return the following values:
* - NI_all: iterate all members through "new_inst_member"
* - NI_single: iterate a single member (the first one)
* - NI_skip: skips the whole array (not a single instance is iterated)
*/
virtual bool new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
virtual new_inst_mode new_inst (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return NI_all; }
/**
* @brief Enters a new array member of the instance
@ -835,16 +860,18 @@ public:
* which holds the complex transformation for this particular instance of
* the array.
*
* "all" is true, if an instance array is iterated in "all" mode (see new_inst).
*
* If this method returns false, this array instance (but not the whole array) is skipped and the cell is not entered.
*/
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { return true; }
virtual bool new_inst_member (const RecursiveShapeIterator * /*iter*/, const db::CellInstArray & /*inst*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool /*all*/) { return true; }
/**
* @brief Delivers a shape
*
* @param trans The transformation which maps the shape to the top cell.
*/
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/) { }
virtual void shape (const RecursiveShapeIterator * /*iter*/, const db::Shape & /*shape*/, const db::ICplxTrans & /*trans*/, const db::Box & /*region*/, const box_tree_type * /*complex_region*/) { }
};
} // namespace db

View File

@ -367,41 +367,24 @@ static std::vector<db::cell_index_type> multi_clip_into (db::Layout *l, db::cell
return db::clip_layout(*l, *t, c, boxes, true);
}
static unsigned int get_layer (db::Layout *l, const db::LayerProperties &lp)
{
if (lp.is_null ()) {
// for a null layer info always create a layer
return l->insert_layer ();
} else {
// if we have a layer with the requested properties already, return this.
for (db::Layout::layer_iterator li = l->begin_layers (); li != l->end_layers (); ++li) {
if ((*li).second->log_equal (lp)) {
return (*li).first;
}
}
// otherwise create a new layer
return l->insert_layer (lp);
}
}
static unsigned int get_layer0 (db::Layout *l)
{
return get_layer (l, db::LayerProperties ());
return l->get_layer (db::LayerProperties ());
}
static unsigned int get_layer1 (db::Layout *l, const std::string &name)
{
return get_layer (l, db::LayerProperties (name));
return l->get_layer (db::LayerProperties (name));
}
static unsigned int get_layer2 (db::Layout *l, int ln, int dn)
{
return get_layer (l, db::LayerProperties (ln, dn));
return l->get_layer (db::LayerProperties (ln, dn));
}
static unsigned int get_layer3 (db::Layout *l, int ln, int dn, const std::string &name)
{
return get_layer (l, db::LayerProperties (ln, dn, name));
return l->get_layer (db::LayerProperties (ln, dn, name));
}
static tl::Variant find_layer (db::Layout *l, const db::LayerProperties &lp)
@ -1297,7 +1280,7 @@ Class<db::Layout> decl_Layout ("db", "Layout",
"\n"
"This method has been introduced in version 0.25.\n"
) +
gsi::method_ext ("layer", &get_layer,
gsi::method ("layer", &db::Layout::get_layer,
"@brief Finds or creates a layer with the given properties\n"
"@args info\n"
"\n"

View File

@ -0,0 +1,337 @@
/*
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 "dbHierarchyBuilder.h"
#include "dbReader.h"
#include "dbTestSupport.h"
#include "dbRegion.h"
#include "tlUnitTest.h"
#include "tlStream.h"
TEST(1)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::HierarchyBuilder builder (&target, false);
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1);
iter.push (&builder);
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au1.gds");
}
TEST(2_WithoutClip)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::HierarchyBuilder builder (&target, false);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000));
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2a.gds");
}
TEST(2_WithClip)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::ClippingHierarchyBuilderShapeReceiver clip;
db::HierarchyBuilder builder (&target, &clip);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000));
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2b.gds");
}
TEST(2_WithClipAndSimplification)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::ReducingHierarchyBuilderShapeReceiver red(0, 1.2, 4);
db::ClippingHierarchyBuilderShapeReceiver clip(&red);
db::HierarchyBuilder builder (&target, &clip);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000));
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2c.gds");
}
TEST(2_WithClipAndRefGeneration)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::PolygonReferenceHierarchyBuilderShapeReceiver ref(&target);
db::ClippingHierarchyBuilderShapeReceiver clip(&ref);
db::HierarchyBuilder builder (&target, &clip);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, -2000, 18500, 6000));
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2d.gds");
}
TEST(2_WithEmptyResult)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l1.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::PolygonReferenceHierarchyBuilderShapeReceiver ref(&target);
db::ClippingHierarchyBuilderShapeReceiver clip(&ref);
db::HierarchyBuilder builder (&target, &clip);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, db::Box (5000, 10000, 18500, 15000));
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au2e.gds");
}
TEST(3_ComplexRegionWithClip)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l2.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::ClippingHierarchyBuilderShapeReceiver clip;
db::HierarchyBuilder builder (&target, &clip);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Region reg;
reg.insert (db::Box (5000, 13000, 18500, 20000));
reg.insert (db::Box (11000, 20000, 18500, 36000));
reg.merge ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, reg);
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au3a.gds");
}
TEST(4_ComplexRegionAndLayoutWithClip)
{
db::Layout ly;
{
std::string fn (tl::testsrc ());
fn += "/testdata/algo/hierarchy_builder_l3.gds";
tl::InputStream stream (fn);
db::Reader reader (stream);
reader.read (ly);
}
db::Layout target;
db::ClippingHierarchyBuilderShapeReceiver clip;
db::HierarchyBuilder builder (&target, &clip);
db::cell_index_type target_top = target.add_cell ("CLIP_TOP");
for (db::Layout::layer_iterator li = ly.begin_layers (); li != ly.end_layers (); ++li) {
builder.reset ();
unsigned int li1 = (*li).first;
unsigned int target_layer = target.insert_layer (*(*li).second);
builder.set_target_layer (target_layer);
db::cell_index_type top_cell_index = *ly.begin_top_down ();
db::Region reg;
reg.insert (db::Box (5000, 13000, 18500, 20000));
reg.insert (db::Box (11000, 20000, 18500, 36000));
reg.merge ();
db::RecursiveShapeIterator iter (ly, ly.cell (top_cell_index), li1, reg);
iter.push (&builder);
target.cell (target_top).insert (db::CellInstArray (db::CellInst (builder.initial_cell ()->cell_index ()), db::Trans ()));
}
CHECKPOINT();
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/hierarchy_builder_au4a.gds");
}

View File

@ -918,19 +918,23 @@ public:
m_text += std::string ("leave_cell(") + iter->layout ()->cell_name (cell->cell_index ()) + ")\n";
}
virtual bool new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
m_text += std::string ("new_inst(") + iter->layout ()->cell_name (inst.object ().cell_index ());
if (all) {
m_text += ",all";
}
m_text += ")\n";
return true;
return NI_all;
}
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/)
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box & /*region*/, const box_tree_type * /*complex_region*/, bool all)
{
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans) + ")\n";
m_text += std::string ("new_inst_member(") + iter->layout ()->cell_name (inst.object ().cell_index ()) + "," + tl::to_string (trans);
if (all) {
m_text += ",all";
}
m_text += ")\n";
return true;
}
@ -949,10 +953,26 @@ class ReceiverRejectingACellInstanceArray
public:
ReceiverRejectingACellInstanceArray (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual bool new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all)
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
return inst.object ().cell_index () != m_rejected;
return inst.object ().cell_index () != m_rejected ? NI_all : NI_skip;
}
private:
db::cell_index_type m_rejected;
};
class ReceiverRejectingACellInstanceArrayExceptOne
: public LoggingReceiver
{
public:
ReceiverRejectingACellInstanceArrayExceptOne (db::cell_index_type rejected) : m_rejected (rejected) { }
virtual new_inst_mode new_inst (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst (iter, inst, region, complex_region, all);
return inst.object ().cell_index () != m_rejected ? NI_all : NI_single;
}
private:
@ -965,9 +985,9 @@ class ReceiverRejectingACellInstance
public:
ReceiverRejectingACellInstance (db::cell_index_type rejected, const db::ICplxTrans &trans_rejected) : m_rejected (rejected), m_trans_rejected (trans_rejected) { }
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region)
virtual bool new_inst_member (const db::RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box &region, const box_tree_type *complex_region, bool all)
{
LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region);
LoggingReceiver::new_inst_member (iter, inst, trans, region, complex_region, all);
return inst.object ().cell_index () != m_rejected || trans != m_trans_rejected;
}
@ -1001,82 +1021,82 @@ TEST(10)
EXPECT_EQ (lr1.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,0)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,2000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 0,6000)\n"
"new_inst_member($2,r0 *1 0,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,6000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,8000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,0)\n"
"new_inst_member($2,r0 *1 6000,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,0)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,6000)\n"
"new_inst_member($2,r0 *1 6000,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n"
"leave_cell($3)\n"
@ -1091,25 +1111,67 @@ TEST(10)
EXPECT_EQ (rr1.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 0,6000)\n"
"new_inst_member($2,r0 *1 0,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,0)\n"
"new_inst_member($2,r0 *1 6000,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,6000)\n"
"new_inst_member($2,r0 *1 6000,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"leave_cell($2)\n"
"end\n"
);
ReceiverRejectingACellInstanceArrayExceptOne rs1 (c2.cell_index ());
db::RecursiveShapeIterator is1 (g, c0, 0);
is1.push (&rs1);
EXPECT_EQ (rs1.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,0)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 0,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,6000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,0)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,6000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"end\n"
);
ReceiverRejectingACellInstance rri1 (c2.cell_index (), db::ICplxTrans ());
db::RecursiveShapeIterator iri1 (g, c0, 0);
iri1.push (&rri1);
@ -1117,70 +1179,70 @@ TEST(10)
EXPECT_EQ (rri1.text (),
"begin\n"
"new_inst($2,all)\n"
"new_inst_member($2,r0 *1 0,0)\n"
"new_inst_member($2,r0 *1 0,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n" // -> skipped
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,0,all)\n" // -> skipped
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,2000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,1000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,3000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 0,6000)\n"
"new_inst_member($2,r0 *1 0,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 0,8000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,7000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 3000,9000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,0)\n"
"new_inst_member($2,r0 *1 6000,0,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,2000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,1000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,3000)\n"
"leave_cell($3)\n"
"leave_cell($2)\n"
"new_inst_member($2,r0 *1 6000,6000)\n"
"new_inst_member($2,r0 *1 6000,6000,all)\n"
"enter_cell($2)\n"
"new_inst($3,all)\n"
"new_inst_member($3,r0 *1 0,0)\n"
"new_inst_member($3,r0 *1 0,2000)\n"
"new_inst_member($3,r0 *1 0,0,all)\n"
"new_inst_member($3,r0 *1 0,2000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 6000,8000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,1000)\n"
"new_inst_member($3,r0 *1 3000,1000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,7000)\n"
"leave_cell($3)\n"
"new_inst_member($3,r0 *1 3000,3000)\n"
"new_inst_member($3,r0 *1 3000,3000,all)\n"
"enter_cell($3)\n"
"shape(box (1000,-500;2000,500),r0 *1 9000,9000)\n"
"leave_cell($3)\n"

View File

@ -53,7 +53,8 @@ SOURCES = \
dbWriterTools.cc \
dbVariableWidthPath.cc \
dbLoadLayoutOptionsTests.cc \
dbSaveLayoutOptionsTests.cc
dbSaveLayoutOptionsTests.cc \
dbHierarchyBuilderTests.cc
INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC
DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC

View File

@ -130,12 +130,12 @@ bool Object::has_strong_references () const
return false;
}
void Object::keep ()
void Object::keep_object ()
{
mp_ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) | size_t (1));
}
void Object::release ()
void Object::release_object ()
{
mp_ptrs = (WeakOrSharedPtr *)(size_t (mp_ptrs) & ~size_t (1));

View File

@ -106,14 +106,14 @@ public:
* no strong pointer is having a reference to this object and longer, the
* object is not deleted.
*/
void keep ();
void keep_object ();
/**
* @brief Releases this object from being kept
* This method may delete the object if no strong pointer holds a
* reference to it.
*/
void release ();
void release_object ();
protected:
/**

BIN
testdata/algo/hierarchy_builder_au1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_au2a.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_au2b.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_au2c.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_au2d.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_au2e.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_au3a.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_au4a.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_l1.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_l2.gds vendored Normal file

Binary file not shown.

BIN
testdata/algo/hierarchy_builder_l3.gds vendored Normal file

Binary file not shown.