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
+4 -2
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") {
+36 -1
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); // @@@
}
}
+22 -4
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 &);
};
}
+332 -110
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 ()));
}
}
+141 -9
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;
};
}
+18
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
{
+8
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
*
+27 -13
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);
}
+41 -14
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
+5 -22
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"
@@ -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");
}
+114 -52
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"
+2 -1
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
+2 -2
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));
+2 -2
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:
/**
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.