mirror of https://github.com/KLayout/klayout.git
WIP: more consistent text handling
Texts are not only kept inside original layers, but also inside deep layers. This enables using texts from DRC. However, texts in deep layers are kept as markers. Mostly they are converted back to texts, but the orientation will be lost. The change eliminates the need to using Iterators in DRC instead of original layers and use of label layers in deep mode. A drawback is the presence of marker shapes in deep mode (unless polygon layers are created). Also, text output to RDB is not supported from deep layers currently.
This commit is contained in:
parent
c07d7e92d4
commit
8b29b30ff9
|
|
@ -461,13 +461,20 @@ unsigned int
|
|||
DeepShapeStore::layout_for_iter (const db::RecursiveShapeIterator &si, const db::ICplxTrans &trans)
|
||||
{
|
||||
layout_map_type::iterator l = m_layout_map.find (std::make_pair (si, trans));
|
||||
if (l == m_layout_map.end ()) {
|
||||
if (l == m_layout_map.end () || m_layouts[l->second] == 0) {
|
||||
|
||||
unsigned int layout_index = (unsigned int) m_layouts.size ();
|
||||
unsigned int layout_index;
|
||||
|
||||
m_layouts.push_back (new LayoutHolder (trans));
|
||||
if (l != m_layout_map.end ()) {
|
||||
// reuse discarded entry
|
||||
layout_index = l->second;
|
||||
m_layouts[layout_index] = new LayoutHolder (trans);
|
||||
} else {
|
||||
layout_index = (unsigned int) m_layouts.size ();
|
||||
m_layouts.push_back (new LayoutHolder (trans));
|
||||
}
|
||||
|
||||
db::Layout &layout = m_layouts.back ()->layout;
|
||||
db::Layout &layout = m_layouts[layout_index]->layout;
|
||||
layout.hier_changed_event.add (this, &DeepShapeStore::invalidate_hier);
|
||||
if (si.layout ()) {
|
||||
layout.dbu (si.layout ()->dbu () / trans.mag ());
|
||||
|
|
@ -577,6 +584,32 @@ DeepLayer DeepShapeStore::create_custom_layer (const db::RecursiveShapeIterator
|
|||
return DeepLayer (this, layout_index, layer_index);
|
||||
}
|
||||
|
||||
DeepLayer DeepShapeStore::create_copy (const DeepLayer &source, HierarchyBuilderShapeReceiver *pipe)
|
||||
{
|
||||
tl_assert (source.store () == this);
|
||||
|
||||
unsigned int from_layer_index = source.layer ();
|
||||
db::Layout &ly = layout ();
|
||||
|
||||
unsigned int layer_index = ly.insert_layer ();
|
||||
|
||||
// Build the working hierarchy from the recursive shape iterator
|
||||
tl::SelfTimer timer (tl::verbosity () >= 41, tl::to_string (tr ("Building working hierarchy")));
|
||||
|
||||
db::Box region = db::Box::world ();
|
||||
db::ICplxTrans trans;
|
||||
|
||||
for (db::Layout::iterator c = ly.begin (); c != ly.end (); ++c) {
|
||||
db::Shapes &into = c->shapes (layer_index);
|
||||
const db::Shapes &from = c->shapes (from_layer_index);
|
||||
for (db::Shapes::shape_iterator s = from.begin (db::ShapeIterator::All); ! s.at_end (); ++s) {
|
||||
pipe->push (*s, trans, region, 0, &into);
|
||||
}
|
||||
}
|
||||
|
||||
return DeepLayer (this, source.layout_index (), layer_index);
|
||||
}
|
||||
|
||||
DeepLayer DeepShapeStore::create_edge_layer (const db::RecursiveShapeIterator &si, bool as_edges, const db::ICplxTrans &trans)
|
||||
{
|
||||
unsigned int layout_index = layout_for_iter (si, trans);
|
||||
|
|
@ -725,6 +758,74 @@ DeepShapeStore::cell_mapping_to_original (unsigned int layout_index, db::Layout
|
|||
return cm->second;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class DeepShapeStoreToShapeTransformer
|
||||
: public ShapesTransformer
|
||||
{
|
||||
public:
|
||||
DeepShapeStoreToShapeTransformer (const DeepShapeStore &dss, const db::Layout &layout)
|
||||
: mp_layout (& layout)
|
||||
{
|
||||
// gets the text annotation property ID -
|
||||
// this is how the texts are passed for annotating the net names
|
||||
m_text_annot_name_id = std::pair<bool, db::property_names_id_type> (false, 0);
|
||||
if (! dss.text_property_name ().is_nil ()) {
|
||||
m_text_annot_name_id = mp_layout->properties_repository ().get_id_of_name (dss.text_property_name ());
|
||||
}
|
||||
}
|
||||
|
||||
void insert_transformed (Shapes &into, const Shapes &from, const ICplxTrans &trans, PropertyMapper &pm) const
|
||||
{
|
||||
if (! m_text_annot_name_id.first) {
|
||||
|
||||
// fast shortcut
|
||||
into.insert_transformed (from, trans, pm);
|
||||
|
||||
} else {
|
||||
|
||||
for (db::Shapes::shape_iterator i = from.begin (db::ShapeIterator::All); ! i.at_end (); ++i) {
|
||||
|
||||
bool is_text = false;
|
||||
|
||||
if (i->prop_id () > 0) {
|
||||
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (i->prop_id ());
|
||||
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end () && ! is_text; ++j) {
|
||||
if (j->first == m_text_annot_name_id.second) {
|
||||
|
||||
db::Text text (j->second.to_string (), db::Trans (i->bbox ().center () - db::Point ()));
|
||||
text.transform (trans);
|
||||
if (into.layout ()) {
|
||||
into.insert (db::TextRef (text, into.layout ()->shape_repository ()));
|
||||
} else {
|
||||
into.insert (text);
|
||||
}
|
||||
|
||||
is_text = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! is_text) {
|
||||
into.insert (*i, trans, pm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
std::pair<bool, db::property_names_id_type> m_text_annot_name_id;
|
||||
const db::Layout *mp_layout;
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
DeepShapeStore::insert (const DeepLayer &deep_layer, db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer)
|
||||
{
|
||||
|
|
@ -750,8 +851,11 @@ DeepShapeStore::insert (const DeepLayer &deep_layer, db::Layout *into_layout, db
|
|||
std::vector <db::cell_index_type> source_cells;
|
||||
source_cells.push_back (*source_layout.begin_top_down());
|
||||
|
||||
// prepare a transformer to convert text-annotated markers back to texts (without transformation however)
|
||||
DeepShapeStoreToShapeTransformer dsst (*this, source_layout);
|
||||
|
||||
// actually copy the shapes
|
||||
db::copy_shapes (*into_layout, source_layout, trans, source_cells, cm.table (), lm);
|
||||
db::copy_shapes (*into_layout, source_layout, trans, source_cells, cm.table (), lm, &dsst);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -334,6 +334,11 @@ public:
|
|||
*/
|
||||
DeepLayer create_custom_layer (const db::RecursiveShapeIterator &si, HierarchyBuilderShapeReceiver *pipe, const ICplxTrans &trans = db::ICplxTrans ());
|
||||
|
||||
/**
|
||||
* @brief Creates a deep layer as a copy from an existing one
|
||||
*/
|
||||
DeepLayer create_copy (const DeepLayer &source, HierarchyBuilderShapeReceiver *pipe);
|
||||
|
||||
/**
|
||||
* @brief Gets the empty working layer
|
||||
*
|
||||
|
|
|
|||
|
|
@ -58,8 +58,6 @@ LayoutToNetlist::LayoutToNetlist (db::DeepShapeStore *dss, unsigned int layout_i
|
|||
if (dss->is_valid_layout_index (m_layout_index)) {
|
||||
m_iter = db::RecursiveShapeIterator (dss->layout (m_layout_index), dss->initial_cell (m_layout_index), std::set<unsigned int> ());
|
||||
}
|
||||
|
||||
init ();
|
||||
}
|
||||
|
||||
LayoutToNetlist::LayoutToNetlist (const std::string &topcell_name, double dbu)
|
||||
|
|
@ -131,9 +129,7 @@ db::Region *LayoutToNetlist::make_layer (const std::string &n)
|
|||
si.shape_flags (db::ShapeIterator::Nothing);
|
||||
|
||||
std::auto_ptr <db::Region> region (new db::Region (si, dss ()));
|
||||
if (! n.empty ()) {
|
||||
register_layer (*region, n);
|
||||
}
|
||||
register_layer (*region, n);
|
||||
return region.release ();
|
||||
}
|
||||
|
||||
|
|
@ -144,9 +140,7 @@ db::Region *LayoutToNetlist::make_layer (unsigned int layer_index, const std::st
|
|||
si.shape_flags (db::ShapeIterator::All);
|
||||
|
||||
std::auto_ptr <db::Region> region (new db::Region (si, dss ()));
|
||||
if (! n.empty ()) {
|
||||
register_layer (*region, n);
|
||||
}
|
||||
register_layer (*region, n);
|
||||
return region.release ();
|
||||
}
|
||||
|
||||
|
|
@ -157,9 +151,7 @@ db::Region *LayoutToNetlist::make_text_layer (unsigned int layer_index, const st
|
|||
si.shape_flags (db::ShapeIterator::Texts);
|
||||
|
||||
std::auto_ptr <db::Region> region (new db::Region (si, dss ()));
|
||||
if (! n.empty ()) {
|
||||
register_layer (*region, n);
|
||||
}
|
||||
register_layer (*region, n);
|
||||
return region.release ();
|
||||
}
|
||||
|
||||
|
|
@ -170,9 +162,7 @@ db::Region *LayoutToNetlist::make_polygon_layer (unsigned int layer_index, const
|
|||
si.shape_flags (db::ShapeIterator::Paths | db::ShapeIterator::Polygons | db::ShapeIterator::Boxes);
|
||||
|
||||
std::auto_ptr <db::Region> region (new db::Region (si, dss ()));
|
||||
if (! n.empty ()) {
|
||||
register_layer (*region, n);
|
||||
}
|
||||
register_layer (*region, n);
|
||||
return region.release ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -259,7 +259,8 @@ copy_or_propagate_shapes (db::Layout &target,
|
|||
db::cell_index_type source_parent_cell_index,
|
||||
unsigned int target_layer, unsigned int source_layer,
|
||||
const std::set<db::cell_index_type> &all_cells_to_copy,
|
||||
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping)
|
||||
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
|
||||
const ShapesTransformer *transformer)
|
||||
{
|
||||
const db::Cell &source_cell = source.cell (source_cell_index);
|
||||
const db::Cell &source_parent_cell = source.cell (source_parent_cell_index);
|
||||
|
|
@ -273,7 +274,7 @@ copy_or_propagate_shapes (db::Layout &target,
|
|||
const db::CellInstArray &cell_inst = p->child_inst ().cell_inst ();
|
||||
for (db::CellInstArray::iterator a = cell_inst.begin (); ! a.at_end (); ++a) {
|
||||
db::ICplxTrans t = db::ICplxTrans (cell_inst.complex_trans (*a)) * propagate_trans;
|
||||
copy_or_propagate_shapes (target, source, trans, t, pm, source_cell_index, p->parent_cell_index (), target_layer, source_layer, all_cells_to_copy, cell_mapping);
|
||||
copy_or_propagate_shapes (target, source, trans, t, pm, source_cell_index, p->parent_cell_index (), target_layer, source_layer, all_cells_to_copy, cell_mapping, transformer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,8 +283,7 @@ copy_or_propagate_shapes (db::Layout &target,
|
|||
} else if (cm->second != DropCell) {
|
||||
|
||||
db::Cell &target_cell = target.cell (cm->second);
|
||||
target_cell.shapes (target_layer).insert_transformed (source_cell.shapes (source_layer), trans * propagate_trans, pm);
|
||||
|
||||
transformer->insert_transformed (target_cell.shapes (target_layer), source_cell.shapes (source_layer), trans * propagate_trans, pm);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +294,9 @@ copy_or_move_shapes (db::Layout &target,
|
|||
const std::vector<db::cell_index_type> &source_cells,
|
||||
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping,
|
||||
bool move)
|
||||
const ShapesTransformer *transformer,
|
||||
bool move
|
||||
)
|
||||
{
|
||||
// collect all called cells and all top level cells
|
||||
std::set<db::cell_index_type> all_top_level_cells;
|
||||
|
|
@ -311,7 +313,7 @@ copy_or_move_shapes (db::Layout &target,
|
|||
for (std::set<db::cell_index_type>::const_iterator c = all_cells_to_copy.begin (); c != all_cells_to_copy.end (); ++c) {
|
||||
for (std::map<unsigned int, unsigned int>::const_iterator lm = layer_mapping.begin (); lm != layer_mapping.end (); ++lm) {
|
||||
++progress;
|
||||
copy_or_propagate_shapes (target, source, trans, db::ICplxTrans (), pm, *c, *c, lm->second, lm->first, all_cells_to_copy, cell_mapping);
|
||||
copy_or_propagate_shapes (target, source, trans, db::ICplxTrans (), pm, *c, *c, lm->second, lm->first, all_cells_to_copy, cell_mapping, transformer);
|
||||
if (move) {
|
||||
source.cell (*c).shapes (lm->first).clear ();
|
||||
}
|
||||
|
|
@ -319,15 +321,33 @@ copy_or_move_shapes (db::Layout &target,
|
|||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class StandardShapesTransformer
|
||||
: public ShapesTransformer
|
||||
{
|
||||
public:
|
||||
void insert_transformed (Shapes &into, const Shapes &from, const ICplxTrans &trans, PropertyMapper &pm) const
|
||||
{
|
||||
into.insert_transformed (from, trans, pm);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
copy_shapes (db::Layout &target,
|
||||
const db::Layout &source,
|
||||
const db::ICplxTrans &trans,
|
||||
const std::vector<db::cell_index_type> &source_cells,
|
||||
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping)
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping,
|
||||
const ShapesTransformer *transformer)
|
||||
{
|
||||
copy_or_move_shapes (target, const_cast<db::Layout &> (source), trans, source_cells, cell_mapping, layer_mapping, false);
|
||||
StandardShapesTransformer st;
|
||||
if (! transformer) {
|
||||
transformer = &st;
|
||||
}
|
||||
copy_or_move_shapes (target, const_cast<db::Layout &> (source), trans, source_cells, cell_mapping, layer_mapping, transformer, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -336,9 +356,14 @@ move_shapes (db::Layout &target,
|
|||
const db::ICplxTrans &trans,
|
||||
const std::vector<db::cell_index_type> &source_cells,
|
||||
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping)
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping,
|
||||
const ShapesTransformer *transformer)
|
||||
{
|
||||
copy_or_move_shapes (target, source, trans, source_cells, cell_mapping, layer_mapping, true);
|
||||
StandardShapesTransformer st;
|
||||
if (! transformer) {
|
||||
transformer = &st;
|
||||
}
|
||||
copy_or_move_shapes (target, source, trans, source_cells, cell_mapping, layer_mapping, transformer, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -140,6 +140,21 @@ merge_layouts (db::Layout &target, const db::Layout &source, const db::ICplxTran
|
|||
const std::map<unsigned int, unsigned int> &layer_mapping,
|
||||
std::map<db::cell_index_type, db::cell_index_type> *final_cell_mapping = 0);
|
||||
|
||||
/**
|
||||
* @brief An interface for the shape inserter
|
||||
*
|
||||
* This interface is used by copy_shapes and move_shapes to insert
|
||||
* a shape collection into a another one. By reimplementing this interface,
|
||||
* more shape transformations can be provided.
|
||||
*/
|
||||
class DB_PUBLIC ShapesTransformer
|
||||
{
|
||||
public:
|
||||
ShapesTransformer () { }
|
||||
virtual ~ShapesTransformer () { }
|
||||
virtual void insert_transformed (db::Shapes &into, const db::Shapes &from, const db::ICplxTrans &trans, db::PropertyMapper &pm) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Copy shapes from one layout to another
|
||||
*
|
||||
|
|
@ -155,7 +170,8 @@ copy_shapes (db::Layout &target,
|
|||
const db::ICplxTrans &trans,
|
||||
const std::vector<db::cell_index_type> &source_cells,
|
||||
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping);
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping,
|
||||
const ShapesTransformer *transformer = 0);
|
||||
|
||||
/**
|
||||
* @brief Move shapes from one layout to another
|
||||
|
|
@ -172,7 +188,8 @@ move_shapes (db::Layout &target,
|
|||
const db::ICplxTrans &trans,
|
||||
const std::vector<db::cell_index_type> &source_cells,
|
||||
const std::map<db::cell_index_type, db::cell_index_type> &cell_mapping,
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping);
|
||||
const std::map<unsigned int, unsigned int> &layer_mapping,
|
||||
const ShapesTransformer *transformer = 0);
|
||||
|
||||
/**
|
||||
* @brief Find an example cell instance from a child to a top cell
|
||||
|
|
|
|||
|
|
@ -149,13 +149,13 @@ void NetlistDeviceExtractor::extract (db::DeepShapeStore &dss, unsigned int layo
|
|||
// provide a substitute empty layer
|
||||
layers.push_back (dss.empty_layer (layout_index).layer ());
|
||||
} else {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction: must be of deep region kind")), ld->name));
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction (device %s): must be of deep region kind")), ld->name, name ()));
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (&dr->deep_layer ().layout () != &dss.layout (layout_index) || &dr->deep_layer ().initial_cell () != &dss.initial_cell (layout_index)) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction: not originating from the same source")), ld->name));
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Invalid region passed to input layer '%s' for device extraction (device %s): not originating from the same source")), ld->name, name ()));
|
||||
}
|
||||
|
||||
layers.push_back (dr->deep_layer ().layer ());
|
||||
|
|
|
|||
|
|
@ -250,6 +250,20 @@ OriginalLayerRegion::init ()
|
|||
m_merged_polygons_valid = false;
|
||||
}
|
||||
|
||||
void
|
||||
OriginalLayerRegion::insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const
|
||||
{
|
||||
db::Shapes &sh = layout->cell (into_cell).shapes (into_layer);
|
||||
|
||||
// NOTE: if the source (r) is from the same layout than the shapes live in, we better
|
||||
// lock the layout against updates while inserting
|
||||
db::LayoutLocker locker (layout);
|
||||
for (db::RecursiveShapeIterator i = m_iter; !i.at_end (); ++i) {
|
||||
tl::ident_map<db::properties_id_type> pm;
|
||||
sh.insert (*i, i.trans (), pm);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OriginalLayerRegion::ensure_merged_polygons_valid () const
|
||||
{
|
||||
|
|
@ -284,165 +298,4 @@ OriginalLayerRegion::ensure_merged_polygons_valid () const
|
|||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class Container>
|
||||
struct dot_delivery
|
||||
{
|
||||
typedef Container container_type;
|
||||
|
||||
dot_delivery ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::Point &pt, Container *container) const
|
||||
{
|
||||
container->insert (db::Edge (pt, pt));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
struct box_delivery
|
||||
{
|
||||
typedef Container container_type;
|
||||
|
||||
box_delivery (db::Coord enl)
|
||||
: m_d (enl, enl)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::Point &pt, Container *container) const
|
||||
{
|
||||
container->insert (db::Box (pt - m_d, pt + m_d));
|
||||
}
|
||||
|
||||
private:
|
||||
db::Vector m_d;
|
||||
};
|
||||
|
||||
template <class Iter, class Delivery>
|
||||
static void fill_texts (const Iter &iter, const std::string &pat, bool pattern, const Delivery &delivery, typename Delivery::container_type *container)
|
||||
{
|
||||
tl::GlobPattern glob_pat;
|
||||
bool all = false;
|
||||
if (pattern) {
|
||||
if (pat == "*") {
|
||||
all = true;
|
||||
} else {
|
||||
glob_pat = tl::GlobPattern (pat);
|
||||
}
|
||||
}
|
||||
|
||||
for (Iter si = iter; ! si.at_end (); ++si) {
|
||||
if (si->is_text () &&
|
||||
(all || (pattern && glob_pat.match (si->text_string ())) || (!pattern && si->text_string () == pat))) {
|
||||
db::Text t;
|
||||
si->text (t);
|
||||
t.transform (si.trans ());
|
||||
delivery.insert (t.box ().center (), container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Delivery>
|
||||
class text_shape_receiver
|
||||
: public db::HierarchyBuilderShapeReceiver
|
||||
{
|
||||
public:
|
||||
text_shape_receiver (const Delivery &delivery, const std::string &pat, bool pattern)
|
||||
: m_delivery (delivery), m_glob_pat (), m_all (false), m_pattern (pattern), m_pat (pat)
|
||||
{
|
||||
if (pattern) {
|
||||
if (m_pat == "*") {
|
||||
m_all = true;
|
||||
} else {
|
||||
m_glob_pat = tl::GlobPattern (pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
|
||||
{
|
||||
if (shape.is_text () &&
|
||||
(m_all || (m_pattern && m_glob_pat.match (shape.text_string ())) || (!m_pattern && shape.text_string () == m_pat))) {
|
||||
|
||||
db::Point pt = shape.bbox ().center ();
|
||||
|
||||
if (! complex_region) {
|
||||
if (region.contains (pt)) {
|
||||
m_delivery.insert (pt.transformed (trans), target);
|
||||
}
|
||||
} else {
|
||||
if (! complex_region->begin_overlapping (db::Box (pt, pt), db::box_convert<db::Box> ()).at_end ()) {
|
||||
m_delivery.insert (pt.transformed (trans), target);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
|
||||
private:
|
||||
Delivery m_delivery;
|
||||
tl::GlobPattern m_glob_pat;
|
||||
bool m_all;
|
||||
bool m_pattern;
|
||||
std::string m_pat;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
db::EdgesDelegate *
|
||||
OriginalLayerRegion::texts_as_dots (const std::string &pat, bool pattern) const
|
||||
{
|
||||
db::RecursiveShapeIterator iter (m_iter);
|
||||
iter.shape_flags (db::ShapeIterator::Texts);
|
||||
|
||||
std::auto_ptr<db::FlatEdges> res (new db::FlatEdges ());
|
||||
res->set_merged_semantics (false);
|
||||
|
||||
fill_texts (iter, pat, pattern, dot_delivery<db::FlatEdges> (), res.get ());
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
db::EdgesDelegate *
|
||||
OriginalLayerRegion::texts_as_dots (const std::string &pat, bool pattern, db::DeepShapeStore &store) const
|
||||
{
|
||||
db::RecursiveShapeIterator iter (m_iter);
|
||||
iter.shape_flags (db::ShapeIterator::Texts);
|
||||
|
||||
text_shape_receiver<dot_delivery<db::Shapes> > pipe = text_shape_receiver<dot_delivery<db::Shapes> > (dot_delivery<db::Shapes> (), pat, pattern);
|
||||
return new db::DeepEdges (store.create_custom_layer (iter, &pipe));
|
||||
}
|
||||
|
||||
db::RegionDelegate *
|
||||
OriginalLayerRegion::texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl) const
|
||||
{
|
||||
db::RecursiveShapeIterator iter (m_iter);
|
||||
iter.shape_flags (db::ShapeIterator::Texts);
|
||||
|
||||
std::auto_ptr<db::FlatRegion> res (new db::FlatRegion ());
|
||||
res->set_merged_semantics (false);
|
||||
|
||||
fill_texts (iter, pat, pattern, box_delivery<db::FlatRegion> (enl), res.get ());
|
||||
|
||||
return res.release ();
|
||||
}
|
||||
|
||||
db::RegionDelegate *
|
||||
OriginalLayerRegion::texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl, db::DeepShapeStore &store) const
|
||||
{
|
||||
db::RecursiveShapeIterator iter (m_iter);
|
||||
iter.shape_flags (db::ShapeIterator::Texts);
|
||||
|
||||
text_shape_receiver<box_delivery<db::Shapes> > pipe = text_shape_receiver<box_delivery<db::Shapes> > (box_delivery<db::Shapes> (enl), pat, pattern);
|
||||
return new db::DeepRegion (store.create_custom_layer (iter, &pipe));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,10 +68,7 @@ public:
|
|||
virtual bool equals (const Region &other) const;
|
||||
virtual bool less (const Region &other) const;
|
||||
|
||||
db::EdgesDelegate *texts_as_dots (const std::string &pat, bool pattern) const;
|
||||
db::EdgesDelegate *texts_as_dots (const std::string &pat, bool pattern, db::DeepShapeStore &store) const;
|
||||
db::RegionDelegate *texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl) const;
|
||||
db::RegionDelegate *texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl, db::DeepShapeStore &store) const;
|
||||
virtual void insert_into (Layout *layout, db::cell_index_type into_cell, unsigned int into_layer) const;
|
||||
|
||||
protected:
|
||||
virtual void merged_semantics_changed ();
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@
|
|||
#include "dbEmptyRegion.h"
|
||||
#include "dbFlatRegion.h"
|
||||
#include "dbDeepRegion.h"
|
||||
#include "dbDeepEdges.h"
|
||||
#include "dbFlatEdges.h"
|
||||
#include "dbPolygonTools.h"
|
||||
#include "tlGlobPattern.h"
|
||||
|
||||
namespace db
|
||||
{
|
||||
|
|
@ -398,6 +401,291 @@ Region::hulls () const
|
|||
return Region (processed (HullExtractionProcessor ()));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <class Container>
|
||||
struct dot_delivery
|
||||
{
|
||||
typedef Container container_type;
|
||||
|
||||
dot_delivery ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::Point &pt, Container *container) const
|
||||
{
|
||||
container->insert (db::Edge (pt, pt));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
struct box_delivery
|
||||
{
|
||||
typedef Container container_type;
|
||||
|
||||
box_delivery (db::Coord enl)
|
||||
: m_d (enl, enl)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void insert (const db::Point &pt, Container *container) const
|
||||
{
|
||||
container->insert (db::Box (pt - m_d, pt + m_d));
|
||||
}
|
||||
|
||||
private:
|
||||
db::Vector m_d;
|
||||
};
|
||||
|
||||
template <class Iter, class Delivery>
|
||||
static void fill_texts (const Iter &iter, const std::string &pat, bool pattern, const Delivery &delivery, typename Delivery::container_type *container, const db::ICplxTrans &trans, const db::DeepRegion *org_deep)
|
||||
{
|
||||
std::pair<bool, db::property_names_id_type> text_annot_name_id;
|
||||
const db::Layout *layout = 0;
|
||||
|
||||
if (org_deep) {
|
||||
layout = &org_deep->deep_layer ().layout ();
|
||||
const db::DeepShapeStore *store = org_deep->deep_layer ().store ();
|
||||
if (! store->text_property_name ().is_nil ()) {
|
||||
text_annot_name_id = layout->properties_repository ().get_id_of_name (store->text_property_name ());
|
||||
}
|
||||
}
|
||||
|
||||
tl::GlobPattern glob_pat;
|
||||
bool all = false;
|
||||
if (pattern) {
|
||||
if (pat == "*") {
|
||||
all = true;
|
||||
} else {
|
||||
glob_pat = tl::GlobPattern (pat);
|
||||
}
|
||||
}
|
||||
|
||||
for (Iter si = iter; ! si.at_end (); ++si) {
|
||||
|
||||
bool is_text = false;
|
||||
std::string text_string;
|
||||
|
||||
if (si->is_text ()) {
|
||||
|
||||
// a raw text
|
||||
is_text = true;
|
||||
text_string = si->text_string ();
|
||||
|
||||
} else if (layout && text_annot_name_id.first && si->prop_id () > 0) {
|
||||
|
||||
// a text marker
|
||||
const db::PropertiesRepository::properties_set &ps = layout->properties_repository ().properties (si->prop_id ());
|
||||
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end () && ! is_text; ++j) {
|
||||
if (j->first == text_annot_name_id.second) {
|
||||
text_string = j->second.to_string ();
|
||||
is_text = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is_text &&
|
||||
(all || (pattern && glob_pat.match (text_string)) || (!pattern && text_string == pat))) {
|
||||
delivery.insert (si.trans () * (trans * si->bbox ().center ()), container);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Delivery>
|
||||
class text_shape_receiver
|
||||
: public db::HierarchyBuilderShapeReceiver
|
||||
{
|
||||
public:
|
||||
text_shape_receiver (const Delivery &delivery, const std::string &pat, bool pattern, const db::DeepRegion *org_deep)
|
||||
: m_delivery (delivery), m_glob_pat (), m_all (false), m_pattern (pattern), m_pat (pat), m_text_annot_name_id (false, 0), mp_layout (0)
|
||||
{
|
||||
if (org_deep) {
|
||||
mp_layout = & org_deep->deep_layer ().layout ();
|
||||
const db::DeepShapeStore *store = org_deep->deep_layer ().store ();
|
||||
if (! store->text_property_name ().is_nil ()) {
|
||||
m_text_annot_name_id = mp_layout->properties_repository ().get_id_of_name (store->text_property_name ());
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern) {
|
||||
if (m_pat == "*") {
|
||||
m_all = true;
|
||||
} else {
|
||||
m_glob_pat = tl::GlobPattern (pat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void push (const db::Shape &shape, const db::ICplxTrans &trans, const db::Box ®ion, const db::RecursiveShapeReceiver::box_tree_type *complex_region, db::Shapes *target)
|
||||
{
|
||||
bool is_text = false;
|
||||
std::string text_string;
|
||||
|
||||
if (shape.is_text ()) {
|
||||
|
||||
// a raw text
|
||||
is_text = true;
|
||||
text_string = shape.text_string ();
|
||||
|
||||
} else if (mp_layout && m_text_annot_name_id.first && shape.prop_id () > 0) {
|
||||
|
||||
// a text marker
|
||||
const db::PropertiesRepository::properties_set &ps = mp_layout->properties_repository ().properties (shape.prop_id ());
|
||||
|
||||
for (db::PropertiesRepository::properties_set::const_iterator j = ps.begin (); j != ps.end () && ! is_text; ++j) {
|
||||
if (j->first == m_text_annot_name_id.second) {
|
||||
text_string = j->second.to_string ();
|
||||
is_text = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (is_text &&
|
||||
(m_all || (m_pattern && m_glob_pat.match (text_string)) || (!m_pattern && text_string == m_pat))) {
|
||||
|
||||
db::Point pt = shape.bbox ().center ();
|
||||
|
||||
if (! complex_region) {
|
||||
if (region.contains (pt)) {
|
||||
m_delivery.insert (pt.transformed (trans), target);
|
||||
}
|
||||
} else {
|
||||
if (! complex_region->begin_overlapping (db::Box (pt, pt), db::box_convert<db::Box> ()).at_end ()) {
|
||||
m_delivery.insert (pt.transformed (trans), target);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
virtual void push (const db::Box &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
virtual void push (const db::Polygon &, const db::ICplxTrans &, const db::Box &, const db::RecursiveShapeReceiver::box_tree_type *, db::Shapes *) { }
|
||||
|
||||
private:
|
||||
Delivery m_delivery;
|
||||
tl::GlobPattern m_glob_pat;
|
||||
bool m_all;
|
||||
bool m_pattern;
|
||||
std::string m_pat;
|
||||
std::pair<bool, db::property_names_id_type> m_text_annot_name_id;
|
||||
const db::Layout *mp_layout;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Edges
|
||||
Region::texts_as_dots (const std::string &pat, bool pattern) const
|
||||
{
|
||||
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (delegate ());
|
||||
if (dr) {
|
||||
return texts_as_dots (pat, pattern, const_cast<db::DeepShapeStore &> (*dr->deep_layer ().store ()));
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> si = begin_iter ();
|
||||
if (! dr) {
|
||||
// some optimization
|
||||
si.first.shape_flags (db::ShapeIterator::Texts);
|
||||
}
|
||||
|
||||
std::auto_ptr<db::FlatEdges> res (new db::FlatEdges ());
|
||||
res->set_merged_semantics (false);
|
||||
|
||||
fill_texts (si.first, pat, pattern, dot_delivery<db::FlatEdges> (), res.get (), si.second, dr);
|
||||
|
||||
return Edges (res.release ());
|
||||
}
|
||||
|
||||
Edges
|
||||
Region::texts_as_dots (const std::string &pat, bool pattern, db::DeepShapeStore &store) const
|
||||
{
|
||||
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (delegate ());
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> si = begin_iter ();
|
||||
if (! dr) {
|
||||
// some optimization
|
||||
si.first.shape_flags (db::ShapeIterator::Texts);
|
||||
}
|
||||
|
||||
if (! si.first.layout ()) {
|
||||
|
||||
// flat fallback if the source isn't a deep or original layer
|
||||
std::auto_ptr<db::FlatEdges> res (new db::FlatEdges ());
|
||||
res->set_merged_semantics (false);
|
||||
|
||||
fill_texts (si.first, pat, pattern, dot_delivery<db::FlatEdges> (), res.get (), si.second, dr);
|
||||
|
||||
return Edges (res.release ());
|
||||
|
||||
}
|
||||
|
||||
text_shape_receiver<dot_delivery<db::Shapes> > pipe = text_shape_receiver<dot_delivery<db::Shapes> > (dot_delivery<db::Shapes> (), pat, pattern, dr);
|
||||
if (dr && dr->deep_layer ().store () == &store) {
|
||||
return Edges (new db::DeepEdges (store.create_copy (dr->deep_layer (), &pipe)));
|
||||
} else {
|
||||
return Edges (new db::DeepEdges (store.create_custom_layer (si.first, &pipe, si.second)));
|
||||
}
|
||||
}
|
||||
|
||||
Region
|
||||
Region::texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl) const
|
||||
{
|
||||
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (delegate ());
|
||||
if (dr) {
|
||||
return texts_as_boxes (pat, pattern, enl, const_cast<db::DeepShapeStore &> (*dr->deep_layer ().store ()));
|
||||
}
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> si = begin_iter ();
|
||||
if (! dr) {
|
||||
// some optimization
|
||||
si.first.shape_flags (db::ShapeIterator::Texts);
|
||||
}
|
||||
|
||||
std::auto_ptr<db::FlatRegion> res (new db::FlatRegion ());
|
||||
res->set_merged_semantics (false);
|
||||
|
||||
fill_texts (si.first, pat, pattern, box_delivery<db::FlatRegion> (enl), res.get (), si.second, dr);
|
||||
|
||||
return Region (res.release ());
|
||||
}
|
||||
|
||||
Region
|
||||
Region::texts_as_boxes (const std::string &pat, bool pattern, db::Coord enl, db::DeepShapeStore &store) const
|
||||
{
|
||||
const db::DeepRegion *dr = dynamic_cast<const db::DeepRegion *> (delegate ());
|
||||
|
||||
std::pair<db::RecursiveShapeIterator, db::ICplxTrans> si = begin_iter ();
|
||||
if (! dr) {
|
||||
// some optimization
|
||||
si.first.shape_flags (db::ShapeIterator::Texts);
|
||||
}
|
||||
|
||||
if (! si.first.layout ()) {
|
||||
|
||||
// flat fallback if the source isn't a deep or original layer
|
||||
std::auto_ptr<db::FlatRegion> res (new db::FlatRegion ());
|
||||
res->set_merged_semantics (false);
|
||||
|
||||
fill_texts (si.first, pat, pattern, box_delivery<db::FlatRegion> (enl), res.get (), si.second, dr);
|
||||
|
||||
return Region (res.release ());
|
||||
|
||||
}
|
||||
|
||||
text_shape_receiver<box_delivery<db::Shapes> > pipe = text_shape_receiver<box_delivery<db::Shapes> > (box_delivery<db::Shapes> (enl), pat, pattern, dr);
|
||||
if (dr && dr->deep_layer ().store () == &store) {
|
||||
return Region (new db::DeepRegion (store.create_copy (dr->deep_layer (), &pipe)));
|
||||
} else {
|
||||
return Region (new db::DeepRegion (store.create_custom_layer (si.first, &pipe, si.second)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace tl
|
||||
|
|
|
|||
|
|
@ -1516,6 +1516,40 @@ public:
|
|||
return mp_delegate->insert_into (layout, into_cell, into_layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Delivers texts as dots (degenerated edges)
|
||||
*
|
||||
* "pat" is a text selector. If "as_pattern" is true, this pattern will be
|
||||
* treated as a glob pattern. Otherwise, the text is taken if "pat" is equal to the text..
|
||||
*/
|
||||
db::Edges texts_as_dots (const std::string &pat, bool as_pattern) const;
|
||||
|
||||
/**
|
||||
* @brief Delivers texts as dots (degenerated edges) in a deep edge collection
|
||||
*
|
||||
* "pat" is a text selector. If "as_pattern" is true, this pattern will be
|
||||
* treated as a glob pattern. Otherwise, the text is taken if "pat" is equal to the text..
|
||||
*/
|
||||
db::Edges texts_as_dots (const std::string &pat, bool as_pattern, db::DeepShapeStore &store) const;
|
||||
|
||||
/**
|
||||
* @brief Delivers texts as boxes
|
||||
*
|
||||
* "pat" is a text selector. If "as_pattern" is true, this pattern will be
|
||||
* treated as a glob pattern. Otherwise, the text is taken if "pat" is equal to the text.
|
||||
* "enl" is the half size of the box (the box is 2*enl wide and 2*enl high).
|
||||
*/
|
||||
db::Region texts_as_boxes (const std::string &pat, bool as_pattern, db::Coord enl) const;
|
||||
|
||||
/**
|
||||
* @brief Delivers texts as boxes in a deep region
|
||||
*
|
||||
* "pat" is a text selector. If "as_pattern" is true, this pattern will be
|
||||
* treated as a glob pattern. Otherwise, the text is taken if "pat" is equal to the text.
|
||||
* "enl" is the half size of the box (the box is 2*enl wide and 2*enl high).
|
||||
*/
|
||||
db::Region texts_as_boxes (const std::string &pat, bool as_pattern, db::Coord enl, db::DeepShapeStore &store) const;
|
||||
|
||||
private:
|
||||
friend class Edges;
|
||||
friend class EdgePairs;
|
||||
|
|
|
|||
|
|
@ -392,12 +392,12 @@ static bool is_deep (const db::Edges *e)
|
|||
|
||||
static db::Edges *new_texts_as_dots1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern)
|
||||
{
|
||||
return new db::Edges (db::OriginalLayerRegion (si, false).texts_as_dots (pat, pattern));
|
||||
return new db::Edges (db::Region (si).texts_as_dots (pat, pattern));
|
||||
}
|
||||
|
||||
static db::Edges *new_texts_as_dots2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const std::string &pat, bool pattern)
|
||||
{
|
||||
return new db::Edges (db::OriginalLayerRegion (si, false).texts_as_dots (pat, pattern, dss));
|
||||
return new db::Edges (db::Region (si).texts_as_dots (pat, pattern, dss));
|
||||
}
|
||||
|
||||
static size_t id (const db::Edges *e)
|
||||
|
|
|
|||
|
|
@ -80,41 +80,32 @@ static db::Region *new_shapes (const db::Shapes &s)
|
|||
|
||||
static db::Region *new_texts_as_boxes1 (const db::RecursiveShapeIterator &si, const std::string &pat, bool pattern, db::Coord enl)
|
||||
{
|
||||
return new db::Region (db::OriginalLayerRegion (si, false).texts_as_boxes (pat, pattern, enl));
|
||||
return new db::Region (db::Region (si).texts_as_boxes (pat, pattern, enl));
|
||||
}
|
||||
|
||||
static db::Region *new_texts_as_boxes2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const std::string &pat, bool pattern, db::Coord enl)
|
||||
{
|
||||
return new db::Region (db::OriginalLayerRegion (si, false).texts_as_boxes (pat, pattern, enl, dss));
|
||||
}
|
||||
|
||||
static const db::OriginalLayerRegion *org_layer (const db::Region *r)
|
||||
{
|
||||
const db::OriginalLayerRegion *org_layer = dynamic_cast<const db::OriginalLayerRegion *> (r->delegate ());
|
||||
if (! org_layer) {
|
||||
throw tl::Exception (tl::to_string (tr ("Texts can only be identified on an original layer")));
|
||||
}
|
||||
return org_layer;
|
||||
return new db::Region (db::Region (si).texts_as_boxes (pat, pattern, enl, dss));
|
||||
}
|
||||
|
||||
static db::Edges *texts_as_dots1 (const db::Region *r, const std::string &pat, bool pattern)
|
||||
{
|
||||
return new db::Edges (org_layer (r)->texts_as_dots (pat, pattern));
|
||||
return new db::Edges (r->texts_as_dots (pat, pattern));
|
||||
}
|
||||
|
||||
static db::Edges *texts_as_dots2 (const db::Region *r, db::DeepShapeStore &dss, const std::string &pat, bool pattern)
|
||||
{
|
||||
return new db::Edges (org_layer (r)->texts_as_dots (pat, pattern, dss));
|
||||
return new db::Edges (r->texts_as_dots (pat, pattern, dss));
|
||||
}
|
||||
|
||||
static db::Region *texts_as_boxes1 (const db::Region *r, const std::string &pat, bool pattern, db::Coord enl)
|
||||
{
|
||||
return new db::Region (org_layer (r)->texts_as_boxes (pat, pattern, enl));
|
||||
return new db::Region (r->texts_as_boxes (pat, pattern, enl));
|
||||
}
|
||||
|
||||
static db::Region *texts_as_boxes2 (const db::Region *r, db::DeepShapeStore &dss, const std::string &pat, bool pattern, db::Coord enl)
|
||||
{
|
||||
return new db::Region (org_layer (r)->texts_as_boxes (pat, pattern, enl, dss));
|
||||
return new db::Region (r->texts_as_boxes (pat, pattern, enl, dss));
|
||||
}
|
||||
|
||||
static db::Edges corners_to_dots (const db::Region *r, double angle_start, double angle_end)
|
||||
|
|
@ -142,6 +133,11 @@ static db::Region *new_si2 (const db::RecursiveShapeIterator &si, const db::ICpl
|
|||
return new db::Region (si, trans);
|
||||
}
|
||||
|
||||
static db::Region *new_sid2 (const db::RecursiveShapeIterator &si, db::DeepShapeStore &dss, const db::ICplxTrans &trans, double area_ratio, size_t max_vertex_count)
|
||||
{
|
||||
return new db::Region (si, dss, trans, area_ratio, max_vertex_count);
|
||||
}
|
||||
|
||||
static std::string to_string0 (const db::Region *r)
|
||||
{
|
||||
return r->to_string ();
|
||||
|
|
@ -653,9 +649,8 @@ Class<db::Region> decl_Region ("db", "Region",
|
|||
"\n"
|
||||
"This constructor has been introduced in version 0.25."
|
||||
) +
|
||||
constructor ("new", &new_si,
|
||||
constructor ("new", &new_si, gsi::arg ("shape_iterator"),
|
||||
"@brief Constructor from a hierarchical shape set\n"
|
||||
"@args shape_iterator\n"
|
||||
"\n"
|
||||
"This constructor creates a region from the shapes delivered by the given recursive shape iterator.\n"
|
||||
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
|
||||
|
|
@ -668,9 +663,8 @@ Class<db::Region> decl_Region ("db", "Region",
|
|||
"r = RBA::Region::new(layout.begin_shapes(cell, layer))\n"
|
||||
"@/code\n"
|
||||
) +
|
||||
constructor ("new", &new_si2,
|
||||
constructor ("new", &new_si2, gsi::arg ("shape_iterator"), gsi::arg ("trans"),
|
||||
"@brief Constructor from a hierarchical shape set with a transformation\n"
|
||||
"@args shape_iterator, trans\n"
|
||||
"\n"
|
||||
"This constructor creates a region from the shapes delivered by the given recursive shape iterator.\n"
|
||||
"Text objects and edges are not inserted, because they cannot be converted to polygons.\n"
|
||||
|
|
@ -698,7 +692,24 @@ Class<db::Region> decl_Region ("db", "Region",
|
|||
"@param shape_iterator The recursive shape iterator which delivers the hierarchy to take\n"
|
||||
"@param deep_shape_store The hierarchical heap (see there)\n"
|
||||
"@param area_ratio The maximum ratio of bounding box to polygon area before polygons are split\n"
|
||||
"@param"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.\n"
|
||||
) +
|
||||
constructor ("new", &new_sid2, gsi::arg ("shape_iterator"), gsi::arg ("deep_shape_store"), gsi::arg ("trans"), gsi::arg ("area_ratio", 0.0), gsi::arg ("max_vertex_count", size_t (0)),
|
||||
"@brief Constructor for a deep region from a hierarchical shape set\n"
|
||||
"\n"
|
||||
"This constructor creates a hierarchical region. Use a \\DeepShapeStore object to "
|
||||
"supply the hierarchical heap. See \\DeepShapeStore for more details.\n"
|
||||
"\n"
|
||||
"'area_ratio' and 'max_vertex' supply two optimization parameters which control how "
|
||||
"big polygons are split to reduce the region's polygon complexity.\n"
|
||||
"\n"
|
||||
"The transformation is useful to scale to a specific database unit for example.\n"
|
||||
"\n"
|
||||
"@param shape_iterator The recursive shape iterator which delivers the hierarchy to take\n"
|
||||
"@param deep_shape_store The hierarchical heap (see there)\n"
|
||||
"@param area_ratio The maximum ratio of bounding box to polygon area before polygons are split\n"
|
||||
"@param trans The transformation to apply when storing the layout data\n"
|
||||
"\n"
|
||||
"This method has been introduced in version 0.26.\n"
|
||||
) +
|
||||
|
|
|
|||
|
|
@ -1198,19 +1198,19 @@ TEST(23_Texts)
|
|||
unsigned int l6 = ly.get_layer (db::LayerProperties (6, 1));
|
||||
unsigned int l8 = ly.get_layer (db::LayerProperties (8, 1));
|
||||
|
||||
db::Region r6boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_boxes ("*", true, 100, dss));
|
||||
db::Region r6boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_boxes ("*", true, 100, dss));
|
||||
db::Region r6dots;
|
||||
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_dots ("*", true, dss)).extended (r6dots, 20, 20, 20, 20);
|
||||
db::Region r8boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_boxes ("VDD", false, 100, dss));
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_dots ("*", true, dss)).extended (r6dots, 20, 20, 20, 20);
|
||||
db::Region r8boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_boxes ("VDD", false, 100, dss));
|
||||
db::Region r8dots;
|
||||
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_dots ("V*", true, dss)).extended (r8dots, 20, 20, 20, 20);
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_dots ("V*", true, dss)).extended (r8dots, 20, 20, 20, 20);
|
||||
|
||||
db::Region rf6boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_boxes ("*", true, 100));
|
||||
db::Region rf6boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_boxes ("*", true, 100));
|
||||
db::Region rf6dots;
|
||||
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_dots ("*", true)).extended (rf6dots, 20, 20, 20, 20);
|
||||
db::Region rf8boxes (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_boxes ("VDD", false, 100));
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6)).texts_as_dots ("*", true)).extended (rf6dots, 20, 20, 20, 20);
|
||||
db::Region rf8boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_boxes ("VDD", false, 100));
|
||||
db::Region rf8dots;
|
||||
db::Edges (db::OriginalLayerRegion (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_dots ("V*", true)).extended (rf8dots, 20, 20, 20, 20);
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8)).texts_as_dots ("V*", true)).extended (rf8dots, 20, 20, 20, 20);
|
||||
|
||||
{
|
||||
db::Layout target;
|
||||
|
|
@ -1230,6 +1230,59 @@ TEST(23_Texts)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(24_TextsFromDeep)
|
||||
{
|
||||
db::Layout ly;
|
||||
{
|
||||
std::string fn (tl::testsrc ());
|
||||
fn += "/testdata/algo/deep_region_l1.gds";
|
||||
tl::InputStream stream (fn);
|
||||
db::Reader reader (stream);
|
||||
reader.read (ly);
|
||||
}
|
||||
|
||||
db::cell_index_type top_cell_index = *ly.begin_top_down ();
|
||||
db::Cell &top_cell = ly.cell (top_cell_index);
|
||||
|
||||
db::DeepShapeStore dss;
|
||||
dss.set_text_enlargement (1);
|
||||
dss.set_text_property_name (tl::Variant ("textstring"));
|
||||
|
||||
unsigned int l6 = ly.get_layer (db::LayerProperties (6, 1));
|
||||
unsigned int l8 = ly.get_layer (db::LayerProperties (8, 1));
|
||||
|
||||
db::Region r6boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6), dss).texts_as_boxes ("*", true, 100, dss));
|
||||
db::Region r6dots;
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6), dss).texts_as_dots ("*", true, dss)).extended (r6dots, 20, 20, 20, 20);
|
||||
db::Region r8boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8), dss).texts_as_boxes ("VDD", false, 100, dss));
|
||||
db::Region r8dots;
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8), dss).texts_as_dots ("V*", true, dss)).extended (r8dots, 20, 20, 20, 20);
|
||||
|
||||
db::Region rf6boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6), dss).texts_as_boxes ("*", true, 100));
|
||||
db::Region rf6dots;
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l6), dss).texts_as_dots ("*", true)).extended (rf6dots, 20, 20, 20, 20);
|
||||
db::Region rf8boxes (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8), dss).texts_as_boxes ("VDD", false, 100));
|
||||
db::Region rf8dots;
|
||||
db::Edges (db::Region (db::RecursiveShapeIterator (ly, top_cell, l8), dss).texts_as_dots ("V*", true)).extended (rf8dots, 20, 20, 20, 20);
|
||||
|
||||
{
|
||||
db::Layout target;
|
||||
unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index));
|
||||
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (10, 0)), r6boxes);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (11, 0)), r6dots);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (12, 0)), rf6boxes);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (13, 0)), rf6dots);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (20, 0)), r8boxes);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (21, 0)), r8dots);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (22, 0)), rf8boxes);
|
||||
target.insert (target_top_cell_index, target.get_layer (db::LayerProperties (23, 0)), rf8dots);
|
||||
|
||||
CHECKPOINT();
|
||||
db::compare_layouts (_this, target, tl::testsrc () + "/testdata/algo/deep_region_au24.gds");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(100_Integration)
|
||||
{
|
||||
db::Layout ly;
|
||||
|
|
|
|||
|
|
@ -3488,10 +3488,21 @@ CODE
|
|||
# @li @tt METAL (17/0) @/tt: A layer named "METAL" or layer 17, datatype 0 (for GDS, which does
|
||||
# not have names)@/li
|
||||
# @/ul
|
||||
#
|
||||
# Layers created with "input" contain both texts and polygons. There is a subtle
|
||||
# difference between flat and deep mode: in flat mode, texts are not visible in polygon
|
||||
# operations. In deep mode, texts appear as small 2x2 DBU rectangles. In flat mode,
|
||||
# some operations such as clipping are not fully supported for texts. Also, texts will
|
||||
# vanish in most polygon operations such as booleans etc.
|
||||
#
|
||||
# Texts can alway be selected by using the \texts method.
|
||||
#
|
||||
# If you don't want to see texts, use \polygons to create an input layer with polygon data
|
||||
# only. If you only want to see texts, use \labels to create an input layer with texts only.
|
||||
|
||||
def input(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, false))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -3501,26 +3512,45 @@ CODE
|
|||
# @synopsis source.labels(layer, datatype)
|
||||
# @synopsis source.labels(layer_into)
|
||||
# @synopsis source.labels(filter, ...)
|
||||
# Creates a layer with the labels from the given layer of the source.
|
||||
# The layer can be specified by layer and optionally datatype, by a RBA::LayerInfo
|
||||
# object or by a sequence of filters.
|
||||
# Filters are expressions describing ranges
|
||||
# of layers and/or datatype numbers or layer names. Multiple filters
|
||||
# can be given and all layers matching at least one of these filter
|
||||
# expressions are joined to render the label collection. See "input" for
|
||||
# more details about the input layer specification.
|
||||
#
|
||||
# Label layers currently can only be passed to an output layer.
|
||||
# Processing of labels is not supported. See "texts" for a way to filter
|
||||
# texts and use the text locations in geometrical operations.
|
||||
#
|
||||
# @code
|
||||
# labels(1, 0).output(100, 0)
|
||||
# @/code
|
||||
# Creates a layer with the labels from the given layer of the source.
|
||||
#
|
||||
# This method is identical to \input, but takes only texts from the given input
|
||||
# layer.
|
||||
|
||||
def labels(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, true))
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::STexts))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name polygons
|
||||
# @brief Gets the polygon shapes (or shapes that can be converted polygons) from an input layer
|
||||
# @synopsis source.polygons(layer)
|
||||
# @synopsis source.polygons(layer, datatype)
|
||||
# @synopsis source.polygons(layer_into)
|
||||
# @synopsis source.polygons(filter, ...)
|
||||
#
|
||||
# Creates a layer with the polygon shapes from the given layer of the source.
|
||||
# With "polygon shapes" we mean all kind of shapes that can be converted to polygons.
|
||||
# Those are boxes, paths and real polygons.
|
||||
#
|
||||
# This method is identical to \input with respect to the options supported.
|
||||
|
||||
def polygons(*args)
|
||||
layers = parse_input_layers(*args)
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SBoxes | RBA::Shapes::SPaths | RBA::Shapes::SPolygons))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name make_layer
|
||||
# @brief Creates an empty polygon layer based on the hierarchy of the layout
|
||||
# @synopsis make_layer
|
||||
# This method delivers a new empty original layer.
|
||||
|
||||
def make_layer
|
||||
layers = []
|
||||
DRCLayer::new(@engine, @engine._cmd(@engine, :_input, @layout_var, @cell.cell_index, layers, @sel, @box, @clip, @overlapping, RBA::Shapes::SAll))
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
|
|
@ -3689,6 +3719,73 @@ CODE
|
|||
@connections << [ a, b ].collect { |l| l.data.data_id }
|
||||
modified
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name connect_global
|
||||
# @brief Connects a layer with a global net
|
||||
# @synopsis connect_global(l, name)
|
||||
# Connects the shapes from the given layer l to a global net with the given name.
|
||||
# Global nets are common to all cells. Global nets automatically connect to parent
|
||||
# cells throughs implied pins. An example is the substrate (bulk) net which connects
|
||||
# to shapes belonging to tie-down diodes.
|
||||
|
||||
def connect_global(l, name)
|
||||
l.is_a?(DRC::DRCLayer) || raise("Layer argument of Netter#connect_global must be a layer")
|
||||
l.requires_region("Netter#connect_global (layer argument)")
|
||||
@layers[l.data.data_id] = l.data
|
||||
@global_connections << [ l.data.data_id, name.to_s ]
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name extract_devices
|
||||
# @brief Extracts devices based on the given extractor class, name and device layer selection
|
||||
# @synopsis extract_devices(extractor, layer_hash)
|
||||
# Runs the device extraction for given device extractor class.
|
||||
#
|
||||
# The device extractor is either an instance of one of the predefined extractor
|
||||
# classes (e.g. RBA::DeviceExtractorMOS4Transistor) or a custom class. It provides the
|
||||
# algorithms for deriving the device parameters from the device geometry. It needs
|
||||
# several device recognition layers which are passed in the layer hash.
|
||||
#
|
||||
# Each device class (e.g. n-MOS/p-MOS or high Vt/low Vt) needs it's own instance
|
||||
# of device extractor. The device extractor beside the algorithm and specific
|
||||
# extraction settings defines the name of the device to be built.
|
||||
#
|
||||
# The layer hash is a map of device type specific functional names (key) and
|
||||
# polygon layers (value). Here is an example:
|
||||
#
|
||||
# @code
|
||||
# deep
|
||||
#
|
||||
# nwell = input(1, 0)
|
||||
# active = input(2, 0)
|
||||
# poly = input(3, 0)
|
||||
# bulk = make_layer # renders an empty layer used for putting the terminals on
|
||||
#
|
||||
# nactive = active - nwell # active area of NMOS
|
||||
# nsd = nactive - poly # source/drain area
|
||||
# gate = nactive & poly # gate area
|
||||
#
|
||||
# mos4_ex = RBA::DeviceExtractorMOS4Transistor::new("NMOS4")
|
||||
# extract_devices(mos4_ex, { :SD => nsd, :G => gate, :P => poly, :W => bulk })
|
||||
# @/code
|
||||
|
||||
def extract_devices(devex, layer_selection)
|
||||
|
||||
devex.is_a?(RBA::DeviceExtractorBase) || raise("First argument of Netter#extract_devices must be a device extractor instance")
|
||||
layer_selection.is_a?(Hash) || raise("Second argument of Netter#extract_devices must be a hash")
|
||||
|
||||
ls = {}
|
||||
layer_selection.each do |n,l|
|
||||
l.requires_region("Netter#extract_devices (#{n} layer)")
|
||||
@layers[l.data.data_id] = l.data
|
||||
ls[n.to_s] = l.data
|
||||
end
|
||||
|
||||
@devices_to_extract << [ devex, ls ]
|
||||
modified
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name clear_connections
|
||||
|
|
@ -3697,7 +3794,9 @@ CODE
|
|||
# See \connect for more details.
|
||||
|
||||
def clear_connections
|
||||
@devices_to_extract = []
|
||||
@connections = []
|
||||
@global_connections = []
|
||||
@layers = {}
|
||||
modified
|
||||
end
|
||||
|
|
@ -3803,6 +3902,18 @@ CODE
|
|||
DRC::DRCLayer::new(@engine, @engine._cmd(@l2n, :antenna_check, gate.data, metal.data, ratio, dl))
|
||||
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name l2n_data
|
||||
# @brief Gets the internal RBA::LayoutToNetlist object
|
||||
# @synopsis l2n_data
|
||||
# The RBA::LayoutToNetlist object provides access to the internal details of
|
||||
# the netter object.
|
||||
|
||||
def l2n_data
|
||||
@l2n || make_l2n
|
||||
@l2n
|
||||
end
|
||||
|
||||
def _finish
|
||||
clear_connections
|
||||
|
|
@ -3830,8 +3941,14 @@ CODE
|
|||
end
|
||||
|
||||
@layers.each { |id,l| @l2n.register(l, "l" + id.to_s) }
|
||||
|
||||
@devices_to_extract.each do |devex,ls|
|
||||
@engine._cmd(@l2n, :extract_devices, devex, ls)
|
||||
end
|
||||
|
||||
@layers.each { |id,l| @l2n.connect(l) }
|
||||
@connections.each { |a,b| @l2n.connect(@layers[a], @layers[b]) }
|
||||
@global_connections.each { |l,n| @l2n.connect_global(@layers[l], n) }
|
||||
|
||||
# run extraction in a timed environment
|
||||
@engine._cmd(@l2n, :extract_netlist)
|
||||
|
|
@ -4200,12 +4317,33 @@ CODE
|
|||
@tt = n.to_i
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name make_layer
|
||||
# @brief Creates an empty polygon layer based on the hierarchical scheme selected
|
||||
# @synopsis make_layer
|
||||
# The intention of this method is to provide an empty polygon layer based on the
|
||||
# hierarchical scheme selected. This will create a new layer with the hierarchy
|
||||
# of the current layout in deep mode and a flat layer in flat mode.
|
||||
# This method is similar to \polygon_layer, but the latter does not create
|
||||
# a hierarchical layer. Hence the layer created by \make_layer is suitable
|
||||
# for use in device extraction for example, while the one
|
||||
# delivered by \polygon_layer is not.
|
||||
#
|
||||
# On the other hand, a layer created by the \make_layer method is not intended to be
|
||||
# filled with \Layer#insert.
|
||||
|
||||
def make_layer
|
||||
layout.make_layer
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name polygon_layer
|
||||
# @brief Creates an empty polygon layer
|
||||
# @synopsis polygon_layer
|
||||
# The intention of that method is to create an empty layer which can be
|
||||
# filled with polygon-like objects using \Layer#insert.
|
||||
# A similar method which creates a hierarchical layer in deep mode is
|
||||
# \make_layer. This other layer is better suited for use with device extraction.
|
||||
|
||||
def polygon_layer
|
||||
DRCLayer::new(self, RBA::Region::new)
|
||||
|
|
@ -4621,12 +4759,24 @@ CODE
|
|||
# @name input
|
||||
# @brief Fetches the shapes from the specified input from the default source
|
||||
# @synopsis input(args)
|
||||
# See \Source#input for a description of that function.
|
||||
# See \Source#input for a description of that function. This method will fetch
|
||||
# polygons and labels. See \polygons and \labels for more specific versions of
|
||||
# this method.
|
||||
|
||||
def input(*args)
|
||||
layout.input(*args)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name polygons
|
||||
# @brief Fetches the polygons (or shapes that can be converted to polygons) from the specified input from the default source
|
||||
# @synopsis polygons(args)
|
||||
# See \Source#polygons for a description of that function.
|
||||
|
||||
def polygons(*args)
|
||||
layout.polygons(*args)
|
||||
end
|
||||
|
||||
# %DRC%
|
||||
# @name labels
|
||||
# @brief Gets the labels (text) from an original layer
|
||||
|
|
@ -4754,6 +4904,12 @@ CODE
|
|||
# @synopsis connect(a, b)
|
||||
# See \Netter#connect for a description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name connect_global
|
||||
# @brief Specifies a connection to a global net
|
||||
# @synopsis connect_global(l, name)
|
||||
# See \Netter#connect_global for a description of that function.
|
||||
|
||||
# %DRC%
|
||||
# @name clear_connections
|
||||
# @brief Clears all connections stored so far
|
||||
|
|
@ -4766,7 +4922,19 @@ CODE
|
|||
# @synopsis antenna_check(gate, metal, ratio, [ diode_specs ... ])
|
||||
# See \Netter#antenna_check for a description of that function
|
||||
|
||||
%w(connect clear_connections antenna_check).each do |f|
|
||||
# %DRC%
|
||||
# @name l2n_data
|
||||
# @brief Gets the internal RBA::LayoutToNetlist object for the default \Netter
|
||||
# @synopsis l2n_data
|
||||
# See \Netter#l2n_data for a description of that function
|
||||
|
||||
# %DRC%
|
||||
# @name extract_devices
|
||||
# @brief Extracts devices for a given device extractor and device layer selection
|
||||
# @synopsis extract_devices(extractor, layer_hash)
|
||||
# See \Netter#extract_devices for a description of that function
|
||||
|
||||
%w(connect connect_global clear_connections antenna_check l2n_data extract_devices).each do |f|
|
||||
eval <<"CODE"
|
||||
def #{f}(*args)
|
||||
_netter.#{f}(*args)
|
||||
|
|
@ -5033,10 +5201,12 @@ CODE
|
|||
end
|
||||
end
|
||||
|
||||
def _input(layout, cell_index, layers, sel, box, clip, overlapping, labels_only)
|
||||
def _input(layout, cell_index, layers, sel, box, clip, overlapping, shape_flags)
|
||||
|
||||
if layers.empty?
|
||||
if layers.empty? && ! @deep
|
||||
|
||||
r = RBA::Region::new
|
||||
|
||||
else
|
||||
|
||||
if box
|
||||
|
|
@ -5044,9 +5214,7 @@ CODE
|
|||
else
|
||||
iter = RBA::RecursiveShapeIterator::new(layout, layout.cell(cell_index), layers)
|
||||
end
|
||||
if labels_only
|
||||
iter.shape_flags = RBA::Shapes::STexts
|
||||
end
|
||||
iter.shape_flags = shape_flags
|
||||
|
||||
sel.each do |s|
|
||||
if s == "-"
|
||||
|
|
@ -5064,31 +5232,17 @@ CODE
|
|||
end
|
||||
end
|
||||
|
||||
if labels_only
|
||||
|
||||
# for labels layers, the iterator is the data (no region)
|
||||
r = iter
|
||||
|
||||
sf = layout.dbu / self.dbu
|
||||
if @deep
|
||||
@dss ||= RBA::DeepShapeStore::new
|
||||
r = RBA::Region::new(iter, @dss, RBA::ICplxTrans::new(sf.to_f))
|
||||
else
|
||||
r = RBA::Region::new(iter, RBA::ICplxTrans::new(sf.to_f))
|
||||
end
|
||||
|
||||
sf = layout.dbu / self.dbu
|
||||
if (sf - 1.0).abs > 1e-6
|
||||
if @deep
|
||||
raise("DBU scaling (" + ("%.12g" % layout.dbu) + " to " + ("%.12g" % self.dbu) + ") is not supported in deep mode currently")
|
||||
end
|
||||
r = RBA::Region::new(iter, RBA::ICplxTrans::new(sf.to_f))
|
||||
elsif @deep
|
||||
@dss ||= RBA::DeepShapeStore::new
|
||||
r = RBA::Region::new(iter, @dss)
|
||||
else
|
||||
r = RBA::Region::new(iter)
|
||||
end
|
||||
|
||||
# clip if a box is specified
|
||||
if box && clip
|
||||
r &= RBA::Region::new(box)
|
||||
end
|
||||
|
||||
# clip if a box is specified
|
||||
if box && clip
|
||||
r &= RBA::Region::new(box)
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -5112,11 +5266,7 @@ CODE
|
|||
cat = @output_rdb.create_category(args[0].to_s)
|
||||
args[1] && cat.description = args[1]
|
||||
|
||||
if data.is_a?(RBA::RecursiveShapeIterator)
|
||||
cat.scan_shapes(data)
|
||||
else
|
||||
cat.scan_collection(@output_rdb_cell, RBA::CplxTrans::new(self.dbu), data)
|
||||
end
|
||||
cat.scan_collection(@output_rdb_cell, RBA::CplxTrans::new(self.dbu), data)
|
||||
|
||||
else
|
||||
|
||||
|
|
@ -5173,24 +5323,11 @@ CODE
|
|||
@used_output_layers[li] = true
|
||||
end
|
||||
|
||||
if data.respond_to?(:is_deep?) && data.is_deep?
|
||||
|
||||
# insert the data into the output layer
|
||||
if data.is_a?(RBA::EdgePairs)
|
||||
data.insert_into_as_polygons(output, output_cell.cell_index, tmp, 1)
|
||||
else
|
||||
data.insert_into(output, output_cell.cell_index, tmp)
|
||||
end
|
||||
|
||||
# insert the data into the output layer
|
||||
if data.is_a?(RBA::EdgePairs)
|
||||
data.insert_into_as_polygons(output, output_cell.cell_index, tmp, 1)
|
||||
else
|
||||
|
||||
# insert the data into the output layer
|
||||
if data.is_a?(RBA::EdgePairs)
|
||||
output_cell.shapes(tmp).insert_as_polygons(data, 1)
|
||||
else
|
||||
output_cell.shapes(tmp).insert(data)
|
||||
end
|
||||
|
||||
data.insert_into(output, output_cell.cell_index, tmp)
|
||||
end
|
||||
|
||||
# make the temp layer the output layer
|
||||
|
|
|
|||
|
|
@ -302,3 +302,43 @@ TEST(7_AntennaWithDiodes)
|
|||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
TEST(8_FlatTextsAndPolygons)
|
||||
{
|
||||
std::string rs = tl::testsrc ();
|
||||
rs += "/testdata/drc/drcSimpleTests_8.drc";
|
||||
|
||||
std::string input = tl::testsrc ();
|
||||
input += "/testdata/drc/texts.gds";
|
||||
|
||||
std::string au = tl::testsrc ();
|
||||
au += "/testdata/drc/drcSimpleTests_au8.oas";
|
||||
|
||||
std::string output = this->tmp_file ("tmp.gds");
|
||||
|
||||
{
|
||||
// Set some variables
|
||||
lym::Macro config;
|
||||
config.set_text (tl::sprintf (
|
||||
"$drc_test_source = '%s'\n"
|
||||
"$drc_test_target = '%s'\n"
|
||||
, input, output)
|
||||
);
|
||||
config.set_interpreter (lym::Macro::Ruby);
|
||||
EXPECT_EQ (config.run (), 0);
|
||||
}
|
||||
|
||||
lym::Macro drc;
|
||||
drc.load_from (rs);
|
||||
EXPECT_EQ (drc.run (), 0);
|
||||
|
||||
db::Layout layout;
|
||||
|
||||
{
|
||||
tl::InputStream stream (output);
|
||||
db::Reader reader (stream);
|
||||
reader.read (layout);
|
||||
}
|
||||
|
||||
db::compare_layouts (_this, layout, au, db::NoNormalization);
|
||||
}
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue