mirror of https://github.com/KLayout/klayout.git
WIP: Improved design of HierarchyBuilder, added tests.
This commit is contained in:
parent
6f4988a764
commit
3f8825cfd1
|
|
@ -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") {
|
||||
|
||||
|
|
|
|||
|
|
@ -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); // @@@
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 &);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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> ®ion)
|
||||
{
|
||||
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> ®ion)
|
||||
{
|
||||
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 ®ion, 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 ®ion, 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 ®ion, const box_tree_type *complex_region)
|
||||
HierarchyBuilder::new_inst_member (const RecursiveShapeIterator *iter, const db::CellInstArray &inst, const db::ICplxTrans &trans, const db::Box ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
|
||||
virtual void push (const db::Box &shape, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target) = 0;
|
||||
virtual void push (const db::Polygon &shape, const db::Box ®ion, 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 ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
|
||||
void insert_clipped (const db::Polygon &poly, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target);
|
||||
static bool is_inside (const db::Box &box, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region);
|
||||
static bool is_outside (const db::Box &box, const db::Box ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
@ -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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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 ®ion, 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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
Loading…
Reference in New Issue